@borisj74/bv-ds 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +94 -0
  3. package/dist/index.cjs +33885 -0
  4. package/dist/index.d.cts +2715 -0
  5. package/dist/index.d.ts +2715 -0
  6. package/dist/index.js +33717 -0
  7. package/package.json +67 -0
  8. package/src/components/ActivityFeed/ActivityFeed.tsx +48 -0
  9. package/src/components/ActivityFeed/index.ts +2 -0
  10. package/src/components/ActivityGauge/ActivityGauge.tsx +155 -0
  11. package/src/components/ActivityGauge/index.ts +7 -0
  12. package/src/components/AdvancedFilterBar/AdvancedFilterBar.tsx +80 -0
  13. package/src/components/AdvancedFilterBar/index.ts +2 -0
  14. package/src/components/Alert/Alert.tsx +210 -0
  15. package/src/components/Alert/index.ts +2 -0
  16. package/src/components/Avatar/Avatar.tsx +111 -0
  17. package/src/components/Avatar/index.ts +2 -0
  18. package/src/components/AvatarAddButton/AvatarAddButton.tsx +65 -0
  19. package/src/components/AvatarAddButton/index.ts +5 -0
  20. package/src/components/AvatarGroup/AvatarGroup.tsx +79 -0
  21. package/src/components/AvatarGroup/index.ts +6 -0
  22. package/src/components/AvatarLabelGroup/AvatarLabelGroup.tsx +62 -0
  23. package/src/components/AvatarLabelGroup/index.ts +5 -0
  24. package/src/components/AvatarProfilePhoto/AvatarProfilePhoto.tsx +117 -0
  25. package/src/components/AvatarProfilePhoto/index.ts +5 -0
  26. package/src/components/Badge/ColorBadge.tsx +36 -0
  27. package/src/components/Badge/ModernBadge.tsx +38 -0
  28. package/src/components/Badge/PillBadge.tsx +36 -0
  29. package/src/components/Badge/badgeShared.tsx +139 -0
  30. package/src/components/Badge/index.ts +7 -0
  31. package/src/components/BadgeCloseX/BadgeCloseX.tsx +64 -0
  32. package/src/components/BadgeCloseX/index.ts +2 -0
  33. package/src/components/BadgeGroup/BadgeGroup.tsx +61 -0
  34. package/src/components/BadgeGroup/index.ts +7 -0
  35. package/src/components/BreadcrumbButtonBase/BreadcrumbButtonBase.tsx +75 -0
  36. package/src/components/BreadcrumbButtonBase/index.ts +5 -0
  37. package/src/components/Breadcrumbs/Breadcrumbs.tsx +62 -0
  38. package/src/components/Breadcrumbs/index.ts +2 -0
  39. package/src/components/Button/Button.tsx +71 -0
  40. package/src/components/Button/index.ts +2 -0
  41. package/src/components/ButtonCloseX/ButtonCloseX.tsx +54 -0
  42. package/src/components/ButtonCloseX/index.ts +2 -0
  43. package/src/components/ButtonDestructive/ButtonDestructive.tsx +67 -0
  44. package/src/components/ButtonDestructive/index.ts +6 -0
  45. package/src/components/ButtonGroup/ButtonGroup.tsx +28 -0
  46. package/src/components/ButtonGroup/index.ts +2 -0
  47. package/src/components/ButtonGroupSegment/ButtonGroupSegment.tsx +54 -0
  48. package/src/components/ButtonGroupSegment/index.ts +5 -0
  49. package/src/components/ButtonUtility/ButtonUtility.tsx +67 -0
  50. package/src/components/ButtonUtility/index.ts +6 -0
  51. package/src/components/CalendarCell/CalendarCell.tsx +82 -0
  52. package/src/components/CalendarCell/index.ts +2 -0
  53. package/src/components/CalendarCellDayWeekView/CalendarCellDayWeekView.tsx +56 -0
  54. package/src/components/CalendarCellDayWeekView/index.ts +2 -0
  55. package/src/components/CalendarColumnHeader/CalendarColumnHeader.tsx +45 -0
  56. package/src/components/CalendarColumnHeader/index.ts +5 -0
  57. package/src/components/CalendarDateIcon/CalendarDateIcon.tsx +25 -0
  58. package/src/components/CalendarDateIcon/index.ts +2 -0
  59. package/src/components/CalendarEvent/CalendarEvent.tsx +76 -0
  60. package/src/components/CalendarEvent/index.ts +2 -0
  61. package/src/components/CalendarEventDayWeekView/CalendarEventDayWeekView.tsx +76 -0
  62. package/src/components/CalendarEventDayWeekView/index.ts +2 -0
  63. package/src/components/CalendarHeader/CalendarHeader.tsx +47 -0
  64. package/src/components/CalendarHeader/index.ts +2 -0
  65. package/src/components/CalendarRowLabel/CalendarRowLabel.tsx +21 -0
  66. package/src/components/CalendarRowLabel/index.ts +2 -0
  67. package/src/components/CalendarTimemarker/CalendarTimemarker.tsx +46 -0
  68. package/src/components/CalendarTimemarker/index.ts +5 -0
  69. package/src/components/CalendarViewDropdown/CalendarViewDropdown.tsx +101 -0
  70. package/src/components/CalendarViewDropdown/index.ts +6 -0
  71. package/src/components/CardHeader/CardHeader.tsx +57 -0
  72. package/src/components/CardHeader/index.ts +2 -0
  73. package/src/components/CarouselArrow/CarouselArrow.tsx +47 -0
  74. package/src/components/CarouselArrow/index.ts +6 -0
  75. package/src/components/CarouselImage/CarouselImage.tsx +60 -0
  76. package/src/components/CarouselImage/index.ts +2 -0
  77. package/src/components/Change/Change.tsx +73 -0
  78. package/src/components/Change/index.ts +2 -0
  79. package/src/components/ChartLegend/ChartLegend.tsx +38 -0
  80. package/src/components/ChartLegend/index.ts +2 -0
  81. package/src/components/ChartMarker/ChartMarker.tsx +54 -0
  82. package/src/components/ChartMarker/index.ts +2 -0
  83. package/src/components/ChartMini/ChartMini.tsx +86 -0
  84. package/src/components/ChartMini/index.ts +2 -0
  85. package/src/components/ChartTooltip/ChartTooltip.tsx +44 -0
  86. package/src/components/ChartTooltip/index.ts +2 -0
  87. package/src/components/Checkbox/Checkbox.tsx +65 -0
  88. package/src/components/Checkbox/checkboxBase.tsx +81 -0
  89. package/src/components/Checkbox/index.ts +3 -0
  90. package/src/components/CodeSnippet/CodeSnippet.tsx +94 -0
  91. package/src/components/CodeSnippet/index.ts +2 -0
  92. package/src/components/CodeSnippetTabs/CodeSnippetTabs.tsx +44 -0
  93. package/src/components/CodeSnippetTabs/index.ts +2 -0
  94. package/src/components/CommandBar/CommandBar.tsx +80 -0
  95. package/src/components/CommandBar/index.ts +2 -0
  96. package/src/components/CommandBarFooter/CommandBarFooter.tsx +125 -0
  97. package/src/components/CommandBarFooter/index.ts +5 -0
  98. package/src/components/CommandBarMenuSection/CommandBarMenuSection.tsx +28 -0
  99. package/src/components/CommandBarMenuSection/index.ts +2 -0
  100. package/src/components/CommandBarNavigationIcon/CommandBarNavigationIcon.tsx +47 -0
  101. package/src/components/CommandBarNavigationIcon/index.ts +2 -0
  102. package/src/components/CommandDropdownMenuItem/CommandDropdownMenuItem.tsx +51 -0
  103. package/src/components/CommandDropdownMenuItem/index.ts +2 -0
  104. package/src/components/CommandInput/CommandInput.tsx +74 -0
  105. package/src/components/CommandInput/index.ts +2 -0
  106. package/src/components/CommandShortcut/CommandShortcut.tsx +26 -0
  107. package/src/components/CommandShortcut/index.ts +2 -0
  108. package/src/components/ContentDivider/ContentDivider.tsx +80 -0
  109. package/src/components/ContentDivider/index.ts +6 -0
  110. package/src/components/ContentFeatureText/ContentFeatureText.tsx +60 -0
  111. package/src/components/ContentFeatureText/index.ts +5 -0
  112. package/src/components/ContentHeading/ContentHeading.tsx +43 -0
  113. package/src/components/ContentHeading/index.ts +5 -0
  114. package/src/components/ContentParagraph/ContentParagraph.tsx +39 -0
  115. package/src/components/ContentParagraph/index.ts +5 -0
  116. package/src/components/ContentQuote/ContentQuote.tsx +114 -0
  117. package/src/components/ContentQuote/index.ts +6 -0
  118. package/src/components/ContentRule/ContentRule.tsx +31 -0
  119. package/src/components/ContentRule/index.ts +2 -0
  120. package/src/components/ContextMenu/ContextMenu.tsx +67 -0
  121. package/src/components/ContextMenu/index.ts +7 -0
  122. package/src/components/ContextMenu/useContextMenu.ts +41 -0
  123. package/src/components/DatePickerCell/DatePickerCell.tsx +77 -0
  124. package/src/components/DatePickerCell/index.ts +2 -0
  125. package/src/components/DatePickerListItem/DatePickerListItem.tsx +39 -0
  126. package/src/components/DatePickerListItem/index.ts +2 -0
  127. package/src/components/DatePickerMenu/DatePickerMenu.tsx +131 -0
  128. package/src/components/DatePickerMenu/index.ts +2 -0
  129. package/src/components/DropdownAccountListItem/DropdownAccountListItem.tsx +69 -0
  130. package/src/components/DropdownAccountListItem/index.ts +2 -0
  131. package/src/components/DropdownMenuFooter/DropdownMenuFooter.tsx +50 -0
  132. package/src/components/DropdownMenuFooter/index.ts +5 -0
  133. package/src/components/DropdownMenuHeader/DropdownMenuHeader.tsx +93 -0
  134. package/src/components/DropdownMenuHeader/index.ts +5 -0
  135. package/src/components/DropdownMenuItemInsetIcon/DropdownMenuItemInsetIcon.tsx +89 -0
  136. package/src/components/DropdownMenuItemInsetIcon/index.ts +5 -0
  137. package/src/components/DropdownMenuListItem/DropdownMenuListItem.tsx +84 -0
  138. package/src/components/DropdownMenuListItem/index.ts +2 -0
  139. package/src/components/EmptyState/EmptyState.tsx +65 -0
  140. package/src/components/EmptyState/index.ts +2 -0
  141. package/src/components/FeedItemBase/FeedItemBase.tsx +135 -0
  142. package/src/components/FeedItemBase/index.ts +2 -0
  143. package/src/components/FileUpload/FileUpload.tsx +112 -0
  144. package/src/components/FileUpload/index.ts +2 -0
  145. package/src/components/FileUploadBase/FileUploadBase.tsx +69 -0
  146. package/src/components/FileUploadBase/index.ts +2 -0
  147. package/src/components/FileUploadItemBase/FileUploadItemBase.tsx +190 -0
  148. package/src/components/FileUploadItemBase/index.ts +7 -0
  149. package/src/components/FilterBar/FilterBar.tsx +62 -0
  150. package/src/components/FilterBar/index.ts +2 -0
  151. package/src/components/FilterTabs/FilterTabs.tsx +41 -0
  152. package/src/components/FilterTabs/index.ts +2 -0
  153. package/src/components/FiltersDropdownMenu/FiltersDropdownMenu.tsx +104 -0
  154. package/src/components/FiltersDropdownMenu/index.ts +2 -0
  155. package/src/components/FiltersSlideoutMenu/FiltersSlideoutMenu.tsx +71 -0
  156. package/src/components/FiltersSlideoutMenu/index.ts +2 -0
  157. package/src/components/HeaderNavigation/HeaderNavigation.tsx +178 -0
  158. package/src/components/HeaderNavigation/index.ts +6 -0
  159. package/src/components/HelpIcon/HelpIcon.tsx +49 -0
  160. package/src/components/HelpIcon/index.ts +2 -0
  161. package/src/components/InputField/InputField.tsx +108 -0
  162. package/src/components/InputField/index.ts +3 -0
  163. package/src/components/InputField/inputFieldShared.tsx +68 -0
  164. package/src/components/LeadingInputField/LeadingInputField.tsx +60 -0
  165. package/src/components/LeadingInputField/index.ts +2 -0
  166. package/src/components/LineAndBarChart/LineAndBarChart.tsx +96 -0
  167. package/src/components/LineAndBarChart/index.ts +2 -0
  168. package/src/components/LinkMessage/LinkMessage.tsx +52 -0
  169. package/src/components/LinkMessage/index.ts +2 -0
  170. package/src/components/LoadingIndicator/LoadingIndicator.tsx +108 -0
  171. package/src/components/LoadingIndicator/index.ts +6 -0
  172. package/src/components/MediaMessage/MediaMessage.tsx +109 -0
  173. package/src/components/MediaMessage/index.ts +2 -0
  174. package/src/components/MegaInputFieldBase/MegaInputFieldBase.tsx +49 -0
  175. package/src/components/MegaInputFieldBase/index.ts +5 -0
  176. package/src/components/Message/Message.tsx +85 -0
  177. package/src/components/Message/index.ts +3 -0
  178. package/src/components/Message/messageShared.tsx +73 -0
  179. package/src/components/MessageAction/MessageAction.tsx +221 -0
  180. package/src/components/MessageAction/index.ts +2 -0
  181. package/src/components/MessageActionButton/MessageActionButton.tsx +36 -0
  182. package/src/components/MessageActionButton/index.ts +2 -0
  183. package/src/components/MessageActionPanel/MessageActionPanel.tsx +36 -0
  184. package/src/components/MessageActionPanel/index.ts +2 -0
  185. package/src/components/MessageReaction/MessageReaction.tsx +37 -0
  186. package/src/components/MessageReaction/index.ts +2 -0
  187. package/src/components/MessageStatusIcon/MessageStatusIcon.tsx +54 -0
  188. package/src/components/MessageStatusIcon/index.ts +2 -0
  189. package/src/components/MetricItem/MetricItem.tsx +147 -0
  190. package/src/components/MetricItem/index.ts +2 -0
  191. package/src/components/ModalActions/ModalActions.tsx +57 -0
  192. package/src/components/ModalActions/index.ts +2 -0
  193. package/src/components/ModalHeader/ModalHeader.tsx +99 -0
  194. package/src/components/ModalHeader/index.ts +2 -0
  195. package/src/components/MultiSelect/MultiSelect.tsx +118 -0
  196. package/src/components/MultiSelect/index.ts +2 -0
  197. package/src/components/NavAccountCard/NavAccountCard.tsx +124 -0
  198. package/src/components/NavAccountCard/index.ts +2 -0
  199. package/src/components/NavAccountCardMenuItem/NavAccountCardMenuItem.tsx +101 -0
  200. package/src/components/NavAccountCardMenuItem/index.ts +5 -0
  201. package/src/components/NavButton/NavButton.tsx +50 -0
  202. package/src/components/NavButton/index.ts +2 -0
  203. package/src/components/NavFeaturedCard/NavFeaturedCard.tsx +82 -0
  204. package/src/components/NavFeaturedCard/index.ts +2 -0
  205. package/src/components/NavItemBase/NavItemBase.tsx +79 -0
  206. package/src/components/NavItemBase/index.ts +2 -0
  207. package/src/components/NavItemDropdownBase/NavItemDropdownBase.tsx +74 -0
  208. package/src/components/NavItemDropdownBase/index.ts +2 -0
  209. package/src/components/NavMenuButton/NavMenuButton.tsx +47 -0
  210. package/src/components/NavMenuButton/index.ts +2 -0
  211. package/src/components/Notification/Notification.tsx +102 -0
  212. package/src/components/Notification/index.ts +2 -0
  213. package/src/components/NumberInput/NumberInput.tsx +114 -0
  214. package/src/components/NumberInput/index.ts +2 -0
  215. package/src/components/PageHeader/PageHeader.tsx +88 -0
  216. package/src/components/PageHeader/index.ts +2 -0
  217. package/src/components/Pagination/Pagination.tsx +124 -0
  218. package/src/components/Pagination/index.ts +2 -0
  219. package/src/components/PaginationButtonGroupBase/PaginationButtonGroupBase.tsx +69 -0
  220. package/src/components/PaginationButtonGroupBase/index.ts +5 -0
  221. package/src/components/PaginationCards/PaginationCards.tsx +72 -0
  222. package/src/components/PaginationCards/index.ts +2 -0
  223. package/src/components/PaginationDotGroup/PaginationDotGroup.tsx +66 -0
  224. package/src/components/PaginationDotGroup/index.ts +2 -0
  225. package/src/components/PaginationDotIndicator/PaginationDotIndicator.tsx +39 -0
  226. package/src/components/PaginationDotIndicator/index.ts +6 -0
  227. package/src/components/PaginationNumberBase/PaginationNumberBase.tsx +42 -0
  228. package/src/components/PaginationNumberBase/index.ts +5 -0
  229. package/src/components/PieChart/PieChart.tsx +73 -0
  230. package/src/components/PieChart/index.ts +2 -0
  231. package/src/components/ProgressBar/ProgressBar.tsx +75 -0
  232. package/src/components/ProgressBar/index.ts +2 -0
  233. package/src/components/ProgressCircle/ProgressCircle.tsx +89 -0
  234. package/src/components/ProgressCircle/index.ts +6 -0
  235. package/src/components/RadarChart/RadarChart.tsx +62 -0
  236. package/src/components/RadarChart/index.ts +2 -0
  237. package/src/components/Radio/Radio.tsx +55 -0
  238. package/src/components/Radio/index.ts +2 -0
  239. package/src/components/RadioGroup/RadioGroup.tsx +54 -0
  240. package/src/components/RadioGroup/index.ts +2 -0
  241. package/src/components/RadioGroupItem/RadioGroupItem.tsx +118 -0
  242. package/src/components/RadioGroupItem/index.ts +6 -0
  243. package/src/components/SectionFooter/SectionFooter.tsx +40 -0
  244. package/src/components/SectionFooter/index.ts +2 -0
  245. package/src/components/SectionHeader/SectionHeader.tsx +44 -0
  246. package/src/components/SectionHeader/index.ts +2 -0
  247. package/src/components/SectionLabel/SectionLabel.tsx +51 -0
  248. package/src/components/SectionLabel/index.ts +2 -0
  249. package/src/components/Select/Select.tsx +121 -0
  250. package/src/components/Select/index.ts +2 -0
  251. package/src/components/SelectMenuItem/SelectMenuItem.tsx +85 -0
  252. package/src/components/SelectMenuItem/index.ts +2 -0
  253. package/src/components/SidebarNavigation/SidebarNavigation.tsx +100 -0
  254. package/src/components/SidebarNavigation/index.ts +2 -0
  255. package/src/components/SlideOutMenuHeader/SlideOutMenuHeader.tsx +56 -0
  256. package/src/components/SlideOutMenuHeader/index.ts +2 -0
  257. package/src/components/Slider/Slider.tsx +125 -0
  258. package/src/components/Slider/index.ts +2 -0
  259. package/src/components/SocialButton/SocialButton.tsx +88 -0
  260. package/src/components/SocialButton/index.ts +2 -0
  261. package/src/components/StatusIcon/StatusIcon.tsx +75 -0
  262. package/src/components/StatusIcon/index.ts +2 -0
  263. package/src/components/StepBase/StepBase.tsx +90 -0
  264. package/src/components/StepBase/index.ts +2 -0
  265. package/src/components/StepIconBase/StepIconBase.tsx +65 -0
  266. package/src/components/StepIconBase/index.ts +7 -0
  267. package/src/components/TabButtonBase/TabButtonBase.tsx +88 -0
  268. package/src/components/TabButtonBase/index.ts +2 -0
  269. package/src/components/TableCell/TableCell.tsx +44 -0
  270. package/src/components/TableCell/index.ts +2 -0
  271. package/src/components/TableHeaderCell/TableHeaderCell.tsx +34 -0
  272. package/src/components/TableHeaderCell/index.ts +2 -0
  273. package/src/components/TableHeaderLabel/TableHeaderLabel.tsx +37 -0
  274. package/src/components/TableHeaderLabel/index.ts +2 -0
  275. package/src/components/Tabs/Tabs.tsx +80 -0
  276. package/src/components/Tabs/index.ts +2 -0
  277. package/src/components/Tag/Tag.tsx +91 -0
  278. package/src/components/Tag/index.ts +2 -0
  279. package/src/components/TagsInputField/TagsInputField.tsx +90 -0
  280. package/src/components/TagsInputField/index.ts +2 -0
  281. package/src/components/TextEditorToolbar/TextEditorToolbar.tsx +33 -0
  282. package/src/components/TextEditorToolbar/index.ts +2 -0
  283. package/src/components/TextEditorTooltip/TextEditorTooltip.tsx +28 -0
  284. package/src/components/TextEditorTooltip/index.ts +2 -0
  285. package/src/components/TextareaInputField/TextareaInputField.tsx +45 -0
  286. package/src/components/TextareaInputField/index.ts +2 -0
  287. package/src/components/Toggle/Toggle.tsx +87 -0
  288. package/src/components/Toggle/index.ts +2 -0
  289. package/src/components/Tooltip/Tooltip.tsx +59 -0
  290. package/src/components/Tooltip/index.ts +2 -0
  291. package/src/components/TrailingInputField/TrailingInputField.tsx +62 -0
  292. package/src/components/TrailingInputField/index.ts +2 -0
  293. package/src/components/TreeView/TreeView.tsx +86 -0
  294. package/src/components/TreeView/index.ts +2 -0
  295. package/src/components/TreeViewConnector/TreeViewConnector.tsx +36 -0
  296. package/src/components/TreeViewConnector/index.ts +2 -0
  297. package/src/components/TreeViewItem/TreeViewItem.tsx +111 -0
  298. package/src/components/TreeViewItem/index.ts +2 -0
  299. package/src/components/VerificationCodeInput/VerificationCodeInput.tsx +114 -0
  300. package/src/components/VerificationCodeInput/index.ts +2 -0
  301. package/src/illustrations/BoxIllustration.tsx +13 -0
  302. package/src/illustrations/CloudIllustration.tsx +18 -0
  303. package/src/illustrations/CreditCardIllustration.tsx +13 -0
  304. package/src/illustrations/DocumentsIllustration.tsx +13 -0
  305. package/src/illustrations/index.ts +4 -0
  306. package/src/index.ts +147 -0
  307. package/src/internal/chartTheme.ts +30 -0
  308. package/src/internal/ringBase.tsx +82 -0
  309. package/src/styles.css +3 -0
  310. package/tailwind-preset.js +295 -0
