@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,88 @@
1
+ import { type ButtonHTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type SocialBrand = "google" | "facebook" | "apple" | "twitter" | "figma" | "dribbble";
5
+ export type SocialButtonTheme = "color" | "gray" | "brand";
6
+ export type SocialButtonSize = "md" | "lg";
7
+
8
+ export interface SocialButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "type"> {
9
+ social: SocialBrand;
10
+ /** `color`/`brand` = full-color logo; `gray` = monochrome. */
11
+ theme?: SocialButtonTheme;
12
+ size?: SocialButtonSize;
13
+ /** Icon-only (no label) — renders a square button. */
14
+ iconOnly?: boolean;
15
+ /** Label override; defaults to "Sign in with <Brand>". */
16
+ children?: ReactNode;
17
+ }
18
+
19
+ const LABEL: Record<SocialBrand, string> = {
20
+ google: "Sign in with Google",
21
+ facebook: "Sign in with Facebook",
22
+ apple: "Sign in with Apple",
23
+ twitter: "Sign in with X",
24
+ figma: "Sign in with Figma",
25
+ dribbble: "Sign in with Dribbble",
26
+ };
27
+
28
+ /** Full-color brand glyphs (viewBox 0 0 24 24). Gray theme desaturates via CSS. */
29
+ const GLYPH: Record<SocialBrand, ReactNode> = {
30
+ google: (
31
+ <>
32
+ <path d="M23.04 12.26c0-.82-.07-1.6-.21-2.36H12v4.48h6.19a5.3 5.3 0 0 1-2.3 3.48v2.9h3.72c2.18-2 3.43-4.96 3.43-8.5Z" fill="#4285F4" />
33
+ <path d="M12 24c3.1 0 5.7-1.03 7.6-2.79l-3.72-2.88c-1.03.69-2.35 1.1-3.88 1.1-2.98 0-5.5-2.01-6.4-4.72H1.75v2.96A12 12 0 0 0 12 24Z" fill="#34A853" />
34
+ <path d="M5.6 14.71A7.2 7.2 0 0 1 5.22 12c0-.94.16-1.86.38-2.71V6.33H1.75A12 12 0 0 0 .48 12c0 1.94.46 3.77 1.27 5.67l3.85-2.96Z" fill="#FBBC05" />
35
+ <path d="M12 4.77c1.68 0 3.19.58 4.38 1.71l3.28-3.28C17.7 1.19 15.1 0 12 0A12 12 0 0 0 1.75 6.33l3.85 2.96C6.5 6.58 9.02 4.77 12 4.77Z" fill="#EA4335" />
36
+ </>
37
+ ),
38
+ facebook: <path d="M24 12a12 12 0 1 0-13.87 11.85v-8.38H7.08V12h3.05V9.36c0-3.01 1.79-4.67 4.53-4.67 1.31 0 2.69.23 2.69.23v2.95h-1.52c-1.49 0-1.96.93-1.96 1.87V12h3.33l-.53 3.47h-2.8v8.38A12 12 0 0 0 24 12Z" fill="#1877F2" />,
39
+ apple: <path d="M18.4 12.74c-.02-2.07 1.69-3.06 1.77-3.11-.96-1.41-2.46-1.6-2.99-1.62-1.27-.13-2.49.75-3.13.75-.65 0-1.65-.73-2.71-.71-1.39.02-2.68.81-3.39 2.05-1.45 2.51-.37 6.22 1.03 8.26.69.99 1.5 2.11 2.57 2.07 1.03-.04 1.42-.67 2.67-.67 1.24 0 1.6.67 2.69.65 1.11-.02 1.81-1.01 2.49-2.01.78-1.15 1.1-2.27 1.12-2.32-.02-.01-2.15-.83-2.17-3.27ZM16.34 6.58c.57-.69.95-1.65.85-2.6-.82.03-1.81.54-2.4 1.23-.52.61-.98 1.59-.86 2.52.91.07 1.84-.46 2.41-1.15Z" fill="#000" />,
40
+ twitter: <path d="M18.24 2.25h3.31l-7.23 8.26L22.83 21.75h-6.66l-5.22-6.82-5.97 6.82H1.66l7.73-8.83L1.17 2.25h6.83l4.71 6.23 5.53-6.23Zm-1.16 17.52h1.83L7.01 4.13H5.04l12.04 15.64Z" fill="#000" />,
41
+ figma: (
42
+ <>
43
+ <path d="M8 24c2.21 0 4-1.79 4-4v-4H8a4 4 0 1 0 0 8Z" fill="#0ACF83" />
44
+ <path d="M4 12a4 4 0 0 1 4-4h4v8H8a4 4 0 0 1-4-4Z" fill="#A259FF" />
45
+ <path d="M4 4a4 4 0 0 1 4-4h4v8H8a4 4 0 0 1-4-4Z" fill="#F24E1E" />
46
+ <path d="M12 0h4a4 4 0 0 1 0 8h-4V0Z" fill="#FF7262" />
47
+ <path d="M20 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z" fill="#1ABCFE" />
48
+ </>
49
+ ),
50
+ dribbble: <path d="M12 0a12 12 0 1 0 0 24 12 12 0 0 0 0-24Zm7.93 5.53a10.16 10.16 0 0 1 2.3 6.36c-.34-.07-3.71-.75-7.1-.33-.08-.18-.15-.36-.23-.55-.21-.5-.45-1-.7-1.49 3.76-1.53 5.47-3.74 5.73-3.99ZM12 1.79c2.55 0 4.88.96 6.65 2.53-.22.31-1.76 2.38-5.39 3.74A52.4 52.4 0 0 0 9.4 2.2 10.2 10.2 0 0 1 12 1.79Zm-4.57 1.1a61.7 61.7 0 0 1 3.83 5.79c-4.83 1.29-9.1 1.26-9.56 1.26a10.24 10.24 0 0 1 5.73-7.05ZM1.78 12.01v-.31c.44.01 5.46.07 10.62-1.48.3.58.58 1.17.84 1.76l-.41.12c-5.33 1.72-8.16 6.42-8.4 6.81a10.18 10.18 0 0 1-2.65-6.9Zm10.22 10.2c-2.3 0-4.42-.78-6.11-2.08.18-.39 2.32-4.5 8.15-6.53l.07-.02c1.45 3.77 2.05 6.93 2.2 7.84a10.13 10.13 0 0 1-4.31.79Zm6.06-1.74c-.1-.63-.65-3.65-2-7.36 3.2-.51 5.99.33 6.34.44a10.2 10.2 0 0 1-4.34 6.92Z" fill="#EA4C89" />,
51
+ };
52
+
53
+ /**
54
+ * Social-login button. All themes share the neutral white shell (border-primary,
55
+ * shadow-xs, `text-secondary` label) — `theme` only controls the brand glyph:
56
+ * `color`/`brand` = full color, `gray` = monochrome (CSS grayscale, flagged
57
+ * approximation of UntitledUI's true single-color gray logos). `iconOnly` drops
58
+ * the label for a square button.
59
+ */
60
+ export function SocialButton({
61
+ social,
62
+ theme = "color",
63
+ size = "md",
64
+ iconOnly = false,
65
+ children,
66
+ className,
67
+ ...rest
68
+ }: SocialButtonProps) {
69
+ return (
70
+ <button
71
+ type="button"
72
+ className={clsx(
73
+ "inline-flex items-center justify-center rounded-md border border-border-primary bg-bg-primary font-semibold text-text-secondary shadow-xs transition-colors hover:bg-bg-primary-hover",
74
+ size === "lg" ? "gap-sm text-md" : "gap-xs text-sm",
75
+ iconOnly
76
+ ? size === "lg" ? "size-11" : "size-10"
77
+ : size === "lg" ? "px-xl py-2.5" : "px-xl py-md",
78
+ className,
79
+ )}
80
+ {...rest}
81
+ >
82
+ <svg viewBox="0 0 24 24" className={clsx("shrink-0", size === "lg" ? "size-5" : "size-5", theme === "gray" && "grayscale")} aria-hidden>
83
+ {GLYPH[social]}
84
+ </svg>
85
+ {!iconOnly && <span className="whitespace-nowrap">{children ?? LABEL[social]}</span>}
86
+ </button>
87
+ );
88
+ }
@@ -0,0 +1,2 @@
1
+ export { SocialButton } from "./SocialButton";
2
+ export type { SocialButtonProps, SocialBrand, SocialButtonTheme, SocialButtonSize } from "./SocialButton";
@@ -0,0 +1,75 @@
1
+ import { type HTMLAttributes } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type StatusIconType = "online" | "offline" | "count" | "avatar" | "verified";
5
+
6
+ export interface StatusIconProps extends HTMLAttributes<HTMLSpanElement> {
7
+ type?: StatusIconType;
8
+ /** Number shown for `type="count"`. */
9
+ count?: number;
10
+ /** Image src for `type="avatar"`. */
11
+ imageUrl?: string;
12
+ /** Outer box size in px (default 16). */
13
+ size?: number;
14
+ }
15
+
16
+ /**
17
+ * Small overlay status badge — meant to sit on the corner of an avatar/icon.
18
+ * `online`/`offline` = colored dot; `count` = error-colored numeric bubble;
19
+ * `avatar` = ringed mini image; `verified` = brand verified tick (approximated
20
+ * as a brand disc + check, no burst star).
21
+ */
22
+ export function StatusIcon({
23
+ type = "offline",
24
+ count,
25
+ imageUrl,
26
+ size = 16,
27
+ className,
28
+ style,
29
+ ...rest
30
+ }: StatusIconProps) {
31
+ const box = { width: size, height: size, ...style };
32
+
33
+ if (type === "avatar") {
34
+ return (
35
+ <span className={clsx("inline-block overflow-hidden rounded-full border-[1.5px] border-bg-primary", className)} style={box} {...rest}>
36
+ {imageUrl && <img src={imageUrl} alt="" className="size-full object-cover" />}
37
+ </span>
38
+ );
39
+ }
40
+
41
+ if (type === "count") {
42
+ return (
43
+ <span
44
+ className={clsx("inline-flex items-center justify-center rounded-full border-[1.5px] border-bg-primary bg-fg-error-secondary text-[10px] font-bold leading-none text-text-white", className)}
45
+ style={box}
46
+ {...rest}
47
+ >
48
+ {count}
49
+ </span>
50
+ );
51
+ }
52
+
53
+ if (type === "verified") {
54
+ return (
55
+ <span className={clsx("inline-flex items-center justify-center rounded-full bg-bg-brand-solid text-fg-white", className)} style={box} {...rest}>
56
+ <svg viewBox="0 0 16 16" fill="none" className="size-2.5" aria-hidden>
57
+ <path d="M13 4.5 6.5 11 3 7.5" stroke="currentColor" strokeWidth="1.67" strokeLinecap="round" strokeLinejoin="round" />
58
+ </svg>
59
+ </span>
60
+ );
61
+ }
62
+
63
+ // online / offline dot
64
+ return (
65
+ <span
66
+ className={clsx(
67
+ "inline-block rounded-full border-[1.5px] border-bg-primary",
68
+ type === "online" ? "bg-fg-success-secondary" : "bg-utility-neutral-300",
69
+ className,
70
+ )}
71
+ style={box}
72
+ {...rest}
73
+ />
74
+ );
75
+ }
@@ -0,0 +1,2 @@
1
+ export { StatusIcon } from "./StatusIcon";
2
+ export type { StatusIconProps, StatusIconType } from "./StatusIcon";
@@ -0,0 +1,90 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+ import {
4
+ StepIconBase,
5
+ type StepIconType,
6
+ type StepStatus,
7
+ type StepIconSize,
8
+ } from "../StepIconBase";
9
+
10
+ export type StepOrientation = "left" | "top";
11
+
12
+ export interface StepBaseProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
13
+ status?: StepStatus;
14
+ size?: StepIconSize;
15
+ /** Icon column position: `left` (vertical list) or `top` (horizontal list). */
16
+ orientation?: StepOrientation;
17
+ /** Indicator style. Ignored when `icon` (featured) is supplied. */
18
+ iconType?: StepIconType;
19
+ /** Step number (number indicator). */
20
+ step?: ReactNode;
21
+ /** Featured-icon slot — replaces the StepIconBase indicator. */
22
+ icon?: ReactNode;
23
+ title?: ReactNode;
24
+ description?: ReactNode;
25
+ /** Render a connecting line toward the next step. */
26
+ connector?: boolean;
27
+ }
28
+
29
+ /**
30
+ * One step row/column for `ProgressSteps`. Composes `StepIconBase` (or a featured
31
+ * `icon` slot) + title/description, with an optional `connector` line (vertical
32
+ * below for `left`, horizontal to the right for `top`). The 5 assembled Figma
33
+ * layout frames are reference-only — build step lists by laying these out.
34
+ *
35
+ * NOTE: the connector renders on one side only (toward the next step); the last
36
+ * step should set `connector={false}`.
37
+ */
38
+ export function StepBase({
39
+ status = "incomplete",
40
+ size = "sm",
41
+ orientation = "left",
42
+ iconType = "check",
43
+ step,
44
+ icon,
45
+ title,
46
+ description,
47
+ connector = false,
48
+ className,
49
+ ...rest
50
+ }: StepBaseProps) {
51
+ const indicator = icon ?? (
52
+ <StepIconBase type={iconType} status={status} size={size} step={step} />
53
+ );
54
+ const lineColor = status === "complete" ? "bg-bg-brand-solid" : "bg-border-primary";
55
+
56
+ const titleEl = title && (
57
+ <p className={clsx("text-sm font-semibold", status === "current" ? "text-text-brand-secondary" : "text-text-secondary")}>
58
+ {title}
59
+ </p>
60
+ );
61
+ const descEl = description && <p className="text-sm text-text-tertiary">{description}</p>;
62
+
63
+ if (orientation === "top") {
64
+ return (
65
+ <div className={clsx("flex flex-col gap-md", className)} {...rest}>
66
+ <div className="flex w-full items-center gap-xs">
67
+ {indicator}
68
+ {connector && <span className={clsx("h-0.5 flex-1 rounded-full", lineColor)} />}
69
+ </div>
70
+ <div className="flex flex-col gap-xxs">
71
+ {titleEl}
72
+ {descEl}
73
+ </div>
74
+ </div>
75
+ );
76
+ }
77
+
78
+ return (
79
+ <div className={clsx("flex gap-md", className)} {...rest}>
80
+ <div className="flex flex-col items-center self-stretch">
81
+ {indicator}
82
+ {connector && <span className={clsx("mt-xs w-0.5 flex-1 rounded-full", lineColor)} />}
83
+ </div>
84
+ <div className="flex flex-col gap-xxs pb-xl">
85
+ {titleEl}
86
+ {descEl}
87
+ </div>
88
+ </div>
89
+ );
90
+ }
@@ -0,0 +1,2 @@
1
+ export { StepBase } from "./StepBase";
2
+ export type { StepBaseProps, StepOrientation } from "./StepBase";
@@ -0,0 +1,65 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type StepIconType = "check" | "number";
5
+ export type StepStatus = "incomplete" | "current" | "complete";
6
+ export type StepIconSize = "sm" | "md";
7
+
8
+ export interface StepIconBaseProps extends HTMLAttributes<HTMLDivElement> {
9
+ type?: StepIconType;
10
+ status?: StepStatus;
11
+ size?: StepIconSize;
12
+ /** Number to show when `type="number"`. */
13
+ step?: ReactNode;
14
+ }
15
+
16
+ const Check = ({ className }: { className?: string }) => (
17
+ <svg viewBox="0 0 16 16" fill="none" className={className} aria-hidden>
18
+ <path d="M13.33 4 6 11.33 2.67 8" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
19
+ </svg>
20
+ );
21
+
22
+ /**
23
+ * Step indicator dot for `ProgressSteps`. `type` check (dot / brand fill / check)
24
+ * or number; `status` incomplete / current (brand ring) / complete (filled +
25
+ * check). Composed by `StepBase`.
26
+ */
27
+ export function StepIconBase({
28
+ type = "check",
29
+ status = "incomplete",
30
+ size = "sm",
31
+ step,
32
+ className,
33
+ ...rest
34
+ }: StepIconBaseProps) {
35
+ const dim = size === "md" ? "size-8" : "size-6";
36
+ const isComplete = status === "complete";
37
+ const isCurrent = status === "current";
38
+ const completeFill = type === "number" ? "bg-bg-success-solid" : "bg-bg-brand-solid";
39
+
40
+ return (
41
+ <div
42
+ className={clsx(
43
+ "relative flex shrink-0 items-center justify-center overflow-visible rounded-full",
44
+ dim,
45
+ isComplete && completeFill,
46
+ isCurrent && type === "check" && "bg-bg-brand-solid ring-2 ring-utility-brand-500 ring-offset-2",
47
+ isCurrent && type === "number" && "border border-border-secondary bg-bg-primary",
48
+ status === "incomplete" && type === "check" && "border-2 border-border-primary bg-bg-primary",
49
+ status === "incomplete" && type === "number" && "border border-border-secondary bg-bg-primary",
50
+ className,
51
+ )}
52
+ {...rest}
53
+ >
54
+ {type === "check" && !isComplete && (
55
+ <span className={clsx("rounded-full", size === "md" ? "size-2.5" : "size-2", isCurrent ? "bg-fg-white" : "bg-fg-quaternary")} />
56
+ )}
57
+ {type === "number" && !isComplete && (
58
+ <span className={clsx("font-semibold", size === "md" ? "text-sm" : "text-xs", isCurrent ? "text-text-secondary" : "text-text-quaternary")}>
59
+ {step}
60
+ </span>
61
+ )}
62
+ {isComplete && <Check className={clsx("text-fg-white", size === "md" ? "size-4" : "size-3")} />}
63
+ </div>
64
+ );
65
+ }
@@ -0,0 +1,7 @@
1
+ export { StepIconBase } from "./StepIconBase";
2
+ export type {
3
+ StepIconBaseProps,
4
+ StepIconType,
5
+ StepStatus,
6
+ StepIconSize,
7
+ } from "./StepIconBase";
@@ -0,0 +1,88 @@
1
+ import { type ButtonHTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type TabButtonType =
5
+ | "buttonBrand"
6
+ | "buttonGray"
7
+ | "buttonWhite"
8
+ | "buttonMinimal"
9
+ | "underline"
10
+ | "line";
11
+ export type TabButtonSize = "sm" | "md";
12
+
13
+ export interface TabButtonBaseProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "type"> {
14
+ /** Visual style. Maps to the Figma `Type` axis. */
15
+ variant?: TabButtonType;
16
+ current?: boolean;
17
+ size?: TabButtonSize;
18
+ /** Leading icon slot. */
19
+ icon?: ReactNode;
20
+ /** Trailing badge/count slot. */
21
+ badge?: ReactNode;
22
+ children?: ReactNode;
23
+ }
24
+
25
+ /**
26
+ * Single tab control consumed by `Tabs`. Six `variant`s: pill styles
27
+ * (`buttonBrand`/`buttonGray`/`buttonWhite`/`buttonMinimal`), `underline`
28
+ * (horizontal bottom border) and `line` (vertical left border). `current` is the
29
+ * active state. The native `type` attribute is Omitted (taken over by `variant`).
30
+ */
31
+ export function TabButtonBase({
32
+ variant = "buttonBrand",
33
+ current = false,
34
+ size = "sm",
35
+ icon,
36
+ badge,
37
+ children,
38
+ className,
39
+ ...rest
40
+ }: TabButtonBaseProps) {
41
+ const pill = variant !== "underline" && variant !== "line";
42
+
43
+ const styles: Record<TabButtonType, string> = {
44
+ buttonBrand: clsx(
45
+ "rounded-sm px-2.5 py-md",
46
+ current ? "bg-bg-brand-primary-alt text-text-secondary" : "text-text-quaternary hover:bg-bg-primary-hover hover:text-text-tertiary",
47
+ ),
48
+ buttonGray: clsx(
49
+ "rounded-sm px-2.5 py-md",
50
+ current ? "bg-bg-primary-hover text-utility-brand-700" : "text-text-quaternary hover:bg-bg-primary-hover hover:text-text-tertiary",
51
+ ),
52
+ buttonWhite: clsx(
53
+ "rounded-sm px-2.5 py-md",
54
+ current ? "border border-border-primary bg-bg-primary text-text-secondary shadow-xs" : "text-text-quaternary hover:text-text-tertiary",
55
+ ),
56
+ buttonMinimal: clsx(
57
+ "rounded-sm px-2.5 py-md",
58
+ current ? "text-text-secondary" : "text-text-quaternary hover:text-text-tertiary",
59
+ ),
60
+ underline: clsx(
61
+ "border-b-2 px-xxs pb-lg",
62
+ current ? "border-fg-brand-primary-alt text-utility-brand-700" : "border-transparent text-text-quaternary hover:text-text-tertiary",
63
+ ),
64
+ line: clsx(
65
+ "border-l-2 px-lg py-xxs",
66
+ current ? "border-fg-brand-primary text-utility-brand-700" : "border-transparent text-text-quaternary hover:text-text-tertiary",
67
+ ),
68
+ };
69
+
70
+ return (
71
+ <button
72
+ type="button"
73
+ aria-current={current ? "page" : undefined}
74
+ className={clsx(
75
+ "inline-flex items-center justify-center gap-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-utility-brand-500 focus-visible:ring-offset-2",
76
+ size === "md" ? "text-sm" : "text-xs",
77
+ pill && "h-9",
78
+ styles[variant],
79
+ className,
80
+ )}
81
+ {...rest}
82
+ >
83
+ {icon && <span className="flex size-4 shrink-0 items-center justify-center">{icon}</span>}
84
+ {children && <span className="whitespace-nowrap px-xxs">{children}</span>}
85
+ {badge}
86
+ </button>
87
+ );
88
+ }
@@ -0,0 +1,2 @@
1
+ export { TabButtonBase } from "./TabButtonBase";
2
+ export type { TabButtonBaseProps, TabButtonType, TabButtonSize } from "./TabButtonBase";
@@ -0,0 +1,44 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type TableCellSize = "sm" | "md";
5
+
6
+ export interface TableCellProps extends HTMLAttributes<HTMLTableCellElement> {
7
+ size?: TableCellSize;
8
+ /** Leading checkbox slot (first column). */
9
+ checkbox?: ReactNode;
10
+ /** Hover/selected row background. */
11
+ selected?: boolean;
12
+ /** Cell content — any of the 14 Figma `Type` layouts (see stories). */
13
+ children?: ReactNode;
14
+ }
15
+
16
+ /**
17
+ * Generic `<td>` shell — border-bottom row cell. One component over the 14 Figma
18
+ * `Type`s (Text, Avatar, Badge, Trend, Progress bar, Action icons, Star ratings,
19
+ * …): the differing content goes in `children`; the shell (height, padding,
20
+ * border, hover bg) is constant. Same one-shell-many-examples pattern as
21
+ * `NavFeaturedCard`. `sm` = 64px row, `md` = 72px.
22
+ *
23
+ * NOTE: the Figma `Star ratings` cell references a raw `Colors/Yellow/400` var —
24
+ * do NOT use it; substitute the `warning-primary`/`utility-yellow` token if a
25
+ * star fill colour is needed.
26
+ */
27
+ export function TableCell({ size = "md", checkbox, selected = false, children, className, ...rest }: TableCellProps) {
28
+ return (
29
+ <td
30
+ className={clsx(
31
+ "border-b border-border-secondary align-middle text-sm",
32
+ size === "md" ? "h-[72px] px-3xl py-xl" : "h-16 px-3xl py-lg",
33
+ selected ? "bg-bg-primary-hover" : "bg-bg-primary",
34
+ className,
35
+ )}
36
+ {...rest}
37
+ >
38
+ <div className="flex items-center gap-lg">
39
+ {checkbox}
40
+ {children}
41
+ </div>
42
+ </td>
43
+ );
44
+ }
@@ -0,0 +1,2 @@
1
+ export { TableCell } from "./TableCell";
2
+ export type { TableCellProps, TableCellSize } from "./TableCell";
@@ -0,0 +1,34 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type TableHeaderCellSize = "sm" | "md";
5
+
6
+ export interface TableHeaderCellProps extends HTMLAttributes<HTMLTableCellElement> {
7
+ size?: TableHeaderCellSize;
8
+ /** Leading checkbox slot (first column). */
9
+ checkbox?: ReactNode;
10
+ /** Label content — typically a `TableHeaderLabel`. */
11
+ children?: ReactNode;
12
+ }
13
+
14
+ /**
15
+ * `<th>` wrapper — white cell with a bottom border; composes a leading `checkbox`
16
+ * slot + a `TableHeaderLabel` (`children`). `sm` = 40px row, `md` = 44px row.
17
+ */
18
+ export function TableHeaderCell({ size = "sm", checkbox, children, className, ...rest }: TableHeaderCellProps) {
19
+ return (
20
+ <th
21
+ className={clsx(
22
+ "border-b border-border-secondary bg-bg-primary text-left align-middle",
23
+ size === "md" ? "h-11 px-3xl py-lg" : "h-10 px-2xl py-md",
24
+ className,
25
+ )}
26
+ {...rest}
27
+ >
28
+ <div className={clsx("flex items-center", checkbox ? "gap-lg" : "gap-xs")}>
29
+ {checkbox}
30
+ {children}
31
+ </div>
32
+ </th>
33
+ );
34
+ }
@@ -0,0 +1,2 @@
1
+ export { TableHeaderCell } from "./TableHeaderCell";
2
+ export type { TableHeaderCellProps, TableHeaderCellSize } from "./TableHeaderCell";
@@ -0,0 +1,37 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+
4
+ export type TableHeaderLabelArrow = "none" | "down" | "up" | "chevronSelector";
5
+
6
+ export interface TableHeaderLabelProps extends HTMLAttributes<HTMLDivElement> {
7
+ children?: ReactNode;
8
+ /** Sort indicator. */
9
+ arrow?: TableHeaderLabelArrow;
10
+ /** Trailing help-icon slot. */
11
+ helpIcon?: ReactNode;
12
+ }
13
+
14
+ function ArrowIcon({ arrow }: { arrow: Exclude<TableHeaderLabelArrow, "none"> }) {
15
+ return (
16
+ <svg viewBox="0 0 12 12" fill="none" className="size-3 shrink-0" aria-hidden>
17
+ {arrow === "down" && <path d="M6 2.5v7M6 9.5 9 6.5M6 9.5 3 6.5" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" />}
18
+ {arrow === "up" && <path d="M6 9.5v-7M6 2.5 9 5.5M6 2.5 3 5.5" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" />}
19
+ {arrow === "chevronSelector" && <path d="M3.5 7.5 6 10l2.5-2.5M3.5 4.5 6 2l2.5 2.5" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" />}
20
+ </svg>
21
+ );
22
+ }
23
+
24
+ /**
25
+ * Column-header label — `text-xs` semibold in `text-quaternary` (→ `text-tertiary`
26
+ * on hover), with an optional sort `arrow` and trailing `helpIcon` slot. Consumed
27
+ * by `TableHeaderCell`.
28
+ */
29
+ export function TableHeaderLabel({ children, arrow = "none", helpIcon, className, ...rest }: TableHeaderLabelProps) {
30
+ return (
31
+ <div className={clsx("group/th inline-flex items-center gap-xs text-xs font-semibold text-text-quaternary", className)} {...rest}>
32
+ <span className="whitespace-nowrap">{children}</span>
33
+ {helpIcon}
34
+ {arrow !== "none" && <ArrowIcon arrow={arrow} />}
35
+ </div>
36
+ );
37
+ }
@@ -0,0 +1,2 @@
1
+ export { TableHeaderLabel } from "./TableHeaderLabel";
2
+ export type { TableHeaderLabelProps, TableHeaderLabelArrow } from "./TableHeaderLabel";
@@ -0,0 +1,80 @@
1
+ import { type ReactNode } from "react";
2
+ import clsx from "clsx";
3
+ import { TabButtonBase, type TabButtonType, type TabButtonSize } from "../TabButtonBase";
4
+
5
+ export type TabsOrientation = "horizontal" | "vertical";
6
+
7
+ export interface TabItem {
8
+ value: string;
9
+ label: ReactNode;
10
+ icon?: ReactNode;
11
+ badge?: ReactNode;
12
+ disabled?: boolean;
13
+ }
14
+
15
+ export interface TabsProps {
16
+ items: TabItem[];
17
+ value?: string;
18
+ onValueChange?: (value: string) => void;
19
+ orientation?: TabsOrientation;
20
+ /** Tab style — passed to `TabButtonBase`. Defaults: horizontal→buttonBrand, vertical→line. */
21
+ variant?: TabButtonType;
22
+ size?: TabButtonSize;
23
+ /** Stretch tabs to fill the row (horizontal only). */
24
+ fullWidth?: boolean;
25
+ className?: string;
26
+ "aria-label"?: string;
27
+ }
28
+
29
+ /**
30
+ * Tab bar composing `TabButtonBase`. `orientation="horizontal"` lays tabs in a
31
+ * row (underline variant gets a shared bottom border); `vertical` stacks them
32
+ * (defaults to the `line` variant). Controlled via `value`/`onValueChange`.
33
+ */
34
+ export function Tabs({
35
+ items,
36
+ value,
37
+ onValueChange,
38
+ orientation = "horizontal",
39
+ variant,
40
+ size = "sm",
41
+ fullWidth = false,
42
+ className,
43
+ "aria-label": ariaLabel,
44
+ }: TabsProps) {
45
+ const vertical = orientation === "vertical";
46
+ const resolved: TabButtonType = variant ?? (vertical ? "line" : "buttonBrand");
47
+ const underlineRow = resolved === "underline" && !vertical;
48
+
49
+ return (
50
+ <div
51
+ role="tablist"
52
+ aria-label={ariaLabel}
53
+ aria-orientation={orientation}
54
+ className={clsx(
55
+ "flex",
56
+ vertical ? "flex-col items-start gap-xxs" : "items-center gap-xs",
57
+ underlineRow && "gap-0 border-b border-border-secondary",
58
+ className,
59
+ )}
60
+ >
61
+ {items.map((item) => (
62
+ <TabButtonBase
63
+ key={item.value}
64
+ role="tab"
65
+ variant={resolved}
66
+ size={size}
67
+ current={item.value === value}
68
+ aria-selected={item.value === value}
69
+ disabled={item.disabled}
70
+ icon={item.icon}
71
+ badge={item.badge}
72
+ onClick={() => onValueChange?.(item.value)}
73
+ className={clsx(fullWidth && !vertical && "flex-1", vertical && "w-full justify-start")}
74
+ >
75
+ {item.label}
76
+ </TabButtonBase>
77
+ ))}
78
+ </div>
79
+ );
80
+ }
@@ -0,0 +1,2 @@
1
+ export { Tabs } from "./Tabs";
2
+ export type { TabsProps, TabsOrientation, TabItem } from "./Tabs";