@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,60 @@
1
+ import { type HTMLAttributes } from "react";
2
+ import clsx from "clsx";
3
+ import { CarouselArrow, type CarouselArrowSize } from "../CarouselArrow";
4
+ import { PaginationDotGroup } from "../PaginationDotGroup";
5
+
6
+ export interface CarouselImageProps extends HTMLAttributes<HTMLDivElement> {
7
+ imageUrl: string;
8
+ size?: CarouselArrowSize;
9
+ /** Total slides (drives the dot pager). */
10
+ count?: number;
11
+ /** Active slide index. */
12
+ current?: number;
13
+ onPrev?: () => void;
14
+ onNext?: () => void;
15
+ }
16
+
17
+ /**
18
+ * Carousel slide — a full-bleed image with overlaid prev/next `CarouselArrow`s
19
+ * and a bottom-centre `PaginationDotGroup` (framed). Aspect 8:5. Composition
20
+ * over the arrow + dot-group primitives.
21
+ */
22
+ export function CarouselImage({
23
+ imageUrl,
24
+ size = "md",
25
+ count = 3,
26
+ current = 0,
27
+ onPrev,
28
+ onNext,
29
+ className,
30
+ ...rest
31
+ }: CarouselImageProps) {
32
+ const inset = size === "lg" ? "left-5 right-5" : "left-4 right-4";
33
+ return (
34
+ <div
35
+ className={clsx("relative aspect-[8/5] w-full overflow-hidden rounded-xl", className)}
36
+ {...rest}
37
+ >
38
+ <img src={imageUrl} alt="" className="absolute inset-0 size-full object-cover" />
39
+ <CarouselArrow
40
+ direction="left"
41
+ size={size}
42
+ onClick={onPrev}
43
+ className={clsx("absolute top-1/2 -translate-y-1/2", inset.split(" ")[0])}
44
+ />
45
+ <CarouselArrow
46
+ direction="right"
47
+ size={size}
48
+ onClick={onNext}
49
+ className={clsx("absolute top-1/2 -translate-y-1/2", inset.split(" ")[1])}
50
+ />
51
+ <PaginationDotGroup
52
+ framed
53
+ size={size}
54
+ count={count}
55
+ current={current}
56
+ className="absolute bottom-4 left-1/2 -translate-x-1/2"
57
+ />
58
+ </div>
59
+ );
60
+ }
@@ -0,0 +1,2 @@
1
+ export { CarouselImage } from "./CarouselImage";
2
+ export type { CarouselImageProps } from "./CarouselImage";
@@ -0,0 +1,73 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type ChangeType = "01" | "02" | "03";
5
+ export type ChangeTrend = "positive" | "negative";
6
+
7
+ export interface ChangeProps extends HTMLAttributes<HTMLDivElement> {
8
+ /** 01 = plain arrow · 02 = trend line · 03 = bordered pill (neutral text). */
9
+ type?: ChangeType;
10
+ trend?: ChangeTrend;
11
+ /** The delta value, e.g. "100%". */
12
+ children: ReactNode;
13
+ }
14
+
15
+ const Stroke = ({ className, d }: { className?: string; d: string }) => (
16
+ <svg className={className} viewBox="0 0 16 16" fill="none" aria-hidden>
17
+ <path d={d} stroke="currentColor" strokeWidth="1.33" strokeLinecap="round" strokeLinejoin="round" />
18
+ </svg>
19
+ );
20
+
21
+ const ICONS: Record<ChangeType, Record<ChangeTrend, ReactNode>> = {
22
+ "01": {
23
+ positive: <Stroke className="size-4" d="M8 12.67V3.33M8 3.33 3.33 8M8 3.33 12.67 8" />,
24
+ negative: <Stroke className="size-4" d="M8 3.33v9.34M8 12.67 3.33 8M8 12.67 12.67 8" />,
25
+ },
26
+ "02": {
27
+ positive: <Stroke className="size-4" d="M14.67 4.67 9 10.33 6.33 7.67 1.33 12.67M14.67 4.67h-4M14.67 4.67v4" />,
28
+ negative: <Stroke className="size-4" d="M14.67 11.33 9 5.67 6.33 8.33 1.33 3.33M14.67 11.33h-4M14.67 11.33v-4" />,
29
+ },
30
+ "03": {
31
+ positive: <Stroke className="size-3" d="M4.5 11.5 11.5 4.5M11.5 4.5h-6M11.5 4.5v6" />,
32
+ negative: <Stroke className="size-3" d="M4.5 4.5 11.5 11.5M11.5 11.5h-6M11.5 11.5v-6" />,
33
+ },
34
+ };
35
+
36
+ /**
37
+ * Trend delta chip used by `MetricItem` (and standalone). Three shapes:
38
+ * - **01** arrow + value, success/error tinted.
39
+ * - **02** trend-line + value, success/error tinted.
40
+ * - **03** bordered pill, diagonal arrow, **neutral** text regardless of trend.
41
+ */
42
+ export function Change({
43
+ type = "01",
44
+ trend = "positive",
45
+ children,
46
+ className,
47
+ ...rest
48
+ }: ChangeProps) {
49
+ const tint =
50
+ type === "03"
51
+ ? "text-text-secondary"
52
+ : trend === "positive"
53
+ ? "text-text-success-primary"
54
+ : "text-text-error-primary";
55
+
56
+ return (
57
+ <div
58
+ className={clsx(
59
+ "inline-flex items-center",
60
+ type === "03" &&
61
+ "gap-xs rounded-sm border border-border-primary bg-bg-primary py-xxs pl-sm pr-md shadow-xs",
62
+ type === "02" && "justify-center gap-xs",
63
+ type === "01" && "justify-center gap-xxs",
64
+ tint,
65
+ className,
66
+ )}
67
+ {...rest}
68
+ >
69
+ {ICONS[type][trend]}
70
+ <span className="text-sm font-medium">{children}</span>
71
+ </div>
72
+ );
73
+ }
@@ -0,0 +1,2 @@
1
+ export { Change } from "./Change";
2
+ export type { ChangeProps, ChangeType, ChangeTrend } from "./Change";
@@ -0,0 +1,38 @@
1
+ import { type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export interface ChartLegendItem {
5
+ label: ReactNode;
6
+ color: string;
7
+ }
8
+
9
+ export interface ChartLegendProps {
10
+ items: ChartLegendItem[];
11
+ /** Layout direction — `horizontal` (top) or `vertical` (right). */
12
+ orientation?: "horizontal" | "vertical";
13
+ className?: string;
14
+ }
15
+
16
+ /**
17
+ * Chart legend — a row (or column) of colored-dot + label entries. Use standalone
18
+ * or feed Recharts' `<Legend content={...} />`. `color` is a real CSS color (the
19
+ * series color), matching the `CHART_COLORS` palette.
20
+ */
21
+ export function ChartLegend({ items, orientation = "horizontal", className }: ChartLegendProps) {
22
+ return (
23
+ <ul
24
+ className={clsx(
25
+ "flex font-body",
26
+ orientation === "vertical" ? "flex-col gap-md" : "flex-wrap items-center gap-lg",
27
+ className,
28
+ )}
29
+ >
30
+ {items.map((item, i) => (
31
+ <li key={i} className="flex items-center gap-sm text-sm text-text-tertiary">
32
+ <span className="size-2.5 shrink-0 rounded-full" style={{ backgroundColor: item.color }} aria-hidden />
33
+ {item.label}
34
+ </li>
35
+ ))}
36
+ </ul>
37
+ );
38
+ }
@@ -0,0 +1,2 @@
1
+ export { ChartLegend } from "./ChartLegend";
2
+ export type { ChartLegendProps, ChartLegendItem } from "./ChartLegend";
@@ -0,0 +1,54 @@
1
+ import clsx from "clsx";
2
+
3
+ export type ChartMarkerLine = "solid" | "dashed" | "none";
4
+
5
+ export interface ChartMarkerProps {
6
+ /** Primary value shown in the bubble (e.g. "1,218"). */
7
+ value: string;
8
+ /** Optional secondary line (e.g. "Jan 10, 2027"). */
9
+ date?: string;
10
+ /** The drop line beneath the marker. */
11
+ line?: ChartMarkerLine;
12
+ /** Drop-line height. Defaults to h-32 (128px). */
13
+ lineHeightClass?: string;
14
+ className?: string;
15
+ }
16
+
17
+ export function ChartMarker({
18
+ value,
19
+ date,
20
+ line = "solid",
21
+ lineHeightClass = "h-32",
22
+ className,
23
+ }: ChartMarkerProps) {
24
+ return (
25
+ <div className={clsx("inline-flex flex-col items-center font-body", className)}>
26
+ {/* Tooltip-style bubble */}
27
+ <div className="rounded-md bg-bg-primary-solid px-md py-xs text-center shadow-lg">
28
+ <div className="text-xs font-semibold text-text-white">{value}</div>
29
+ {/*
30
+ TOKEN NOTE: the source colour is `Component colors/Components/Tooltips/
31
+ tooltip-supporting-text` (#d4d4d4). It's approximated here as
32
+ `utility-neutral-300`, which is an exact HEX match but a SEMANTIC
33
+ mismatch (a tooltip-specific token mapped onto a generic utility
34
+ shade). If a real `tooltip-supporting-text` token is added to the
35
+ preset later (e.g. when Tooltip is built), swap this for it.
36
+ */}
37
+ {date ? (
38
+ <div className="text-xs font-medium text-utility-neutral-300">{date}</div>
39
+ ) : null}
40
+ </div>
41
+ {/* Marker dot (ring) */}
42
+ <span className="mt-xs size-3 rounded-full border-2 border-utility-brand-600 bg-bg-primary" aria-hidden />
43
+ {/* Drop line */}
44
+ {line === "solid" ? (
45
+ <span className={clsx("w-0.5 bg-utility-brand-600", lineHeightClass)} aria-hidden />
46
+ ) : line === "dashed" ? (
47
+ <span
48
+ className={clsx("border-l-2 border-dashed border-utility-brand-600", lineHeightClass)}
49
+ aria-hidden
50
+ />
51
+ ) : null}
52
+ </div>
53
+ );
54
+ }
@@ -0,0 +1,2 @@
1
+ export { ChartMarker } from "./ChartMarker";
2
+ export type { ChartMarkerProps, ChartMarkerLine } from "./ChartMarker";
@@ -0,0 +1,86 @@
1
+ import { type CSSProperties } from "react";
2
+ import { Line, LineChart, ResponsiveContainer } from "recharts";
3
+
4
+ export interface ChartMiniDatum {
5
+ value: number;
6
+ }
7
+
8
+ export type ChartMiniTrend = "positive" | "negative" | "neutral";
9
+
10
+ export interface ChartMiniProps {
11
+ /** Series points — only `value` is read. */
12
+ data: ChartMiniDatum[];
13
+ /**
14
+ * Stroke colour. A design-token name (e.g. `"utility-brand-500"`,
15
+ * `"utility-success-500"`) resolved to its hex, or a raw `#hex`. Defaults to
16
+ * the `trend` colour (`utility-brand-500` for neutral).
17
+ */
18
+ color?: string;
19
+ /** Drives the default stroke colour when `color` is omitted. */
20
+ trend?: ChartMiniTrend;
21
+ /** Container size (px). Figma sparkline is 112×56. */
22
+ width?: number | string;
23
+ height?: number;
24
+ className?: string;
25
+ style?: CSSProperties;
26
+ }
27
+
28
+ /**
29
+ * Token hex values mirrored from `tailwind-preset.js`. Recharts colour props
30
+ * take hex strings (not Tailwind class names), so the chart palette is resolved
31
+ * here. Keep in sync with the preset's `utility-*` ramp.
32
+ */
33
+ const TOKEN_HEX: Record<string, string> = {
34
+ "utility-brand-400": "#b692f6",
35
+ "utility-brand-500": "#9e77ed",
36
+ "utility-brand-600": "#7f56d9",
37
+ "utility-brand-700": "#6941c6",
38
+ "utility-success-500": "#22c55e",
39
+ "utility-error-500": "#dc2626",
40
+ };
41
+
42
+ const TREND_COLOR: Record<ChartMiniTrend, string> = {
43
+ positive: TOKEN_HEX["utility-success-500"],
44
+ negative: TOKEN_HEX["utility-error-500"],
45
+ neutral: TOKEN_HEX["utility-brand-500"],
46
+ };
47
+
48
+ function resolveColor(color: string | undefined, trend: ChartMiniTrend): string {
49
+ if (!color) return TREND_COLOR[trend];
50
+ if (color.startsWith("#")) return color;
51
+ return TOKEN_HEX[color] ?? TREND_COLOR[trend];
52
+ }
53
+
54
+ /**
55
+ * Sparkline — a thin Recharts `LineChart` wrapper. No axes, legend, tooltip or
56
+ * dots: line only. Consumed by `MetricItem`'s `chart` slot. Recharts is an
57
+ * optional peer dependency — install it in the consuming app to use this.
58
+ */
59
+ export function ChartMini({
60
+ data,
61
+ color,
62
+ trend = "neutral",
63
+ width = 112,
64
+ height = 56,
65
+ className,
66
+ style,
67
+ }: ChartMiniProps) {
68
+ const stroke = resolveColor(color, trend);
69
+
70
+ return (
71
+ <div className={className} style={{ width, height, ...style }}>
72
+ <ResponsiveContainer width="100%" height="100%">
73
+ <LineChart data={data} margin={{ top: 4, right: 4, bottom: 4, left: 4 }}>
74
+ <Line
75
+ type="monotone"
76
+ dataKey="value"
77
+ stroke={stroke}
78
+ strokeWidth={2}
79
+ dot={false}
80
+ isAnimationActive={false}
81
+ />
82
+ </LineChart>
83
+ </ResponsiveContainer>
84
+ </div>
85
+ );
86
+ }
@@ -0,0 +1,2 @@
1
+ export { ChartMini } from "./ChartMini";
2
+ export type { ChartMiniProps, ChartMiniDatum, ChartMiniTrend } from "./ChartMini";
@@ -0,0 +1,44 @@
1
+ import { type ReactNode } from "react";
2
+
3
+ export interface ChartTooltipPayloadItem {
4
+ name?: string;
5
+ value?: number | string;
6
+ color?: string;
7
+ dataKey?: string | number;
8
+ }
9
+
10
+ export interface ChartTooltipProps {
11
+ /** Recharts passes this when the tooltip is shown. */
12
+ active?: boolean;
13
+ /** Series entries at the hovered point (Recharts shape). */
14
+ payload?: ChartTooltipPayloadItem[];
15
+ /** The category/x label at the hovered point. */
16
+ label?: ReactNode;
17
+ /** Format a value for display. */
18
+ formatValue?: (value: number | string | undefined) => ReactNode;
19
+ }
20
+
21
+ /**
22
+ * Themed tooltip card for the Recharts chart wrappers — pass as the chart's
23
+ * `<Tooltip content={<ChartTooltip />} />`. Renders a `bg-primary` card with the
24
+ * point label and one colored-dot row per series. Returns null when inactive.
25
+ */
26
+ export function ChartTooltip({ active, payload, label, formatValue }: ChartTooltipProps) {
27
+ if (!active || !payload?.length) return null;
28
+ return (
29
+ <div className="rounded-md border border-border-secondary-alt bg-bg-primary px-lg py-md font-body shadow-lg">
30
+ {label != null && <div className="mb-xs text-xs font-semibold text-text-secondary">{label}</div>}
31
+ <div className="flex flex-col gap-xxs">
32
+ {payload.map((item, i) => (
33
+ <div key={i} className="flex items-center gap-sm text-xs">
34
+ <span className="size-2 shrink-0 rounded-full" style={{ backgroundColor: item.color }} aria-hidden />
35
+ <span className="text-text-tertiary">{item.name ?? item.dataKey}</span>
36
+ <span className="ml-auto font-semibold text-text-primary">
37
+ {formatValue ? formatValue(item.value) : item.value}
38
+ </span>
39
+ </div>
40
+ ))}
41
+ </div>
42
+ </div>
43
+ );
44
+ }
@@ -0,0 +1,2 @@
1
+ export { ChartTooltip } from "./ChartTooltip";
2
+ export type { ChartTooltipProps, ChartTooltipPayloadItem } from "./ChartTooltip";
@@ -0,0 +1,65 @@
1
+ import type { InputHTMLAttributes } from "react";
2
+ import clsx from "clsx";
3
+ import { CheckControlVisual, type CheckControlSize } from "./checkboxBase";
4
+
5
+ export interface CheckboxProps
6
+ extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
7
+ size?: CheckControlSize;
8
+ /** Indeterminate (mixed) visual state. */
9
+ indeterminate?: boolean;
10
+ label?: string;
11
+ supportingText?: string;
12
+ }
13
+
14
+ const textSize: Record<CheckControlSize, string> = { sm: "text-sm", md: "text-md" };
15
+
16
+ export function Checkbox({
17
+ size = "sm",
18
+ indeterminate = false,
19
+ checked,
20
+ disabled,
21
+ label,
22
+ supportingText,
23
+ className,
24
+ ...rest
25
+ }: CheckboxProps) {
26
+ return (
27
+ <label
28
+ className={clsx(
29
+ "inline-flex items-start gap-md font-body",
30
+ disabled ? "cursor-not-allowed opacity-70" : "cursor-pointer",
31
+ className,
32
+ )}
33
+ >
34
+ <input
35
+ type="checkbox"
36
+ checked={checked}
37
+ disabled={disabled}
38
+ className="peer sr-only"
39
+ aria-checked={indeterminate ? "mixed" : checked}
40
+ {...rest}
41
+ />
42
+ <CheckControlVisual
43
+ type="checkbox"
44
+ checked={checked}
45
+ indeterminate={indeterminate}
46
+ size={size}
47
+ disabled={disabled}
48
+ />
49
+ {label || supportingText ? (
50
+ <span className="flex flex-col">
51
+ {label ? (
52
+ <span className={clsx("font-medium text-text-secondary", textSize[size])}>
53
+ {label}
54
+ </span>
55
+ ) : null}
56
+ {supportingText ? (
57
+ <span className={clsx("font-normal text-text-tertiary", textSize[size])}>
58
+ {supportingText}
59
+ </span>
60
+ ) : null}
61
+ </span>
62
+ ) : null}
63
+ </label>
64
+ );
65
+ }
@@ -0,0 +1,81 @@
1
+ import clsx from "clsx";
2
+
3
+ export type CheckControlSize = "sm" | "md";
4
+ export type CheckControlType = "checkbox" | "radio";
5
+
6
+ const boxSize: Record<CheckControlSize, string> = {
7
+ sm: "size-4", // 16px
8
+ md: "size-5", // 20px
9
+ };
10
+
11
+ const glyphSize: Record<CheckControlSize, string> = {
12
+ sm: "size-3",
13
+ md: "size-3.5",
14
+ };
15
+
16
+ export interface CheckControlVisualProps {
17
+ type: CheckControlType;
18
+ checked?: boolean;
19
+ indeterminate?: boolean;
20
+ size?: CheckControlSize;
21
+ disabled?: boolean;
22
+ }
23
+
24
+ /**
25
+ * Shared visual control for Checkbox and Radio (the `_Checkbox base` in Figma).
26
+ * Renders the box/circle + glyph from props; the wrapping component owns the
27
+ * native input, label, and events. Place it immediately AFTER a `peer` input so
28
+ * the focus ring (peer-focus-visible) works.
29
+ */
30
+ export function CheckControlVisual({
31
+ type,
32
+ checked = false,
33
+ indeterminate = false,
34
+ size = "sm",
35
+ disabled = false,
36
+ }: CheckControlVisualProps) {
37
+ const active = checked || indeterminate;
38
+ return (
39
+ <span
40
+ aria-hidden
41
+ className={clsx(
42
+ "flex shrink-0 items-center justify-center border transition-colors",
43
+ "peer-focus-visible:ring-2 peer-focus-visible:ring-border-brand peer-focus-visible:ring-offset-2 peer-focus-visible:ring-offset-bg-primary",
44
+ type === "radio" ? "rounded-full" : "rounded-sm",
45
+ boxSize[size],
46
+ disabled
47
+ ? "border-border-primary bg-bg-tertiary"
48
+ : active
49
+ ? "border-brand-solid bg-brand-solid"
50
+ : "border-border-primary bg-bg-primary",
51
+ )}
52
+ >
53
+ {type === "checkbox" && checked && !indeterminate ? (
54
+ <svg viewBox="0 0 16 16" fill="none" className={glyphSize[size]} aria-hidden>
55
+ <path
56
+ d="m13 4-7 7-3-3"
57
+ stroke="currentColor"
58
+ strokeWidth="2"
59
+ strokeLinecap="round"
60
+ strokeLinejoin="round"
61
+ className="text-white"
62
+ />
63
+ </svg>
64
+ ) : null}
65
+ {type === "checkbox" && indeterminate ? (
66
+ <svg viewBox="0 0 16 16" fill="none" className={glyphSize[size]} aria-hidden>
67
+ <path d="M4 8h8" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="text-white" />
68
+ </svg>
69
+ ) : null}
70
+ {type === "radio" && checked ? (
71
+ <span className={clsx("rounded-full bg-white", size === "sm" ? "size-1.5" : "size-2")} />
72
+ ) : null}
73
+ </span>
74
+ );
75
+ }
76
+
77
+ export interface CheckControlLabelProps {
78
+ label?: string;
79
+ supportingText?: string;
80
+ size?: CheckControlSize;
81
+ }
@@ -0,0 +1,3 @@
1
+ export { Checkbox } from "./Checkbox";
2
+ export type { CheckboxProps } from "./Checkbox";
3
+ export type { CheckControlSize } from "./checkboxBase";
@@ -0,0 +1,94 @@
1
+ import { useState } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export interface CodeSnippetProps {
5
+ /** Raw code string. Rendered verbatim — see the highlighting note below. */
6
+ code: string;
7
+ /** Optional language label (shown in the toolbar). */
8
+ language?: string;
9
+ /** Show the line-number gutter. */
10
+ showLineNumbers?: boolean;
11
+ /** Override the copy handler (defaults to navigator.clipboard). */
12
+ onCopy?: (code: string) => void;
13
+ className?: string;
14
+ }
15
+
16
+ /*
17
+ SCOPE NOTE: this is the DS *shell* only — dark container, toolbar (copy +
18
+ expand), and an optional line-number gutter. It renders `code` as plain
19
+ monospace text. SYNTAX HIGHLIGHTING IS NOT IMPLEMENTED HERE: Untitled UI's
20
+ snippet uses per-token colours (utility-blue/green/pink/red-600), which means
21
+ real tokenization via a library (Prism / Shiki / highlight.js) rather than
22
+ hand-rolled regex. Treat the <code> body as the plug-point: wrap or replace it
23
+ with a highlighter's output once a library is chosen (same "wrap a lib" caution
24
+ flagged in figma-map.md). Tabs (npm/yarn/bun) variant is also not modelled yet.
25
+ */
26
+
27
+ function CopyIcon() {
28
+ return (
29
+ <svg viewBox="0 0 20 20" fill="none" className="size-4" aria-hidden>
30
+ <path
31
+ d="M6.667 6.667V4.333c0-.92.746-1.666 1.666-1.666h7.334c.92 0 1.666.746 1.666 1.666v7.334c0 .92-.746 1.666-1.666 1.666h-2.334M11.667 6.667H4.333c-.92 0-1.666.746-1.666 1.666v7.334c0 .92.746 1.666 1.666 1.666h7.334c.92 0 1.666-.746 1.666-1.666V8.333c0-.92-.746-1.666-1.666-1.666Z"
32
+ stroke="currentColor"
33
+ strokeWidth="1.667"
34
+ strokeLinecap="round"
35
+ strokeLinejoin="round"
36
+ />
37
+ </svg>
38
+ );
39
+ }
40
+
41
+ export function CodeSnippet({
42
+ code,
43
+ language,
44
+ showLineNumbers = false,
45
+ onCopy,
46
+ className,
47
+ }: CodeSnippetProps) {
48
+ const [copied, setCopied] = useState(false);
49
+ const lines = code.replace(/\n$/, "").split("\n");
50
+
51
+ const handleCopy = () => {
52
+ if (onCopy) onCopy(code);
53
+ else void navigator.clipboard?.writeText(code);
54
+ setCopied(true);
55
+ setTimeout(() => setCopied(false), 1500);
56
+ };
57
+
58
+ return (
59
+ <div
60
+ className={clsx(
61
+ "overflow-hidden rounded-lg bg-bg-primary-solid font-body",
62
+ className,
63
+ )}
64
+ >
65
+ <div className="flex items-center justify-between px-xl py-md">
66
+ <span className="text-xs font-medium text-utility-neutral-400">
67
+ {language ?? "code"}
68
+ </span>
69
+ <button
70
+ type="button"
71
+ onClick={handleCopy}
72
+ aria-label="Copy code"
73
+ className="text-utility-neutral-400 transition-colors hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-brand"
74
+ >
75
+ {copied ? <span className="text-xs">Copied</span> : <CopyIcon />}
76
+ </button>
77
+ </div>
78
+ <pre className="overflow-x-auto px-xl pb-xl text-sm leading-5">
79
+ <code className="font-mono text-white">
80
+ {showLineNumbers
81
+ ? lines.map((line, i) => (
82
+ <div key={i} className="grid grid-cols-[2rem_1fr] gap-md">
83
+ <span className="select-none text-right text-utility-neutral-500">
84
+ {i + 1}
85
+ </span>
86
+ <span className="whitespace-pre">{line || " "}</span>
87
+ </div>
88
+ ))
89
+ : code}
90
+ </code>
91
+ </pre>
92
+ </div>
93
+ );
94
+ }
@@ -0,0 +1,2 @@
1
+ export { CodeSnippet } from "./CodeSnippet";
2
+ export type { CodeSnippetProps } from "./CodeSnippet";
@@ -0,0 +1,44 @@
1
+ import clsx from "clsx";
2
+
3
+ export interface CodeSnippetTabsProps {
4
+ /** Tab labels (e.g. ["npm", "yarn", "bun"]). */
5
+ tabs: string[];
6
+ /** Currently-selected tab. */
7
+ value: string;
8
+ onChange?: (tab: string) => void;
9
+ className?: string;
10
+ }
11
+
12
+ /** Tab strip for CodeSnippet's "Vertical with tabs" type. */
13
+ export function CodeSnippetTabs({
14
+ tabs,
15
+ value,
16
+ onChange,
17
+ className,
18
+ }: CodeSnippetTabsProps) {
19
+ return (
20
+ <div role="tablist" className={clsx("inline-flex items-center gap-xs font-body", className)}>
21
+ {tabs.map((tab) => {
22
+ const current = tab === value;
23
+ return (
24
+ <button
25
+ key={tab}
26
+ type="button"
27
+ role="tab"
28
+ aria-selected={current}
29
+ onClick={() => onChange?.(tab)}
30
+ className={clsx(
31
+ "rounded-sm px-md py-xs text-sm font-semibold transition-colors",
32
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-brand",
33
+ current
34
+ ? "border border-border-brand text-text-primary"
35
+ : "border border-transparent text-text-quaternary hover:text-text-primary",
36
+ )}
37
+ >
38
+ {tab}
39
+ </button>
40
+ );
41
+ })}
42
+ </div>
43
+ );
44
+ }