@@ -0,0 +1,102 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type NotificationVariant = "default" | "success" | "warning" | "error" | "gray";
5
+
6
+ export interface NotificationProps
7
+ extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
8
+ /** Colours the default featured-icon ring (ignored if `leadingMedia` set). */
9
+ variant?: NotificationVariant;
10
+ title: ReactNode;
11
+ description?: ReactNode;
12
+ /** Left media slot (icon / avatar / progress). Overrides the default ring icon. */
13
+ leadingMedia?: ReactNode;
14
+ /** Full-bleed image (the "Image" type) rendered below the text. */
15
+ imageUrl?: string;
16
+ /** Action row — compose link/text buttons. */
17
+ actions?: ReactNode;
18
+ /** Renders an x-close button top-right. */
19
+ onDismiss?: () => void;
20
+ }
21
+
22
+ const RING: Record<NotificationVariant, string> = {
23
+ default: "border-fg-brand-primary text-fg-brand-primary",
24
+ success: "border-fg-success-primary text-fg-success-primary",
25
+ warning: "border-fg-warning-primary text-fg-warning-primary",
26
+ error: "border-fg-error-primary text-fg-error-primary",
27
+ gray: "border-fg-quaternary text-fg-quaternary",
28
+ };
29
+
30
+ const GLYPH: Record<NotificationVariant, string> = {
31
+ default: "M10 13.33V10M10 6.67h.01M18.33 10a8.33 8.33 0 1 1-16.66 0 8.33 8.33 0 0 1 16.66 0Z",
32
+ gray: "M10 13.33V10M10 6.67h.01M18.33 10a8.33 8.33 0 1 1-16.66 0 8.33 8.33 0 0 1 16.66 0Z",
33
+ success: "M6.25 10l2.5 2.5 5-5M18.33 10a8.33 8.33 0 1 1-16.66 0 8.33 8.33 0 0 1 16.66 0Z",
34
+ warning: "M10 6.67V10m0 3.33h.01M18.33 10a8.33 8.33 0 1 1-16.66 0 8.33 8.33 0 0 1 16.66 0Z",
35
+ error: "M10 6.67V10m0 3.33h.01M18.33 10a8.33 8.33 0 1 1-16.66 0 8.33 8.33 0 0 1 16.66 0Z",
36
+ };
37
+
38
+ const XClose = () => (
39
+ <svg viewBox="0 0 20 20" fill="none" className="size-5" aria-hidden>
40
+ <path d="M15 5 5 15M5 5l10 10" stroke="currentColor" strokeWidth="1.67" strokeLinecap="round" strokeLinejoin="round" />
41
+ </svg>
42
+ );
43
+
44
+ const FeaturedIcon = ({ variant }: { variant: NotificationVariant }) => (
45
+ <span className={clsx("relative inline-flex size-5 shrink-0 items-center justify-center", RING[variant].split(" ")[1])}>
46
+ <span className={clsx("absolute inset-[-20%] rounded-full border-2 opacity-30", RING[variant].split(" ")[0])} />
47
+ <span className={clsx("absolute inset-[-45%] rounded-full border-2 opacity-10", RING[variant].split(" ")[0])} />
48
+ <svg viewBox="0 0 20 20" fill="none" className="relative size-5" aria-hidden>
49
+ <path d={GLYPH[variant]} stroke="currentColor" strokeWidth="1.67" strokeLinecap="round" strokeLinejoin="round" />
50
+ </svg>
51
+ </span>
52
+ );
53
+
54
+ /**
55
+ * Toast / inline notification. One component: `variant` colours the default
56
+ * featured-icon ring; `leadingMedia` overrides it with any node (avatar, custom
57
+ * icon, progress). `imageUrl` adds the full-bleed image type, `actions` the CTA
58
+ * row, `onDismiss` the x-close. `shadow-lg` approximates Figma's 3-layer lg.
59
+ */
60
+ export function Notification({
61
+ variant = "default",
62
+ title,
63
+ description,
64
+ leadingMedia,
65
+ imageUrl,
66
+ actions,
67
+ onDismiss,
68
+ className,
69
+ ...rest
70
+ }: NotificationProps) {
71
+ return (
72
+ <div
73
+ className={clsx(
74
+ "relative flex w-full items-start gap-xl rounded-xl border border-border-secondary-alt bg-bg-primary-alt p-xl shadow-lg",
75
+ className,
76
+ )}
77
+ {...rest}
78
+ >
79
+ {leadingMedia ?? <FeaturedIcon variant={variant} />}
80
+
81
+ <div className="flex min-w-0 flex-1 flex-col gap-lg pr-8">
82
+ <div className="flex flex-col gap-xs">
83
+ <p className="text-sm font-semibold text-fg-primary">{title}</p>
84
+ {description && <p className="text-sm text-fg-secondary">{description}</p>}
85
+ </div>
86
+ {imageUrl && <img src={imageUrl} alt="" className="h-40 w-full rounded-md object-cover" />}
87
+ {actions && <div className="flex items-center gap-lg">{actions}</div>}
88
+ </div>
89
+
90
+ {onDismiss && (
91
+ <button
92
+ type="button"
93
+ onClick={onDismiss}
94
+ aria-label="Dismiss"
95
+ className="absolute right-2 top-2 flex size-9 items-center justify-center rounded-md text-fg-quaternary transition-colors hover:text-fg-quaternary-hover"
96
+ >
97
+ <XClose />
98
+ </button>
99
+ )}
100
+ </div>
101
+ );
102
+ }
@@ -0,0 +1,2 @@
1
+ export { Notification } from "./Notification";
2
+ export type { NotificationProps, NotificationVariant } from "./Notification";
@@ -0,0 +1,114 @@
1
+ import { type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+ import { FieldWrapper, boxClasses } from "../InputField/inputFieldShared";
4
+
5
+ export type NumberInputLayout = "horizontal" | "vertical";
6
+
7
+ export interface NumberInputProps {
8
+ layout?: NumberInputLayout;
9
+ value?: number;
10
+ onChange?: (value: number) => void;
11
+ min?: number;
12
+ max?: number;
13
+ step?: number;
14
+ label?: ReactNode;
15
+ hint?: ReactNode;
16
+ required?: boolean;
17
+ destructive?: boolean;
18
+ disabled?: boolean;
19
+ className?: string;
20
+ "aria-label"?: string;
21
+ }
22
+
23
+ /**
24
+ * Standalone numeric counter (NOT an `InputField` type). `horizontal` flanks the
25
+ * value with −/+ buttons; `vertical` stacks up/down chevrons on the right. Reuses
26
+ * the input family's `FieldWrapper` + `boxClasses`. Controlled via
27
+ * `value`/`onChange`, clamped to `min`/`max` by `step`.
28
+ */
29
+ export function NumberInput({
30
+ layout = "horizontal",
31
+ value = 0,
32
+ onChange,
33
+ min = -Infinity,
34
+ max = Infinity,
35
+ step = 1,
36
+ label,
37
+ hint,
38
+ required,
39
+ destructive,
40
+ disabled,
41
+ className,
42
+ "aria-label": ariaLabel,
43
+ }: NumberInputProps) {
44
+ const clamp = (n: number) => Math.min(max, Math.max(min, n));
45
+ const set = (n: number) => onChange?.(clamp(n));
46
+ const dec = () => set(value - step);
47
+ const inc = () => set(value + step);
48
+
49
+ const Minus = (
50
+ <svg viewBox="0 0 20 20" fill="none" className="size-5" aria-hidden>
51
+ <path d="M4.167 10h11.666" stroke="currentColor" strokeWidth="1.67" strokeLinecap="round" />
52
+ </svg>
53
+ );
54
+ const Plus = (
55
+ <svg viewBox="0 0 20 20" fill="none" className="size-5" aria-hidden>
56
+ <path d="M10 4.167v11.666M4.167 10h11.666" stroke="currentColor" strokeWidth="1.67" strokeLinecap="round" />
57
+ </svg>
58
+ );
59
+ const Chevron = ({ up }: { up: boolean }) => (
60
+ <svg viewBox="0 0 12 12" fill="none" className={clsx("size-3", up && "rotate-180")} aria-hidden>
61
+ <path d="M3 4.5 6 7.5 9 4.5" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" />
62
+ </svg>
63
+ );
64
+
65
+ const numberEl = (
66
+ <input
67
+ type="text"
68
+ inputMode="numeric"
69
+ aria-label={ariaLabel ?? (typeof label === "string" ? label : "Number")}
70
+ value={value}
71
+ disabled={disabled}
72
+ onChange={(e) => {
73
+ const n = Number(e.target.value.replace(/[^\d.-]/g, ""));
74
+ if (!Number.isNaN(n)) set(n);
75
+ }}
76
+ className={clsx(
77
+ "min-w-0 flex-1 bg-transparent py-md text-md text-text-primary outline-none",
78
+ layout === "horizontal" ? "px-lg text-center" : "px-lg text-left",
79
+ )}
80
+ />
81
+ );
82
+
83
+ const box =
84
+ layout === "horizontal" ? (
85
+ <div className={clsx(boxClasses(destructive), "gap-0 overflow-hidden p-0")}>
86
+ <button type="button" onClick={dec} disabled={disabled} aria-label="Decrease" className="flex items-center justify-center border-r border-border-primary p-2.5 text-fg-quaternary hover:bg-bg-primary-hover disabled:opacity-60">
87
+ {Minus}
88
+ </button>
89
+ {numberEl}
90
+ <button type="button" onClick={inc} disabled={disabled} aria-label="Increase" className="flex items-center justify-center border-l border-border-primary p-2.5 text-fg-quaternary hover:bg-bg-primary-hover disabled:opacity-60">
91
+ {Plus}
92
+ </button>
93
+ </div>
94
+ ) : (
95
+ <div className={clsx(boxClasses(destructive), "gap-0 overflow-hidden p-0")}>
96
+ {numberEl}
97
+ <div className="flex flex-col self-stretch border-l border-border-primary">
98
+ <button type="button" onClick={inc} disabled={disabled} aria-label="Increase" className="flex flex-1 items-center justify-center px-md text-fg-quaternary hover:bg-bg-primary-hover disabled:opacity-60">
99
+ <Chevron up />
100
+ </button>
101
+ <span className="h-px w-full bg-border-primary" />
102
+ <button type="button" onClick={dec} disabled={disabled} aria-label="Decrease" className="flex flex-1 items-center justify-center px-md text-fg-quaternary hover:bg-bg-primary-hover disabled:opacity-60">
103
+ <Chevron up={false} />
104
+ </button>
105
+ </div>
106
+ </div>
107
+ );
108
+
109
+ return (
110
+ <FieldWrapper label={label} required={required} hint={hint} destructive={destructive} className={className}>
111
+ {box}
112
+ </FieldWrapper>
113
+ );
114
+ }
@@ -0,0 +1,2 @@
1
+ export { NumberInput } from "./NumberInput";
2
+ export type { NumberInputProps, NumberInputLayout } from "./NumberInput";
@@ -0,0 +1,88 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type PageHeaderStyle =
5
+ | "simple"
6
+ | "avatar"
7
+ | "bannerAvatar"
8
+ | "bannerAvatarCentered"
9
+ | "bannerSimpleCentered"
10
+ | "bannerSimple";
11
+
12
+ export interface PageHeaderProps
13
+ extends Omit<HTMLAttributes<HTMLDivElement>, "title" | "style"> {
14
+ style?: PageHeaderStyle;
15
+ title: ReactNode;
16
+ description?: ReactNode;
17
+ /** Avatar / featured visual (avatar styles). */
18
+ avatar?: ReactNode;
19
+ /** Trailing actions row (buttons). */
20
+ actions?: ReactNode;
21
+ /** Optional breadcrumbs slot above the title. */
22
+ breadcrumbs?: ReactNode;
23
+ /** Banner background image (banner styles); falls back to `bg-tertiary`. */
24
+ bannerUrl?: string;
25
+ }
26
+
27
+ /**
28
+ * Page header — one component over the 6 Figma `Style`s. `banner*` styles render
29
+ * a banner strip the content overlaps; `*Centered` styles centre the text;
30
+ * `avatar` styles show the `avatar` slot. Breakpoint handled with Tailwind
31
+ * responsive prefixes. Constrained to `container-max-width-desktop` (1280) with
32
+ * container padding.
33
+ */
34
+ export function PageHeader({
35
+ style = "simple",
36
+ title,
37
+ description,
38
+ avatar,
39
+ actions,
40
+ breadcrumbs,
41
+ bannerUrl,
42
+ className,
43
+ ...rest
44
+ }: PageHeaderProps) {
45
+ const isBanner = style.startsWith("banner");
46
+ const isCentered = style.endsWith("Centered");
47
+ const hasAvatar = style === "avatar" || style === "bannerAvatar" || style === "bannerAvatarCentered";
48
+
49
+ return (
50
+ <div
51
+ className={clsx(
52
+ "mx-auto w-full max-w-screen-xl px-container-padding-mobile md:px-container-padding-desktop",
53
+ className,
54
+ )}
55
+ {...rest}
56
+ >
57
+ {isBanner && (
58
+ <div
59
+ className="h-32 w-full rounded-2xl bg-bg-tertiary bg-cover bg-center md:h-40"
60
+ style={bannerUrl ? { backgroundImage: `url(${bannerUrl})` } : undefined}
61
+ />
62
+ )}
63
+
64
+ <div className={clsx("flex flex-col gap-xl", isCentered && "items-center text-center", isBanner && "px-md")}>
65
+ {breadcrumbs}
66
+
67
+ {hasAvatar && avatar && (
68
+ <div className={clsx("shrink-0", isBanner && "-mt-10", isCentered && "flex justify-center")}>
69
+ {avatar}
70
+ </div>
71
+ )}
72
+
73
+ <div
74
+ className={clsx(
75
+ "flex w-full gap-xl",
76
+ isCentered ? "flex-col items-center" : "flex-col items-start justify-between md:flex-row md:items-center",
77
+ )}
78
+ >
79
+ <div className={clsx("flex flex-col gap-xxs", isCentered && "max-w-width-lg items-center")}>
80
+ <h1 className="text-xl font-semibold text-text-primary">{title}</h1>
81
+ {description && <p className="text-md text-text-tertiary">{description}</p>}
82
+ </div>
83
+ {actions && <div className="flex shrink-0 items-center gap-lg">{actions}</div>}
84
+ </div>
85
+ </div>
86
+ </div>
87
+ );
88
+ }
@@ -0,0 +1,2 @@
1
+ export { PageHeader } from "./PageHeader";
2
+ export type { PageHeaderProps, PageHeaderStyle } from "./PageHeader";
@@ -0,0 +1,124 @@
1
+ import { type HTMLAttributes } from "react";
2
+ import clsx from "clsx";
3
+ import { PaginationNumberBase, type PaginationNumberShape } from "../PaginationNumberBase";
4
+ import { PaginationButtonGroupBase } from "../PaginationButtonGroupBase";
5
+
6
+ export type PaginationType = "default" | "minimal" | "buttonGroup";
7
+
8
+ export interface PaginationProps extends HTMLAttributes<HTMLDivElement> {
9
+ /** 1-based current page. */
10
+ page: number;
11
+ /** Total page count. */
12
+ total: number;
13
+ onPageChange?: (page: number) => void;
14
+ /** default = Prev / numbers / Next · minimal = Prev / "Page x of y" / Next · buttonGroup = bordered group. */
15
+ type?: PaginationType;
16
+ /** Number-cell shape (default/minimal). */
17
+ shape?: PaginationNumberShape;
18
+ /** Max page cells before collapsing the middle with ellipsis. Default 7. */
19
+ maxVisible?: number;
20
+ }
21
+
22
+ type PageToken = number | "ellipsis";
23
+
24
+ /**
25
+ * Build the visible page tokens: always first + last + current±2, with an
26
+ * `"ellipsis"` marker inserted wherever consecutive pages are skipped.
27
+ */
28
+ function pageTokens(current: number, total: number, maxVisible: number): PageToken[] {
29
+ if (total <= maxVisible) {
30
+ return Array.from({ length: total }, (_, i) => i + 1);
31
+ }
32
+ const wanted = new Set<number>([1, total, current, current - 1, current - 2, current + 1, current + 2]);
33
+ const sorted = [...wanted].filter((p) => p >= 1 && p <= total).sort((a, b) => a - b);
34
+ const out: PageToken[] = [];
35
+ let prev = 0;
36
+ for (const p of sorted) {
37
+ if (p - prev > 1) out.push("ellipsis");
38
+ out.push(p);
39
+ prev = p;
40
+ }
41
+ return out;
42
+ }
43
+
44
+ const Arrow = ({ dir }: { dir: "left" | "right" }) => (
45
+ <svg viewBox="0 0 20 20" fill="none" className="size-5" aria-hidden>
46
+ <path d={dir === "left" ? "M15.83 10H4.17M4.17 10l5 5M4.17 10l5-5" : "M4.17 10h11.66M15.83 10l-5 5M15.83 10l-5-5"} stroke="currentColor" strokeWidth="1.67" strokeLinecap="round" strokeLinejoin="round" />
47
+ </svg>
48
+ );
49
+
50
+ const PrevNext = ({ dir, disabled, onClick }: { dir: "left" | "right"; disabled: boolean; onClick: () => void }) => (
51
+ <button
52
+ type="button"
53
+ disabled={disabled}
54
+ onClick={onClick}
55
+ className="flex items-center gap-xs text-sm font-semibold text-text-tertiary disabled:opacity-50"
56
+ >
57
+ {dir === "left" && <Arrow dir="left" />}
58
+ {dir === "left" ? "Previous" : "Next"}
59
+ {dir === "right" && <Arrow dir="right" />}
60
+ </button>
61
+ );
62
+
63
+ /**
64
+ * Number/button-based pagination. `default` = Previous · number cells · Next;
65
+ * `minimal` = Previous · "Page x of y" · Next; `buttonGroup` = a bordered
66
+ * connected group. Composes `PaginationNumberBase` + `PaginationButtonGroupBase`.
67
+ * Collapses the middle with ellipsis past `maxVisible` (always shows first/last
68
+ * + current±2).
69
+ */
70
+ export function Pagination({
71
+ page,
72
+ total,
73
+ onPageChange,
74
+ type = "default",
75
+ shape = "square",
76
+ maxVisible = 7,
77
+ className,
78
+ ...rest
79
+ }: PaginationProps) {
80
+ const go = (p: number) => p >= 1 && p <= total && onPageChange?.(p);
81
+ const tokens = pageTokens(page, total, maxVisible);
82
+
83
+ if (type === "buttonGroup") {
84
+ return (
85
+ <div className={clsx("inline-flex overflow-hidden rounded-md border border-border-primary [&>*:last-child]:border-r-0", className)} {...rest}>
86
+ <PaginationButtonGroupBase cellType="leadingIcon" onClick={() => go(page - 1)} />
87
+ {tokens.map((t, i) =>
88
+ t === "ellipsis" ? (
89
+ <span key={`e${i}`} className="flex min-h-9 min-w-9 items-center justify-center border-r border-border-primary bg-bg-primary p-md text-sm font-semibold text-text-quaternary">
90
+
91
+ </span>
92
+ ) : (
93
+ <PaginationButtonGroupBase key={t} cellType="number" active={t === page} onClick={() => go(t)}>
94
+ {t}
95
+ </PaginationButtonGroupBase>
96
+ ),
97
+ )}
98
+ <PaginationButtonGroupBase cellType="trailingIcon" onClick={() => go(page + 1)} />
99
+ </div>
100
+ );
101
+ }
102
+
103
+ return (
104
+ <div className={clsx("flex w-full items-center justify-between gap-md", className)} {...rest}>
105
+ <PrevNext dir="left" disabled={page <= 1} onClick={() => go(page - 1)} />
106
+ {type === "minimal" ? (
107
+ <span className="text-sm font-medium text-text-secondary">Page {page} of {total}</span>
108
+ ) : (
109
+ <div className="flex items-center gap-xxs">
110
+ {tokens.map((t, i) =>
111
+ t === "ellipsis" ? (
112
+ <span key={`e${i}`} className="flex size-9 items-center justify-center text-sm font-medium text-text-quaternary">…</span>
113
+ ) : (
114
+ <PaginationNumberBase key={t} shape={shape} active={t === page} onClick={() => go(t)}>
115
+ {t}
116
+ </PaginationNumberBase>
117
+ ),
118
+ )}
119
+ </div>
120
+ )}
121
+ <PrevNext dir="right" disabled={page >= total} onClick={() => go(page + 1)} />
122
+ </div>
123
+ );
124
+ }
@@ -0,0 +1,2 @@
1
+ export { Pagination } from "./Pagination";
2
+ export type { PaginationProps, PaginationType } from "./Pagination";
@@ -0,0 +1,69 @@
1
+ import { type ButtonHTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type PaginationButtonGroupType = "number" | "leadingIcon" | "trailingIcon" | "iconOnly";
5
+
6
+ export interface PaginationButtonGroupBaseProps
7
+ extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "type" | "children"> {
8
+ /** number cell · leading/trailing icon+label · icon-only arrow. */
9
+ cellType?: PaginationButtonGroupType;
10
+ /** Active/current cell — applies the hover background + darker text. */
11
+ active?: boolean;
12
+ /** Number or label text. */
13
+ children?: ReactNode;
14
+ /** Override the default arrow glyph. */
15
+ icon?: ReactNode;
16
+ }
17
+
18
+ const ArrowLeft = () => (
19
+ <svg viewBox="0 0 20 20" fill="none" className="size-5" aria-hidden>
20
+ <path d="M15.83 10H4.17M4.17 10l5 5M4.17 10l5-5" stroke="currentColor" strokeWidth="1.67" strokeLinecap="round" strokeLinejoin="round" />
21
+ </svg>
22
+ );
23
+ const ArrowRight = () => (
24
+ <svg viewBox="0 0 20 20" fill="none" className="size-5" aria-hidden>
25
+ <path d="M4.17 10h11.66M15.83 10l-5 5M15.83 10l-5-5" stroke="currentColor" strokeWidth="1.67" strokeLinecap="round" strokeLinejoin="round" />
26
+ </svg>
27
+ );
28
+
29
+ /**
30
+ * One cell of a button-group pagination bar (the bordered Page/Card-button-group
31
+ * style). `cellType` picks number / leading-icon (Previous) / trailing-icon
32
+ * (Next) / icon-only. Carries a right divider; `active` highlights it.
33
+ */
34
+ export function PaginationButtonGroupBase({
35
+ cellType = "number",
36
+ active = false,
37
+ children,
38
+ icon,
39
+ className,
40
+ ...rest
41
+ }: PaginationButtonGroupBaseProps) {
42
+ const isIcon = cellType === "iconOnly";
43
+ const isLeading = cellType === "leadingIcon";
44
+ const isTrailing = cellType === "trailingIcon";
45
+ const isNumber = cellType === "number";
46
+
47
+ return (
48
+ <button
49
+ type="button"
50
+ aria-current={active && isNumber ? "page" : undefined}
51
+ className={clsx(
52
+ "flex min-h-9 items-center justify-center border-r border-border-primary text-sm font-semibold outline-none transition-colors",
53
+ "focus-visible:relative focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-utility-brand-500",
54
+ isNumber ? "min-w-9 p-md" : isIcon ? "p-md" : "gap-xs px-lg py-md",
55
+ active ? "bg-bg-primary-hover text-text-secondary-hover" : "bg-bg-primary hover:bg-bg-primary-hover",
56
+ isNumber && !active && "text-text-quaternary",
57
+ (isLeading || isTrailing) && "text-text-secondary",
58
+ className,
59
+ )}
60
+ {...rest}
61
+ >
62
+ {isLeading && (icon ?? <ArrowLeft />)}
63
+ {(isLeading || isTrailing) && <span className="px-xxs">{children ?? (isLeading ? "Previous" : "Next")}</span>}
64
+ {isTrailing && (icon ?? <ArrowRight />)}
65
+ {isNumber && children}
66
+ {isIcon && (icon ?? <ArrowRight />)}
67
+ </button>
68
+ );
69
+ }
@@ -0,0 +1,5 @@
1
+ export { PaginationButtonGroupBase } from "./PaginationButtonGroupBase";
2
+ export type {
3
+ PaginationButtonGroupBaseProps,
4
+ PaginationButtonGroupType,
5
+ } from "./PaginationButtonGroupBase";
@@ -0,0 +1,72 @@
1
+ import { type HTMLAttributes } from "react";
2
+ import clsx from "clsx";
3
+ import { PaginationDotGroup } from "../PaginationDotGroup";
4
+
5
+ export type PaginationCardsVariant = "default" | "minimal" | "advanced";
6
+
7
+ export interface PaginationCardsProps extends HTMLAttributes<HTMLDivElement> {
8
+ page: number;
9
+ total: number;
10
+ onPageChange?: (page: number) => void;
11
+ /** default = arrows + dots · minimal = dots + "Page x of y" · advanced = bordered card. */
12
+ variant?: PaginationCardsVariant;
13
+ }
14
+
15
+ const ArrowBtn = ({ dir, disabled, onClick }: { dir: "left" | "right"; disabled: boolean; onClick: () => void }) => (
16
+ <button
17
+ type="button"
18
+ aria-label={dir === "left" ? "Previous" : "Next"}
19
+ disabled={disabled}
20
+ onClick={onClick}
21
+ className="flex size-9 items-center justify-center rounded-md border border-border-primary bg-bg-primary text-fg-secondary shadow-xs disabled:opacity-50"
22
+ >
23
+ <svg viewBox="0 0 20 20" fill="none" className="size-5" aria-hidden>
24
+ <path d={dir === "left" ? "M12.5 15l-5-5 5-5" : "M7.5 15l5-5-5-5"} stroke="currentColor" strokeWidth="1.67" strokeLinecap="round" strokeLinejoin="round" />
25
+ </svg>
26
+ </button>
27
+ );
28
+
29
+ /**
30
+ * Card/dot-based pagination. `default` = arrow buttons flanking a dot pager;
31
+ * `minimal` = dots + "Page x of y"; `advanced` = the same in a bordered card.
32
+ * Composes `PaginationDotGroup`.
33
+ */
34
+ export function PaginationCards({
35
+ page,
36
+ total,
37
+ onPageChange,
38
+ variant = "default",
39
+ className,
40
+ ...rest
41
+ }: PaginationCardsProps) {
42
+ const go = (p: number) => p >= 1 && p <= total && onPageChange?.(p);
43
+ const dots = <PaginationDotGroup count={total} current={page - 1} />;
44
+
45
+ const body =
46
+ variant === "minimal" ? (
47
+ <>
48
+ {dots}
49
+ <span className="text-sm font-medium text-text-secondary">Page {page} of {total}</span>
50
+ </>
51
+ ) : (
52
+ <>
53
+ <ArrowBtn dir="left" disabled={page <= 1} onClick={() => go(page - 1)} />
54
+ {dots}
55
+ <ArrowBtn dir="right" disabled={page >= total} onClick={() => go(page + 1)} />
56
+ </>
57
+ );
58
+
59
+ return (
60
+ <div
61
+ className={clsx(
62
+ "flex items-center gap-lg",
63
+ variant === "default" && "justify-between",
64
+ variant === "advanced" && "rounded-xl border border-border-secondary bg-bg-primary p-lg shadow-xs",
65
+ className,
66
+ )}
67
+ {...rest}
68
+ >
69
+ {body}
70
+ </div>
71
+ );
72
+ }
@@ -0,0 +1,2 @@
1
+ export { PaginationCards } from "./PaginationCards";
2
+ export type { PaginationCardsProps, PaginationCardsVariant } from "./PaginationCards";
@@ -0,0 +1,66 @@
1
+ import { type HTMLAttributes } from "react";
2
+ import clsx from "clsx";
3
+ import {
4
+ PaginationDotIndicator,
5
+ type PaginationDotSize,
6
+ type PaginationDotVariant,
7
+ } from "../PaginationDotIndicator";
8
+
9
+ export interface PaginationDotGroupProps
10
+ extends HTMLAttributes<HTMLDivElement> {
11
+ /** Total indicators. */
12
+ count?: number;
13
+ /** Active index. */
14
+ current?: number;
15
+ size?: PaginationDotSize;
16
+ variant?: PaginationDotVariant;
17
+ /** Floating pill on a translucent blurred background (carousel overlay). */
18
+ framed?: boolean;
19
+ }
20
+
21
+ /**
22
+ * Row of `PaginationDotIndicator`s (carousel pager). `count`/`current` drive the
23
+ * dots; `framed` wraps them in a blurred translucent pill for image overlays.
24
+ * Line variant stretches indicators to fill. framed uses the
25
+ * `alpha-white-90` token.
26
+ */
27
+ export function PaginationDotGroup({
28
+ count = 3,
29
+ current = 0,
30
+ size = "md",
31
+ variant = "dot",
32
+ framed = false,
33
+ className,
34
+ ...rest
35
+ }: PaginationDotGroupProps) {
36
+ const gap =
37
+ variant === "line"
38
+ ? size === "lg"
39
+ ? "gap-lg"
40
+ : "gap-md"
41
+ : size === "lg"
42
+ ? "gap-xl"
43
+ : "gap-lg";
44
+
45
+ return (
46
+ <div
47
+ className={clsx(
48
+ "flex items-center justify-center",
49
+ gap,
50
+ framed && "rounded-full bg-alpha-white-90 p-md backdrop-blur-sm",
51
+ className,
52
+ )}
53
+ {...rest}
54
+ >
55
+ {Array.from({ length: count }).map((_, i) => (
56
+ <PaginationDotIndicator
57
+ key={i}
58
+ current={i === current}
59
+ size={size}
60
+ variant={variant}
61
+ className={variant === "line" ? "h-1.5 min-w-0 flex-1" : undefined}
62
+ />
63
+ ))}
64
+ </div>
65
+ );
66
+ }
@@ -0,0 +1,2 @@
1
+ export { PaginationDotGroup } from "./PaginationDotGroup";
2
+ export type { PaginationDotGroupProps } from "./PaginationDotGroup";