@juspay/blend-design-system 0.0.37-beta.8 → 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 (240) hide show
  1. package/dist/components/Accordion/index.d.ts +2 -0
  2. package/dist/components/AccordionV2/accordionV2.animations.d.ts +1 -1
  3. package/dist/components/Alert/index.d.ts +1 -0
  4. package/dist/components/Avatar/index.d.ts +1 -0
  5. package/dist/components/Breadcrumb/index.d.ts +1 -0
  6. package/dist/components/Button/index.d.ts +1 -0
  7. package/dist/components/ButtonGroup/index.d.ts +1 -0
  8. package/dist/components/Card/index.d.ts +1 -0
  9. package/dist/components/CardV2/CardV2.d.ts +45 -0
  10. package/dist/components/CardV2/CardV2.utils.d.ts +14 -0
  11. package/dist/components/CardV2/CardV2Components.d.ts +8 -0
  12. package/dist/components/CardV2/CardV2Context.d.ts +14 -0
  13. package/dist/components/CardV2/CardV2Skeleton.d.ts +6 -0
  14. package/dist/components/CardV2/accessibility/CardV2AccessibilityReport.d.ts +2 -0
  15. package/dist/components/CardV2/accessibility/index.d.ts +1 -0
  16. package/dist/components/CardV2/cardV2.dark.tokens.d.ts +3 -0
  17. package/dist/components/CardV2/cardV2.light.tokens.d.ts +3 -0
  18. package/dist/components/CardV2/cardV2.tokens.d.ts +5 -0
  19. package/dist/components/CardV2/cardV2.tokens.types.d.ts +92 -0
  20. package/dist/components/CardV2/cardV2.types.d.ts +106 -0
  21. package/dist/components/CardV2/index.d.ts +5 -0
  22. package/dist/components/Charts/index.d.ts +10 -0
  23. package/dist/components/Charts/types.d.ts +2 -0
  24. package/dist/components/ChatInput/index.d.ts +1 -0
  25. package/dist/components/Checkbox/index.d.ts +1 -0
  26. package/dist/components/CodeEditor/index.d.ts +1 -0
  27. package/dist/components/DataTable/PivotTableModal/pivotModal.styled.d.ts +184 -0
  28. package/dist/components/DataTable/TableBody/types.d.ts +3 -1
  29. package/dist/components/DataTable/hooks/index.d.ts +2 -0
  30. package/dist/components/DataTable/hooks/useReducedMotion.d.ts +1 -0
  31. package/dist/components/DataTable/hooks/useRowFlip.d.ts +6 -0
  32. package/dist/components/DataTable/types.d.ts +26 -0
  33. package/dist/components/DateRangePicker/CalendarGrid.d.ts +5 -2
  34. package/dist/components/DateRangePicker/types.d.ts +3 -1
  35. package/dist/components/DateRangePicker/utils.d.ts +5 -5
  36. package/dist/components/Directory/Directory.d.ts +1 -1
  37. package/dist/components/Directory/NavItem.d.ts +1 -1
  38. package/dist/components/Directory/Section.d.ts +1 -1
  39. package/dist/components/Directory/VirtualizedDirectory.d.ts +3 -0
  40. package/dist/components/Directory/directory.tokens.d.ts +7 -0
  41. package/dist/components/Directory/types.d.ts +38 -1
  42. package/dist/components/Directory/utils.d.ts +3 -1
  43. package/dist/components/Drawer/index.d.ts +1 -0
  44. package/dist/components/Inputs/MultiValueInput/index.d.ts +1 -0
  45. package/dist/components/Inputs/NumberInput/index.d.ts +1 -0
  46. package/dist/components/Inputs/OTPInput/index.d.ts +1 -0
  47. package/dist/components/Inputs/SearchInput/index.d.ts +1 -0
  48. package/dist/components/Inputs/TextArea/index.d.ts +1 -0
  49. package/dist/components/Inputs/TextInput/index.d.ts +1 -0
  50. package/dist/components/InputsV2/TextAreaV2/utils.d.ts +2 -1
  51. package/dist/components/InputsV2/TextInputV2/utils.d.ts +2 -1
  52. package/dist/components/InputsV2/UploadV2/UploadContainerV2.d.ts +24 -0
  53. package/dist/components/InputsV2/UploadV2/UploadV2.d.ts +31 -0
  54. package/dist/components/InputsV2/UploadV2/UploadV2.dark.tokens.d.ts +3 -0
  55. package/dist/components/InputsV2/UploadV2/UploadV2.light.tokens.d.ts +3 -0
  56. package/dist/components/InputsV2/UploadV2/UploadV2.tokens.d.ts +5 -0
  57. package/dist/components/InputsV2/UploadV2/UploadV2.tokens.types.d.ts +115 -0
  58. package/dist/components/InputsV2/UploadV2/UploadV2.types.d.ts +56 -0
  59. package/dist/components/InputsV2/UploadV2/index.d.ts +3 -0
  60. package/dist/components/InputsV2/UploadV2/utils.d.ts +32 -0
  61. package/dist/components/KeyValuePair/index.d.ts +1 -0
  62. package/dist/components/Menu/Menu.d.ts +1 -1
  63. package/dist/components/Menu/index.d.ts +1 -0
  64. package/dist/components/Menu/types.d.ts +7 -0
  65. package/dist/components/Menu/utils.d.ts +10 -2
  66. package/dist/components/Modal/index.d.ts +1 -0
  67. package/dist/components/ModalV2/ModalV2.d.ts +22 -0
  68. package/dist/components/ModalV2/ModalV2Footer.d.ts +10 -0
  69. package/dist/components/ModalV2/ModalV2Header.d.ts +15 -0
  70. package/dist/components/ModalV2/ModalV2Skeleton.d.ts +4 -0
  71. package/dist/components/ModalV2/index.d.ts +4 -0
  72. package/dist/components/ModalV2/mobileModalV2.d.ts +23 -0
  73. package/dist/components/ModalV2/modalAnimationV2.d.ts +3 -0
  74. package/dist/components/ModalV2/modalV2.dark.tokens.d.ts +3 -0
  75. package/dist/components/ModalV2/modalV2.light.tokens.d.ts +3 -0
  76. package/dist/components/ModalV2/modalV2.tokens.d.ts +5 -0
  77. package/dist/components/ModalV2/modalV2.tokens.types.d.ts +91 -0
  78. package/dist/components/ModalV2/modalV2.types.d.ts +66 -0
  79. package/dist/components/MultiSelect/index.d.ts +2 -0
  80. package/dist/components/Popover/index.d.ts +1 -0
  81. package/dist/components/Primitives/Block/Block.d.ts +1 -1
  82. package/dist/components/ProgressBar/index.d.ts +1 -0
  83. package/dist/components/Radio/index.d.ts +2 -0
  84. package/dist/components/Sidebar/SidebarContent.d.ts +9 -1
  85. package/dist/components/Sidebar/index.d.ts +1 -0
  86. package/dist/components/Sidebar/types.d.ts +9 -1
  87. package/dist/components/SidebarV2/SidebarV2Panel.d.ts +10 -2
  88. package/dist/components/SidebarV2/types.d.ts +9 -1
  89. package/dist/components/SingleSelect/index.d.ts +1 -0
  90. package/dist/components/Skeleton/SkeletonCompound.d.ts +24 -33
  91. package/dist/components/Snackbar/index.d.ts +2 -0
  92. package/dist/components/StatCard/index.d.ts +1 -0
  93. package/dist/components/Stepper/index.d.ts +1 -0
  94. package/dist/components/Switch/index.d.ts +2 -0
  95. package/dist/components/Tabs/index.d.ts +1 -0
  96. package/dist/components/Tags/index.d.ts +1 -0
  97. package/dist/components/Timeline/Timeline.d.ts +13 -37
  98. package/dist/components/Tooltip/index.d.ts +1 -0
  99. package/dist/components/Topbar/index.d.ts +1 -0
  100. package/dist/components/Upload/index.d.ts +1 -0
  101. package/dist/context/ThemeContext.d.ts +6 -0
  102. package/dist/context/useComponentToken.d.ts +4 -1
  103. package/dist/main.d.ts +6 -0
  104. package/dist/main.js +45081 -41934
  105. package/dist/node-B3rrXW84.js +1023 -0
  106. package/dist/node.d.ts +2 -0
  107. package/dist/node.js +21 -18
  108. package/dist/token-engine.js +1 -1
  109. package/lib/components/Accordion/AccordionItem.tsx +2 -6
  110. package/lib/components/Accordion/index.ts +2 -0
  111. package/lib/components/AccordionV2/AccordionV2Item.tsx +1 -1
  112. package/lib/components/AccordionV2/accordionV2.animations.ts +1 -5
  113. package/lib/components/Alert/index.ts +1 -0
  114. package/lib/components/Avatar/index.ts +1 -0
  115. package/lib/components/Breadcrumb/index.ts +1 -0
  116. package/lib/components/Button/index.ts +1 -0
  117. package/lib/components/ButtonGroup/index.ts +1 -0
  118. package/lib/components/Card/index.ts +1 -0
  119. package/lib/components/CardV2/CardV2.tsx +327 -0
  120. package/lib/components/CardV2/CardV2.utils.tsx +77 -0
  121. package/lib/components/CardV2/CardV2Components.tsx +297 -0
  122. package/lib/components/CardV2/CardV2Context.tsx +18 -0
  123. package/lib/components/CardV2/CardV2Skeleton.tsx +40 -0
  124. package/lib/components/CardV2/accessibility/CardV2AccessibilityReport.ts +284 -0
  125. package/lib/components/CardV2/accessibility/index.ts +1 -0
  126. package/lib/components/CardV2/cardV2.dark.tokens.ts +177 -0
  127. package/lib/components/CardV2/cardV2.light.tokens.ts +177 -0
  128. package/lib/components/CardV2/cardV2.tokens.ts +21 -0
  129. package/lib/components/CardV2/cardV2.tokens.types.ts +94 -0
  130. package/lib/components/CardV2/cardV2.types.ts +131 -0
  131. package/lib/components/CardV2/index.ts +13 -0
  132. package/lib/components/Charts/ChartLegend.tsx +25 -5
  133. package/lib/components/Charts/Charts.tsx +10 -0
  134. package/lib/components/Charts/index.ts +10 -0
  135. package/lib/components/Charts/types.tsx +2 -0
  136. package/lib/components/ChatInput/index.tsx +1 -0
  137. package/lib/components/Checkbox/index.ts +1 -0
  138. package/lib/components/CodeEditor/index.ts +1 -0
  139. package/lib/components/DataTable/DataTable.tsx +8 -0
  140. package/lib/components/DataTable/TableBody/index.tsx +47 -11
  141. package/lib/components/DataTable/TableBody/types.ts +7 -1
  142. package/lib/components/DataTable/TableCell/index.tsx +1 -1
  143. package/lib/components/DataTable/hooks/index.ts +2 -0
  144. package/lib/components/DataTable/hooks/useReducedMotion.ts +19 -0
  145. package/lib/components/DataTable/hooks/useRowFlip.ts +170 -0
  146. package/lib/components/DataTable/types.ts +32 -0
  147. package/lib/components/DateRangePicker/CalendarGrid.tsx +36 -6
  148. package/lib/components/DateRangePicker/DateRangePicker.tsx +22 -3
  149. package/lib/components/DateRangePicker/types.ts +6 -1
  150. package/lib/components/DateRangePicker/utils.ts +123 -12
  151. package/lib/components/Directory/Directory.tsx +31 -0
  152. package/lib/components/Directory/NavItem.tsx +177 -86
  153. package/lib/components/Directory/Section.tsx +9 -0
  154. package/lib/components/Directory/VirtualizedDirectory.tsx +670 -0
  155. package/lib/components/Directory/directory.tokens.ts +21 -0
  156. package/lib/components/Directory/types.ts +43 -1
  157. package/lib/components/Directory/utils.ts +81 -1
  158. package/lib/components/Drawer/index.ts +1 -0
  159. package/lib/components/Inputs/DropdownInput/DropdownInput.tsx +6 -2
  160. package/lib/components/Inputs/MultiValueInput/index.ts +1 -0
  161. package/lib/components/Inputs/NumberInput/NumberInput.tsx +6 -2
  162. package/lib/components/Inputs/NumberInput/index.ts +1 -0
  163. package/lib/components/Inputs/OTPInput/index.ts +1 -0
  164. package/lib/components/Inputs/SearchInput/index.ts +1 -0
  165. package/lib/components/Inputs/TextArea/TextArea.tsx +4 -2
  166. package/lib/components/Inputs/TextArea/index.ts +1 -0
  167. package/lib/components/Inputs/TextInput/TextInput.tsx +6 -2
  168. package/lib/components/Inputs/TextInput/index.ts +1 -0
  169. package/lib/components/Inputs/UnitInput/UnitInput.tsx +6 -2
  170. package/lib/components/InputsV2/NumberInputV2/NumberInputV2.tsx +6 -2
  171. package/lib/components/InputsV2/TextAreaV2/TextAreaV2.tsx +2 -1
  172. package/lib/components/InputsV2/TextAreaV2/utils.ts +3 -1
  173. package/lib/components/InputsV2/TextInputV2/TextInputV2.tsx +1 -0
  174. package/lib/components/InputsV2/TextInputV2/utils.ts +6 -8
  175. package/lib/components/InputsV2/UploadV2/UploadContainerV2.tsx +470 -0
  176. package/lib/components/InputsV2/UploadV2/UploadV2.dark.tokens.ts +348 -0
  177. package/lib/components/InputsV2/UploadV2/UploadV2.light.tokens.ts +348 -0
  178. package/lib/components/InputsV2/UploadV2/UploadV2.tokens.ts +20 -0
  179. package/lib/components/InputsV2/UploadV2/UploadV2.tokens.types.ts +117 -0
  180. package/lib/components/InputsV2/UploadV2/UploadV2.tsx +336 -0
  181. package/lib/components/InputsV2/UploadV2/UploadV2.types.ts +67 -0
  182. package/lib/components/InputsV2/UploadV2/index.ts +3 -0
  183. package/lib/components/InputsV2/UploadV2/utils.ts +170 -0
  184. package/lib/components/KeyValuePair/index.ts +1 -0
  185. package/lib/components/Menu/Menu.tsx +18 -2
  186. package/lib/components/Menu/SubMenu.tsx +25 -3
  187. package/lib/components/Menu/index.ts +1 -0
  188. package/lib/components/Menu/types.tsx +14 -0
  189. package/lib/components/Menu/utils.ts +46 -3
  190. package/lib/components/Modal/index.ts +1 -0
  191. package/lib/components/ModalV2/ModalV2.tsx +269 -0
  192. package/lib/components/ModalV2/ModalV2Footer.tsx +76 -0
  193. package/lib/components/ModalV2/ModalV2Header.tsx +144 -0
  194. package/lib/components/ModalV2/ModalV2Skeleton.tsx +80 -0
  195. package/lib/components/ModalV2/index.ts +4 -0
  196. package/lib/components/ModalV2/mobileModalV2.tsx +411 -0
  197. package/lib/components/ModalV2/modalAnimationV2.tsx +19 -0
  198. package/lib/components/ModalV2/modalV2.dark.tokens.ts +183 -0
  199. package/lib/components/ModalV2/modalV2.light.tokens.ts +183 -0
  200. package/lib/components/ModalV2/modalV2.tokens.ts +21 -0
  201. package/lib/components/ModalV2/modalV2.tokens.types.ts +94 -0
  202. package/lib/components/ModalV2/modalV2.types.ts +80 -0
  203. package/lib/components/MultiSelect/MultiSelect.tsx +2 -1
  204. package/lib/components/MultiSelect/MultiSelectTrigger.tsx +2 -1
  205. package/lib/components/MultiSelect/index.ts +2 -0
  206. package/lib/components/MultiSelectV2/MultiSelectV2Trigger.tsx +4 -1
  207. package/lib/components/Popover/index.ts +1 -0
  208. package/lib/components/Primitives/Block/Block.tsx +1 -1
  209. package/lib/components/ProgressBar/index.ts +1 -0
  210. package/lib/components/Radio/index.ts +2 -0
  211. package/lib/components/Sidebar/Sidebar.tsx +38 -0
  212. package/lib/components/Sidebar/SidebarContent.tsx +25 -1
  213. package/lib/components/Sidebar/index.ts +1 -0
  214. package/lib/components/Sidebar/types.ts +13 -1
  215. package/lib/components/SidebarV2/SidebarV2.tsx +30 -0
  216. package/lib/components/SidebarV2/SidebarV2Panel.tsx +25 -1
  217. package/lib/components/SidebarV2/types.ts +9 -1
  218. package/lib/components/SingleSelect/SingleSelect.tsx +2 -1
  219. package/lib/components/SingleSelect/SingleSelectTrigger.tsx +3 -1
  220. package/lib/components/SingleSelect/index.ts +1 -0
  221. package/lib/components/SingleSelectV2/SingleSelectV2Trigger.tsx +3 -1
  222. package/lib/components/Skeleton/SkeletonCompound.tsx +45 -31
  223. package/lib/components/Snackbar/index.ts +2 -0
  224. package/lib/components/StatCard/index.ts +1 -0
  225. package/lib/components/Stepper/index.ts +1 -0
  226. package/lib/components/Switch/index.ts +2 -0
  227. package/lib/components/Tabs/index.ts +1 -0
  228. package/lib/components/Tags/index.ts +1 -0
  229. package/lib/components/Timeline/Timeline.tsx +9 -1
  230. package/lib/components/Tooltip/index.ts +1 -0
  231. package/lib/components/Topbar/index.ts +1 -0
  232. package/lib/components/Upload/index.ts +1 -0
  233. package/lib/context/ThemeContext.tsx +16 -0
  234. package/lib/context/initComponentTokens.ts +11 -0
  235. package/lib/context/useComponentToken.ts +15 -1
  236. package/lib/hooks/useResponsiveTokens.ts +63 -0
  237. package/lib/main.ts +16 -0
  238. package/lib/node.ts +2 -0
  239. package/package.json +1 -1
  240. /package/dist/{node-CovJEwot.js → breadcrumbV2.tokens-CovJEwot.js} +0 -0
