@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.
Files changed (86) hide show
  1. package/dist/cjs/hooks/UIProvider.d.ts +10 -1
  2. package/dist/cjs/hooks/UIProvider.js +24 -0
  3. package/dist/cjs/hooks/UIProvider.js.map +1 -1
  4. package/dist/cjs/hooks/index.d.ts +2 -1
  5. package/dist/cjs/hooks/index.js +5 -3
  6. package/dist/cjs/hooks/index.js.map +1 -1
  7. package/dist/cjs/hooks/useOnClickOutside.d.ts +4 -0
  8. package/dist/cjs/hooks/useOnClickOutside.js +33 -0
  9. package/dist/cjs/hooks/useOnClickOutside.js.map +1 -0
  10. package/dist/cjs/index.d.ts +2 -0
  11. package/dist/cjs/index.js +4 -2
  12. package/dist/cjs/index.js.map +1 -1
  13. package/dist/cjs/molecules/Modal/Modal.d.ts +14 -6
  14. package/dist/cjs/molecules/Modal/Modal.js +13 -4
  15. package/dist/cjs/molecules/Modal/Modal.js.map +1 -1
  16. package/dist/cjs/molecules/Popover/Popover.d.ts +67 -0
  17. package/dist/cjs/molecules/Popover/Popover.js +65 -0
  18. package/dist/cjs/molecules/Popover/Popover.js.map +1 -0
  19. package/dist/cjs/molecules/Popover/index.d.ts +2 -0
  20. package/dist/cjs/molecules/Popover/index.js +9 -0
  21. package/dist/cjs/molecules/Popover/index.js.map +1 -0
  22. package/dist/cjs/molecules/RegionBar/RegionBar.d.ts +13 -4
  23. package/dist/cjs/molecules/RegionBar/RegionBar.js +5 -3
  24. package/dist/cjs/molecules/RegionBar/RegionBar.js.map +1 -1
  25. package/dist/cjs/molecules/SearchProducts/SearchProductItemContent.d.ts +24 -0
  26. package/dist/cjs/molecules/SearchProducts/SearchProductItemContent.js +9 -3
  27. package/dist/cjs/molecules/SearchProducts/SearchProductItemContent.js.map +1 -1
  28. package/dist/cjs/molecules/SearchProducts/SearchProductItemControl.d.ts +50 -0
  29. package/dist/cjs/molecules/SearchProducts/SearchProductItemControl.js +62 -0
  30. package/dist/cjs/molecules/SearchProducts/SearchProductItemControl.js.map +1 -0
  31. package/dist/cjs/organisms/RegionModal/RegionModal.d.ts +10 -1
  32. package/dist/cjs/organisms/RegionModal/RegionModal.js +15 -8
  33. package/dist/cjs/organisms/RegionModal/RegionModal.js.map +1 -1
  34. package/dist/cjs/organisms/SKUMatrix/SKUMatrixSidebar.js +1 -1
  35. package/dist/cjs/organisms/SKUMatrix/SKUMatrixSidebar.js.map +1 -1
  36. package/dist/cjs/organisms/ShippingSimulation/ShippingSimulation.d.ts +2 -2
  37. package/dist/esm/hooks/UIProvider.d.ts +10 -1
  38. package/dist/esm/hooks/UIProvider.js +24 -0
  39. package/dist/esm/hooks/UIProvider.js.map +1 -1
  40. package/dist/esm/hooks/index.d.ts +2 -1
  41. package/dist/esm/hooks/index.js +2 -1
  42. package/dist/esm/hooks/index.js.map +1 -1
  43. package/dist/esm/hooks/useOnClickOutside.d.ts +4 -0
  44. package/dist/esm/hooks/useOnClickOutside.js +29 -0
  45. package/dist/esm/hooks/useOnClickOutside.js.map +1 -0
  46. package/dist/esm/index.d.ts +2 -0
  47. package/dist/esm/index.js +1 -0
  48. package/dist/esm/index.js.map +1 -1
  49. package/dist/esm/molecules/Modal/Modal.d.ts +14 -6
  50. package/dist/esm/molecules/Modal/Modal.js +13 -4
  51. package/dist/esm/molecules/Modal/Modal.js.map +1 -1
  52. package/dist/esm/molecules/Popover/Popover.d.ts +67 -0
  53. package/dist/esm/molecules/Popover/Popover.js +62 -0
  54. package/dist/esm/molecules/Popover/Popover.js.map +1 -0
  55. package/dist/esm/molecules/Popover/index.d.ts +2 -0
  56. package/dist/esm/molecules/Popover/index.js +2 -0
  57. package/dist/esm/molecules/Popover/index.js.map +1 -0
  58. package/dist/esm/molecules/RegionBar/RegionBar.d.ts +13 -4
  59. package/dist/esm/molecules/RegionBar/RegionBar.js +5 -3
  60. package/dist/esm/molecules/RegionBar/RegionBar.js.map +1 -1
  61. package/dist/esm/molecules/SearchProducts/SearchProductItemContent.d.ts +24 -0
  62. package/dist/esm/molecules/SearchProducts/SearchProductItemContent.js +10 -4
  63. package/dist/esm/molecules/SearchProducts/SearchProductItemContent.js.map +1 -1
  64. package/dist/esm/molecules/SearchProducts/SearchProductItemControl.d.ts +50 -0
  65. package/dist/esm/molecules/SearchProducts/SearchProductItemControl.js +59 -0
  66. package/dist/esm/molecules/SearchProducts/SearchProductItemControl.js.map +1 -0
  67. package/dist/esm/organisms/RegionModal/RegionModal.d.ts +10 -1
  68. package/dist/esm/organisms/RegionModal/RegionModal.js +15 -8
  69. package/dist/esm/organisms/RegionModal/RegionModal.js.map +1 -1
  70. package/dist/esm/organisms/SKUMatrix/SKUMatrixSidebar.js +1 -1
  71. package/dist/esm/organisms/SKUMatrix/SKUMatrixSidebar.js.map +1 -1
  72. package/dist/esm/organisms/ShippingSimulation/ShippingSimulation.d.ts +2 -2
  73. package/package.json +2 -2
  74. package/src/hooks/UIProvider.tsx +48 -1
  75. package/src/hooks/index.ts +2 -1
  76. package/src/hooks/useOnClickOutside.ts +40 -0
  77. package/src/index.ts +2 -0
  78. package/src/molecules/Modal/Modal.tsx +29 -8
  79. package/src/molecules/Popover/Popover.tsx +209 -0
  80. package/src/molecules/Popover/index.tsx +2 -0
  81. package/src/molecules/RegionBar/RegionBar.tsx +21 -5
  82. package/src/molecules/SearchProducts/SearchProductItemContent.tsx +61 -10
  83. package/src/molecules/SearchProducts/SearchProductItemControl.tsx +199 -0
  84. package/src/organisms/RegionModal/RegionModal.tsx +29 -7
  85. package/src/organisms/SKUMatrix/SKUMatrixSidebar.tsx +1 -1
  86. 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 = 'Prices, offers and availability may vary according to your location.',
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
- onClose={() => {
111
- fadeOut()
112
- onClose?.()
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
- <Link data-fs-region-modal-link {...idkPostalCodeLinkProps} />
157
+ {idkPostalCodeLinkProps && (
158
+ <Link data-fs-region-modal-link {...idkPostalCodeLinkProps} />
159
+ )}
138
160
  </ModalBody>
139
161
  </>
140
162
  )}
@@ -104,7 +104,7 @@ function SKUMatrixSidebar({
104
104
 
105
105
  function resetQuantityItems() {
106
106
  setAllVariantProducts((prev) =>
107
- prev.map((item) => ({ ...item, quantity: 0 }))
107
+ prev.map((item) => ({ ...item, selectedCount: 0 }))
108
108
  )
109
109
  }
110
110
 
@@ -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