@faststore/components 3.98.0-dev.1 → 3.98.0-dev.8

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 (198) hide show
  1. package/dist/cjs/atoms/Link/Link.d.ts +1 -1
  2. package/dist/cjs/atoms/Link/Link.d.ts.map +1 -1
  3. package/dist/cjs/atoms/Link/Link.js.map +1 -1
  4. package/dist/cjs/atoms/List/List.d.ts.map +1 -1
  5. package/dist/cjs/atoms/List/List.js.map +1 -1
  6. package/dist/cjs/hooks/index.d.ts +7 -3
  7. package/dist/cjs/hooks/index.d.ts.map +1 -1
  8. package/dist/cjs/hooks/index.js +12 -6
  9. package/dist/cjs/hooks/index.js.map +1 -1
  10. package/dist/cjs/hooks/useCSVParser.d.ts +43 -0
  11. package/dist/cjs/hooks/useCSVParser.d.ts.map +1 -0
  12. package/dist/cjs/hooks/useCSVParser.js +264 -0
  13. package/dist/cjs/hooks/useCSVParser.js.map +1 -0
  14. package/dist/cjs/hooks/useFileUpload.d.ts +26 -0
  15. package/dist/cjs/hooks/useFileUpload.d.ts.map +1 -0
  16. package/dist/cjs/hooks/useFileUpload.js +68 -0
  17. package/dist/cjs/hooks/useFileUpload.js.map +1 -0
  18. package/dist/cjs/index.d.ts +58 -50
  19. package/dist/cjs/index.d.ts.map +1 -1
  20. package/dist/cjs/index.js +47 -32
  21. package/dist/cjs/index.js.map +1 -1
  22. package/dist/cjs/molecules/Accordion/AccordionItem.d.ts.map +1 -1
  23. package/dist/cjs/molecules/Accordion/AccordionItem.js.map +1 -1
  24. package/dist/cjs/molecules/Dropzone/Dropzone.d.ts +87 -0
  25. package/dist/cjs/molecules/Dropzone/Dropzone.d.ts.map +1 -0
  26. package/dist/cjs/molecules/Dropzone/Dropzone.js +85 -0
  27. package/dist/cjs/molecules/Dropzone/Dropzone.js.map +1 -0
  28. package/dist/cjs/molecules/Dropzone/index.d.ts +3 -0
  29. package/dist/cjs/molecules/Dropzone/index.d.ts.map +1 -0
  30. package/dist/cjs/molecules/Dropzone/index.js +9 -0
  31. package/dist/cjs/molecules/Dropzone/index.js.map +1 -0
  32. package/dist/cjs/molecules/FileUploadCard/FileUploadCard.d.ts +113 -0
  33. package/dist/cjs/molecules/FileUploadCard/FileUploadCard.d.ts.map +1 -0
  34. package/dist/cjs/molecules/FileUploadCard/FileUploadCard.js +169 -0
  35. package/dist/cjs/molecules/FileUploadCard/FileUploadCard.js.map +1 -0
  36. package/dist/cjs/molecules/FileUploadCard/index.d.ts +3 -0
  37. package/dist/cjs/molecules/FileUploadCard/index.d.ts.map +1 -0
  38. package/dist/cjs/molecules/FileUploadCard/index.js +9 -0
  39. package/dist/cjs/molecules/FileUploadCard/index.js.map +1 -0
  40. package/dist/cjs/molecules/FileUploadStatus/FileUploadStatus.d.ts +93 -0
  41. package/dist/cjs/molecules/FileUploadStatus/FileUploadStatus.d.ts.map +1 -0
  42. package/dist/cjs/molecules/FileUploadStatus/FileUploadStatus.js +77 -0
  43. package/dist/cjs/molecules/FileUploadStatus/FileUploadStatus.js.map +1 -0
  44. package/dist/cjs/molecules/FileUploadStatus/index.d.ts +3 -0
  45. package/dist/cjs/molecules/FileUploadStatus/index.d.ts.map +1 -0
  46. package/dist/cjs/molecules/FileUploadStatus/index.js +11 -0
  47. package/dist/cjs/molecules/FileUploadStatus/index.js.map +1 -0
  48. package/dist/cjs/molecules/SearchInputField/SearchInputField.d.ts +23 -1
  49. package/dist/cjs/molecules/SearchInputField/SearchInputField.d.ts.map +1 -1
  50. package/dist/cjs/molecules/SearchInputField/SearchInputField.js +9 -4
  51. package/dist/cjs/molecules/SearchInputField/SearchInputField.js.map +1 -1
  52. package/dist/cjs/molecules/SearchProducts/SearchProductItem.d.ts +1 -1
  53. package/dist/cjs/molecules/SearchProducts/SearchProductItem.d.ts.map +1 -1
  54. package/dist/cjs/molecules/SearchProducts/SearchProductItem.js +2 -2
  55. package/dist/cjs/molecules/SearchProducts/SearchProductItem.js.map +1 -1
  56. package/dist/cjs/molecules/SearchProvider/SearchProvider.d.ts +5 -1
  57. package/dist/cjs/molecules/SearchProvider/SearchProvider.d.ts.map +1 -1
  58. package/dist/cjs/molecules/SearchProvider/SearchProvider.js +2 -2
  59. package/dist/cjs/molecules/SearchProvider/SearchProvider.js.map +1 -1
  60. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawer.d.ts +24 -0
  61. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawer.d.ts.map +1 -0
  62. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawer.js +14 -0
  63. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawer.js.map +1 -0
  64. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.d.ts +16 -0
  65. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.d.ts.map +1 -0
  66. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.js +37 -0
  67. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.js.map +1 -0
  68. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.d.ts +9 -0
  69. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.d.ts.map +1 -0
  70. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.js +24 -0
  71. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.js.map +1 -0
  72. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.d.ts +35 -0
  73. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.d.ts.map +1 -0
  74. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.js +91 -0
  75. package/dist/cjs/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.js.map +1 -0
  76. package/dist/cjs/organisms/QuickOrderDrawer/index.d.ts +11 -0
  77. package/dist/cjs/organisms/QuickOrderDrawer/index.d.ts.map +1 -0
  78. package/dist/cjs/organisms/QuickOrderDrawer/index.js +18 -0
  79. package/dist/cjs/organisms/QuickOrderDrawer/index.js.map +1 -0
  80. package/dist/cjs/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.d.ts +61 -0
  81. package/dist/cjs/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.d.ts.map +1 -0
  82. package/dist/cjs/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.js +86 -0
  83. package/dist/cjs/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.js.map +1 -0
  84. package/dist/cjs/organisms/SearchInput/SearchInput.d.ts +8 -0
  85. package/dist/cjs/organisms/SearchInput/SearchInput.d.ts.map +1 -1
  86. package/dist/cjs/organisms/SearchInput/SearchInput.js +2 -2
  87. package/dist/cjs/organisms/SearchInput/SearchInput.js.map +1 -1
  88. package/dist/esm/atoms/Link/Link.d.ts +1 -1
  89. package/dist/esm/atoms/Link/Link.d.ts.map +1 -1
  90. package/dist/esm/atoms/Link/Link.js.map +1 -1
  91. package/dist/esm/atoms/List/List.d.ts.map +1 -1
  92. package/dist/esm/atoms/List/List.js.map +1 -1
  93. package/dist/esm/hooks/index.d.ts +7 -3
  94. package/dist/esm/hooks/index.d.ts.map +1 -1
  95. package/dist/esm/hooks/index.js +6 -3
  96. package/dist/esm/hooks/index.js.map +1 -1
  97. package/dist/esm/hooks/useCSVParser.d.ts +43 -0
  98. package/dist/esm/hooks/useCSVParser.d.ts.map +1 -0
  99. package/dist/esm/hooks/useCSVParser.js +259 -0
  100. package/dist/esm/hooks/useCSVParser.js.map +1 -0
  101. package/dist/esm/hooks/useFileUpload.d.ts +26 -0
  102. package/dist/esm/hooks/useFileUpload.d.ts.map +1 -0
  103. package/dist/esm/hooks/useFileUpload.js +64 -0
  104. package/dist/esm/hooks/useFileUpload.js.map +1 -0
  105. package/dist/esm/index.d.ts +58 -50
  106. package/dist/esm/index.d.ts.map +1 -1
  107. package/dist/esm/index.js +24 -20
  108. package/dist/esm/index.js.map +1 -1
  109. package/dist/esm/molecules/Accordion/AccordionItem.d.ts.map +1 -1
  110. package/dist/esm/molecules/Accordion/AccordionItem.js.map +1 -1
  111. package/dist/esm/molecules/Dropzone/Dropzone.d.ts +87 -0
  112. package/dist/esm/molecules/Dropzone/Dropzone.d.ts.map +1 -0
  113. package/dist/esm/molecules/Dropzone/Dropzone.js +82 -0
  114. package/dist/esm/molecules/Dropzone/Dropzone.js.map +1 -0
  115. package/dist/esm/molecules/Dropzone/index.d.ts +3 -0
  116. package/dist/esm/molecules/Dropzone/index.d.ts.map +1 -0
  117. package/dist/esm/molecules/Dropzone/index.js +2 -0
  118. package/dist/esm/molecules/Dropzone/index.js.map +1 -0
  119. package/dist/esm/molecules/FileUploadCard/FileUploadCard.d.ts +113 -0
  120. package/dist/esm/molecules/FileUploadCard/FileUploadCard.d.ts.map +1 -0
  121. package/dist/esm/molecules/FileUploadCard/FileUploadCard.js +166 -0
  122. package/dist/esm/molecules/FileUploadCard/FileUploadCard.js.map +1 -0
  123. package/dist/esm/molecules/FileUploadCard/index.d.ts +3 -0
  124. package/dist/esm/molecules/FileUploadCard/index.d.ts.map +1 -0
  125. package/dist/esm/molecules/FileUploadCard/index.js +2 -0
  126. package/dist/esm/molecules/FileUploadCard/index.js.map +1 -0
  127. package/dist/esm/molecules/FileUploadStatus/FileUploadStatus.d.ts +93 -0
  128. package/dist/esm/molecules/FileUploadStatus/FileUploadStatus.d.ts.map +1 -0
  129. package/dist/esm/molecules/FileUploadStatus/FileUploadStatus.js +73 -0
  130. package/dist/esm/molecules/FileUploadStatus/FileUploadStatus.js.map +1 -0
  131. package/dist/esm/molecules/FileUploadStatus/index.d.ts +3 -0
  132. package/dist/esm/molecules/FileUploadStatus/index.d.ts.map +1 -0
  133. package/dist/esm/molecules/FileUploadStatus/index.js +2 -0
  134. package/dist/esm/molecules/FileUploadStatus/index.js.map +1 -0
  135. package/dist/esm/molecules/SearchInputField/SearchInputField.d.ts +23 -1
  136. package/dist/esm/molecules/SearchInputField/SearchInputField.d.ts.map +1 -1
  137. package/dist/esm/molecules/SearchInputField/SearchInputField.js +9 -4
  138. package/dist/esm/molecules/SearchInputField/SearchInputField.js.map +1 -1
  139. package/dist/esm/molecules/SearchProducts/SearchProductItem.d.ts +1 -1
  140. package/dist/esm/molecules/SearchProducts/SearchProductItem.d.ts.map +1 -1
  141. package/dist/esm/molecules/SearchProducts/SearchProductItem.js +2 -2
  142. package/dist/esm/molecules/SearchProducts/SearchProductItem.js.map +1 -1
  143. package/dist/esm/molecules/SearchProvider/SearchProvider.d.ts +5 -1
  144. package/dist/esm/molecules/SearchProvider/SearchProvider.d.ts.map +1 -1
  145. package/dist/esm/molecules/SearchProvider/SearchProvider.js +2 -2
  146. package/dist/esm/molecules/SearchProvider/SearchProvider.js.map +1 -1
  147. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawer.d.ts +24 -0
  148. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawer.d.ts.map +1 -0
  149. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawer.js +11 -0
  150. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawer.js.map +1 -0
  151. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.d.ts +16 -0
  152. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.d.ts.map +1 -0
  153. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.js +34 -0
  154. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.js.map +1 -0
  155. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.d.ts +9 -0
  156. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.d.ts.map +1 -0
  157. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.js +21 -0
  158. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.js.map +1 -0
  159. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.d.ts +35 -0
  160. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.d.ts.map +1 -0
  161. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.js +88 -0
  162. package/dist/esm/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.js.map +1 -0
  163. package/dist/esm/organisms/QuickOrderDrawer/index.d.ts +11 -0
  164. package/dist/esm/organisms/QuickOrderDrawer/index.d.ts.map +1 -0
  165. package/dist/esm/organisms/QuickOrderDrawer/index.js +6 -0
  166. package/dist/esm/organisms/QuickOrderDrawer/index.js.map +1 -0
  167. package/dist/esm/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.d.ts +61 -0
  168. package/dist/esm/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.d.ts.map +1 -0
  169. package/dist/esm/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.js +80 -0
  170. package/dist/esm/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.js.map +1 -0
  171. package/dist/esm/organisms/SearchInput/SearchInput.d.ts +8 -0
  172. package/dist/esm/organisms/SearchInput/SearchInput.d.ts.map +1 -1
  173. package/dist/esm/organisms/SearchInput/SearchInput.js +2 -2
  174. package/dist/esm/organisms/SearchInput/SearchInput.js.map +1 -1
  175. package/package.json +5 -2
  176. package/src/atoms/Link/Link.tsx +4 -1
  177. package/src/atoms/List/List.tsx +18 -16
  178. package/src/hooks/index.ts +11 -3
  179. package/src/hooks/useCSVParser.ts +367 -0
  180. package/src/hooks/useFileUpload.ts +88 -0
  181. package/src/index.ts +97 -66
  182. package/src/molecules/Accordion/AccordionItem.tsx +4 -3
  183. package/src/molecules/Dropzone/Dropzone.tsx +248 -0
  184. package/src/molecules/Dropzone/index.ts +2 -0
  185. package/src/molecules/FileUploadCard/FileUploadCard.tsx +406 -0
  186. package/src/molecules/FileUploadCard/index.tsx +2 -0
  187. package/src/molecules/FileUploadStatus/FileUploadStatus.tsx +258 -0
  188. package/src/molecules/FileUploadStatus/index.tsx +6 -0
  189. package/src/molecules/SearchInputField/SearchInputField.tsx +72 -23
  190. package/src/molecules/SearchProducts/SearchProductItem.tsx +8 -3
  191. package/src/molecules/SearchProvider/SearchProvider.tsx +6 -1
  192. package/src/organisms/QuickOrderDrawer/QuickOrderDrawer.tsx +58 -0
  193. package/src/organisms/QuickOrderDrawer/QuickOrderDrawerFooter.tsx +72 -0
  194. package/src/organisms/QuickOrderDrawer/QuickOrderDrawerHeader.tsx +43 -0
  195. package/src/organisms/QuickOrderDrawer/QuickOrderDrawerProducts.tsx +323 -0
  196. package/src/organisms/QuickOrderDrawer/index.ts +19 -0
  197. package/src/organisms/QuickOrderDrawer/provider/QuickOrderDrawerProvider.tsx +205 -0
  198. package/src/organisms/SearchInput/SearchInput.tsx +6 -0