@@ -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
  }
@@ -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
@@ -0,0 +1,144 @@
1
+ import { useResponsiveTokens } from '../../hooks/useResponsiveTokens'
2
+ import type { ReactNode } from 'react'
3
+ import { SkeletonVariant } from '../Skeleton'
4
+ import type { ModalV2TokensType } from './modalV2.tokens.types'
5
+ import ModalV2Skeleton from './ModalV2Skeleton'
6
+ import Block from '../Primitives/Block/Block'
7
+ import Text from '../Text/Text'
8
+ import { ButtonV2, ButtonV2Type, ButtonV2SubType } from '../ButtonV2'
9
+ import { XIcon } from '@phosphor-icons/react'
10
+
11
+ const formatLineHeight = (value: string | number | undefined) =>
12
+ typeof value === 'number' ? `${value}px` : value
13
+
14
+ const ModalV2Header = ({
15
+ title,
16
+ subtitle,
17
+ onClose,
18
+ showCloseButton,
19
+ headerSlot,
20
+ showDivider,
21
+ showSkeleton,
22
+ skeletonVariant,
23
+ titleId,
24
+ subtitleId,
25
+ }: {
26
+ title?: string
27
+ subtitle?: string
28
+ onClose: () => void
29
+ showCloseButton?: boolean
30
+ headerSlot?: ReactNode
31
+ showDivider?: boolean
32
+ showSkeleton?: boolean
33
+ skeletonVariant?: SkeletonVariant
34
+ titleId?: string
35
+ subtitleId?: string
36
+ }) => {
37
+ const modalTokens = useResponsiveTokens<ModalV2TokensType>('MODALV2')
38
+
39
+ if (showSkeleton) {
40
+ return (
41
+ <ModalV2Skeleton
42
+ modalTokens={modalTokens}
43
+ headerSkeleton={{
44
+ show: showSkeleton || false,
45
+ showDivider: showDivider || false,
46
+ showCloseButton: showCloseButton || false,
47
+ }}
48
+ skeletonVariant={
49
+ skeletonVariant || ('pulse' as SkeletonVariant)
50
+ }
51
+ />
52
+ )
53
+ }
54
+
55
+ if (!title && !subtitle && !headerSlot && !showCloseButton) return null
56
+
57
+ return (
58
+ <Block
59
+ display="flex"
60
+ justifyContent="space-between"
61
+ alignItems="flex-start"
62
+ paddingTop={modalTokens.header.paddingTop}
63
+ paddingRight={modalTokens.header.paddingRight}
64
+ paddingBottom={modalTokens.header.paddingBottom}
65
+ paddingLeft={modalTokens.header.paddingLeft}
66
+ flexShrink={0}
67
+ overflow="auto"
68
+ maxHeight={modalTokens.header.maxHeight}
69
+ gap={modalTokens.header.gap}
70
+ backgroundColor={modalTokens.header.backgroundColor}
71
+ borderTopLeftRadius={modalTokens.header.borderTopLeftRadius}
72
+ borderTopRightRadius={modalTokens.header.borderTopRightRadius}
73
+ borderBottom={
74
+ showDivider ? modalTokens.header.borderBottom : undefined
75
+ }
76
+ >
77
+ <Block display="flex" flexDirection="column">
78
+ <Block
79
+ display="flex"
80
+ flexDirection="row"
81
+ gap={modalTokens.header.slot.gap}
82
+ alignItems="center"
83
+ >
84
+ {title && (
85
+ <Text
86
+ id={titleId}
87
+ data-element="header"
88
+ data-id={title ?? ''}
89
+ as="span"
90
+ fontSize={modalTokens.header.text.title.fontSize}
91
+ fontWeight={
92
+ modalTokens.header.text.title.fontWeight
93
+ }
94
+ lineHeight={formatLineHeight(
95
+ modalTokens.header.text.title.lineHeight
96
+ )}
97
+ color={modalTokens.header.text.title.color}
98
+ >
99
+ {title}
100
+ </Text>
101
+ )}
102
+ {headerSlot}
103
+ </Block>
104
+
105
+ {subtitle && (
106
+ <Text
107
+ id={subtitleId}
108
+ data-element="header-subtitle"
109
+ data-id={subtitle}
110
+ as="span"
111
+ fontSize={modalTokens.header.text.subtitle.fontSize}
112
+ color={modalTokens.header.text.subtitle.color}
113
+ fontWeight={modalTokens.header.text.subtitle.fontWeight}
114
+ lineHeight={formatLineHeight(
115
+ modalTokens.header.text.subtitle.lineHeight
116
+ )}
117
+ >
118
+ {subtitle}
119
+ </Text>
120
+ )}
121
+ </Block>
122
+ {showCloseButton && (
123
+ <ButtonV2
124
+ subType={ButtonV2SubType.INLINE}
125
+ buttonType={ButtonV2Type.SECONDARY}
126
+ leftSlot={{
127
+ slot: (
128
+ <XIcon
129
+ size={modalTokens.closeButton.width}
130
+ color={modalTokens.closeButton.color}
131
+ aria-hidden="true"
132
+ />
133
+ ),
134
+ maxHeight: modalTokens.closeButton.height,
135
+ }}
136
+ onClick={onClose}
137
+ aria-label="Close modal"
138
+ />
139
+ )}
140
+ </Block>
141
+ )
142
+ }
143
+
144
+ export default ModalV2Header
@@ -0,0 +1,80 @@
1
+ import Block from '../Primitives/Block/Block'
2
+ import { Skeleton } from '../Skeleton'
3
+ import type { FC } from 'react'
4
+ import type { ModalV2SkeletonProps } from './modalV2.types'
5
+
6
+ const ModalV2Skeleton: FC<ModalV2SkeletonProps> = ({
7
+ modalTokens,
8
+ headerSkeleton,
9
+ bodySkeleton,
10
+ footerSkeleton,
11
+
12
+ skeletonVariant,
13
+ }) => {
14
+ const {
15
+ show: showHeaderSkeleton = false,
16
+ showDivider: showHeaderDivider = false,
17
+ } = headerSkeleton || {}
18
+ const { show: showBodySkeleton = false, width, height } = bodySkeleton || {}
19
+ const { show: showFooterSkeleton = false } = footerSkeleton || {}
20
+
21
+ if (showHeaderSkeleton) {
22
+ return (
23
+ <Block
24
+ display="flex"
25
+ justifyContent="space-between"
26
+ alignItems="flex-start"
27
+ paddingTop={modalTokens.skeleton.header.paddingTop}
28
+ paddingRight={modalTokens.skeleton.header.paddingRight}
29
+ paddingBottom={modalTokens.skeleton.header.paddingBottom}
30
+ paddingLeft={modalTokens.skeleton.header.paddingLeft}
31
+ flexShrink={0}
32
+ gap={modalTokens.skeleton.header.gap}
33
+ borderBottom={
34
+ showHeaderDivider
35
+ ? modalTokens.skeleton.header.borderBottom
36
+ : undefined
37
+ }
38
+ >
39
+ <Block
40
+ display="flex"
41
+ flexDirection="column"
42
+ flexGrow={1}
43
+ gap={modalTokens.skeleton.header.gap}
44
+ >
45
+ <Skeleton
46
+ variant={skeletonVariant}
47
+ width={modalTokens.skeleton.header.width}
48
+ height={modalTokens.skeleton.header.height}
49
+ borderRadius={modalTokens.skeleton.header.borderRadius}
50
+ />
51
+ </Block>
52
+ </Block>
53
+ )
54
+ }
55
+
56
+ if (showBodySkeleton) {
57
+ return (
58
+ <Block
59
+ display="flex"
60
+ flexDirection="column"
61
+ gap={modalTokens.skeleton.body.gap}
62
+ >
63
+ <Skeleton
64
+ variant={skeletonVariant}
65
+ width={width || modalTokens.skeleton.body.width}
66
+ height={height || modalTokens.skeleton.body.height}
67
+ borderRadius={modalTokens.skeleton.body.borderRadius}
68
+ />
69
+ </Block>
70
+ )
71
+ }
72
+
73
+ if (showFooterSkeleton) {
74
+ return null
75
+ }
76
+
77
+ return null
78
+ }
79
+
80
+ export default ModalV2Skeleton
@@ -0,0 +1,4 @@
1
+ export { default as ModalV2 } from './ModalV2'
2
+ export * from './modalV2.tokens'
3
+ export * from './modalV2.tokens.types'
4
+ export * from './modalV2.types'