@juspay/blend-design-system 0.0.37-beta.7 → 0.0.37

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 (290) hide show
  1. package/dist/{node-C_DmV86X.js → breadcrumbV2.tokens-CovJEwot.js} +16 -0
  2. package/dist/components/Accordion/index.d.ts +2 -0
  3. package/dist/components/AccordionV2/accordionV2.animations.d.ts +1 -1
  4. package/dist/components/Alert/index.d.ts +1 -0
  5. package/dist/components/Avatar/index.d.ts +1 -0
  6. package/dist/components/Breadcrumb/index.d.ts +1 -0
  7. package/dist/components/Button/index.d.ts +1 -0
  8. package/dist/components/ButtonGroup/index.d.ts +1 -0
  9. package/dist/components/Card/index.d.ts +1 -0
  10. package/dist/components/CardV2/CardV2.d.ts +45 -0
  11. package/dist/components/CardV2/CardV2.utils.d.ts +14 -0
  12. package/dist/components/CardV2/CardV2Components.d.ts +8 -0
  13. package/dist/components/CardV2/CardV2Context.d.ts +14 -0
  14. package/dist/components/CardV2/CardV2Skeleton.d.ts +6 -0
  15. package/dist/components/CardV2/accessibility/CardV2AccessibilityReport.d.ts +2 -0
  16. package/dist/components/CardV2/accessibility/index.d.ts +1 -0
  17. package/dist/components/CardV2/cardV2.dark.tokens.d.ts +3 -0
  18. package/dist/components/CardV2/cardV2.light.tokens.d.ts +3 -0
  19. package/dist/components/CardV2/cardV2.tokens.d.ts +5 -0
  20. package/dist/components/CardV2/cardV2.tokens.types.d.ts +92 -0
  21. package/dist/components/CardV2/cardV2.types.d.ts +106 -0
  22. package/dist/components/CardV2/index.d.ts +5 -0
  23. package/dist/components/Charts/index.d.ts +10 -0
  24. package/dist/components/Charts/types.d.ts +2 -0
  25. package/dist/components/ChatInput/index.d.ts +1 -0
  26. package/dist/components/Checkbox/index.d.ts +1 -0
  27. package/dist/components/CodeEditor/index.d.ts +1 -0
  28. package/dist/components/CodeEditor/types.d.ts +22 -2
  29. package/dist/components/CodeEditorV2/CodeEditorV2.d.ts +1 -1
  30. package/dist/components/CodeEditorV2/codeEditorV2.types.d.ts +23 -2
  31. package/dist/components/DataTable/PivotTableModal/pivotModal.styled.d.ts +184 -0
  32. package/dist/components/DataTable/TableBody/types.d.ts +3 -1
  33. package/dist/components/DataTable/hooks/index.d.ts +2 -0
  34. package/dist/components/DataTable/hooks/useReducedMotion.d.ts +1 -0
  35. package/dist/components/DataTable/hooks/useRowFlip.d.ts +6 -0
  36. package/dist/components/DataTable/types.d.ts +26 -0
  37. package/dist/components/DateRangePicker/CalendarGrid.d.ts +5 -2
  38. package/dist/components/DateRangePicker/types.d.ts +3 -1
  39. package/dist/components/DateRangePicker/utils.d.ts +5 -5
  40. package/dist/components/Directory/Directory.d.ts +1 -1
  41. package/dist/components/Directory/NavItem.d.ts +1 -1
  42. package/dist/components/Directory/Section.d.ts +1 -1
  43. package/dist/components/Directory/VirtualizedDirectory.d.ts +3 -0
  44. package/dist/components/Directory/directory.tokens.d.ts +7 -0
  45. package/dist/components/Directory/types.d.ts +38 -1
  46. package/dist/components/Directory/utils.d.ts +3 -1
  47. package/dist/components/Drawer/index.d.ts +1 -0
  48. package/dist/components/Inputs/MultiValueInput/index.d.ts +1 -0
  49. package/dist/components/Inputs/NumberInput/index.d.ts +1 -0
  50. package/dist/components/Inputs/OTPInput/index.d.ts +1 -0
  51. package/dist/components/Inputs/SearchInput/index.d.ts +1 -0
  52. package/dist/components/Inputs/TextArea/index.d.ts +1 -0
  53. package/dist/components/Inputs/TextInput/index.d.ts +1 -0
  54. package/dist/components/InputsV2/TextAreaV2/utils.d.ts +2 -1
  55. package/dist/components/InputsV2/TextInputV2/utils.d.ts +2 -1
  56. package/dist/components/InputsV2/UploadV2/UploadContainerV2.d.ts +24 -0
  57. package/dist/components/InputsV2/UploadV2/UploadV2.d.ts +31 -0
  58. package/dist/components/InputsV2/UploadV2/UploadV2.dark.tokens.d.ts +3 -0
  59. package/dist/components/InputsV2/UploadV2/UploadV2.light.tokens.d.ts +3 -0
  60. package/dist/components/InputsV2/UploadV2/UploadV2.tokens.d.ts +5 -0
  61. package/dist/components/InputsV2/UploadV2/UploadV2.tokens.types.d.ts +115 -0
  62. package/dist/components/InputsV2/UploadV2/UploadV2.types.d.ts +56 -0
  63. package/dist/components/InputsV2/UploadV2/index.d.ts +3 -0
  64. package/dist/components/InputsV2/UploadV2/utils.d.ts +32 -0
  65. package/dist/components/KeyValuePair/index.d.ts +1 -0
  66. package/dist/components/Menu/Menu.d.ts +1 -1
  67. package/dist/components/Menu/index.d.ts +1 -0
  68. package/dist/components/Menu/types.d.ts +7 -0
  69. package/dist/components/Menu/utils.d.ts +10 -2
  70. package/dist/components/MenuV2/MenuV2Content.d.ts +1 -0
  71. package/dist/components/MenuV2/menuV2.types.d.ts +5 -0
  72. package/dist/components/MenuV2/menuV2.utils.d.ts +10 -2
  73. package/dist/components/Modal/index.d.ts +1 -0
  74. package/dist/components/ModalV2/ModalV2.d.ts +22 -0
  75. package/dist/components/ModalV2/ModalV2Footer.d.ts +10 -0
  76. package/dist/components/ModalV2/ModalV2Header.d.ts +15 -0
  77. package/dist/components/ModalV2/ModalV2Skeleton.d.ts +4 -0
  78. package/dist/components/ModalV2/index.d.ts +4 -0
  79. package/dist/components/ModalV2/mobileModalV2.d.ts +23 -0
  80. package/dist/components/ModalV2/modalAnimationV2.d.ts +3 -0
  81. package/dist/components/ModalV2/modalV2.dark.tokens.d.ts +3 -0
  82. package/dist/components/ModalV2/modalV2.light.tokens.d.ts +3 -0
  83. package/dist/components/ModalV2/modalV2.tokens.d.ts +5 -0
  84. package/dist/components/ModalV2/modalV2.tokens.types.d.ts +91 -0
  85. package/dist/components/ModalV2/modalV2.types.d.ts +66 -0
  86. package/dist/components/MultiSelect/MultiSelect.d.ts +1 -1
  87. package/dist/components/MultiSelect/MultiSelectMenu.d.ts +1 -1
  88. package/dist/components/MultiSelect/index.d.ts +2 -0
  89. package/dist/components/MultiSelect/types.d.ts +2 -0
  90. package/dist/components/MultiSelectV2/MultiSelectV2.d.ts +1 -1
  91. package/dist/components/MultiSelectV2/MultiSelectV2Menu.d.ts +1 -1
  92. package/dist/components/MultiSelectV2/multiSelectV2.types.d.ts +2 -0
  93. package/dist/components/Popover/index.d.ts +1 -0
  94. package/dist/components/Primitives/Block/Block.d.ts +1 -1
  95. package/dist/components/ProgressBar/index.d.ts +1 -0
  96. package/dist/components/Radio/index.d.ts +2 -0
  97. package/dist/components/Sidebar/SidebarContent.d.ts +9 -1
  98. package/dist/components/Sidebar/index.d.ts +1 -0
  99. package/dist/components/Sidebar/types.d.ts +9 -1
  100. package/dist/components/SidebarV2/SidebarV2Panel.d.ts +10 -2
  101. package/dist/components/SidebarV2/types.d.ts +9 -1
  102. package/dist/components/SingleSelect/SingleSelect.d.ts +1 -1
  103. package/dist/components/SingleSelect/SingleSelectMenu.d.ts +2 -1
  104. package/dist/components/SingleSelect/index.d.ts +1 -0
  105. package/dist/components/SingleSelect/types.d.ts +1 -0
  106. package/dist/components/SingleSelectV2/SingleSelectV2.d.ts +1 -1
  107. package/dist/components/SingleSelectV2/SingleSelectV2Menu.d.ts +1 -1
  108. package/dist/components/SingleSelectV2/singleSelectV2.tokens.types.d.ts +8 -0
  109. package/dist/components/SingleSelectV2/singleSelectV2.types.d.ts +2 -0
  110. package/dist/components/Skeleton/SkeletonCompound.d.ts +24 -33
  111. package/dist/components/Snackbar/Snackbar.d.ts +1 -1
  112. package/dist/components/Snackbar/index.d.ts +2 -0
  113. package/dist/components/Snackbar/snackbar.tokens.d.ts +1 -0
  114. package/dist/components/Snackbar/types.d.ts +2 -0
  115. package/dist/components/StatCard/index.d.ts +1 -0
  116. package/dist/components/Stepper/index.d.ts +1 -0
  117. package/dist/components/Switch/index.d.ts +2 -0
  118. package/dist/components/Tabs/index.d.ts +1 -0
  119. package/dist/components/Tags/index.d.ts +1 -0
  120. package/dist/components/Timeline/Timeline.d.ts +13 -37
  121. package/dist/components/Tooltip/index.d.ts +1 -0
  122. package/dist/components/Topbar/index.d.ts +1 -0
  123. package/dist/components/Upload/index.d.ts +1 -0
  124. package/dist/context/ThemeContext.d.ts +6 -0
  125. package/dist/context/useComponentToken.d.ts +4 -1
  126. package/dist/main.d.ts +6 -0
  127. package/dist/main.js +45436 -42186
  128. package/dist/node-B3rrXW84.js +1023 -0
  129. package/dist/node.d.ts +2 -0
  130. package/dist/node.js +21 -18
  131. package/dist/{tokens.js → token-engine.js} +1 -1
  132. package/lib/components/Accordion/AccordionItem.tsx +2 -6
  133. package/lib/components/Accordion/index.ts +2 -0
  134. package/lib/components/AccordionV2/AccordionV2Item.tsx +1 -1
  135. package/lib/components/AccordionV2/accordionV2.animations.ts +1 -5
  136. package/lib/components/Alert/index.ts +1 -0
  137. package/lib/components/Avatar/index.ts +1 -0
  138. package/lib/components/Breadcrumb/index.ts +1 -0
  139. package/lib/components/Button/index.ts +1 -0
  140. package/lib/components/ButtonGroup/index.ts +1 -0
  141. package/lib/components/Card/index.ts +1 -0
  142. package/lib/components/CardV2/CardV2.tsx +327 -0
  143. package/lib/components/CardV2/CardV2.utils.tsx +77 -0
  144. package/lib/components/CardV2/CardV2Components.tsx +297 -0
  145. package/lib/components/CardV2/CardV2Context.tsx +18 -0
  146. package/lib/components/CardV2/CardV2Skeleton.tsx +40 -0
  147. package/lib/components/CardV2/accessibility/CardV2AccessibilityReport.ts +284 -0
  148. package/lib/components/CardV2/accessibility/index.ts +1 -0
  149. package/lib/components/CardV2/cardV2.dark.tokens.ts +177 -0
  150. package/lib/components/CardV2/cardV2.light.tokens.ts +177 -0
  151. package/lib/components/CardV2/cardV2.tokens.ts +21 -0
  152. package/lib/components/CardV2/cardV2.tokens.types.ts +94 -0
  153. package/lib/components/CardV2/cardV2.types.ts +131 -0
  154. package/lib/components/CardV2/index.ts +13 -0
  155. package/lib/components/Charts/ChartLegend.tsx +25 -5
  156. package/lib/components/Charts/Charts.tsx +10 -0
  157. package/lib/components/Charts/index.ts +10 -0
  158. package/lib/components/Charts/types.tsx +2 -0
  159. package/lib/components/ChatInput/index.tsx +1 -0
  160. package/lib/components/Checkbox/index.ts +1 -0
  161. package/lib/components/CodeEditor/MonacoEditorWrapper.tsx +6 -2
  162. package/lib/components/CodeEditor/index.ts +1 -0
  163. package/lib/components/CodeEditor/types.ts +52 -2
  164. package/lib/components/CodeEditorV2/MonacoEditor/MonacoEditorWrapper.tsx +6 -2
  165. package/lib/components/CodeEditorV2/codeEditorV2.types.ts +44 -5
  166. package/lib/components/DataTable/DataTable.tsx +8 -0
  167. package/lib/components/DataTable/TableBody/index.tsx +47 -11
  168. package/lib/components/DataTable/TableBody/types.ts +7 -1
  169. package/lib/components/DataTable/TableCell/index.tsx +1 -1
  170. package/lib/components/DataTable/hooks/index.ts +2 -0
  171. package/lib/components/DataTable/hooks/useReducedMotion.ts +19 -0
  172. package/lib/components/DataTable/hooks/useRowFlip.ts +170 -0
  173. package/lib/components/DataTable/types.ts +32 -0
  174. package/lib/components/DateRangePicker/CalendarGrid.tsx +39 -6
  175. package/lib/components/DateRangePicker/DateRangePicker.tsx +27 -4
  176. package/lib/components/DateRangePicker/types.ts +6 -1
  177. package/lib/components/DateRangePicker/utils.ts +123 -12
  178. package/lib/components/Directory/Directory.tsx +31 -0
  179. package/lib/components/Directory/NavItem.tsx +177 -86
  180. package/lib/components/Directory/Section.tsx +9 -0
  181. package/lib/components/Directory/VirtualizedDirectory.tsx +670 -0
  182. package/lib/components/Directory/directory.tokens.ts +21 -0
  183. package/lib/components/Directory/types.ts +43 -1
  184. package/lib/components/Directory/utils.ts +81 -1
  185. package/lib/components/Drawer/index.ts +1 -0
  186. package/lib/components/Inputs/DropdownInput/DropdownInput.tsx +6 -2
  187. package/lib/components/Inputs/MultiValueInput/index.ts +1 -0
  188. package/lib/components/Inputs/NumberInput/NumberInput.tsx +6 -2
  189. package/lib/components/Inputs/NumberInput/index.ts +1 -0
  190. package/lib/components/Inputs/OTPInput/index.ts +1 -0
  191. package/lib/components/Inputs/SearchInput/index.ts +1 -0
  192. package/lib/components/Inputs/TextArea/TextArea.tsx +4 -2
  193. package/lib/components/Inputs/TextArea/index.ts +1 -0
  194. package/lib/components/Inputs/TextInput/TextInput.tsx +6 -2
  195. package/lib/components/Inputs/TextInput/index.ts +1 -0
  196. package/lib/components/Inputs/UnitInput/UnitInput.tsx +6 -2
  197. package/lib/components/InputsV2/NumberInputV2/NumberInputV2.tsx +6 -2
  198. package/lib/components/InputsV2/TextAreaV2/TextAreaV2.tsx +2 -1
  199. package/lib/components/InputsV2/TextAreaV2/utils.ts +3 -1
  200. package/lib/components/InputsV2/TextInputV2/TextInputV2.tsx +1 -0
  201. package/lib/components/InputsV2/TextInputV2/utils.ts +6 -8
  202. package/lib/components/InputsV2/UploadV2/UploadContainerV2.tsx +470 -0
  203. package/lib/components/InputsV2/UploadV2/UploadV2.dark.tokens.ts +348 -0
  204. package/lib/components/InputsV2/UploadV2/UploadV2.light.tokens.ts +348 -0
  205. package/lib/components/InputsV2/UploadV2/UploadV2.tokens.ts +20 -0
  206. package/lib/components/InputsV2/UploadV2/UploadV2.tokens.types.ts +117 -0
  207. package/lib/components/InputsV2/UploadV2/UploadV2.tsx +336 -0
  208. package/lib/components/InputsV2/UploadV2/UploadV2.types.ts +67 -0
  209. package/lib/components/InputsV2/UploadV2/index.ts +3 -0
  210. package/lib/components/InputsV2/UploadV2/utils.ts +170 -0
  211. package/lib/components/KeyValuePair/index.ts +1 -0
  212. package/lib/components/Menu/Menu.tsx +18 -2
  213. package/lib/components/Menu/SubMenu.tsx +25 -3
  214. package/lib/components/Menu/index.ts +1 -0
  215. package/lib/components/Menu/types.tsx +14 -0
  216. package/lib/components/Menu/utils.ts +46 -3
  217. package/lib/components/MenuV2/MenuV2.tsx +9 -2
  218. package/lib/components/MenuV2/MenuV2Content.tsx +6 -0
  219. package/lib/components/MenuV2/MenuV2SubMenu.tsx +16 -2
  220. package/lib/components/MenuV2/menuV2.types.ts +11 -0
  221. package/lib/components/MenuV2/menuV2.utils.ts +45 -3
  222. package/lib/components/Modal/index.ts +1 -0
  223. package/lib/components/ModalV2/ModalV2.tsx +269 -0
  224. package/lib/components/ModalV2/ModalV2Footer.tsx +76 -0
  225. package/lib/components/ModalV2/ModalV2Header.tsx +144 -0
  226. package/lib/components/ModalV2/ModalV2Skeleton.tsx +80 -0
  227. package/lib/components/ModalV2/index.ts +4 -0
  228. package/lib/components/ModalV2/mobileModalV2.tsx +411 -0
  229. package/lib/components/ModalV2/modalAnimationV2.tsx +19 -0
  230. package/lib/components/ModalV2/modalV2.dark.tokens.ts +183 -0
  231. package/lib/components/ModalV2/modalV2.light.tokens.ts +183 -0
  232. package/lib/components/ModalV2/modalV2.tokens.ts +21 -0
  233. package/lib/components/ModalV2/modalV2.tokens.types.ts +94 -0
  234. package/lib/components/ModalV2/modalV2.types.ts +80 -0
  235. package/lib/components/MultiSelect/MultiSelect.tsx +4 -1
  236. package/lib/components/MultiSelect/MultiSelectMenu.tsx +8 -0
  237. package/lib/components/MultiSelect/MultiSelectTrigger.tsx +2 -1
  238. package/lib/components/MultiSelect/index.ts +2 -0
  239. package/lib/components/MultiSelect/types.ts +2 -0
  240. package/lib/components/MultiSelectV2/MultiSelectV2.tsx +2 -0
  241. package/lib/components/MultiSelectV2/MultiSelectV2Menu.tsx +8 -0
  242. package/lib/components/MultiSelectV2/MultiSelectV2Trigger.tsx +4 -1
  243. package/lib/components/MultiSelectV2/multiSelectV2.types.ts +2 -0
  244. package/lib/components/Popover/index.ts +1 -0
  245. package/lib/components/Primitives/Block/Block.tsx +1 -1
  246. package/lib/components/ProgressBar/index.ts +1 -0
  247. package/lib/components/Radio/index.ts +2 -0
  248. package/lib/components/Sidebar/Sidebar.tsx +38 -0
  249. package/lib/components/Sidebar/SidebarContent.tsx +25 -1
  250. package/lib/components/Sidebar/index.ts +1 -0
  251. package/lib/components/Sidebar/types.ts +13 -1
  252. package/lib/components/SidebarV2/SidebarV2.tsx +30 -0
  253. package/lib/components/SidebarV2/SidebarV2Panel.tsx +25 -1
  254. package/lib/components/SidebarV2/types.ts +9 -1
  255. package/lib/components/SingleSelect/SingleSelect.tsx +4 -1
  256. package/lib/components/SingleSelect/SingleSelectMenu.tsx +171 -138
  257. package/lib/components/SingleSelect/SingleSelectTrigger.tsx +3 -1
  258. package/lib/components/SingleSelect/index.ts +1 -0
  259. package/lib/components/SingleSelect/types.ts +1 -0
  260. package/lib/components/SingleSelectV2/SingleSelectV2.tsx +2 -0
  261. package/lib/components/SingleSelectV2/SingleSelectV2Menu.tsx +84 -58
  262. package/lib/components/SingleSelectV2/SingleSelectV2Search.tsx +1 -0
  263. package/lib/components/SingleSelectV2/SingleSelectV2Trigger.tsx +3 -1
  264. package/lib/components/SingleSelectV2/singleSelectV2.dark.tokens.ts +8 -0
  265. package/lib/components/SingleSelectV2/singleSelectV2.light.tokens.ts +8 -0
  266. package/lib/components/SingleSelectV2/singleSelectV2.tokens.types.ts +8 -0
  267. package/lib/components/SingleSelectV2/singleSelectV2.types.ts +2 -0
  268. package/lib/components/Skeleton/SkeletonCompound.tsx +45 -31
  269. package/lib/components/Snackbar/Snackbar.tsx +18 -8
  270. package/lib/components/Snackbar/index.ts +2 -0
  271. package/lib/components/Snackbar/snackbar.tokens.ts +6 -0
  272. package/lib/components/Snackbar/types.ts +2 -0
  273. package/lib/components/StatCard/StatCard.tsx +29 -0
  274. package/lib/components/StatCard/index.ts +1 -0
  275. package/lib/components/Stepper/index.ts +1 -0
  276. package/lib/components/Switch/index.ts +2 -0
  277. package/lib/components/Tabs/index.ts +1 -0
  278. package/lib/components/Tags/index.ts +1 -0
  279. package/lib/components/Timeline/Timeline.tsx +9 -1
  280. package/lib/components/Tooltip/index.ts +1 -0
  281. package/lib/components/Topbar/index.ts +1 -0
  282. package/lib/components/Upload/index.ts +1 -0
  283. package/lib/context/ThemeContext.tsx +16 -0
  284. package/lib/context/initComponentTokens.ts +11 -0
  285. package/lib/context/useComponentToken.ts +15 -1
  286. package/lib/hooks/useResponsiveTokens.ts +63 -0
  287. package/lib/main.ts +16 -0
  288. package/lib/node.ts +2 -0
  289. package/package.json +5 -4
  290. package/dist/tokens.d.ts +0 -2