@@ -0,0 +1,258 @@
1
+ import type { HTMLAttributes } from 'react'
2
+ import React from 'react'
3
+
4
+ import { Button, Icon } from '../..'
5
+
6
+ export enum FileUploadState {
7
+ Uploading = 'uploading',
8
+ Completed = 'completed',
9
+ Error = 'error',
10
+ }
11
+
12
+ export enum FileUploadErrorType {
13
+ Unexpected = 'unexpected',
14
+ Unsupported = 'unsupported',
15
+ Unreadable = 'unreadable',
16
+ InvalidStructure = 'invalid-structure',
17
+ Empty = 'empty',
18
+ TooLarge = 'too-large',
19
+ NoProductsFound = 'no-products-found',
20
+ }
21
+
22
+ export interface FileUploadStatusProps extends HTMLAttributes<HTMLDivElement> {
23
+ /**
24
+ * ID to find this component in testing tools (e.g.: cypress, testing library, and jest).
25
+ */
26
+ testId?: string
27
+ /**
28
+ * The file being uploaded.
29
+ */
30
+ file: File
31
+ /**
32
+ * Current upload state.
33
+ * @default 'uploading'
34
+ */
35
+ state?: FileUploadState
36
+ /**
37
+ * Type of error when state is 'error'.
38
+ */
39
+ errorType?: FileUploadErrorType
40
+ /**
41
+ * Custom error message. If provided, overrides the default error message for the errorType.
42
+ */
43
+ errorMessage?: string
44
+ /**
45
+ * Callback when the remove/cancel button is clicked.
46
+ */
47
+ onRemove?: () => void
48
+ /**
49
+ * Callback when the search button is clicked (only shown when state is 'completed').
50
+ */
51
+ onSearch?: () => void
52
+ /**
53
+ * Callback when download template is clicked (only shown when state is 'error').
54
+ */
55
+ onDownloadTemplate?: () => void
56
+ /**
57
+ * Callback when select file is clicked (only shown when state is 'error').
58
+ */
59
+ onSelectFile?: () => void
60
+ /**
61
+ * Aria-label for the remove button (e.g. from CMS).
62
+ */
63
+ removeButtonAriaLabel: string
64
+ /**
65
+ * Label for the search button when state is 'completed' (e.g. from CMS).
66
+ */
67
+ searchButtonLabel: string
68
+ /**
69
+ * Label for the download template button (e.g. from CMS).
70
+ */
71
+ downloadTemplateButtonLabel: string
72
+ /**
73
+ * Label for the select file button (e.g. from CMS).
74
+ */
75
+ selectFileButtonLabel: string
76
+ /**
77
+ * Error messages per error type (e.g. from CMS). Required when state is Error to show messages.
78
+ */
79
+ errorMessages: Partial<
80
+ Record<FileUploadErrorType, { title: string; description: string }>
81
+ >
82
+ /**
83
+ * Status text when state is Uploading (e.g. from CMS).
84
+ */
85
+ uploadingStatusText: string
86
+ /**
87
+ * Status text when state is Completed (e.g. from CMS). May include file size.
88
+ */
89
+ completedStatusText: string
90
+ /**
91
+ * Custom file name display (optional).
92
+ */
93
+ fileName?: string
94
+ }
95
+
96
+ const FileUploadStatus = ({
97
+ testId = 'fs-file-upload-status',
98
+ file,
99
+ state = FileUploadState.Uploading,
100
+ errorType,
101
+ errorMessage,
102
+ onRemove,
103
+ onSearch,
104
+ onDownloadTemplate,
105
+ onSelectFile,
106
+ removeButtonAriaLabel,
107
+ searchButtonLabel,
108
+ downloadTemplateButtonLabel,
109
+ selectFileButtonLabel,
110
+ errorMessages,
111
+ uploadingStatusText,
112
+ completedStatusText,
113
+ fileName,
114
+ ...otherProps
115
+ }: FileUploadStatusProps) => {
116
+ const getErrorMessage = (): { title: string; description: string } => {
117
+ if (errorMessage) {
118
+ return { title: errorMessage, description: '' }
119
+ }
120
+
121
+ if (errorType && errorMessages?.[errorType]) {
122
+ return errorMessages[errorType]!
123
+ }
124
+
125
+ return (
126
+ errorMessages?.[FileUploadErrorType.Unexpected] ?? {
127
+ title: '',
128
+ description: '',
129
+ }
130
+ )
131
+ }
132
+
133
+ const getStatusText = (): string => {
134
+ switch (state) {
135
+ case FileUploadState.Uploading:
136
+ return uploadingStatusText
137
+ case FileUploadState.Completed:
138
+ return completedStatusText
139
+ default:
140
+ return ''
141
+ }
142
+ }
143
+
144
+ const getIcon = () => {
145
+ switch (state) {
146
+ case FileUploadState.Uploading:
147
+ return (
148
+ <div data-fs-file-upload-status-icon-loading>
149
+ <Icon name="CircleNotch" width={24} height={24} strokeWidth={5} />
150
+ </div>
151
+ )
152
+ case FileUploadState.Completed:
153
+ return (
154
+ <div data-fs-file-upload-status-icon-completed>
155
+ <Icon name="Table" width={24} height={24} strokeWidth={5} />
156
+ </div>
157
+ )
158
+ case FileUploadState.Error:
159
+ return (
160
+ <div data-fs-file-upload-status-icon-error>
161
+ <Icon
162
+ name="WarningOctagon"
163
+ width={24}
164
+ height={24}
165
+ strokeWidth={5}
166
+ />
167
+ </div>
168
+ )
169
+ default:
170
+ return null
171
+ }
172
+ }
173
+
174
+ return (
175
+ <div
176
+ data-fs-file-upload-status
177
+ data-fs-file-upload-status-state={state}
178
+ data-testid={testId}
179
+ {...otherProps}
180
+ >
181
+ <div
182
+ data-fs-file-upload-status-file-info
183
+ data-fs-file-upload-state={state}
184
+ >
185
+ <div data-fs-file-upload-status-icon>{getIcon()}</div>
186
+
187
+ <div data-fs-file-upload-status-details>
188
+ {state === FileUploadState.Error ? (
189
+ <>
190
+ <p data-fs-file-upload-status-text-error>
191
+ {getErrorMessage().title}
192
+ </p>
193
+ <p data-fs-file-upload-status-text-error>
194
+ {getErrorMessage().description}
195
+ </p>
196
+ </>
197
+ ) : (
198
+ <>
199
+ <p data-fs-file-upload-status-filename>{fileName ?? file.name}</p>
200
+ <p data-fs-file-upload-status-text>{getStatusText()}</p>
201
+ </>
202
+ )}
203
+ </div>
204
+
205
+ {onRemove && (
206
+ <Button
207
+ type="button"
208
+ onClick={onRemove}
209
+ data-fs-file-upload-status-remove
210
+ aria-label={removeButtonAriaLabel}
211
+ >
212
+ <Icon name="X" width={16} height={16} />
213
+ </Button>
214
+ )}
215
+ </div>
216
+ {state === FileUploadState.Completed && onSearch && (
217
+ <Button
218
+ type="button"
219
+ variant="primary"
220
+ size="regular"
221
+ onClick={onSearch}
222
+ data-fs-file-upload-status-search-button
223
+ >
224
+ {searchButtonLabel}
225
+ </Button>
226
+ )}
227
+
228
+ {state === FileUploadState.Error && (
229
+ <div data-fs-file-upload-status-error-actions>
230
+ {onDownloadTemplate && (
231
+ <Button
232
+ type="button"
233
+ variant="secondary"
234
+ size="regular"
235
+ onClick={onDownloadTemplate}
236
+ data-fs-file-upload-status-download-button
237
+ >
238
+ {downloadTemplateButtonLabel}
239
+ </Button>
240
+ )}
241
+ {onSelectFile && (
242
+ <Button
243
+ type="button"
244
+ variant="primary"
245
+ size="regular"
246
+ onClick={onSelectFile}
247
+ data-fs-file-upload-status-select-button
248
+ >
249
+ {selectFileButtonLabel}
250
+ </Button>
251
+ )}
252
+ </div>
253
+ )}
254
+ </div>
255
+ )
256
+ }
257
+
258
+ export default FileUploadStatus
@@ -0,0 +1,6 @@
1
+ export {
2
+ default,
3
+ FileUploadState,
4
+ FileUploadErrorType,
5
+ } from './FileUploadStatus'
6
+ export type { FileUploadStatusProps } from './FileUploadStatus'
@@ -14,6 +14,7 @@ type ButtonProps = {
14
14
  onClick?: () => void
15
15
  testId?: string
16
16
  }
