Skip to content

Commit 9223ac5

Browse files
authored
Merge pull request #33 from vtex-apps/feat/css-handles-modals
Add CSS handles for modal components
2 parents 0815dac + 18d0ee4 commit 9223ac5

6 files changed

Lines changed: 117 additions & 62 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- CSS handles for `UnavailableItemsModal`, `AddLocation`, and `ProductItem` components to enable theme customization.
13+
1014
## [1.3.0] - 2026-07-08
1115

1216
### Added

docs/README.md

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -127,41 +127,50 @@ The default `PickupModal` block is wired to `DeliveryPromiseProvider` and sessio
127127

128128
In order to apply CSS customizations in this and other blocks, follow the instructions given in the recipe on [Using CSS Handles for store customization](https://vtex.io/docs/recipes/style/using-css-handles-for-store-customization).
129129

130-
| CSS Handles |
131-
| ---------------------------------------- |
132-
| `shopperLocationSetterButtonLabel` |
133-
| `shopperLocationSetterButtonValue` |
134-
| `shopperLocationSetterButtonWrapper` |
135-
| `shopperLocationSetterContainer` |
136-
| `shopperLocationPopover` |
137-
| `shopperLocationPopoverArrow` |
138-
| `shopperLocationPopoverInputContainer` |
139-
| `shippingMethodSelector` |
140-
| `shippingMethodSelectorLabel` |
141-
| `shippingMethodSelectorLabelLimited` |
142-
| `shippingMethodOptionButton` |
143-
| `shippingMethodOptionButtonSelected` |
144-
| `shippingMethodModalOptions` |
145-
| `shopperLocationDetectorButton` |
146-
| `shopperLocationDetectorButtonContainer` |
147-
| `shopperLocationDetectorButtonIcon` |
148-
| `noPickupPointStateContent` |
149-
| `pickupPointItem` |
150-
| `pickupPointItemSelected` |
151-
| `postalCodeHelpLink` |
152-
| `postalCodeInputClearButton` |
153-
| `postalCodeInputContainer` |
154-
| `shopperLocationPopoverText` |
155-
| `pickupPointIconPath` |
156-
| `pickupPointIconSVG` |
157-
| `pickupPointSelectorButtonValue` |
158-
| `pickupPointSelectorButtonWrapper` |
159-
| `pickupPointSelectorContainer` |
160-
| `shopperLocationPinIconPath` |
161-
| `shopperLocationPinIconSVG` |
162-
| `updateButtonContainer` |
163-
| `clearButton` |
164-
| `updateButton` |
130+
| CSS Handles |
131+
| -------------------------------------------- |
132+
| `shopperLocationSetterButtonLabel` |
133+
| `shopperLocationSetterButtonValue` |
134+
| `shopperLocationSetterButtonWrapper` |
135+
| `shopperLocationSetterContainer` |
136+
| `shopperLocationPopover` |
137+
| `shopperLocationPopoverArrow` |
138+
| `shopperLocationPopoverInputContainer` |
139+
| `shippingMethodSelector` |
140+
| `shippingMethodSelectorLabel` |
141+
| `shippingMethodSelectorLabelLimited` |
142+
| `shippingMethodOptionButton` |
143+
| `shippingMethodOptionButtonSelected` |
144+
| `shippingMethodModalOptions` |
145+
| `shopperLocationDetectorButton` |
146+
| `shopperLocationDetectorButtonContainer` |
147+
| `shopperLocationDetectorButtonIcon` |
148+
| `noPickupPointStateContent` |
149+
| `pickupPointItem` |
150+
| `pickupPointItemSelected` |
151+
| `postalCodeHelpLink` |
152+
| `postalCodeInputClearButton` |
153+
| `postalCodeInputContainer` |
154+
| `shopperLocationPopoverText` |
155+
| `pickupPointIconPath` |
156+
| `pickupPointIconSVG` |
157+
| `pickupPointSelectorButtonValue` |
158+
| `pickupPointSelectorButtonWrapper` |
159+
| `pickupPointSelectorContainer` |
160+
| `shopperLocationPinIconPath` |
161+
| `shopperLocationPinIconSVG` |
162+
| `shopperLocationModalContainer` |
163+
| `shopperLocationModalDescription` |
164+
| `shopperLocationModalSubmitButtonContainer` |
165+
| `unavailableItemsModalContainer` |
166+
| `unavailableItemsModalMessage` |
167+
| `unavailableItemsModalList` |
168+
| `unavailableItemsModalProductItem` |
169+
| `unavailableItemsModalRemoveButtonContainer` |
170+
| `unavailableItemsModalRetryButtonContainer` |
171+
| `updateButtonContainer` |
172+
| `clearButton` |
173+
| `updateButton` |
165174

166175
<!-- DOCS-IGNORE:start -->
167176

manifest.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@
2121
"vtex.order-items": "0.x",
2222
"vtex.session-client": "1.x"
2323
},
24-
"registries": [
25-
"smartcheckout"
26-
],
24+
"registries": ["smartcheckout"],
2725
"policies": [],
2826
"$schema": "https://raw.githubusercontent.com/vtex/node-vtex-api/master/gen/manifest.schema"
2927
}