@@ -0,0 +1,336 @@
1
+ import { forwardRef, useEffect, useId, useMemo, useRef, useState } from 'react'
2
+ import Block from '../../Primitives/Block/Block'
3
+ import {
4
+ UploadDragState,
5
+ UploadErrorReason,
6
+ UploadFileV2,
7
+ UploadState,
8
+ UploadV2Props,
9
+ } from './UploadV2.types'
10
+ import InputLabelsV2 from '../utils/InputLabels/InputLabelsV2'
11
+ import { InputLabelsV2Tokens } from '../inputV2.tokens'
12
+ import { useResponsiveTokens } from '../../../hooks/useResponsiveTokens'
13
+ import type { UploadV2TokensType } from './UploadV2.tokens.types'
14
+ import { InputSizeV2, InputStateV2, type AnyRef } from '../inputV2.types'
15
+ import { createClickHandler, getFileId, isFileTypeAccepted } from './utils'
16
+ import UploadContainerV2 from './UploadContainerV2'
17
+ import { generateAccessibilityIds, setExternalRef } from '../utils/utils'
18
+ import InputFooterV2 from '../utils/InputFooter/InputFooterV2'
19
+ import { filterBlockedProps } from '../../../utils/prop-helpers'
20
+
21
+ const UploadV2 = forwardRef<HTMLInputElement, UploadV2Props>(
22
+ (
23
+ {
24
+ id: providedId,
25
+ name = 'upload',
26
+ label,
27
+ subLabel,
28
+ description = '',
29
+ size = InputSizeV2.SM,
30
+ helpIconText,
31
+ required,
32
+ multiple = true,
33
+ acceptedFileTypes = [],
34
+ disabled = false,
35
+ slot,
36
+ files = [],
37
+ onChange,
38
+ state = UploadState.IDLE,
39
+ error = { show: false, message: '' },
40
+ maxSize = 0,
41
+ maxFiles = multiple ? undefined : 1,
42
+ errorText = '',
43
+ hintText,
44
+ progressBarValue = 0,
45
+ progressBarMaxWidth = '300px',
46
+ uploadHeaderText = 'Choose a file or drag & drop it here',
47
+ ...rest
48
+ },
49
+ ref
50
+ ) => {
51
+ const tokens = useResponsiveTokens<UploadV2TokensType>('UPLOADV2')
52
+ const fileInputRef = useRef<HTMLInputElement>(null)
53
+ const generatedUploadId = useId()
54
+ const uploadId = providedId ?? generatedUploadId
55
+ const { errorId, hintId } = generateAccessibilityIds(uploadId)
56
+ const filteredRest = filterBlockedProps(rest)
57
+ const [uploadState, setUploadState] = useState<UploadState>(
58
+ UploadState.IDLE
59
+ )
60
+ const [dragState, setDragState] = useState<UploadDragState>(
61
+ UploadDragState.DRAG_LEAVE
62
+ )
63
+ const isDisabled = disabled || state === UploadState.DISABLED
64
+ const isUploading = state === UploadState.UPLOADING
65
+ const isSuccess = state === UploadState.SUCCESS
66
+ const isInteractionBlocked = isDisabled || isUploading || isSuccess
67
+ const hasInvalidFiles = files.some((file) => !file.isValid)
68
+ const displayUploadState = isDisabled
69
+ ? UploadState.DISABLED
70
+ : hasInvalidFiles
71
+ ? UploadState.ERROR
72
+ : uploadState
73
+ const descriptionId =
74
+ description && files.length === 0 && !isUploading
75
+ ? `${uploadId}-description`
76
+ : undefined
77
+ const hasError = Boolean(
78
+ error?.show || displayUploadState === UploadState.ERROR
79
+ )
80
+ const showLabelError = Boolean(error?.show || (!multiple && hasError))
81
+ const effectiveErrorText = error?.message || errorText
82
+ const shouldDescribeError = Boolean(
83
+ hasError && (effectiveErrorText || (!multiple && hasInvalidFiles))
84
+ )
85
+ const ariaDescribedBy = useMemo(() => {
86
+ const ids = [
87
+ descriptionId,
88
+ hintText && !hasError ? hintId : undefined,
89
+ shouldDescribeError ? errorId : undefined,
90
+ ].filter(Boolean) as string[]
91
+ return ids.length > 0 ? ids.join(' ') : undefined
92
+ }, [
93
+ descriptionId,
94
+ errorId,
95
+ hasError,
96
+ hintId,
97
+ hintText,
98
+ shouldDescribeError,
99
+ ])
100
+ const setInputRef = (node: HTMLInputElement | null) => {
101
+ fileInputRef.current = node
102
+ setExternalRef(ref as AnyRef<HTMLInputElement>, node)
103
+ }
104
+
105
+ // Validate files and mark with isValid flag instead of filtering
106
+ const validateFiles = (newFiles: File[]): UploadFileV2[] => {
107
+ const limit = maxFiles ?? (multiple ? undefined : 1)
108
+ const remainingSlots =
109
+ limit && multiple ? limit - files.length : Infinity
110
+ let hasRejection = false
111
+
112
+ const validatedFiles: UploadFileV2[] = newFiles.map(
113
+ (file, index) => {
114
+ // Check maxFiles limit
115
+ if (limit && index >= remainingSlots) {
116
+ hasRejection = true
117
+ return {
118
+ id: `${file.name}-${file.size}-${file.lastModified}-${Date.now()}-${index}`,
119
+ file,
120
+ isValid: false,
121
+ errorReason: UploadErrorReason.MAX_FILES,
122
+ }
123
+ }
124
+
125
+ // Check accepted file types for drag/drop and direct file input.
126
+ if (!isFileTypeAccepted(file, acceptedFileTypes)) {
127
+ hasRejection = true
128
+ return {
129
+ id: `${file.name}-${file.size}-${file.lastModified}-${Date.now()}-${index}`,
130
+ file,
131
+ isValid: false,
132
+ errorReason: UploadErrorReason.INVALID_TYPE,
133
+ }
134
+ }
135
+
136
+ // Check maxSize
137
+ if (maxSize && file.size > maxSize) {
138
+ hasRejection = true
139
+ return {
140
+ id: `${file.name}-${file.size}-${file.lastModified}-${Date.now()}-${index}`,
141
+ file,
142
+ isValid: false,
143
+ errorReason: UploadErrorReason.OVERSIZED,
144
+ }
145
+ }
146
+
147
+ return {
148
+ id: `${file.name}-${file.size}-${file.lastModified}-${Date.now()}-${index}`,
149
+ file,
150
+ isValid: true,
151
+ }
152
+ }
153
+ )
154
+
155
+ // Set state based on validation results
156
+ if (hasRejection) {
157
+ setUploadState(UploadState.ERROR)
158
+ } else if (validatedFiles.length > 0) {
159
+ setUploadState(UploadState.IDLE)
160
+ }
161
+
162
+ return validatedFiles
163
+ }
164
+ useEffect(() => {
165
+ if (state === UploadState.UPLOADING) {
166
+ setUploadState(UploadState.UPLOADING)
167
+ } else if (state === UploadState.SUCCESS) {
168
+ setUploadState(UploadState.SUCCESS)
169
+ } else if (state === UploadState.ERROR) {
170
+ setUploadState(UploadState.ERROR)
171
+ } else if (isDisabled) {
172
+ setUploadState(UploadState.DISABLED)
173
+ } else {
174
+ setUploadState(UploadState.IDLE)
175
+ }
176
+ }, [state, isDisabled])
177
+ return (
178
+ <Block
179
+ data-upload={label ?? ''}
180
+ data-status={isDisabled ? 'disabled' : 'enabled'}
181
+ display="flex"
182
+ flexDirection="column"
183
+ gap={tokens.gap}
184
+ width="100%"
185
+ >
186
+ <InputLabelsV2
187
+ tokens={tokens.topContainer as InputLabelsV2Tokens}
188
+ label={label}
189
+ sublabel={subLabel}
190
+ size={size}
191
+ state={
192
+ showLabelError
193
+ ? InputStateV2.ERROR
194
+ : displayUploadState === UploadState.DISABLED
195
+ ? InputStateV2.DISABLED
196
+ : InputStateV2.DEFAULT
197
+ }
198
+ helpIconText={helpIconText}
199
+ inputId={uploadId}
200
+ required={required}
201
+ />
202
+ {/* fake input file */}
203
+ <Block
204
+ cursor={isDisabled ? 'not-allowed' : 'pointer'}
205
+ onClick={(e) => {
206
+ if (isInteractionBlocked) {
207
+ e.preventDefault()
208
+ return
209
+ }
210
+ createClickHandler(
211
+ isDisabled,
212
+ fileInputRef as React.RefObject<HTMLInputElement>
213
+ )()
214
+ }}
215
+ onDragEnter={(e) => {
216
+ if (isInteractionBlocked) {
217
+ e.preventDefault()
218
+ return
219
+ }
220
+ setDragState(UploadDragState.DRAG_ENTER)
221
+ }}
222
+ onDragLeave={(e) => {
223
+ if (isInteractionBlocked) {
224
+ e.preventDefault()
225
+ return
226
+ }
227
+ setDragState(UploadDragState.DRAG_LEAVE)
228
+ }}
229
+ onDragOver={(e) => {
230
+ if (isInteractionBlocked) {
231
+ e.preventDefault()
232
+ return
233
+ }
234
+ e.preventDefault()
235
+ setDragState(UploadDragState.DRAG_OVER)
236
+ }}
237
+ onDrop={(e) => {
238
+ if (isInteractionBlocked) {
239
+ e.preventDefault()
240
+ return
241
+ }
242
+ e.preventDefault()
243
+ e.stopPropagation()
244
+ const droppedFiles = Array.from(e.dataTransfer.files)
245
+ const validatedFiles = validateFiles(droppedFiles)
246
+ const updatedFiles = multiple
247
+ ? [...files, ...validatedFiles]
248
+ : validatedFiles[0]
249
+ ? [validatedFiles[0]]
250
+ : []
251
+ onChange?.(updatedFiles)
252
+ setDragState(UploadDragState.DRAG_LEAVE)
253
+ }}
254
+ >
255
+ <UploadContainerV2
256
+ description={description}
257
+ descriptionId={descriptionId}
258
+ slot={slot}
259
+ disabled={isDisabled}
260
+ onClick={() => {
261
+ fileInputRef.current?.click()
262
+ }}
263
+ tokens={tokens}
264
+ files={files}
265
+ multiple={multiple}
266
+ onFileRemove={(fileId) => {
267
+ const updatedFiles = files.filter(
268
+ (f, index) => getFileId(f, index) !== fileId
269
+ )
270
+ // Check if any invalid files remain
271
+ const hasInvalidFiles = updatedFiles.some(
272
+ (f) => !f.isValid
273
+ )
274
+ setUploadState(
275
+ hasInvalidFiles
276
+ ? UploadState.ERROR
277
+ : UploadState.IDLE
278
+ )
279
+ onChange?.(updatedFiles)
280
+ }}
281
+ state={displayUploadState}
282
+ errorText={error?.message ? '' : errorText}
283
+ errorId={error?.message ? undefined : errorId}
284
+ progressBarValue={progressBarValue}
285
+ progressBarMaxWidth={progressBarMaxWidth}
286
+ uploadHeaderText={uploadHeaderText}
287
+ dragState={dragState}
288
+ maxSize={maxSize}
289
+ maxFiles={maxFiles}
290
+ />
291
+ </Block>
292
+
293
+ {/* real input file */}
294
+ <input
295
+ {...filteredRest}
296
+ ref={setInputRef}
297
+ id={uploadId}
298
+ name={name}
299
+ type="file"
300
+ multiple={multiple}
301
+ accept={acceptedFileTypes.join(',')}
302
+ onChange={(e) => {
303
+ const newFiles = Array.from(e.target.files || [])
304
+ const validatedFiles = validateFiles(newFiles)
305
+ const updatedFiles = multiple
306
+ ? [...files, ...validatedFiles]
307
+ : validatedFiles[0]
308
+ ? [validatedFiles[0]]
309
+ : []
310
+ onChange?.(updatedFiles)
311
+ e.target.value = ''
312
+ }}
313
+ disabled={isDisabled}
314
+ required={required}
315
+ aria-required={required}
316
+ aria-invalid={hasError}
317
+ aria-describedby={ariaDescribedBy}
318
+ aria-label={label ? undefined : 'File upload'}
319
+ style={{ display: 'none' }}
320
+ />
321
+ <InputFooterV2
322
+ tokens={tokens.bottomContainer}
323
+ error={Boolean(error?.show && error?.message)}
324
+ errorMessage={error?.message}
325
+ hintText={hintText}
326
+ errorId={errorId}
327
+ hintId={hintId}
328
+ size={size}
329
+ />
330
+ </Block>
331
+ )
332
+ }
333
+ )
334
+
335
+ UploadV2.displayName = 'UploadV2'
336
+ export default UploadV2
@@ -0,0 +1,67 @@
1
+ import { InputSizeV2 } from '../inputV2.types'
2
+
3
+ export enum UploadState {
4
+ IDLE = 'idle',
5
+ UPLOADING = 'uploading',
6
+ SUCCESS = 'success',
7
+ ERROR = 'error',
8
+
9
+ DISABLED = 'disabled',
10
+ }
11
+
12
+ export enum UploadDragState {
13
+ DRAG_ENTER = 'drag_enter',
14
+ DRAG_LEAVE = 'drag_leave',
15
+ DRAG_OVER = 'drag_over',
16
+ DROP = 'drop',
17
+ }
18
+
19
+ export const UploadErrorReason = {
20
+ OVERSIZED: 'oversized',
21
+ MAX_FILES: 'maxFiles',
22
+ INVALID_TYPE: 'invalidType',
23
+ } as const
24
+
25
+ export type UploadErrorReasonValue =
26
+ (typeof UploadErrorReason)[keyof typeof UploadErrorReason]
27
+
28
+ export type UploadFileV2 = {
29
+ id?: string
30
+ file: File
31
+ isValid: boolean
32
+ errorReason?: UploadErrorReasonValue
33
+ }
34
+
35
+ export type UploadV2Props = {
36
+ id?: string
37
+ name?: string
38
+ label?: string
39
+ subLabel?: string
40
+ description?: string
41
+ size?: InputSizeV2
42
+ helpIconText?: string
43
+ required?: boolean
44
+ multiple?: boolean
45
+ /** File types to accept (e.g., ['.jpg', '.png', 'image/*', '.pdf']) */
46
+ acceptedFileTypes?: string[]
47
+ disabled?: boolean
48
+ slot?: React.ReactNode
49
+ files?: UploadFileV2[]
50
+ /** Callback when files are selected or changed */
51
+ onChange?: (files: UploadFileV2[]) => void
52
+ state?: UploadState
53
+ error?: {
54
+ show: boolean
55
+ message?: string
56
+ }
57
+ errorText?: string
58
+ hintText?: string
59
+ maxSize?: number
60
+ maxFiles?: number
61
+ progressBarValue?: number
62
+ progressBarMaxWidth?: string
63
+ uploadHeaderText?: string
64
+ } & Omit<
65
+ React.InputHTMLAttributes<HTMLInputElement>,
66
+ 'size' | 'style' | 'className' | 'multiple' | 'slot' | 'onChange'
67
+ >
@@ -0,0 +1,3 @@
1
+ export { default as UploadV2 } from './UploadV2'
2
+ export * from './UploadV2.types'
3
+ export * from './UploadV2.tokens'
@@ -0,0 +1,170 @@
1
+ import { useState } from 'react'
2
+ import { UploadFileV2 } from './UploadV2.types'
3
+
4
+ export const FILE_NAME_TAG_MAX_LEN = 24
5
+
6
+ export const createClickHandler =
7
+ (disabled: boolean, fileInputRef: React.RefObject<HTMLInputElement>) =>
8
+ () => {
9
+ if (disabled) return
10
+ fileInputRef.current?.click()
11
+ }
12
+
13
+ export const useUploadState = () => {
14
+ const [internalDragState, setInternalDragState] = useState({
15
+ isDragActive: false,
16
+ isDragAccept: false,
17
+ isDragReject: false,
18
+ })
19
+ const [, setDragCounter] = useState(0)
20
+
21
+ return {
22
+ internalDragState,
23
+ setInternalDragState,
24
+ setDragCounter,
25
+ }
26
+ }
27
+
28
+ export const createDragHandlers = (
29
+ disabled: boolean,
30
+ setDragCounter: (fn: (prev: number) => number) => void,
31
+ updateDragStateFn: (isDragActive: boolean, files?: File[]) => void,
32
+ processFilesFn: (files: FileList) => void
33
+ ) => {
34
+ const handleDragEnter = (e: React.DragEvent) => {
35
+ e.preventDefault()
36
+ e.stopPropagation()
37
+ if (disabled) return
38
+
39
+ setDragCounter((prev) => {
40
+ const newCounter = prev + 1
41
+ if (newCounter === 1 && e.dataTransfer.items) {
42
+ const files = Array.from(e.dataTransfer.items)
43
+ .filter((item) => item.kind === 'file')
44
+ .map((item) => item.getAsFile())
45
+ .filter(Boolean) as File[]
46
+ updateDragStateFn(true, files)
47
+ }
48
+ return newCounter
49
+ })
50
+ }
51
+
52
+ const handleDragLeave = (e: React.DragEvent) => {
53
+ e.preventDefault()
54
+ e.stopPropagation()
55
+ if (disabled) return
56
+
57
+ setDragCounter((prev) => {
58
+ const newCounter = prev - 1
59
+ if (newCounter === 0) {
60
+ updateDragStateFn(false)
61
+ }
62
+ return newCounter
63
+ })
64
+ }
65
+
66
+ const handleDragOver = (e: React.DragEvent) => {
67
+ e.preventDefault()
68
+ e.stopPropagation()
69
+ }
70
+
71
+ const handleDrop = (e: React.DragEvent) => {
72
+ e.preventDefault()
73
+ e.stopPropagation()
74
+ if (disabled) return
75
+
76
+ setDragCounter(() => 0)
77
+ updateDragStateFn(false)
78
+
79
+ if (e.dataTransfer.files) {
80
+ processFilesFn(e.dataTransfer.files)
81
+ }
82
+ }
83
+
84
+ return {
85
+ handleDragEnter,
86
+ handleDragLeave,
87
+ handleDragOver,
88
+ handleDrop,
89
+ }
90
+ }
91
+
92
+ export const truncateFileNameForTag = (name: string): string =>
93
+ name.length > FILE_NAME_TAG_MAX_LEN
94
+ ? `${name.slice(0, FILE_NAME_TAG_MAX_LEN)}…`
95
+ : name
96
+
97
+ export const getFileId = (uploadFile: UploadFileV2, index: number) =>
98
+ uploadFile.id ??
99
+ `${uploadFile.file.name}-${uploadFile.file.size}-${uploadFile.file.lastModified}-${index}`
100
+
101
+ export const isFileTypeAccepted = (file: File, acceptedFileTypes: string[]) => {
102
+ if (acceptedFileTypes.length === 0) return true
103
+
104
+ const fileName = file.name.toLowerCase()
105
+ const fileType = file.type.toLowerCase()
106
+
107
+ return acceptedFileTypes.some((acceptedType) => {
108
+ const normalizedAcceptedType = acceptedType.trim().toLowerCase()
109
+ if (!normalizedAcceptedType) return false
110
+
111
+ if (normalizedAcceptedType.startsWith('.')) {
112
+ return fileName.endsWith(normalizedAcceptedType)
113
+ }
114
+
115
+ if (normalizedAcceptedType.endsWith('/*')) {
116
+ const acceptedGroup = normalizedAcceptedType.slice(0, -1)
117
+ return fileType.startsWith(acceptedGroup)
118
+ }
119
+
120
+ return fileType === normalizedAcceptedType
121
+ })
122
+ }
123
+
124
+ const KNOWN_UPLOAD_ERROR_REASONS = [
125
+ 'oversized',
126
+ 'maxFiles',
127
+ 'invalidType',
128
+ ] as const
129
+ type KnownUploadErrorReason = (typeof KNOWN_UPLOAD_ERROR_REASONS)[number]
130
+
131
+ export const formatFileSize = (sizeInBytes: number) => {
132
+ if (sizeInBytes >= 1024 * 1024) {
133
+ const sizeInMb = sizeInBytes / (1024 * 1024)
134
+ return `${Number(sizeInMb.toFixed(2))} MB`
135
+ }
136
+ if (sizeInBytes >= 1024) {
137
+ const sizeInKb = sizeInBytes / 1024
138
+ return `${Number(sizeInKb.toFixed(2))} KB`
139
+ }
140
+ return `${sizeInBytes} B`
141
+ }
142
+
143
+ export const isKnownUploadErrorReason = (
144
+ reason: unknown
145
+ ): reason is KnownUploadErrorReason =>
146
+ KNOWN_UPLOAD_ERROR_REASONS.includes(reason as KnownUploadErrorReason)
147
+
148
+ export const normalizeUploadErrorReason = (reason: unknown) =>
149
+ isKnownUploadErrorReason(reason) ? reason : undefined
150
+
151
+ export const getValidationMessage = (
152
+ reason?: unknown,
153
+ maxSize?: number,
154
+ maxFiles?: number
155
+ ) => {
156
+ switch (normalizeUploadErrorReason(reason)) {
157
+ case 'oversized':
158
+ return maxSize
159
+ ? `File is too large. Max size is ${formatFileSize(maxSize)}`
160
+ : 'File is too large'
161
+ case 'maxFiles':
162
+ return maxFiles
163
+ ? `File limit exceeded. Maximum ${maxFiles} files allowed`
164
+ : 'File limit exceeded'
165
+ case 'invalidType':
166
+ return 'Invalid file type'
167
+ default:
168
+ return 'Invalid file'
169
+ }
170
+ }
@@ -1,3 +1,4 @@
1
+ /** @deprecated Will be deprecated soon. Use KeyValuePairV2 instead. */
1
2
  export { default as KeyValuePair } from './KeyValuePair'