17
+
17
18
  export interface SearchInputFieldProps extends InputProps {
18
19
  /**
19
20
  * ID to find this component in testing tools (e.g.: cypress, testing library, and jest).
@@ -29,7 +30,29 @@ export interface SearchInputFieldProps extends InputProps {
29
30
  */
30
31
  buttonIcon?: ReactNode
31
32
  /**
32
- * Custom aria-label for input and button.
33
+ * Whether to show the attachment button.
34
+ * @default false
35
+ */
36
+ showAttachmentButton?: boolean
37
+ /**
38
+ * Props for the paperclip button inside the input.
39
+ */
40
+ attachmentButtonProps?: ButtonProps
41
+ /**
42
+ * Aria-label for the attachment button (e.g. from CMS).
43
+ */
44
+ attachmentButtonAriaLabel?: string
45
+ /**
46
+ * Aria-label for the submit button (e.g. from CMS).
47
+ */
48
+ submitButtonAriaLabel?: string
49
+ /**
50
+ * A React component that will be rendered as an icon (attachment button).
51
+ * @default <Icon name="Paperclip" />
52
+ */
53
+ attachmentButtonIcon?: ReactNode
54
+ /**
55
+ * Aria-label for the search input (e.g. from CMS).
33
56
  */
34
57
  'aria-label'?: AriaAttributes['aria-label']
35
58
  /**
@@ -50,7 +73,12 @@ const SearchInputField = forwardRef<
50
73
  {
51
74
  onSubmit,
52
75
  buttonIcon,
53
- 'aria-label': ariaLabel = 'search',
76
+ showAttachmentButton = false,
77
+ attachmentButtonAriaLabel,
78
+ attachmentButtonIcon,
79
+ attachmentButtonProps,
80
+ submitButtonAriaLabel,
81
+ 'aria-label': ariaLabel,
54
82
  testId = 'fs-search-input',
55
83
  buttonProps,
56
84
  ...otherProps
@@ -74,27 +102,48 @@ const SearchInputField = forwardRef<
74
102
  }))
75
103
 
76
104
  return (
77
- <form
78
- ref={formRef}
79
- data-fs-search-input-field
80
- data-testid={testId}
81
- onSubmit={handleSubmit}
82
- role="search"
83
- >
84
- <Input
85
- ref={inputRef}
86
- aria-label={ariaLabel}
87
- data-fs-search-input-field-input
88
- {...otherProps}
89
- />
90
- <IconButton
91
- type="submit"
92
- aria-label="Submit Search"
93
- icon={buttonIcon ?? <Icon name="MagnifyingGlass" />}
94
- size="small"
95
- {...buttonProps}
96
- />
97
- </form>
105
+ <div data-fs-search-input-field-wrapper>
106
+ <form
107
+ ref={formRef}
108
+ data-fs-search-input-field
109
+ data-testid={testId}
110
+ onSubmit={handleSubmit}
111
+ role="search"
112
+ >
113
+ <Input
114
+ ref={inputRef}
115
+ aria-label={ariaLabel}
116
+ data-fs-search-input-field-input
117
+ {...otherProps}
118
+ />
119
+
120
+ <div data-fs-search-input-field-actions>
121
+ {showAttachmentButton && (
122
+ <>
123
+ <IconButton
124
+ type="button"
125
+ aria-label={attachmentButtonAriaLabel}
126
+ icon={attachmentButtonIcon ?? <Icon name="Paperclip" />}
127
+ size="small"
128
+ data-fs-search-input-field-attachment-button
129
+ {...attachmentButtonProps}
130
+ />
131
+
132
+ <span data-fs-search-input-field-separator />
133
+ </>
134
+ )}
135
+
136
+ <IconButton
137
+ type="submit"
138
+ aria-label={submitButtonAriaLabel}
139
+ icon={buttonIcon ?? <Icon name="MagnifyingGlass" />}
140
+ size="small"
141
+ data-fs-search-input-field-submit-button
142
+ {...buttonProps}
143
+ />
144
+ </div>
145
+ </form>
146
+ </div>
98
147
  )
99
148
  })
100
149
 
@@ -3,7 +3,7 @@ import React, { forwardRef } from 'react'
3
3
 
4
4
  import { Link, type LinkElementType, type LinkProps } from '../..'
5
5
 
6
- export interface SearchProductItemProps extends HTMLAttributes<HTMLDivElement> {
6
+ export interface SearchProductItemProps extends HTMLAttributes<HTMLLIElement> {
7
7
  /**
8
8
  * ID to find this component in testing tools (e.g.: cypress,
9
9
  * testing-library, and jest).
@@ -17,11 +17,16 @@ export interface SearchProductItemProps extends HTMLAttributes<HTMLDivElement> {
17
17
 
18
18
  const SearchProductItem = forwardRef<HTMLLIElement, SearchProductItemProps>(
19
19
  function ProductItem(
20
- { testId = 'fs-search-product-item', linkProps, children },
20
+ { testId = 'fs-search-product-item', linkProps, children, ...otherProps },
21
21
  ref
22
22
  ) {
23
23
  return (
24
- <li ref={ref} data-fs-search-product-item data-testid={testId}>
24
+ <li
25
+ ref={ref}
26
+ data-fs-search-product-item
27
+ data-testid={testId}
28
+ {...otherProps}
29
+ >
25
30
  <Link {...linkProps} data-fs-search-product-item-link variant="display">
26
31
  {children}
27
32
  </Link>
@@ -23,6 +23,10 @@ export interface SearchProviderContextValue {
23
23
  * Callback function when a search term is selected.
24
24
  */
25
25
  onSearchSelection?: (term: string, path: string) => void
26
+ /**
27
+ * Search result searchId.
28
+ */
29
+ searchId?: string
26
30
  }
