@faststore/components 3.41.3 → 3.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/hooks/UIProvider.d.ts +10 -1
- package/dist/cjs/hooks/UIProvider.js +24 -0
- package/dist/cjs/hooks/UIProvider.js.map +1 -1
- package/dist/cjs/hooks/index.d.ts +2 -1
- package/dist/cjs/hooks/index.js +5 -3
- package/dist/cjs/hooks/index.js.map +1 -1
- package/dist/cjs/hooks/useOnClickOutside.d.ts +4 -0
- package/dist/cjs/hooks/useOnClickOutside.js +33 -0
- package/dist/cjs/hooks/useOnClickOutside.js.map +1 -0
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.js +4 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/molecules/Modal/Modal.d.ts +14 -6
- package/dist/cjs/molecules/Modal/Modal.js +13 -4
- package/dist/cjs/molecules/Modal/Modal.js.map +1 -1
- package/dist/cjs/molecules/Popover/Popover.d.ts +67 -0
- package/dist/cjs/molecules/Popover/Popover.js +65 -0
- package/dist/cjs/molecules/Popover/Popover.js.map +1 -0
- package/dist/cjs/molecules/Popover/index.d.ts +2 -0
- package/dist/cjs/molecules/Popover/index.js +9 -0
- package/dist/cjs/molecules/Popover/index.js.map +1 -0
- package/dist/cjs/molecules/RegionBar/RegionBar.d.ts +13 -4
- package/dist/cjs/molecules/RegionBar/RegionBar.js +5 -3
- package/dist/cjs/molecules/RegionBar/RegionBar.js.map +1 -1
- package/dist/cjs/molecules/SearchProducts/SearchProductItemContent.d.ts +24 -0
- package/dist/cjs/molecules/SearchProducts/SearchProductItemContent.js +9 -3
- package/dist/cjs/molecules/SearchProducts/SearchProductItemContent.js.map +1 -1
- package/dist/cjs/molecules/SearchProducts/SearchProductItemControl.d.ts +50 -0
- package/dist/cjs/molecules/SearchProducts/SearchProductItemControl.js +62 -0
- package/dist/cjs/molecules/SearchProducts/SearchProductItemControl.js.map +1 -0
- package/dist/cjs/organisms/RegionModal/RegionModal.d.ts +10 -1
- package/dist/cjs/organisms/RegionModal/RegionModal.js +15 -8
- package/dist/cjs/organisms/RegionModal/RegionModal.js.map +1 -1
- package/dist/cjs/organisms/SKUMatrix/SKUMatrixSidebar.js +1 -1
- package/dist/cjs/organisms/SKUMatrix/SKUMatrixSidebar.js.map +1 -1
- package/dist/cjs/organisms/ShippingSimulation/ShippingSimulation.d.ts +2 -2
- package/dist/esm/hooks/UIProvider.d.ts +10 -1
- package/dist/esm/hooks/UIProvider.js +24 -0
- package/dist/esm/hooks/UIProvider.js.map +1 -1
- package/dist/esm/hooks/index.d.ts +2 -1
- package/dist/esm/hooks/index.js +2 -1
- package/dist/esm/hooks/index.js.map +1 -1
- package/dist/esm/hooks/useOnClickOutside.d.ts +4 -0
- package/dist/esm/hooks/useOnClickOutside.js +29 -0
- package/dist/esm/hooks/useOnClickOutside.js.map +1 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/molecules/Modal/Modal.d.ts +14 -6
- package/dist/esm/molecules/Modal/Modal.js +13 -4
- package/dist/esm/molecules/Modal/Modal.js.map +1 -1
- package/dist/esm/molecules/Popover/Popover.d.ts +67 -0
- package/dist/esm/molecules/Popover/Popover.js +62 -0
- package/dist/esm/molecules/Popover/Popover.js.map +1 -0
- package/dist/esm/molecules/Popover/index.d.ts +2 -0
- package/dist/esm/molecules/Popover/index.js +2 -0
- package/dist/esm/molecules/Popover/index.js.map +1 -0
- package/dist/esm/molecules/RegionBar/RegionBar.d.ts +13 -4
- package/dist/esm/molecules/RegionBar/RegionBar.js +5 -3
- package/dist/esm/molecules/RegionBar/RegionBar.js.map +1 -1
- package/dist/esm/molecules/SearchProducts/SearchProductItemContent.d.ts +24 -0
- package/dist/esm/molecules/SearchProducts/SearchProductItemContent.js +10 -4
- package/dist/esm/molecules/SearchProducts/SearchProductItemContent.js.map +1 -1
- package/dist/esm/molecules/SearchProducts/SearchProductItemControl.d.ts +50 -0
- package/dist/esm/molecules/SearchProducts/SearchProductItemControl.js +59 -0
- package/dist/esm/molecules/SearchProducts/SearchProductItemControl.js.map +1 -0
- package/dist/esm/organisms/RegionModal/RegionModal.d.ts +10 -1
- package/dist/esm/organisms/RegionModal/RegionModal.js +15 -8
- package/dist/esm/organisms/RegionModal/RegionModal.js.map +1 -1
- package/dist/esm/organisms/SKUMatrix/SKUMatrixSidebar.js +1 -1
- package/dist/esm/organisms/SKUMatrix/SKUMatrixSidebar.js.map +1 -1
- package/dist/esm/organisms/ShippingSimulation/ShippingSimulation.d.ts +2 -2
- package/package.json +2 -2
- package/src/hooks/UIProvider.tsx +48 -1
- package/src/hooks/index.ts +2 -1
- package/src/hooks/useOnClickOutside.ts +40 -0
- package/src/index.ts +2 -0
- package/src/molecules/Modal/Modal.tsx +29 -8
- package/src/molecules/Popover/Popover.tsx +209 -0
- package/src/molecules/Popover/index.tsx +2 -0
- package/src/molecules/RegionBar/RegionBar.tsx +21 -5
- package/src/molecules/SearchProducts/SearchProductItemContent.tsx +61 -10
- package/src/molecules/SearchProducts/SearchProductItemControl.tsx +199 -0
- package/src/organisms/RegionModal/RegionModal.tsx +29 -7
- package/src/organisms/SKUMatrix/SKUMatrixSidebar.tsx +1 -1
- package/src/organisms/ShippingSimulation/ShippingSimulation.tsx +2 -2
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
forwardRef,
|
|
3
|
+
type HTMLAttributes,
|
|
4
|
+
useCallback,
|
|
5
|
+
useState,
|
|
6
|
+
} from 'react'
|
|
7
|
+
import { Badge, Icon, IconButton, Input, Loader, QuantitySelector } from '../..'
|
|
8
|
+
|
|
9
|
+
import type { MouseEvent, ReactNode } from 'react'
|
|
10
|
+
|
|
11
|
+
type StatusButtonAddToCartType = 'default' | 'inProgress' | 'completed'
|
|
12
|
+
|
|
13
|
+
export interface SearchProductItemControlProps
|
|
14
|
+
extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'onClick'> {
|
|
15
|
+
/**
|
|
16
|
+
* Renders child elements.
|
|
17
|
+
*/
|
|
18
|
+
children: ReactNode
|
|
19
|
+
/**
|
|
20
|
+
* Specifies the label for out-of-stock products.
|
|
21
|
+
*/
|
|
22
|
+
outOfStockLabel: string
|
|
23
|
+
/**
|
|
24
|
+
* Specifies whether the product is available.
|
|
25
|
+
*/
|
|
26
|
+
availability: boolean
|
|
27
|
+
/**
|
|
28
|
+
* Specifies whether the product has variations.
|
|
29
|
+
*/
|
|
30
|
+
hasVariants: boolean
|
|
31
|
+
/**
|
|
32
|
+
* Renders the elements of the SKUMatrix.
|
|
33
|
+
*/
|
|
34
|
+
skuMatrixControl: ReactNode
|
|
35
|
+
/**
|
|
36
|
+
* The maximum value the input can receive
|
|
37
|
+
*/
|
|
38
|
+
max?: number
|
|
39
|
+
/**
|
|
40
|
+
* The minimum value the input can receive
|
|
41
|
+
*/
|
|
42
|
+
min?: number
|
|
43
|
+
/**
|
|
44
|
+
* Specifies the quantity to be added to the cart.
|
|
45
|
+
*/
|
|
46
|
+
quantity: number
|
|
47
|
+
/**
|
|
48
|
+
* Callback that fires when the add to cart button is clicked.
|
|
49
|
+
*/
|
|
50
|
+
onClick?: (e: MouseEvent<HTMLButtonElement>) => void
|
|
51
|
+
/**
|
|
52
|
+
* Callback that fires when the input value changes.
|
|
53
|
+
*/
|
|
54
|
+
onChangeQuantity: (value: number) => void
|
|
55
|
+
/**
|
|
56
|
+
* Event emitted when value is out of the min and max bounds
|
|
57
|
+
*/
|
|
58
|
+
onValidateBlur?: (min: number, maxValue: number, quantity: number) => void
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const SearchProductItemControl = forwardRef<
|
|
62
|
+
HTMLDivElement,
|
|
63
|
+
SearchProductItemControlProps
|
|
64
|
+
>(function SearchProductItemControl(
|
|
65
|
+
{
|
|
66
|
+
availability,
|
|
67
|
+
children,
|
|
68
|
+
hasVariants,
|
|
69
|
+
skuMatrixControl,
|
|
70
|
+
quantity,
|
|
71
|
+
outOfStockLabel,
|
|
72
|
+
min = 1,
|
|
73
|
+
max = undefined,
|
|
74
|
+
onClick,
|
|
75
|
+
onChangeQuantity,
|
|
76
|
+
onValidateBlur,
|
|
77
|
+
...otherProps
|
|
78
|
+
},
|
|
79
|
+
ref
|
|
80
|
+
) {
|
|
81
|
+
const [statusAddToCart, setStatusAddToCart] =
|
|
82
|
+
useState<StatusButtonAddToCartType>('default')
|
|
83
|
+
|
|
84
|
+
const showSKUMatrixControl = availability && hasVariants
|
|
85
|
+
|
|
86
|
+
function stopPropagationClick(e: MouseEvent) {
|
|
87
|
+
e.preventDefault()
|
|
88
|
+
e.stopPropagation()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function handleAddToCart(event: MouseEvent<HTMLButtonElement>) {
|
|
92
|
+
if (onClick) {
|
|
93
|
+
setStatusAddToCart('inProgress')
|
|
94
|
+
|
|
95
|
+
setTimeout(() => {
|
|
96
|
+
setStatusAddToCart('completed')
|
|
97
|
+
onClick(event)
|
|
98
|
+
}, 1000)
|
|
99
|
+
|
|
100
|
+
setTimeout(() => {
|
|
101
|
+
setStatusAddToCart('default')
|
|
102
|
+
onChangeQuantity(1)
|
|
103
|
+
}, 2000)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const getIcon = useCallback(() => {
|
|
108
|
+
switch (statusAddToCart) {
|
|
109
|
+
case 'inProgress':
|
|
110
|
+
return <Loader />
|
|
111
|
+
case 'completed':
|
|
112
|
+
return <Icon name="Checked" width={24} height={24} />
|
|
113
|
+
default:
|
|
114
|
+
return <Icon name="ShoppingCart" width={24} height={24} />
|
|
115
|
+
}
|
|
116
|
+
}, [statusAddToCart])
|
|
117
|
+
|
|
118
|
+
function validateBlur() {
|
|
119
|
+
const maxValue = max ?? (min ? Math.max(quantity, min) : quantity)
|
|
120
|
+
const isOutOfBounds = quantity > maxValue || quantity < min
|
|
121
|
+
const minQuantity = quantity < min ? min : quantity
|
|
122
|
+
const realQuantity = quantity > maxValue ? maxValue : minQuantity
|
|
123
|
+
|
|
124
|
+
if (isOutOfBounds) {
|
|
125
|
+
onValidateBlur?.(min, maxValue, realQuantity)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
onChangeQuantity(realQuantity)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<div ref={ref} data-fs-search-product-item-control {...otherProps}>
|
|
133
|
+
<div data-fs-search-product-item-control-content>
|
|
134
|
+
{!availability && (
|
|
135
|
+
<Badge data-fs-search-product-item-control-badge variant="warning">
|
|
136
|
+
{outOfStockLabel}
|
|
137
|
+
</Badge>
|
|
138
|
+
)}
|
|
139
|
+
{children}
|
|
140
|
+
</div>
|
|
141
|
+
{availability && !hasVariants && (
|
|
142
|
+
<div
|
|
143
|
+
data-fs-search-product-item-control-actions
|
|
144
|
+
role="group"
|
|
145
|
+
aria-hidden={true}
|
|
146
|
+
tabIndex={-1}
|
|
147
|
+
onKeyDown={() => {}}
|
|
148
|
+
onClick={stopPropagationClick}
|
|
149
|
+
>
|
|
150
|
+
<div data-fs-search-product-item-control-actions-desktop>
|
|
151
|
+
<QuantitySelector
|
|
152
|
+
disabled={statusAddToCart !== 'default'}
|
|
153
|
+
max={max}
|
|
154
|
+
onValidateBlur={onValidateBlur}
|
|
155
|
+
initial={quantity}
|
|
156
|
+
onChange={onChangeQuantity}
|
|
157
|
+
/>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<div data-fs-search-product-item-control-actions-mobile>
|
|
161
|
+
<Input
|
|
162
|
+
data-fs-product-item-control-input
|
|
163
|
+
min={1}
|
|
164
|
+
value={quantity}
|
|
165
|
+
onChange={(e) =>
|
|
166
|
+
onChangeQuantity(e.target.value ? Number(e.target.value) : 0)
|
|
167
|
+
}
|
|
168
|
+
onBlur={validateBlur}
|
|
169
|
+
onInput={(event: React.FormEvent<HTMLInputElement>) => {
|
|
170
|
+
const input = event.currentTarget
|
|
171
|
+
input.value = input.value.replace(/\D/g, '')
|
|
172
|
+
}}
|
|
173
|
+
/>
|
|
174
|
+
</div>
|
|
175
|
+
|
|
176
|
+
<IconButton
|
|
177
|
+
variant="primary"
|
|
178
|
+
aria-label="Add product to cart"
|
|
179
|
+
onClick={handleAddToCart}
|
|
180
|
+
disabled={statusAddToCart === 'inProgress'}
|
|
181
|
+
icon={getIcon()}
|
|
182
|
+
/>
|
|
183
|
+
</div>
|
|
184
|
+
)}
|
|
185
|
+
|
|
186
|
+
{showSKUMatrixControl && (
|
|
187
|
+
<div
|
|
188
|
+
onClick={stopPropagationClick}
|
|
189
|
+
aria-hidden={true}
|
|
190
|
+
tabIndex={-1}
|
|
191
|
+
onKeyDown={() => {}}
|
|
192
|
+
>
|
|
193
|
+
{skuMatrixControl}
|
|
194
|
+
</div>
|
|
195
|
+
)}
|
|
196
|
+
</div>
|
|
197
|
+
)
|
|
198
|
+
})
|
|
199
|
+
export default SearchProductItemControl
|
|
@@ -51,6 +51,10 @@ export interface RegionModalProps extends Omit<ModalProps, 'children'> {
|
|
|
51
51
|
* Postal code input's label.
|
|
52
52
|
*/
|
|
53
53
|
inputLabel?: string
|
|
54
|
+
/**
|
|
55
|
+
* The text displayed on the InputField Button. Suggestion: maximum 9 characters.
|
|
56
|
+
*/
|
|
57
|
+
inputButtonActionText?: string
|
|
54
58
|
/**
|
|
55
59
|
* Enables fadeOut effect on modal after onSubmit function
|
|
56
60
|
*/
|
|
@@ -75,24 +79,31 @@ export interface RegionModalProps extends Omit<ModalProps, 'children'> {
|
|
|
75
79
|
* Callback function when the input clear button is clicked.
|
|
76
80
|
*/
|
|
77
81
|
onClear?: () => void
|
|
82
|
+
/**
|
|
83
|
+
* Determines if the modal can be dismissed using the close button or the Escape key.
|
|
84
|
+
* @default true
|
|
85
|
+
*/
|
|
86
|
+
dismissible?: boolean
|
|
78
87
|
}
|
|
79
88
|
|
|
80
89
|
function RegionModal({
|
|
81
90
|
testId = 'fs-region-modal',
|
|
82
91
|
title = 'Set your location',
|
|
83
|
-
description = '
|
|
92
|
+
description = 'Offers and availability vary by location.',
|
|
84
93
|
closeButtonAriaLabel = 'Close Region Modal',
|
|
85
94
|
idkPostalCodeLinkProps,
|
|
86
95
|
errorMessage,
|
|
87
96
|
inputRef,
|
|
88
97
|
inputValue,
|
|
89
98
|
inputLabel = 'Postal Code',
|
|
99
|
+
inputButtonActionText = 'Apply',
|
|
90
100
|
fadeOutOnSubmit,
|
|
91
101
|
overlayProps,
|
|
92
102
|
onClose,
|
|
93
103
|
onInput,
|
|
94
104
|
onSubmit,
|
|
95
105
|
onClear,
|
|
106
|
+
dismissible = true,
|
|
96
107
|
...otherProps
|
|
97
108
|
}: RegionModalProps) {
|
|
98
109
|
return (
|
|
@@ -102,15 +113,24 @@ function RegionModal({
|
|
|
102
113
|
overlayProps={overlayProps}
|
|
103
114
|
title="Region modal"
|
|
104
115
|
aria-label="Region modal"
|
|
116
|
+
disableEscapeKeyDown={!dismissible}
|
|
117
|
+
onEntered={() => {
|
|
118
|
+
if (inputRef?.current) {
|
|
119
|
+
inputRef.current.focus()
|
|
120
|
+
}
|
|
121
|
+
}}
|
|
105
122
|
{...otherProps}
|
|
106
123
|
>
|
|
107
124
|
{({ fadeOut }) => (
|
|
108
125
|
<>
|
|
109
126
|
<ModalHeader
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
127
|
+
{...(dismissible && {
|
|
128
|
+
onClose: () => {
|
|
129
|
+
fadeOut()
|
|
130
|
+
onClear?.()
|
|
131
|
+
onClose?.()
|
|
132
|
+
},
|
|
133
|
+
})}
|
|
114
134
|
title={title}
|
|
115
135
|
description={description}
|
|
116
136
|
closeBtnProps={{
|
|
@@ -125,6 +145,7 @@ function RegionModal({
|
|
|
125
145
|
label={inputLabel}
|
|
126
146
|
actionable
|
|
127
147
|
value={inputValue}
|
|
148
|
+
buttonActionText={inputButtonActionText}
|
|
128
149
|
onInput={(event) => onInput?.(event)}
|
|
129
150
|
onSubmit={() => {
|
|
130
151
|
onSubmit?.()
|
|
@@ -133,8 +154,9 @@ function RegionModal({
|
|
|
133
154
|
onClear={() => onClear?.()}
|
|
134
155
|
error={errorMessage}
|
|
135
156
|
/>
|
|
136
|
-
|
|
137
|
-
|
|
157
|
+
{idkPostalCodeLinkProps && (
|
|
158
|
+
<Link data-fs-region-modal-link {...idkPostalCodeLinkProps} />
|
|
159
|
+
)}
|
|
138
160
|
</ModalBody>
|
|
139
161
|
</>
|
|
140
162
|
)}
|
|
@@ -69,9 +69,9 @@ interface Address {
|
|
|
69
69
|
*/
|
|
70
70
|
reference?: string
|
|
71
71
|
/**
|
|
72
|
-
* Address geoCoordinates
|
|
72
|
+
* Address geoCoordinates. [longitude, latitude]
|
|
73
73
|
*/
|
|
74
|
-
geoCoordinates?: [number]
|
|
74
|
+
geoCoordinates?: [number, number]
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
export interface ShippingSimulationProps
|