@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
@@ -21,6 +21,11 @@ export type MenuSkeletonProps = {
21
21
  variant?: SkeletonVariant
22
22
  }
23
23
 
24
+ export type MenuSearchSortFn = (
25
+ items: MenuItemType[],
26
+ searchText: string
27
+ ) => MenuItemType[]
28
+
24
29
  export type MenuProps = {
25
30
  trigger: React.ReactNode
26
31
  items?: MenuGroupType[]
@@ -32,6 +37,8 @@ export type MenuProps = {
32
37
 
33
38
  enableSearch?: boolean
34
39
  searchPlaceholder?: string
40
+ searchSortFn?: MenuSearchSortFn
41
+ onEnter?: (searchText: string, filteredGroups: MenuGroupType[]) => void
35
42
  enableVirtualScrolling?: boolean
36
43
  virtualItemHeight?: number | ((item: MenuItemType, index: number) => number)
37
44
  virtualOverscan?: number
@@ -79,6 +86,13 @@ export type MenuItemType = {
79
86
  subMenu?: MenuItemType[]
80
87
  enableSubMenuSearch?: boolean
81
88
  subMenuSearchPlaceholder?: string
89
+ /** Custom sort function for submenu search results. Defaults to exact → prefix → substring. */
90
+ subMenuSearchSortFn?: MenuSearchSortFn
91
+ /** Called when the user presses Enter while focused on the submenu search input. */
92
+ onSubMenuSearchEnter?: (
93
+ searchText: string,
94
+ filteredResults: MenuItemType[]
95
+ ) => void
82
96
  tooltip?: string | React.ReactNode
83
97
  tooltipProps?: {
84
98
  side?: TooltipSide
@@ -1,9 +1,52 @@
1
- import { MenuGroupType, type MenuItemType } from './types'
1
+ import {
2
+ MenuGroupType,
3
+ type MenuItemType,
4
+ type MenuSearchSortFn,
5
+ } from './types'
6
+
7
+ export enum MenuMatchRank {
8
+ EXACT = 0,
9
+ PREFIX = 1,
10
+ SUBSTRING = 2,
11
+ NONE = 3,
12
+ }
13
+
14
+ const getFieldMatchRank = (
15
+ fieldValue: string | undefined,
16
+ lower: string
17
+ ): MenuMatchRank => {
18
+ if (!fieldValue) return MenuMatchRank.NONE
19
+ const value = fieldValue.toLowerCase()
20
+ if (value === lower) return MenuMatchRank.EXACT
21
+ if (value.startsWith(lower)) return MenuMatchRank.PREFIX
22
+ if (value.includes(lower)) return MenuMatchRank.SUBSTRING
23
+ return MenuMatchRank.NONE
24
+ }
25
+
26
+ export const getItemMatchRank = (
27
+ item: MenuItemType,
28
+ lower: string
29
+ ): MenuMatchRank => {
30
+ return Math.min(
31
+ getFieldMatchRank(item.label, lower),
32
+ getFieldMatchRank(item.subLabel, lower)
33
+ ) as MenuMatchRank
34
+ }
35
+
36
+ export const defaultSearchSortFn: MenuSearchSortFn = (items, searchText) => {
37
+ if (!searchText.trim()) return items
38
+ const lower = searchText.toLowerCase()
39
+ return items
40
+ .map((item) => ({ item, rank: getItemMatchRank(item, lower) }))
41
+ .sort((a, b) => a.rank - b.rank)
42
+ .map((x) => x.item)
43
+ }
2
44
 
3
45
  // Utility: Recursively filter menu items and groups by search text
4
46
  export const filterMenuGroups = (
5
47
  groups: MenuGroupType[],
6
- searchText: string
48
+ searchText: string,
49
+ searchSortFn: MenuSearchSortFn = defaultSearchSortFn
7
50
  ): MenuGroupType[] => {
8
51
  if (!searchText) return groups
9
52
  const lower = searchText.toLowerCase()
@@ -17,7 +60,7 @@ export const filterMenuGroups = (
17
60
  .map((item: MenuItemType) => filterMenuItem(item, lower))
18
61
  .filter(Boolean) as MenuItemType[]
19
62
  if (filteredItems.length === 0) return null
20
- return { ...group, items: filteredItems }
63
+ return { ...group, items: searchSortFn(filteredItems, searchText) }
21
64
  })
22
65
  .filter(Boolean) as MenuGroupType[]
23
66
  }
@@ -23,6 +23,8 @@ const MenuV2 = React.forwardRef<HTMLDivElement, MenuV2Props>(
23
23
  dimensions = {} as MenuV2Dimensions,
24
24
  enableSearch = false,
25
25
  searchPlaceholder = 'Search',
26
+ searchSortFn,
27
+ onEnter,
26
28
  enableVirtualScrolling = false,
27
29
  virtualScrolling,
28
30
  open: controlledOpen,
@@ -61,10 +63,14 @@ const MenuV2 = React.forwardRef<HTMLDivElement, MenuV2Props>(
61
63
  )
62
64
 
63
65
  const filteredItems = useMemo(
64
- () => filterMenuV2Groups(items, searchText),
65
- [items, searchText]
66
+ () => filterMenuV2Groups(items, searchText, searchSortFn),
67
+ [items, searchText, searchSortFn]
66
68
  )
67
69
 
70
+ const handleSearchEnter = useCallback(() => {
71
+ onEnter?.(searchText, filteredItems)
72
+ }, [onEnter, searchText, filteredItems])
73
+
68
74
  const handleInteractOutside = useCallback((e: unknown) => {
69
75
  const event = e as {
70
76
  target: HTMLElement | null
@@ -104,6 +110,7 @@ const MenuV2 = React.forwardRef<HTMLDivElement, MenuV2Props>(
104
110
  searchPlaceholder={searchPlaceholder}
105
111
  searchText={searchText}
106
112
  onSearchTextChange={setSearchText}
113
+ onEnter={handleSearchEnter}
107
114
  maxHeight={
108
115
  dimensions.maxHeight as CSSObject['maxHeight']
109
116
  }
@@ -104,6 +104,7 @@ export type MenuV2ContentProps = {
104
104
  searchPlaceholder: string
105
105
  searchText: string
106
106
  onSearchTextChange: (value: string) => void
107
+ onEnter?: () => void
107
108
  maxHeight?: CSSObject['maxHeight']
108
109
  minHeight?: CSSObject['minHeight']
109
110
  minWidth?: CSSObject['minWidth']
@@ -130,6 +131,7 @@ const MenuV2Content = React.forwardRef<HTMLDivElement, MenuV2ContentProps>(
130
131
  searchPlaceholder,
131
132
  searchText,
132
133
  onSearchTextChange,
134
+ onEnter,
133
135
  maxHeight,
134
136
  minHeight,
135
137
  minWidth: minWidthProp,
@@ -250,6 +252,10 @@ const MenuV2Content = React.forwardRef<HTMLDivElement, MenuV2ContentProps>(
250
252
  onChange={(e) => onSearchTextChange(e.target.value)}
251
253
  onKeyDown={(e) => {
252
254
  e.stopPropagation()
255
+ if (e.key === 'Enter') {
256
+ e.preventDefault()
257
+ onEnter?.()
258
+ }
253
259
  }}
254
260
  aria-label={
255
261
  searchPlaceholder
@@ -14,6 +14,7 @@ import {
14
14
  getMenuItemDescriptionColor,
15
15
  filterMenuV2Item,
16
16
  getItemSlots,
17
+ defaultSearchSortFn,
17
18
  } from './menuV2.utils'
18
19
  import { menuV2SubmenuContentAnimations } from './menuV2.animations'
19
20
  import { useResponsiveTokens } from '../../hooks/useResponsiveTokens'
@@ -64,12 +65,15 @@ const MenuV2SubMenu = ({ item, index, maxHeight }: MenuV2SubMenuProps) => {
64
65
 
65
66
  const lower = searchText.toLowerCase()
66
67
 
67
- return item.subMenu.reduce<MenuV2ItemType[]>((acc, sub) => {
68
+ const matched = item.subMenu.reduce<MenuV2ItemType[]>((acc, sub) => {
68
69
  const result = filterMenuV2Item(sub, lower)
69
70
  if (result) acc.push(result)
70
71
  return acc
71
72
  }, [])
72
- }, [item.subMenu, searchText])
73
+
74
+ const sortFn = item.subMenuSearchSortFn ?? defaultSearchSortFn
75
+ return sortFn(matched, searchText)
76
+ }, [item.subMenu, searchText, item.subMenuSearchSortFn])
73
77
 
74
78
  const {
75
79
  bgDefault,
@@ -262,6 +266,16 @@ const MenuV2SubMenu = ({ item, index, maxHeight }: MenuV2SubMenuProps) => {
262
266
  }
263
267
  value={searchText}
264
268
  onChange={(e) => setSearchText(e.target.value)}
269
+ onKeyDown={(e) => {
270
+ e.stopPropagation()
271
+ if (e.key === 'Enter') {
272
+ e.preventDefault()
273
+ item.onSubMenuSearchEnter?.(
274
+ searchText,
275
+ filteredSubMenuItems
276
+ )
277
+ }
278
+ }}
265
279
  aria-label="Search submenu"
266
280
  />
267
281
  </Block>
@@ -38,6 +38,10 @@ export type MenuV2ItemLabel = {
38
38
  text: string
39
39
  leftSlot?: React.ReactElement
40
40
  }
41
+ export type MenuV2SearchSortFn = (
42
+ items: MenuV2ItemType[],
43
+ searchText: string
44
+ ) => MenuV2ItemType[]
41
45
  export type MenuV2ItemType = {
42
46
  id?: string
43
47
  label: MenuV2ItemLabel
@@ -49,6 +53,11 @@ export type MenuV2ItemType = {
49
53
  subMenu?: MenuV2ItemType[]
50
54
  enableSubMenuSearch?: boolean
51
55
  subMenuSearchPlaceholder?: string
56
+ subMenuSearchSortFn?: MenuV2SearchSortFn
57
+ onSubMenuSearchEnter?: (
58
+ searchText: string,
59
+ filteredResults: MenuV2ItemType[]
60
+ ) => void
52
61
  tooltip?: string | ReactNode
53
62
  tooltipProps?: MenuV2ItemTooltipProps
54
63
  }
@@ -82,6 +91,8 @@ export type MenuV2Props = {
82
91
  dimensions?: MenuV2Dimensions
83
92
  enableSearch?: boolean
84
93
  searchPlaceholder?: string
94
+ searchSortFn?: MenuV2SearchSortFn
95
+ onEnter?: (searchText: string, filteredGroups: MenuV2GroupType[]) => void
85
96
  enableVirtualScrolling?: boolean
86
97
  virtualScrolling?: MenuV2VirtualScrollingConfig
87
98
  open?: boolean
@@ -1,5 +1,9 @@
1
1
  import type { ReactNode } from 'react'
2
- import type { MenuV2GroupType, MenuV2ItemType } from './menuV2.types'
2
+ import type {
3
+ MenuV2GroupType,
4
+ MenuV2ItemType,
5
+ MenuV2SearchSortFn,
6
+ } from './menuV2.types'
3
7
  import type { MenuV2TokensType } from './menuV2.tokens'
4
8
 
5
9
  import { MenuV2ItemActionType, MenuV2ItemVariant } from './menuV2.types'
@@ -11,6 +15,43 @@ export const getItemSlots = (item: MenuV2ItemType): [ReactNode?] => {
11
15
  return [item.label.leftSlot]
12
16
  }
13
17
 
18
+ export enum MenuV2MatchRank {
19
+ EXACT = 0,
20
+ PREFIX = 1,
21
+ SUBSTRING = 2,
22
+ NONE = 3,
23
+ }
24
+
25
+ const getFieldMatchRank = (
26
+ fieldValue: string | undefined,
27
+ lower: string
28
+ ): MenuV2MatchRank => {
29
+ if (!fieldValue) return MenuV2MatchRank.NONE
30
+ const value = fieldValue.toLowerCase()
31
+ if (value === lower) return MenuV2MatchRank.EXACT
32
+ if (value.startsWith(lower)) return MenuV2MatchRank.PREFIX
33
+ if (value.includes(lower)) return MenuV2MatchRank.SUBSTRING
34
+ return MenuV2MatchRank.NONE
35
+ }
36
+
37
+ export const getItemMatchRank = (
38
+ item: MenuV2ItemType,
39
+ lower: string
40
+ ): MenuV2MatchRank => {
41
+ return Math.min(
42
+ getFieldMatchRank(item.label.text, lower),
43
+ getFieldMatchRank(item.subLabel, lower)
44
+ ) as MenuV2MatchRank
45
+ }
46
+
47
+ export const defaultSearchSortFn: MenuV2SearchSortFn = (items, searchText) => {
48
+ if (!searchText.trim()) return items
49
+ const lower = searchText.toLowerCase()
50
+ return [...items].sort(
51
+ (a, b) => getItemMatchRank(a, lower) - getItemMatchRank(b, lower)
52
+ )
53
+ }
54
+
14
55
  export const filterMenuV2Item = (
15
56
  item: MenuV2ItemType,
16
57
  lower: string
@@ -140,7 +181,8 @@ export const flattenMenuV2Groups = (
140
181
 
141
182
  export const filterMenuV2Groups = (
142
183
  groups: MenuV2GroupType[],
143
- searchText: string
184
+ searchText: string,
185
+ searchSortFn: MenuV2SearchSortFn = defaultSearchSortFn
144
186
  ): MenuV2GroupType[] => {
145
187
  if (!searchText) return groups
146
188
  const lower = searchText.toLowerCase()
@@ -150,7 +192,7 @@ export const filterMenuV2Groups = (
150
192
  .map((item) => filterMenuV2Item(item, lower))
151
193
  .filter(Boolean) as MenuV2ItemType[]
152
194
  if (filteredItems.length === 0) return null
153
- return { ...group, items: filteredItems }
195
+ return { ...group, items: searchSortFn(filteredItems, searchText) }
154
196
  })
155
197
  .filter(Boolean) as MenuV2GroupType[]
156
198
  }
@@ -1,3 +1,4 @@
1
+ /** @deprecated Will be deprecated soon. Use ModalV2 instead. */
1
2
  export { default as Modal } from './Modal'
2
3
  export * from './modal.tokens'
3
4
  export * from './types'
@@ -0,0 +1,269 @@
1
+ import { forwardRef, useCallback } from 'react'
2
+ import { ModalV2Props } from './modalV2.types'
3
+ import { useResponsiveTokens } from '../../hooks/useResponsiveTokens'
4
+ import type { ModalV2TokensType } from './modalV2.tokens.types'
5
+ import { useBreakpoints } from '../../hooks/useBreakPoints'
6
+ import { useModal } from '../Modal/useModal'
7
+ import { useId } from 'react'
8
+ import Block from '../Primitives/Block/Block'
9
+ import MobileModalV2 from './mobileModalV2'
10
+ import styled from 'styled-components'
11
+ import { modalBackdropAnimationsV2 } from './modalAnimationV2'
12
+ import { modalContentAnimationsV2 } from './modalAnimationV2'
13
+ import ModalV2Header from './ModalV2Header'
14
+ import ModalV2Skeleton from './ModalV2Skeleton'
15
+ import ModalV2Footer from './ModalV2Footer'
16
+ import { createPortal } from 'react-dom'
17
+ import { filterBlockedProps } from '../../utils/prop-helpers'
18
+
19
+ const AnimatedBackdrop = styled(Block)<{ $isAnimatingIn: boolean }>`
20
+ ${({ $isAnimatingIn }) => modalBackdropAnimationsV2($isAnimatingIn)}
21
+ `
22
+
23
+ const AnimatedModalContent = styled(Block)<{ $isAnimatingIn: boolean }>`
24
+ ${({ $isAnimatingIn }) => modalContentAnimationsV2($isAnimatingIn)}
25
+ `
26
+
27
+ const ModalV2 = forwardRef<HTMLDivElement, ModalV2Props>(
28
+ (
29
+ {
30
+ isOpen,
31
+ isCustom = false,
32
+ onClose,
33
+ title,
34
+ subtitle,
35
+ children,
36
+ primaryAction,
37
+ secondaryAction,
38
+ showCloseButton = true,
39
+ showHeader = true,
40
+ showFooter = true,
41
+ closeOnBackdropClick = true,
42
+ customHeader,
43
+ customFooter,
44
+ headerSlot,
45
+ showDivider = true,
46
+ dimensions = {},
47
+ useDrawerOnMobile = true,
48
+ skeleton,
49
+ ...props
50
+ },
51
+ ref
52
+ ) => {
53
+ const filteredRest = filterBlockedProps(props)
54
+ const {
55
+ 'aria-label': ariaLabel,
56
+ 'aria-labelledby': ariaLabelledBy,
57
+ 'aria-describedby': ariaDescribedBy,
58
+ ...dialogProps
59
+ } = filteredRest
60
+ const modalTokens = useResponsiveTokens<ModalV2TokensType>('MODALV2')
61
+ const { innerWidth } = useBreakpoints()
62
+ const isMobile = innerWidth < 1024
63
+ const { shouldRender, isAnimatingIn, portalContainer } = useModal(
64
+ isOpen,
65
+ onClose
66
+ )
67
+
68
+ const baseId = useId()
69
+ const shouldUseGeneratedHeader = showHeader && !customHeader
70
+ const titleId =
71
+ shouldUseGeneratedHeader && title ? `${baseId}-title` : undefined
72
+ const subtitleId =
73
+ shouldUseGeneratedHeader && subtitle
74
+ ? `${baseId}-subtitle`
75
+ : undefined
76
+
77
+ const handleBackdropClick = useCallback(() => {
78
+ if (closeOnBackdropClick) {
79
+ onClose()
80
+ }
81
+ }, [closeOnBackdropClick, onClose])
82
+
83
+ if (!shouldRender || !portalContainer) return null
84
+
85
+ const shouldShowSkeleton = skeleton?.show
86
+ const skeletonVariant = skeleton?.variant || 'pulse'
87
+ const shouldShowBodySkeleton = Boolean(
88
+ shouldShowSkeleton && skeleton?.bodySkeletonProps?.show
89
+ )
90
+ const hasFooterContent = Boolean(
91
+ customFooter ||
92
+ primaryAction ||
93
+ secondaryAction ||
94
+ shouldShowSkeleton
95
+ )
96
+ const {
97
+ width,
98
+ height,
99
+ minWidth = '',
100
+ minHeight = '',
101
+ maxWidth = '90vw',
102
+ maxHeight = '90vh',
103
+ } = dimensions
104
+
105
+ const modalContent = (() => {
106
+ if (isMobile && useDrawerOnMobile) {
107
+ return (
108
+ <MobileModalV2
109
+ isOpen={isOpen}
110
+ onClose={onClose}
111
+ skeleton={skeleton}
112
+ title={title}
113
+ subtitle={subtitle}
114
+ primaryAction={primaryAction}
115
+ secondaryAction={secondaryAction}
116
+ showCloseButton={showCloseButton}
117
+ showHeader={showHeader}
118
+ showFooter={showFooter}
119
+ closeOnBackdropClick={closeOnBackdropClick}
120
+ customHeader={customHeader}
121
+ customFooter={customFooter}
122
+ headerSlot={headerSlot}
123
+ showDivider={showDivider}
124
+ ref={ref}
125
+ {...filteredRest}
126
+ >
127
+ {children}
128
+ </MobileModalV2>
129
+ )
130
+ }
131
+
132
+ return (
133
+ <Block
134
+ position="fixed"
135
+ inset={0}
136
+ zIndex={99}
137
+ display="flex"
138
+ alignItems="center"
139
+ justifyContent="center"
140
+ boxShadow={modalTokens.boxShadow}
141
+ paddingTop={modalTokens.paddingTop}
142
+ paddingRight={modalTokens.paddingRight}
143
+ paddingBottom={modalTokens.paddingBottom}
144
+ paddingLeft={modalTokens.paddingLeft}
145
+ >
146
+ <AnimatedBackdrop
147
+ onClick={handleBackdropClick}
148
+ position="absolute"
149
+ inset={0}
150
+ backgroundColor={modalTokens.overlay.backgroundColor}
151
+ pointerEvents="auto"
152
+ role="presentation"
153
+ aria-hidden="true"
154
+ zIndex={0}
155
+ $isAnimatingIn={isAnimatingIn}
156
+ />
157
+
158
+ <AnimatedModalContent
159
+ {...dialogProps}
160
+ data-modal={title ?? 'modal'}
161
+ ref={ref}
162
+ display="flex"
163
+ flexDirection="column"
164
+ position="relative"
165
+ backgroundColor={modalTokens.backgroundColor}
166
+ width={width}
167
+ height={height}
168
+ minWidth={minWidth}
169
+ minHeight={minHeight}
170
+ maxWidth={maxWidth}
171
+ maxHeight={maxHeight}
172
+ borderRadius={modalTokens.borderRadius}
173
+ boxShadow={modalTokens.boxShadow}
174
+ role="dialog"
175
+ aria-modal="true"
176
+ aria-labelledby={
177
+ ariaLabel ? undefined : (ariaLabelledBy ?? titleId)
178
+ }
179
+ aria-label={
180
+ ariaLabel ??
181
+ (ariaLabelledBy || titleId
182
+ ? undefined
183
+ : title || 'Modal dialog')
184
+ }
185
+ aria-describedby={ariaDescribedBy ?? subtitleId}
186
+ zIndex={1}
187
+ pointerEvents="auto"
188
+ $isAnimatingIn={isAnimatingIn}
189
+ >
190
+ {showHeader &&
191
+ (customHeader ?? (
192
+ <ModalV2Header
193
+ title={title}
194
+ subtitle={subtitle}
195
+ onClose={onClose}
196
+ showCloseButton={showCloseButton}
197
+ headerSlot={headerSlot}
198
+ showDivider={showDivider}
199
+ showSkeleton={shouldShowSkeleton}
200
+ skeletonVariant={skeletonVariant}
201
+ titleId={titleId}
202
+ subtitleId={subtitleId}
203
+ />
204
+ ))}
205
+
206
+ <Block
207
+ data-element="body"
208
+ paddingTop={
209
+ isCustom ? '0' : modalTokens.body.paddingTop
210
+ }
211
+ paddingRight={
212
+ isCustom ? '0' : modalTokens.body.paddingRight
213
+ }
214
+ paddingBottom={
215
+ isCustom ? '0' : modalTokens.body.paddingBottom
216
+ }
217
+ paddingLeft={
218
+ isCustom ? '0' : modalTokens.body.paddingLeft
219
+ }
220
+ overflow="auto"
221
+ flexShrink={1}
222
+ minHeight={0}
223
+ borderRadius={
224
+ !showFooter || !hasFooterContent
225
+ ? `0 0 ${modalTokens.borderRadius} ${modalTokens.borderRadius}`
226
+ : undefined
227
+ }
228
+ >
229
+ {shouldShowBodySkeleton ? (
230
+ <ModalV2Skeleton
231
+ modalTokens={modalTokens}
232
+ bodySkeleton={{
233
+ show: true,
234
+ width:
235
+ skeleton?.bodySkeletonProps
236
+ ?.width || '100%',
237
+ height:
238
+ skeleton?.bodySkeletonProps
239
+ ?.height || 300,
240
+ }}
241
+ skeletonVariant={skeletonVariant}
242
+ />
243
+ ) : (
244
+ children
245
+ )}
246
+ </Block>
247
+
248
+ {showFooter &&
249
+ (customFooter ?? (
250
+ <ModalV2Footer
251
+ primaryAction={primaryAction}
252
+ secondaryAction={secondaryAction}
253
+ showDivider={showDivider}
254
+ showSkeleton={shouldShowSkeleton}
255
+ skeletonVariant={skeletonVariant}
256
+ />
257
+ ))}
258
+ </AnimatedModalContent>
259
+ </Block>
260
+ )
261
+ })()
262
+
263
+ return createPortal(modalContent, portalContainer)
264
+ }
265
+ )
266
+
267
+ ModalV2.displayName = 'ModalV2'
268
+
269
+ export default ModalV2
@@ -0,0 +1,76 @@
1
+ import Block from '../Primitives/Block/Block'
2
+ import { useResponsiveTokens } from '../../hooks/useResponsiveTokens'
3
+ import { ButtonV2, ButtonV2Type } from '../ButtonV2'
4
+ import type { ModalV2TokensType } from './modalV2.tokens.types'
5
+ import { ModalV2Props } from './modalV2.types'
6
+ import { SkeletonVariant } from '../Skeleton'
7
+ import ModalV2Skeleton from './ModalV2Skeleton'
8
+
9
+ const ModalV2Footer = ({
10
+ primaryAction,
11
+ secondaryAction,
12
+ showDivider,
13
+ showSkeleton,
14
+ skeletonVariant,
15
+ }: {
16
+ primaryAction?: ModalV2Props['primaryAction']
17
+ secondaryAction?: ModalV2Props['secondaryAction']
18
+ showDivider?: boolean
19
+ showSkeleton?: boolean
20
+ skeletonVariant?: SkeletonVariant
21
+ }) => {
22
+ const modalTokens = useResponsiveTokens<ModalV2TokensType>('MODALV2')
23
+
24
+ if (showSkeleton) {
25
+ return (
26
+ <ModalV2Skeleton
27
+ modalTokens={modalTokens}
28
+ footerSkeleton={{
29
+ show: showSkeleton || false,
30
+ showDivider: showDivider || false,
31
+ }}
32
+ skeletonVariant={
33
+ skeletonVariant || ('pulse' as SkeletonVariant)
34
+ }
35
+ />
36
+ )
37
+ }
38
+
39
+ if (!primaryAction && !secondaryAction) return null
40
+
41
+ return (
42
+ <Block
43
+ data-element="footer"
44
+ display="flex"
45
+ backgroundColor={modalTokens.footer.backgroundColor}
46
+ justifyContent="flex-end"
47
+ gap={modalTokens.footer.gap}
48
+ paddingTop={modalTokens.footer.paddingTop}
49
+ paddingRight={modalTokens.footer.paddingRight}
50
+ paddingBottom={modalTokens.footer.paddingBottom}
51
+ paddingLeft={modalTokens.footer.paddingLeft}
52
+ flexShrink={0}
53
+ borderTop={showDivider ? modalTokens.footer.borderTop : undefined}
54
+ borderRadius={`0 0 ${modalTokens.borderRadius} ${modalTokens.borderRadius}`}
55
+ >
56
+ {secondaryAction && (
57
+ <ButtonV2
58
+ {...secondaryAction}
59
+ buttonType={
60
+ secondaryAction.buttonType || ButtonV2Type.SECONDARY
61
+ }
62
+ />
63
+ )}
64
+ {primaryAction && (
65
+ <ButtonV2
66
+ {...primaryAction}
67
+ buttonType={
68
+ primaryAction.buttonType || ButtonV2Type.PRIMARY
69
+ }
70
+ />
71
+ )}
72
+ </Block>
73
+ )
74
+ }
75
+
76
+ export default ModalV2Footer