react/components/ShopperLocationModal/AddLocation.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
import React from 'react'
22
import { Button } from 'vtex.styleguide'
3+
import { useCssHandles } from 'vtex.css-handles'
34
import { useIntl } from 'react-intl'
45

56
import PostalCodeInput from '../PostalCodeInput'
67
import messages from '../../messages'
78
import PostalCodeHelpLink from '../PostalCodeHelpLink'
89
import ShopperLocationDetectorButton from '../ShopperLocationDetectorButton'
910

11+
const CSS_HANDLES = [
12+
'shopperLocationModalContainer',
13+
'shopperLocationModalDescription',
14+
'shopperLocationModalSubmitButtonContainer',
15+
] as const
16+
1017
interface AddLocationProps {
1118
onSubmit: (zipcode: string) => void
1219
onChange: (zipCode: string) => void
@@ -25,10 +32,13 @@ const AddLocation = ({
2532
showLocationDetectorButton,
2633
}: AddLocationProps) => {
2734
const intl = useIntl()
35+
const handles = useCssHandles(CSS_HANDLES)
2836

2937
return (
30-
<div className="flex-auto flex flex-column justify-between mt0">
31-
<p className="mid-gray ma0">
38+
<div
39+
className={`flex-auto flex flex-column justify-between mt0 ${handles.shopperLocationModalContainer}`}
40+
>
41+
<p className={`mid-gray ma0 ${handles.shopperLocationModalDescription}`}>
3242
{intl.formatMessage(messages.shopperLocationModalDescription)}
3343
</p>
3444

@@ -47,9 +57,11 @@ const AddLocation = ({
4757
</div>
4858
</div>
4959

50-
<Button isLoading={isLoading} onClick={() => onSubmit(zipcode)}>
51-
{intl.formatMessage(messages.shopperLocationPopoverSubmitButtonLabel)}
52-
</Button>
60+
<div className={handles.shopperLocationModalSubmitButtonContainer}>
61+
<Button block isLoading={isLoading} onClick={() => onSubmit(zipcode)}>
62+
{intl.formatMessage(messages.shopperLocationPopoverSubmitButtonLabel)}
63+
</Button>
64+
</div>
5365
{showLocationDetectorButton && <ShopperLocationDetectorButton />}
5466
</div>
5567
)

react/components/UnavailableItemsModal/ProductItem.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
import React from 'react'
2+
import { useCssHandles } from 'vtex.css-handles'
3+
4+
const CSS_HANDLES = ['unavailableItemsModalProductItem'] as const
25

36
interface Props {
47
imageUrl: string
58
productName: string
69
}
710

811
const ProductItem = ({ imageUrl, productName }: Props) => {
12+
const handles = useCssHandles(CSS_HANDLES)
13+
914
return (
10-
<div className="flex flex-row pa5 bg-base t-body c-on-base br3 b--muted-4 ba mb5">
15+
<div
16+
className={`flex flex-row pa5 bg-base t-body c-on-base br3 b--muted-4 ba mb5 ${handles.unavailableItemsModalProductItem}`}
17+
>
1118
<img
1219
className="br2"
1320
style={{ width: '64px', height: '64px' }}

react/components/UnavailableItemsModal/index.tsx

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
/* eslint-disable no-restricted-globals */
22
import React, { useEffect, useState } from 'react'
33
import { Button } from 'vtex.styleguide'
4+
import { useCssHandles } from 'vtex.css-handles'
45
import { useIntl } from 'react-intl'
56

67
import Modal from '../Modal'
78
import ProductItem from './ProductItem'
89
import messages from '../../messages'
910

11+
const CSS_HANDLES = [
12+
'unavailableItemsModalContainer',
13+
'unavailableItemsModalMessage',
14+
'unavailableItemsModalList',
15+
'unavailableItemsModalRemoveButtonContainer',
16+
'unavailableItemsModalRetryButtonContainer',
17+
] as const
18+
1019
export type CartProduct = { id: string; name: string; imageUrl: string }
1120

1221
export type CartItem = {
@@ -32,6 +41,7 @@ const UnavailableItemsModal = ({
3241
unavailabilityMessage,
3342
}: Props) => {
3443
const intl = useIntl()
44+
const handles = useCssHandles(CSS_HANDLES)
3545

3646
const [isLoading, setIsLoading] = useState(false)
3747

@@ -62,9 +72,15 @@ const UnavailableItemsModal = ({
6272
nonDismissible
6373
overlayZIndex={100000}
6474
>
65-
<div className="flex-auto flex flex-column justify-between mt0">
66-
<p className="mid-gray ma0">{unavailabilityMessage}</p>
67-
<div className="mv7 overflow-auto">
75+
<div
76+
className={`flex-auto flex flex-column justify-between mt0 ${handles.unavailableItemsModalContainer}`}
77+
>
78+
<p className={`mid-gray ma0 ${handles.unavailableItemsModalMessage}`}>
79+
{unavailabilityMessage}
80+
</p>
81+
<div
82+
className={`mv7 overflow-auto ${handles.unavailableItemsModalList}`}
83+
>
6884
{unavailableCartItems.map(({ product }) => (
6985
<ProductItem
7086
key={product.id}
@@ -74,22 +90,31 @@ const UnavailableItemsModal = ({
7490
))}
7591
</div>
7692
<div style={{ gap: '.75rem' }} className="flex flex-column">
77-
<Button
78-
className="mb3"
79-
isLoading={isLoading}
80-
onClick={handleRemoveItemsClick}
81-
>
82-
{intl.formatMessage(
83-
messages.unavailableItemsModalRemoveButtonLabel
84-
)}
85-
</Button>
86-
<Button
87-
isLoading={isLoading}
88-
variation="secondary"
89-
onClick={onTryAgain}
93+
<div
94+
className={`mb3 ${handles.unavailableItemsModalRemoveButtonContainer}`}
9095
>
91-
{intl.formatMessage(messages.unavailableItemsModalRetryButtonLabel)}
92-
</Button>
96+
<Button
97+
block
98+
isLoading={isLoading}
99+
onClick={handleRemoveItemsClick}
100+
>
101+
{intl.formatMessage(
102+
messages.unavailableItemsModalRemoveButtonLabel
103+
)}
104+
</Button>
105+
</div>
106+
<div className={handles.unavailableItemsModalRetryButtonContainer}>
107+
<Button
108+
block
109+
isLoading={isLoading}
110+
variation="secondary"
111+
onClick={onTryAgain}
112+
>
113+
{intl.formatMessage(
114+
messages.unavailableItemsModalRetryButtonLabel
115+
)}
116+
</Button>
117+
</div>
93118
</div>
94119
</div>
95120
</Modal>

0 commit comments

Comments
 (0)