27
31
 
28
32
  export const SearchContext = createContext<SearchProviderContextValue | null>(
@@ -36,10 +40,11 @@ function SearchProvider({
36
40
  terms,
37
41
  products,
38
42
  isLoading,
43
+ searchId,
39
44
  }: PropsWithChildren<SearchProviderContextValue>) {
40
45
  return (
41
46
  <SearchContext.Provider
42
- value={{ onSearchSelection, term, terms, products, isLoading }}
47
+ value={{ onSearchSelection, term, terms, products, isLoading, searchId }}
43
48
  >
44
49
  {children}
45
50
  </SearchContext.Provider>
@@ -0,0 +1,58 @@
1
+ import React, { type PropsWithChildren } from 'react'
2
+ import type { OverlayProps } from '../../atoms/Overlay'
3
+ import { useFadeEffect } from '../../hooks'
4
+ import SlideOver from '../SlideOver/SlideOver'
5
+
6
+ import {
7
+ QuickOrderDrawerProvider,
8
+ type QuickOrderDrawerProviderProps,
9
+ } from './provider/QuickOrderDrawerProvider'
10
+
11
+ export type QuickOrderDrawerProps = {
12
+ /**
13
+ * ID to find this component in testing tools (e.g.: cypress, testing library, and jest).
14
+ */
15
+ testId?: string
16
+
17
+ /**
18
+ * Controls the state
19
+ */
20
+ isOpen: boolean
21
+
22
+ /**
23
+ * Props forwarded to the `Overlay` component.
24
+ */
25
+ overlayProps?: OverlayProps
26
+
27
+ /**
28
+ * Props forwarded to the `QuickOrderDrawerProvider` component.
29
+ */
30
+ providerProps?: Omit<QuickOrderDrawerProviderProps, 'children'>
31
+ }
32
+
33
+ const QuickOrderDrawer = ({
34
+ testId = 'fs-quick-order-drawer',
35
+ isOpen,
36
+ overlayProps,
37
+ providerProps,
38
+ children,
39
+ }: PropsWithChildren<QuickOrderDrawerProps>) => {
40
+ const { fade } = useFadeEffect()
41
+ return (
42
+ <QuickOrderDrawerProvider {...providerProps}>
43
+ <SlideOver
44
+ testId={testId}
45
+ fade={fade}
46
+ isOpen={isOpen}
47
+ size="partial"
48
+ direction="rightSide"
49
+ overlayProps={overlayProps}
50
+ data-fs-quick-order-drawer
51
+ >
52
+ {children}
53
+ </SlideOver>
54
+ </QuickOrderDrawerProvider>
55
+ )
56
+ }
57
+
58
+ export default QuickOrderDrawer
@@ -0,0 +1,72 @@
1
+ import React, { useState } from 'react'
2
+ import Button from '../../atoms/Button'
3
+ import Icon from '../../atoms/Icon'
4
+ import Price, { type PriceFormatter } from '../../atoms/Price'
5
+ import { useQuickOrderDrawer } from './provider/QuickOrderDrawerProvider'
6
+
7
+ export type QuickOrderDrawerFooterProps = {
8
+ formatter?: PriceFormatter
9
+ /**
10
+ * Text labels for CMS configuration
11
+ */
12
+ labels?: {
13
+ itemsLabel?: string
14
+ addToCartLabel?: string
15
+ addToCartAriaLabel?: string
16
+ }
17
+ }
18
+
19
+ const QuickOrderDrawerFooter = ({
20
+ formatter,
21
+ labels,
22
+ }: QuickOrderDrawerFooterProps) => {
23
+ const [loading, setLoading] = useState(false)
24
+ const {
25
+ itemsCount,
26
+ totalPrice,
27
+ onAddToCart,
28
+ formatter: contextFormatter,
29
+ } = useQuickOrderDrawer()
30
+ const priceFormatter = formatter || contextFormatter
31
+ const { itemsLabel, addToCartLabel, addToCartAriaLabel } = labels || {}
32
+
33
+ const handleAddToCart = async () => {
34
+ if (itemsCount === 0) return
35
+ setLoading(true)
36
+ try {
37
+ onAddToCart()
38
+ } finally {
39
+ setLoading(false)
40
+ }
41
+ }
42
+
43
+ return (
44
+ <div data-fs-quick-order-drawer-footer>
45
+ <div data-fs-quick-order-drawer-footer-items>
46
+ <Icon name="Inventory" width={24} height={24} />
47
+ <span>
48
+ {itemsCount} {itemsLabel || ''}
49
+ </span>
50
+ </div>
51
+ <div data-fs-quick-order-drawer-footer-actions>
52
+ <Price
53
+ value={totalPrice}
54
+ variant="selling"
55
+ formatter={priceFormatter}
56
+ />
57
+ <Button
58
+ data-fs-quick-order-drawer-add-to-cart-btn
59
+ variant="primary"
60
+ disabled={itemsCount === 0}
61
+ loading={loading}
62
+ onClick={handleAddToCart}
63
+ aria-label={addToCartAriaLabel}
64
+ >
65
+ {addToCartLabel}
66
+ </Button>
67
+ </div>
68
+ </div>
69
+ )
70
+ }
71
+
72
+ export default QuickOrderDrawerFooter
@@ -0,0 +1,43 @@
1
+ import React from 'react'
2
+ import Icon from '../../atoms/Icon'
3
+ import { SlideOverHeader } from '../SlideOver'
4
+
5
+ export type QuickOrderDrawerHeaderProps = {
6
+ title: string
7
+ titleCharLimit?: number
8
+ onCloseDrawer?: () => void
9
+ }
10
+
11
+ const QuickOrderDrawerHeader = ({
12
+ onCloseDrawer,
13
+ title,
14
+ titleCharLimit = 30,
15
+ }: QuickOrderDrawerHeaderProps) => {
16
+ const leftOffset = Math.floor(titleCharLimit / 2) - 3
17
+ const rightOffset = Math.floor(titleCharLimit / 2)
18
+ const titleFormatted =
19
+ title.length > titleCharLimit
20
+ ? `${title.slice(0, leftOffset)}...${title.slice(-rightOffset)}`
21
+ : title
22
+
23
+ return (
24
+ <SlideOverHeader
25
+ data-fs-quick-order-drawer-header
26
+ closeBtnProps={{
27
+ variant: 'tertiary',
28
+ color: 'black',
29
+ 'aria-label': 'Close quick order drawer',
30
+ }}
31
+ onClose={() => onCloseDrawer?.()}
32
+ >
33
+ <div data-fs-quick-order-drawer-title-container>
34
+ <div data-fs-quick-order-drawer-icon>
35
+ <Icon name="Table" weight="bold" width={32} height={32} />
36
+ </div>
37
+ <div data-fs-quick-order-drawer-title>{titleFormatted}</div>
38
+ </div>
39
+ </SlideOverHeader>
40
+ )
41
+ }
42
+
43
+ export default QuickOrderDrawerHeader