2
3
  export * from './KeyValuePair.tokens'
3
4
  export * from './types'
@@ -8,7 +8,7 @@ import {
8
8
  type MenuItemType,
9
9
  } from './types'
10
10
  import React, { useState, useRef, useMemo, useCallback, useEffect } from 'react'
11
- import { filterMenuGroups } from './utils'
11
+ import { filterMenuGroups, defaultSearchSortFn } from './utils'
12
12
  import MenuItem from './MenuItem'
13
13
  import Block from '../Primitives/Block/Block'
14
14
  import SearchInput from '../Inputs/SearchInput/SearchInput'
@@ -62,6 +62,8 @@ const Menu = ({
62
62
  maxHeight,
63
63
  enableSearch = false,
64
64
  searchPlaceholder = 'Search',
65
+ searchSortFn = defaultSearchSortFn,
66
+ onEnter,
65
67
  minWidth,
66
68
  maxWidth,
67
69
  open,
@@ -81,7 +83,7 @@ const Menu = ({
81
83
  const searchInputRef = useRef<HTMLInputElement>(null)
82
84
  const justOpenedRef = useRef(false)
83
85
  const timeoutRef = useRef<NodeJS.Timeout | null>(null)
84
- const filteredItems = filterMenuGroups(items, searchText)
86
+ const filteredItems = filterMenuGroups(items, searchText, searchSortFn)
85
87
  const menuTokens = useResponsiveTokens<MenuTokensType>('MENU')
86
88
  const { target: portalContainer } = useShadowRoot()
87
89
 
@@ -353,6 +355,20 @@ const Menu = ({
353
355
  value={searchText}
354
356
  onChange={handleSearchChange}
355
357
  autoFocus
358
+ onKeyDown={(e) => {
359
+ if (e.key === 'Enter') {
360
+ e.stopPropagation()
361
+ e.preventDefault()
362
+ onEnter?.(
363
+ searchText,
364
+ filteredItems
365
+ )
366
+ return
367
+ }
368
+ if (e.key.length === 1) {
369
+ e.stopPropagation()
370
+ }
371
+ }}
356
372
  aria-label={`Search menu items${searchPlaceholder ? `: ${searchPlaceholder}` : ''}`}
357
373
  />
358
374
  </Block>
@@ -11,7 +11,7 @@ import PrimitiveText from '../Primitives/PrimitiveText/PrimitiveText'
11
11
  import { useResponsiveTokens } from '../../hooks/useResponsiveTokens'
12
12
  import SearchInput from '../Inputs/SearchInput/SearchInput'
13
13
  import { FOUNDATION_THEME } from '../../tokens'
14
- import { filterMenuItem } from './utils'
14
+ import { filterMenuItem, defaultSearchSortFn } from './utils'
15
15
  import React, { useState, useRef, useMemo, useCallback } from 'react'
16
16
  import { submenuContentAnimations } from './menu.animations'
17
17
  import { VirtualList, type VirtualListItem } from '../VirtualList'
@@ -183,10 +183,18 @@ export const SubMenu = ({
183
183
  if (!searchText || !item.enableSubMenuSearch) return item.subMenu
184
184
 
185
185
  const lower = searchText.toLowerCase()
186
- return item.subMenu
186
+ const matched = item.subMenu
187
187
  .map((subItem) => filterMenuItem(subItem, lower))
188
188
  .filter(Boolean) as MenuItemType[]
189
- }, [item.subMenu, searchText, item.enableSubMenuSearch])
189
+
190
+ const sortFn = item.subMenuSearchSortFn ?? defaultSearchSortFn
191
+ return sortFn(matched, searchText)
192
+ }, [
193
+ item.subMenu,
194
+ searchText,
195
+ item.enableSubMenuSearch,
196
+ item.subMenuSearchSortFn,
197
+ ])
190
198
 
191
199
  const totalItemCount = useMemo(() => {
192
200
  return filteredSubMenuItems.length
@@ -383,6 +391,20 @@ export const SubMenu = ({
383
391
  value={searchText}
384
392
  onChange={handleSearchChange}
385
393
  autoFocus
394
+ onKeyDown={(e) => {
395
+ if (e.key === 'Enter') {
396
+ e.stopPropagation()
397
+ e.preventDefault()
398
+ item.onSubMenuSearchEnter?.(
399
+ searchText,
400
+ filteredSubMenuItems
401
+ )
402
+ return
403
+ }
404
+ if (e.key.length === 1) {
405
+ e.stopPropagation()
406
+ }
407
+ }}
386
408
  />
387
409
  </Block>
388
410
  )}
@@ -1,3 +1,4 @@
1
+ /** @deprecated Will be deprecated soon. Use MenuV2 instead. */
1
2
  export { default as Menu } from './Menu'
2
3
  export * from './menu.tokens'
3
4
  export * from './types'