@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,40 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type SectionFooterType = "section" | "card";
5
+
6
+ export interface SectionFooterProps extends HTMLAttributes<HTMLDivElement> {
7
+ /** `section` = flush footer; `card` = inset with horizontal + bottom padding. */
8
+ type?: SectionFooterType;
9
+ /** Top divider line. */
10
+ divider?: boolean;
11
+ /** Left-aligned slot — button group, "Learn more" link, etc. */
12
+ leading?: ReactNode;
13
+ /** Right-aligned action buttons. */
14
+ actions?: ReactNode;
15
+ }
16
+
17
+ /**
18
+ * Footer row for a section or card: optional top `divider`, a left `leading`
19
+ * slot (button group / link) and right-aligned `actions`. Layout shell only —
20
+ * compose `Button`, `ButtonGroup`, etc. as slots, don't reimplement them.
21
+ */
22
+ export function SectionFooter({
23
+ type = "section",
24
+ divider = true,
25
+ leading,
26
+ actions,
27
+ className,
28
+ ...rest
29
+ }: SectionFooterProps) {
30
+ const card = type === "card";
31
+ return (
32
+ <div className={clsx("flex w-full flex-col", card ? "gap-xl pb-xl" : "gap-2xl", className)} {...rest}>
33
+ {divider && <span className="h-px w-full bg-border-secondary" />}
34
+ <div className={clsx("flex w-full items-center gap-xl", card && "px-3xl")}>
35
+ {leading}
36
+ <div className="ml-auto flex items-center gap-lg">{actions}</div>
37
+ </div>
38
+ </div>
39
+ );
40
+ }
@@ -0,0 +1,2 @@
1
+ export { SectionFooter } from "./SectionFooter";
2
+ export type { SectionFooterProps, SectionFooterType } from "./SectionFooter";
@@ -0,0 +1,44 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export interface SectionHeaderProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
5
+ title?: ReactNode;
6
+ supportingText?: ReactNode;
7
+ /** Right-aligned slot — buttons, button group, or a search input. */
8
+ actions?: ReactNode;
9
+ /** Tabs row rendered below the title/actions, above the divider. */
10
+ tabs?: ReactNode;
11
+ /** Bottom divider line. */
12
+ divider?: boolean;
13
+ }
14
+
15
+ /**
16
+ * Section heading: title + supporting text on the left, an `actions` slot on the
17
+ * right (buttons / button group / search), an optional `tabs` row, and a bottom
18
+ * `divider`. Layout shell — pass controls as slots.
19
+ */
20
+ export function SectionHeader({
21
+ title,
22
+ supportingText,
23
+ actions,
24
+ tabs,
25
+ divider = true,
26
+ className,
27
+ ...rest
28
+ }: SectionHeaderProps) {
29
+ return (
30
+ <div className={clsx("flex w-full flex-col gap-xl", className)} {...rest}>
31
+ <div className="flex flex-col gap-xl">
32
+ <div className="flex items-start gap-xl">
33
+ <div className="flex min-w-0 flex-1 flex-col gap-xxs">
34
+ {title && <h2 className="text-lg font-semibold text-text-primary">{title}</h2>}
35
+ {supportingText && <p className="text-sm text-text-tertiary">{supportingText}</p>}
36
+ </div>
37
+ {actions && <div className="flex shrink-0 items-center gap-lg">{actions}</div>}
38
+ </div>
39
+ {tabs}
40
+ </div>
41
+ {divider && <span className="h-px w-full bg-border-secondary" />}
42
+ </div>
43
+ );
44
+ }
@@ -0,0 +1,2 @@
1
+ export { SectionHeader } from "./SectionHeader";
2
+ export type { SectionHeaderProps } from "./SectionHeader";
@@ -0,0 +1,51 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type SectionLabelSize = "sm" | "md";
5
+
6
+ export interface SectionLabelProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
7
+ size?: SectionLabelSize;
8
+ title?: ReactNode;
9
+ /** Append a brand-colored `*` after the title. */
10
+ required?: boolean;
11
+ /** Trailing help-icon slot (e.g. a help-circle with tooltip). */
12
+ helpIcon?: ReactNode;
13
+ supportingText?: ReactNode;
14
+ /** Action buttons rendered below (used in wide form layouts). */
15
+ actions?: ReactNode;
16
+ }
17
+
18
+ /**
19
+ * Left-column label for a form section: title (+ optional `required` asterisk and
20
+ * `helpIcon`), supporting text, and optional `actions`. `md` bumps the title to
21
+ * `text-md`.
22
+ */
23
+ export function SectionLabel({
24
+ size = "sm",
25
+ title,
26
+ required = false,
27
+ helpIcon,
28
+ supportingText,
29
+ actions,
30
+ className,
31
+ ...rest
32
+ }: SectionLabelProps) {
33
+ const md = size === "md";
34
+ return (
35
+ <div className={clsx("flex flex-col items-start", actions && "gap-lg", className)} {...rest}>
36
+ <div className="flex flex-col gap-xxs">
37
+ <div className={clsx("flex items-center", md ? "gap-xs" : "gap-xxs")}>
38
+ {title && (
39
+ <p className={clsx("font-semibold text-text-secondary", md ? "text-md" : "text-sm")}>{title}</p>
40
+ )}
41
+ {required && <span className="text-sm font-semibold text-text-brand-tertiary">*</span>}
42
+ {helpIcon}
43
+ </div>
44
+ {supportingText && (
45
+ <p className={clsx("text-text-tertiary", md ? "text-md" : "text-sm")}>{supportingText}</p>
46
+ )}
47
+ </div>
48
+ {actions && <div className="flex items-start gap-md">{actions}</div>}
49
+ </div>
50
+ );
51
+ }
@@ -0,0 +1,2 @@
1
+ export { SectionLabel } from "./SectionLabel";
2
+ export type { SectionLabelProps, SectionLabelSize } from "./SectionLabel";
@@ -0,0 +1,121 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type SelectType =
5
+ | "default"
6
+ | "iconLeading"
7
+ | "search"
8
+ | "tags"
9
+ | "avatarLeading"
10
+ | "dotLeading";
11
+ export type SelectSize = "sm" | "md" | "lg";
12
+
13
+ export interface SelectProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
14
+ /** Cosmetic — documents the leading-slot intent; the leading element itself is the `leading` slot. */
15
+ type?: SelectType;
16
+ size?: SelectSize;
17
+ label?: ReactNode;
18
+ /** Append a brand `*` after the label. */
19
+ required?: boolean;
20
+ /** Trailing label help-icon slot. */
21
+ helpIcon?: ReactNode;
22
+ hintText?: ReactNode;
23
+ /** Leading visual inside the trigger — icon / avatar / dot / search icon. */
24
+ leading?: ReactNode;
25
+ /** Selected display value. Falls back to `placeholder` when empty. */
26
+ value?: ReactNode;
27
+ placeholder?: ReactNode;
28
+ open?: boolean;
29
+ disabled?: boolean;
30
+ invalid?: boolean;
31
+ onToggle?: () => void;
32
+ /** Dropdown panel content — a list of `SelectMenuItem`. */
33
+ children?: ReactNode;
34
+ }
35
+
36
+ const TRIGGER_PAD: Record<SelectSize, string> = {
37
+ sm: "px-lg py-md text-sm",
38
+ md: "px-lg py-md text-md",
39
+ lg: "px-lg py-2.5 text-md",
40
+ };
41
+
42
+ /**
43
+ * Select trigger + shared dropdown panel. The leading element is a `leading`
44
+ * slot (the `type` prop only documents intent); the panel is the same across all
45
+ * types — pass `SelectMenuItem`s as `children`. Controlled via `open`/`onToggle`;
46
+ * the panel renders only when `open`.
47
+ */
48
+ export function Select({
49
+ type = "default",
50
+ size = "md",
51
+ label,
52
+ required = false,
53
+ helpIcon,
54
+ hintText,
55
+ leading,
56
+ value,
57
+ placeholder,
58
+ open = false,
59
+ disabled = false,
60
+ invalid = false,
61
+ onToggle,
62
+ children,
63
+ className,
64
+ ...rest
65
+ }: SelectProps) {
66
+ const showPlaceholder = value == null || value === "";
67
+ return (
68
+ <div className={clsx("flex w-full flex-col gap-sm font-body", className)} {...rest}>
69
+ {label && (
70
+ <span className="flex items-center gap-xxs">
71
+ <span className="text-sm font-medium text-text-secondary">{label}</span>
72
+ {required && <span className="text-sm font-medium text-text-brand-tertiary">*</span>}
73
+ {helpIcon}
74
+ </span>
75
+ )}
76
+
77
+ <div className="relative">
78
+ <button
79
+ type="button"
80
+ aria-haspopup="listbox"
81
+ aria-expanded={open}
82
+ disabled={disabled}
83
+ onClick={onToggle}
84
+ className={clsx(
85
+ "flex w-full items-center gap-md rounded-md border bg-bg-primary text-left shadow-xs transition-colors",
86
+ TRIGGER_PAD[size],
87
+ invalid
88
+ ? "border-border-error"
89
+ : open
90
+ ? "border-border-brand ring-2 ring-utility-brand-500/40"
91
+ : "border-border-primary",
92
+ disabled && "cursor-not-allowed bg-bg-secondary opacity-60",
93
+ )}
94
+ >
95
+ {leading && <span className="flex shrink-0 items-center">{leading}</span>}
96
+ <span className="min-w-0 flex-1 truncate">
97
+ <span className={clsx("font-medium", showPlaceholder ? "text-text-placeholder" : "text-text-primary")}>
98
+ {showPlaceholder ? placeholder : value}
99
+ </span>
100
+ </span>
101
+ <svg
102
+ viewBox="0 0 16 16"
103
+ fill="none"
104
+ className={clsx("size-4 shrink-0 text-fg-quaternary transition-transform", open && "rotate-180")}
105
+ aria-hidden
106
+ >
107
+ <path d="M4 6l4 4 4-4" stroke="currentColor" strokeWidth="1.33" strokeLinecap="round" strokeLinejoin="round" />
108
+ </svg>
109
+ </button>
110
+
111
+ {open && (
112
+ <div className="absolute left-0 right-0 top-full z-50 mt-xs flex max-h-[320px] flex-col gap-px overflow-auto rounded-md border border-border-secondary-alt bg-bg-primary p-xs shadow-lg">
113
+ {children}
114
+ </div>
115
+ )}
116
+ </div>
117
+
118
+ {hintText && <p className="text-sm text-text-tertiary">{hintText}</p>}
119
+ </div>
120
+ );
121
+ }
@@ -0,0 +1,2 @@
1
+ export { Select } from "./Select";
2
+ export type { SelectProps, SelectType, SelectSize } from "./Select";
@@ -0,0 +1,85 @@
1
+ import { type ButtonHTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type SelectMenuItemSize = "sm" | "md" | "lg";
5
+
6
+ export interface SelectMenuItemProps
7
+ extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "title"> {
8
+ label?: ReactNode;
9
+ /** Inline secondary text beside the label (e.g. "@olivia", "10 users"). */
10
+ supportingText?: ReactNode;
11
+ selected?: boolean;
12
+ size?: SelectMenuItemSize;
13
+ /** Leading visual — icon / avatar / dot. Ignored when `multi`. */
14
+ leading?: ReactNode;
15
+ /**
16
+ * Multi-select variant: render a leading checkbox (bound to `selected`)
17
+ * instead of the trailing selected-check.
18
+ */
19
+ multi?: boolean;
20
+ }
21
+
22
+ function CheckboxBox({ selected, big }: { selected: boolean; big: boolean }) {
23
+ return (
24
+ <span
25
+ className={clsx(
26
+ "flex shrink-0 items-center justify-center rounded-xs border",
27
+ big ? "size-5" : "size-4",
28
+ selected ? "border-transparent bg-bg-brand-solid" : "border-border-primary bg-bg-primary",
29
+ )}
30
+ >
31
+ {selected && (
32
+ <svg viewBox="0 0 16 16" fill="none" className="size-3 text-fg-white" aria-hidden>
33
+ <path d="M13.33 4 6 11.33 2.67 8" stroke="currentColor" strokeWidth="1.67" strokeLinecap="round" strokeLinejoin="round" />
34
+ </svg>
35
+ )}
36
+ </span>
37
+ );
38
+ }
39
+
40
+ /**
41
+ * List-item primitive for `Select` and Multi-select dropdowns. One component over
42
+ * both: `multi` swaps the trailing selected-check for a leading checkbox. The
43
+ * shared shell is a full-width row with hover `bg-primary-hover`; `label` is
44
+ * `text-primary`, `supportingText` sits inline in `text-tertiary`.
45
+ */
46
+ export function SelectMenuItem({
47
+ label,
48
+ supportingText,
49
+ selected = false,
50
+ size = "sm",
51
+ leading,
52
+ multi = false,
53
+ disabled,
54
+ className,
55
+ ...rest
56
+ }: SelectMenuItemProps) {
57
+ const big = size !== "sm";
58
+ return (
59
+ <button
60
+ type="button"
61
+ role="option"
62
+ aria-selected={selected}
63
+ disabled={disabled}
64
+ className={clsx(
65
+ "flex w-full items-center gap-md rounded-sm text-left transition-colors",
66
+ size === "lg" ? "py-2.5 pl-md pr-2.5" : "p-md",
67
+ disabled ? "opacity-50" : "hover:bg-bg-primary-hover",
68
+ className,
69
+ )}
70
+ {...rest}
71
+ >
72
+ {multi && <CheckboxBox selected={selected} big={big} />}
73
+ {!multi && leading && <span className="shrink-0">{leading}</span>}
74
+ <span className={clsx("flex min-w-0 flex-1 items-center gap-sm", big ? "text-md" : "text-sm")}>
75
+ <span className="truncate font-medium text-text-primary">{label}</span>
76
+ {supportingText && <span className="truncate font-normal text-text-tertiary">{supportingText}</span>}
77
+ </span>
78
+ {!multi && selected && (
79
+ <svg viewBox="0 0 20 20" fill="none" className="size-5 shrink-0 text-fg-brand-primary" aria-hidden>
80
+ <path d="M16.67 5 7.5 14.17 3.33 10" stroke="currentColor" strokeWidth="1.67" strokeLinecap="round" strokeLinejoin="round" />
81
+ </svg>
82
+ )}
83
+ </button>
84
+ );
85
+ }
@@ -0,0 +1,2 @@
1
+ export { SelectMenuItem } from "./SelectMenuItem";
2
+ export type { SelectMenuItemProps, SelectMenuItemSize } from "./SelectMenuItem";
@@ -0,0 +1,100 @@
1
+ import { useState, type HTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+ import { NavMenuButton } from "../NavMenuButton";
4
+
5
+ export type SidebarNavigationType =
6
+ | "simple"
7
+ | "dualTier"
8
+ | "sectionsDividers"
9
+ | "sectionsSubheadings"
10
+ | "slim";
11
+
12
+ export interface SidebarNavigationProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {
13
+ type?: SidebarNavigationType;
14
+ /** Brand logo / wordmark slot (top of the rail). */
15
+ logo?: ReactNode;
16
+ /** Optional header content under the logo (e.g. a search input). */
17
+ header?: ReactNode;
18
+ /** Nav items — compose `NavItemBase` / `NavItemDropdownBase` children. */
19
+ children?: ReactNode;
20
+ /** Footer slot — typically `NavFeaturedCard` + `NavAccountCard`. */
21
+ footer?: ReactNode;
22
+ /** Controlled mobile-drawer open state. Omit to use internal state. */
23
+ open?: boolean;
24
+ onOpenChange?: (open: boolean) => void;
25
+ }
26
+
27
+ const WIDTH: Record<SidebarNavigationType, string> = {
28
+ simple: "w-[280px]",
29
+ dualTier: "w-[280px]",
30
+ sectionsDividers: "w-[280px]",
31
+ sectionsSubheadings: "w-[280px]",
32
+ slim: "w-[68px]",
33
+ };
34
+
35
+ /**
36
+ * Application sidebar shell. Lays out logo → header → scrollable nav → footer in
37
+ * a fixed-width rail (`slim` collapses to 68px). Composes existing `Nav*`
38
+ * components via slots/children — it does not reimplement nav items. On mobile
39
+ * the rail is hidden behind a hamburger (`NavMenuButton`); opening it shows a
40
+ * `bg-overlay` + `backdrop-blur-md` scrim and slides the rail in as a drawer.
41
+ *
42
+ * NOTE: `dualTier`'s icon-rail + expanding-panel split is simplified to a single
43
+ * 280px column here — compose the icon rail separately if you need the two-tier
44
+ * layout. (flagged)
45
+ */
46
+ export function SidebarNavigation({
47
+ type = "simple",
48
+ logo,
49
+ header,
50
+ children,
51
+ footer,
52
+ open,
53
+ onOpenChange,
54
+ className,
55
+ ...rest
56
+ }: SidebarNavigationProps) {
57
+ const [internalOpen, setInternalOpen] = useState(false);
58
+ const isOpen = open ?? internalOpen;
59
+ const setOpen = (v: boolean) => (onOpenChange ? onOpenChange(v) : setInternalOpen(v));
60
+ const slim = type === "slim";
61
+
62
+ const rail = (
63
+ <nav
64
+ className={clsx(
65
+ "flex h-full flex-col gap-2xl border-r border-border-secondary bg-bg-primary",
66
+ slim ? "items-center px-md py-xl" : "px-lg py-xl",
67
+ WIDTH[type],
68
+ className,
69
+ )}
70
+ {...rest}
71
+ >
72
+ {logo && <div className={clsx("shrink-0", slim ? "" : "px-md")}>{logo}</div>}
73
+ {header && !slim && <div className="shrink-0">{header}</div>}
74
+ <div className="flex min-h-0 flex-1 flex-col gap-xxs overflow-y-auto">{children}</div>
75
+ {footer && <div className="flex shrink-0 flex-col gap-lg">{footer}</div>}
76
+ </nav>
77
+ );
78
+
79
+ return (
80
+ <>
81
+ {/* Desktop rail */}
82
+ <aside className="hidden h-full md:block">{rail}</aside>
83
+
84
+ {/* Mobile trigger + drawer */}
85
+ <div className="md:hidden">
86
+ <NavMenuButton opened={isOpen} onClick={() => setOpen(!isOpen)} />
87
+ {isOpen && (
88
+ <div className="fixed inset-0 z-50 flex">
89
+ <div
90
+ className="absolute inset-0 bg-bg-overlay/70 backdrop-blur-md"
91
+ onClick={() => setOpen(false)}
92
+ aria-hidden
93
+ />
94
+ <div className="relative h-full">{rail}</div>
95
+ </div>
96
+ )}
97
+ </div>
98
+ </>
99
+ );
100
+ }
@@ -0,0 +1,2 @@
1
+ export { SidebarNavigation } from "./SidebarNavigation";
2
+ export type { SidebarNavigationProps, SidebarNavigationType } from "./SidebarNavigation";
@@ -0,0 +1,56 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export interface SlideOutMenuHeaderProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
5
+ /** Featured-icon slot (left of the heading). */
6
+ icon?: ReactNode;
7
+ title?: ReactNode;
8
+ supportingText?: ReactNode;
9
+ /** Tabs row rendered below the heading (adds a bottom divider). */
10
+ tabs?: ReactNode;
11
+ /** Close button callback — renders an X in the top-right when set. */
12
+ onClose?: () => void;
13
+ }
14
+
15
+ /**
16
+ * Header for a slide-out / drawer panel: optional featured `icon` + `title` +
17
+ * `supportingText`, a top-right close X, and an optional `tabs` row (which adds a
18
+ * bottom divider). Padding follows the Figma `p-3xl` desktop spec.
19
+ */
20
+ export function SlideOutMenuHeader({
21
+ icon,
22
+ title,
23
+ supportingText,
24
+ tabs,
25
+ onClose,
26
+ className,
27
+ ...rest
28
+ }: SlideOutMenuHeaderProps) {
29
+ return (
30
+ <div
31
+ className={clsx("relative flex flex-col gap-2xl bg-bg-primary p-3xl", tabs && "border-b border-border-secondary-alt", className)}
32
+ {...rest}
33
+ >
34
+ <div className="flex items-start gap-lg">
35
+ {icon && <span className="shrink-0">{icon}</span>}
36
+ <div className="flex min-w-0 flex-1 flex-col gap-xxs pr-2xl">
37
+ {title && <p className="text-lg font-semibold text-text-primary">{title}</p>}
38
+ {supportingText && <p className="text-sm text-text-tertiary">{supportingText}</p>}
39
+ </div>
40
+ </div>
41
+ {tabs}
42
+ {onClose && (
43
+ <button
44
+ type="button"
45
+ onClick={onClose}
46
+ aria-label="Close"
47
+ className="absolute right-3 top-3 flex size-9 items-center justify-center rounded-md text-fg-quaternary hover:bg-bg-primary-hover"
48
+ >
49
+ <svg viewBox="0 0 20 20" fill="none" className="size-5" aria-hidden>
50
+ <path d="M15 5 5 15M5 5l10 10" stroke="currentColor" strokeWidth="1.67" strokeLinecap="round" strokeLinejoin="round" />
51
+ </svg>
52
+ </button>
53
+ )}
54
+ </div>
55
+ );
56
+ }
@@ -0,0 +1,2 @@
1
+ export { SlideOutMenuHeader } from "./SlideOutMenuHeader";
2
+ export type { SlideOutMenuHeaderProps } from "./SlideOutMenuHeader";
@@ -0,0 +1,125 @@
1
+ import { useRef, type PointerEvent as ReactPointerEvent } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type SliderLabel = "none" | "bottom" | "topFloating";
5
+
6
+ export interface SliderProps {
7
+ min?: number;
8
+ max?: number;
9
+ step?: number;
10
+ /** Single-handle value. Ignored when `values` is set. */
11
+ value?: number;
12
+ onChange?: (value: number) => void;
13
+ /** Dual-handle range `[low, high]`. Takes precedence over `value`. */
14
+ values?: [number, number];
15
+ onRangeChange?: (values: [number, number]) => void;
16
+ /** Value-label placement. */
17
+ label?: SliderLabel;
18
+ /** Format the value shown in labels (default `${v}%`). */
19
+ formatLabel?: (v: number) => string;
20
+ disabled?: boolean;
21
+ className?: string;
22
+ "aria-label"?: string;
23
+ }
24
+
25
+ const clampStep = (v: number, min: number, max: number, step: number) => {
26
+ const snapped = Math.round((v - min) / step) * step + min;
27
+ return Math.min(max, Math.max(min, snapped));
28
+ };
29
+
30
+ /**
31
+ * Range slider — track + draggable thumb(s), pure pointer math (no library).
32
+ * Single-handle via `value`/`onChange`; dual-handle range via
33
+ * `values`/`onRangeChange`. The thumb is implemented inline (not a separate
34
+ * exported component). `label` shows the value below the thumb or in a floating
35
+ * tooltip above it.
36
+ */
37
+ export function Slider({
38
+ min = 0,
39
+ max = 100,
40
+ step = 1,
41
+ value = 0,
42
+ onChange,
43
+ values,
44
+ onRangeChange,
45
+ label = "none",
46
+ formatLabel = (v) => `${v}%`,
47
+ disabled = false,
48
+ className,
49
+ "aria-label": ariaLabel,
50
+ }: SliderProps) {
51
+ const trackRef = useRef<HTMLDivElement>(null);
52
+ const dual = values != null;
53
+ const lo = dual ? values![0] : min;
54
+ const hi = dual ? values![1] : value;
55
+ const pct = (v: number) => ((v - min) / (max - min)) * 100;
56
+
57
+ const valueFromClientX = (clientX: number) => {
58
+ const el = trackRef.current;
59
+ if (!el) return min;
60
+ const rect = el.getBoundingClientRect();
61
+ const ratio = Math.min(1, Math.max(0, (clientX - rect.left) / rect.width));
62
+ return clampStep(min + ratio * (max - min), min, max, step);
63
+ };
64
+
65
+ const startDrag = (which: "single" | "lo" | "hi") => (e: ReactPointerEvent) => {
66
+ if (disabled) return;
67
+ e.preventDefault();
68
+ (e.target as HTMLElement).setPointerCapture(e.pointerId);
69
+ const move = (ev: PointerEvent) => {
70
+ const next = valueFromClientX(ev.clientX);
71
+ if (which === "single") {
72
+ onChange?.(next);
73
+ } else if (which === "lo") {
74
+ onRangeChange?.([Math.min(next, hi), hi]);
75
+ } else {
76
+ onRangeChange?.([lo, Math.max(next, lo)]);
77
+ }
78
+ };
79
+ const up = () => {
80
+ window.removeEventListener("pointermove", move);
81
+ window.removeEventListener("pointerup", up);
82
+ };
83
+ window.addEventListener("pointermove", move);
84
+ window.addEventListener("pointerup", up);
85
+ };
86
+
87
+ const Handle = ({ at, onDown, role }: { at: number; onDown: (e: ReactPointerEvent) => void; role: string }) => (
88
+ <div
89
+ role="slider"
90
+ aria-label={role}
91
+ aria-valuemin={min}
92
+ aria-valuemax={max}
93
+ aria-valuenow={at}
94
+ aria-disabled={disabled || undefined}
95
+ tabIndex={disabled ? -1 : 0}
96
+ onPointerDown={onDown}
97
+ className="absolute top-1/2 size-6 -translate-x-1/2 -translate-y-1/2 cursor-grab touch-none rounded-full border-2 border-slider-handle-border bg-slider-handle-bg shadow-md active:cursor-grabbing"
98
+ style={{ left: `${pct(at)}%` }}
99
+ >
100
+ {label === "topFloating" && (
101
+ <span className="pointer-events-none absolute bottom-[calc(100%+8px)] left-1/2 -translate-x-1/2 whitespace-nowrap rounded-md border border-border-secondary-alt bg-bg-primary-alt px-md py-sm text-xs font-semibold text-text-secondary shadow-lg">
102
+ {formatLabel(at)}
103
+ </span>
104
+ )}
105
+ {label === "bottom" && (
106
+ <span className="pointer-events-none absolute left-1/2 top-[calc(100%+12px)] -translate-x-1/2 whitespace-nowrap text-md font-medium text-text-primary">
107
+ {formatLabel(at)}
108
+ </span>
109
+ )}
110
+ </div>
111
+ );
112
+
113
+ return (
114
+ <div className={clsx("relative w-full select-none", disabled && "opacity-60", className)} aria-label={ariaLabel}>
115
+ <div ref={trackRef} className="relative h-2 w-full rounded-full bg-bg-quaternary">
116
+ <div
117
+ className="absolute top-0 h-2 rounded-full bg-fg-brand-primary"
118
+ style={{ left: `${dual ? pct(lo) : 0}%`, right: `${100 - pct(hi)}%` }}
119
+ />
120
+ {dual && <Handle at={lo} onDown={startDrag("lo")} role="Minimum" />}
121
+ <Handle at={hi} onDown={startDrag(dual ? "hi" : "single")} role={dual ? "Maximum" : "Value"} />
122
+ </div>
123
+ </div>
124
+ );
125
+ }
@@ -0,0 +1,2 @@
1
+ export { Slider } from "./Slider";
2
+ export type { SliderProps, SliderLabel } from "./Slider";