banhaten 0.1.3 → 0.2.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 (258) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/CONTRIBUTING.md +44 -0
  3. package/README.md +65 -13
  4. package/SECURITY.md +15 -0
  5. package/banhaten.config.example.json +0 -2
  6. package/docs/design-system/README.md +9 -0
  7. package/docs/design-system/adoption-quality-remediation.md +87 -0
  8. package/docs/design-system/agent-usage.md +13 -0
  9. package/docs/design-system/appearance-presets.md +6 -1
  10. package/docs/design-system/component-docs-pattern.md +81 -0
  11. package/docs/design-system/component-token-consistency-audit.md +13 -3
  12. package/docs/design-system/components/README.md +3 -2
  13. package/docs/design-system/components/accordion.md +16 -0
  14. package/docs/design-system/components/activity-feed.md +15 -1
  15. package/docs/design-system/components/alert-dialog.md +17 -0
  16. package/docs/design-system/components/alert.md +46 -14
  17. package/docs/design-system/components/aspect-ratio.md +15 -0
  18. package/docs/design-system/components/attribute.md +16 -0
  19. package/docs/design-system/components/autocomplete.md +19 -0
  20. package/docs/design-system/components/avatar.md +18 -0
  21. package/docs/design-system/components/badge.md +19 -0
  22. package/docs/design-system/components/banner.md +15 -1
  23. package/docs/design-system/components/breadcrumbs.md +14 -0
  24. package/docs/design-system/components/button-group.md +34 -0
  25. package/docs/design-system/components/button.md +18 -0
  26. package/docs/design-system/components/card.md +18 -1
  27. package/docs/design-system/components/carousel.md +20 -3
  28. package/docs/design-system/components/catalog-components.md +15 -1
  29. package/docs/design-system/components/chart.md +15 -0
  30. package/docs/design-system/components/checkbox.md +16 -0
  31. package/docs/design-system/components/collapsible.md +15 -0
  32. package/docs/design-system/components/command.md +15 -0
  33. package/docs/design-system/components/context-menu.md +15 -0
  34. package/docs/design-system/components/date-picker.md +21 -1
  35. package/docs/design-system/components/divider.md +16 -0
  36. package/docs/design-system/components/empty-state.md +17 -0
  37. package/docs/design-system/components/field.md +17 -0
  38. package/docs/design-system/components/file-upload.md +14 -0
  39. package/docs/design-system/components/hover-card.md +15 -0
  40. package/docs/design-system/components/input-group.md +17 -0
  41. package/docs/design-system/components/input-otp.md +18 -0
  42. package/docs/design-system/components/input.md +43 -7
  43. package/docs/design-system/components/item.md +72 -0
  44. package/docs/design-system/components/kbd.md +18 -0
  45. package/docs/design-system/components/label.md +16 -0
  46. package/docs/design-system/components/menu.md +17 -0
  47. package/docs/design-system/components/menubar.md +15 -0
  48. package/docs/design-system/components/modal.md +25 -4
  49. package/docs/design-system/components/native-select.md +18 -0
  50. package/docs/design-system/components/navigation-menu.md +15 -0
  51. package/docs/design-system/components/onboarding-step-list-item.md +15 -1
  52. package/docs/design-system/components/page-header.md +15 -1
  53. package/docs/design-system/components/pagination.md +30 -8
  54. package/docs/design-system/components/popover.md +19 -0
  55. package/docs/design-system/components/progress-slider.md +18 -0
  56. package/docs/design-system/components/progress.md +17 -0
  57. package/docs/design-system/components/radio-card.md +16 -0
  58. package/docs/design-system/components/radio-group.md +17 -0
  59. package/docs/design-system/components/resizable.md +15 -0
  60. package/docs/design-system/components/scroll-area.md +15 -0
  61. package/docs/design-system/components/segmented-control.md +71 -0
  62. package/docs/design-system/components/select.md +44 -7
  63. package/docs/design-system/components/sheet.md +17 -0
  64. package/docs/design-system/components/sidebar.md +15 -0
  65. package/docs/design-system/components/skeleton.md +18 -0
  66. package/docs/design-system/components/slideout.md +14 -0
  67. package/docs/design-system/components/slider.md +20 -0
  68. package/docs/design-system/components/social-button.md +21 -3
  69. package/docs/design-system/components/spinner.md +16 -0
  70. package/docs/design-system/components/steps.md +14 -0
  71. package/docs/design-system/components/table.md +15 -1
  72. package/docs/design-system/components/tabs.md +17 -0
  73. package/docs/design-system/components/tag.md +17 -0
  74. package/docs/design-system/components/textarea.md +16 -0
  75. package/docs/design-system/components/timeline.md +14 -0
  76. package/docs/design-system/components/toast.md +17 -0
  77. package/docs/design-system/components/toggle.md +17 -0
  78. package/docs/design-system/components/toolbar.md +21 -1
  79. package/docs/design-system/components/tooltip.md +18 -1
  80. package/docs/design-system/density-and-elevation.md +44 -0
  81. package/docs/design-system/direction-and-localization.md +23 -0
  82. package/docs/design-system/form-recipes.md +73 -0
  83. package/docs/design-system/gap-promotion-policy.md +21 -0
  84. package/docs/design-system/gap-promotion-report.md +166 -0
  85. package/docs/design-system/installation.md +68 -0
  86. package/docs/design-system/launch-comparison-shadcn.md +98 -0
  87. package/docs/design-system/registry-and-cli.md +30 -7
  88. package/docs/design-system/release-policy.md +30 -0
  89. package/docs/design-system/roadmap.md +14 -0
  90. package/docs/design-system/support-matrix.md +23 -0
  91. package/docs/design-system/tabs.md +1 -1
  92. package/docs/design-system/token-governance.md +23 -1
  93. package/package.json +29 -15
  94. package/registry/component-contract.json +40 -0
  95. package/registry/components/alert-dialog.tsx +1 -1
  96. package/registry/components/alert.tsx +86 -65
  97. package/registry/components/autocomplete.tsx +23 -9
  98. package/registry/components/avatar.tsx +7 -7
  99. package/registry/components/badge.tsx +1 -1
  100. package/registry/components/button-group.tsx +321 -4
  101. package/registry/components/button.tsx +38 -17
  102. package/registry/components/card.tsx +68 -59
  103. package/registry/components/carousel.tsx +53 -5
  104. package/registry/components/chart.tsx +36 -3
  105. package/registry/components/checkbox.tsx +3 -3
  106. package/registry/components/collapsible.tsx +1 -1
  107. package/registry/components/command.tsx +1 -1
  108. package/registry/components/context-menu.tsx +1 -1
  109. package/registry/components/date-picker.tsx +245 -104
  110. package/registry/components/expanded/ActivityFeed.tsx +6 -15
  111. package/registry/components/expanded/Banner.tsx +3 -3
  112. package/registry/components/expanded/Breadcrumbs.tsx +5 -5
  113. package/registry/components/expanded/CatalogComponentsShowcase.tsx +13 -13
  114. package/registry/components/expanded/CatalogDivider.tsx +1 -1
  115. package/registry/components/expanded/EmptyState.tsx +1 -1
  116. package/registry/components/expanded/FileUpload.tsx +9 -2
  117. package/registry/components/expanded/OnboardingStepListItem.tsx +2 -4
  118. package/registry/components/expanded/PageHeader.tsx +13 -13
  119. package/registry/components/expanded/Slideout.tsx +15 -415
  120. package/registry/components/expanded/Steps.tsx +4 -4
  121. package/registry/components/expanded/Table.tsx +116 -69
  122. package/registry/components/expanded/Timeline.tsx +3 -3
  123. package/registry/components/expanded/activityFeed.css +1 -1
  124. package/registry/components/expanded/breadcrumbs.css +1 -1
  125. package/registry/components/expanded/divider.css +1 -1
  126. package/registry/components/expanded/emptyState.css +1 -1
  127. package/registry/components/expanded/fileUpload.css +6 -6
  128. package/registry/components/expanded/slideout.css +9 -685
  129. package/registry/components/expanded/steps.css +3 -3
  130. package/registry/components/expanded/table.css +2 -2
  131. package/registry/components/expanded/timeline.css +2 -2
  132. package/registry/components/input-content.ts +1 -0
  133. package/registry/components/input-otp.tsx +13 -3
  134. package/registry/components/input.tsx +68 -43
  135. package/registry/components/item.tsx +189 -0
  136. package/registry/components/kbd.tsx +111 -4
  137. package/registry/components/menu.tsx +31 -245
  138. package/registry/components/menubar.tsx +1 -1
  139. package/registry/components/modal.tsx +142 -102
  140. package/registry/components/native-select.tsx +2 -2
  141. package/registry/components/pagination.tsx +80 -58
  142. package/registry/components/popover.tsx +162 -664
  143. package/registry/components/radio-card.tsx +116 -87
  144. package/registry/components/segmented-control.tsx +87 -0
  145. package/registry/components/select-content.tsx +2 -2
  146. package/registry/components/select.tsx +52 -16
  147. package/registry/components/sheet.tsx +1 -1
  148. package/registry/components/sidebar.tsx +1 -1
  149. package/registry/components/skeleton.css +0 -3
  150. package/registry/components/social-button.tsx +47 -25
  151. package/registry/components/spinner.tsx +18 -55
  152. package/registry/components/tabs.css +1 -1
  153. package/registry/components/tabs.tsx +8 -4
  154. package/registry/components/tag.tsx +2 -2
  155. package/registry/components/textarea.tsx +3 -3
  156. package/registry/components/toast.tsx +16 -11
  157. package/registry/components/toggle.tsx +2 -2
  158. package/registry/components/toolbar.tsx +89 -17
  159. package/registry/components/tooltip.tsx +1 -1
  160. package/registry/examples/alert-demo.tsx +25 -5
  161. package/registry/examples/attribute-demo.tsx +1 -1
  162. package/registry/examples/autocomplete-demo.tsx +3 -3
  163. package/registry/examples/avatar-demo.tsx +7 -7
  164. package/registry/examples/badge-demo.tsx +1 -1
  165. package/registry/examples/button-demo.tsx +6 -6
  166. package/registry/examples/button-group-demo.tsx +23 -2
  167. package/registry/examples/card-demo.tsx +46 -8
  168. package/registry/examples/carousel-demo.tsx +20 -2
  169. package/registry/examples/chart-demo.tsx +1 -1
  170. package/registry/examples/checkbox-demo.tsx +5 -5
  171. package/registry/examples/collection-filter-bar-demo.tsx +135 -0
  172. package/registry/examples/command-demo.tsx +3 -3
  173. package/registry/examples/{expanded/command-bar-demo.tsx → command-palette-demo.tsx} +5 -15
  174. package/registry/examples/context-menu-demo.tsx +1 -1
  175. package/registry/examples/control-density-contract-demo.tsx +61 -0
  176. package/registry/examples/date-picker-demo.tsx +12 -12
  177. package/registry/examples/divider-demo.tsx +3 -3
  178. package/registry/examples/expanded/banner-demo.tsx +1 -1
  179. package/registry/examples/expanded/breadcrumbs-demo.tsx +1 -1
  180. package/registry/examples/expanded/empty-state-demo.tsx +1 -1
  181. package/registry/examples/expanded/file-upload-demo.tsx +1 -1
  182. package/registry/examples/expanded/onboarding-step-demo.tsx +1 -1
  183. package/registry/examples/expanded/slideout-demo.tsx +2 -2
  184. package/registry/examples/expanded/steps-demo.tsx +1 -1
  185. package/registry/examples/expanded/tabs-demo.tsx +1 -1
  186. package/registry/examples/expanded/timeline-demo.tsx +1 -1
  187. package/registry/examples/hover-card-demo.tsx +2 -2
  188. package/registry/examples/input-demo.tsx +6 -6
  189. package/registry/examples/input-otp-demo.tsx +4 -4
  190. package/registry/examples/item-demo.tsx +46 -0
  191. package/registry/examples/kbd-demo.tsx +1 -1
  192. package/registry/examples/label-demo.tsx +1 -1
  193. package/registry/examples/menu-demo.tsx +1 -1
  194. package/registry/examples/modal-demo.tsx +67 -9
  195. package/registry/examples/navigation-menu-demo.tsx +1 -1
  196. package/registry/examples/pagination-demo.tsx +6 -3
  197. package/registry/examples/popover-demo.tsx +19 -19
  198. package/registry/examples/progress-demo.tsx +1 -1
  199. package/registry/examples/progress-slider-demo.tsx +1 -1
  200. package/registry/examples/radio-card-demo.tsx +4 -4
  201. package/registry/examples/radio-group-demo.tsx +2 -2
  202. package/registry/examples/resizable-demo.tsx +1 -1
  203. package/registry/examples/results-toolbar-demo.tsx +44 -0
  204. package/registry/examples/scroll-area-demo.tsx +3 -3
  205. package/registry/examples/segmented-control-demo.tsx +39 -0
  206. package/registry/examples/select-demo.tsx +1 -1
  207. package/registry/examples/sidebar-demo.tsx +1 -1
  208. package/registry/examples/slider-demo.tsx +3 -3
  209. package/registry/examples/social-button-demo.tsx +18 -8
  210. package/registry/examples/spinner-demo.tsx +13 -13
  211. package/registry/examples/tabs-demo.tsx +1 -1
  212. package/registry/examples/tag-demo.tsx +1 -1
  213. package/registry/examples/textarea-demo.tsx +4 -4
  214. package/registry/examples/toast-demo.tsx +1 -1
  215. package/registry/examples/toggle-demo.tsx +6 -6
  216. package/registry/examples/tooltip-demo.tsx +4 -4
  217. package/registry/guidance/USAGE.md +27 -0
  218. package/registry/hooks/use-direction.ts +193 -13
  219. package/registry/index.json +5311 -377
  220. package/registry/styles/globals.css +2440 -4061
  221. package/registry.json +119 -149
  222. package/schema/config.schema.json +11 -8
  223. package/schema/registry.schema.json +150 -45
  224. package/schema/tokens.schema.json +134 -34
  225. package/src/cli/command-line.js +194 -0
  226. package/src/cli/config-editors.js +9 -0
  227. package/src/cli/doctor.js +399 -0
  228. package/src/cli/file-transaction.js +295 -0
  229. package/src/cli/global-css.js +153 -0
  230. package/src/cli/index.js +567 -1613
  231. package/src/cli/install-plan.js +592 -0
  232. package/src/cli/install-receipt.js +171 -0
  233. package/src/cli/jsonc.js +203 -0
  234. package/src/cli/package-install-state.js +254 -0
  235. package/src/cli/package-manager.js +238 -0
  236. package/src/cli/package-plan.js +185 -0
  237. package/src/cli/package-version.js +97 -0
  238. package/src/cli/registry-query.js +207 -0
  239. package/src/cli/reporting.js +55 -0
  240. package/src/cli/schema-validation.js +19 -0
  241. package/src/cli/source-scanner.js +686 -0
  242. package/src/cli/vite-config.js +478 -0
  243. package/tokens/banhaten.tokens.json +4312 -309
  244. package/docs/design-system/components/command-bar.md +0 -57
  245. package/registry/components/expanded/BannerBoard.tsx +0 -225
  246. package/registry/components/expanded/CatalogTag.tsx +0 -85
  247. package/registry/components/expanded/CommandBar.tsx +0 -386
  248. package/registry/components/expanded/IconExplorer.tsx +0 -612
  249. package/registry/components/expanded/TimelineShowcase.tsx +0 -158
  250. package/registry/components/expanded/commandBar.css +0 -470
  251. package/registry/components/expanded/iconExplorer.css +0 -764
  252. package/registry/components/expanded/iconPacks.ts +0 -866
  253. package/registry/components/expanded/tag.css +0 -148
  254. package/registry/examples/expanded/icons-demo.tsx +0 -5
  255. package/tokens/Color mode.zip +0 -0
  256. package/tokens/Numbers.zip +0 -0
  257. package/tokens/Radius.zip +0 -0
  258. package/tokens/Theme.zip +0 -0
@@ -1,16 +1,21 @@
1
- import { useEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode } from "react";
1
+ import { useMemo, useState, type CSSProperties, type ReactNode } from "react";
2
2
  import {
3
3
  ArrowUpDownIcon,
4
- CheckIcon as LucideCheckIcon,
5
4
  EditIcon as LucideEditIcon,
6
5
  EllipsisIcon,
7
6
  EyeIcon,
8
7
  FileIcon as LucideFileIcon,
9
- MinusIcon,
10
8
  Trash2Icon,
11
9
  } from "lucide-react";
12
10
  import { Pagination, type PaginationPage, type PaginationProps } from "@/components/ui/pagination";
13
11
  import { Spinner } from "@/components/ui/spinner";
12
+ import { Avatar as AvatarPrimitive, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
13
+ import { Badge } from "@/components/ui/badge";
14
+ import { Button } from "@/components/ui/button";
15
+ import { Checkbox } from "@/components/ui/checkbox";
16
+ import { Progress as ProgressPrimitive } from "@/components/ui/progress";
17
+ import { Tag } from "@/components/ui/tag";
18
+ import { Toggle } from "@/components/ui/toggle";
14
19
  import {
15
20
  Toolbar,
16
21
  ToolbarBadge,
@@ -65,21 +70,22 @@ export type AvatarItem = {
65
70
  };
66
71
 
67
72
  export type TableAction = {
73
+ disabled?: boolean;
68
74
  icon: "view" | "edit" | "delete" | "more";
69
75
  label: string;
70
76
  onAction?: () => void;
71
77
  };
72
78
 
73
79
  export type TableItem =
74
- | { type: "checkbox"; checked: boolean; indeterminate?: boolean }
80
+ | { type: "checkbox"; ariaLabel?: string; checked: boolean; disabled?: boolean; indeterminate?: boolean; onCheckedChange?: (checked: boolean) => void }
75
81
  | { type: "text"; tone?: "default" | "subtle"; value: string; weight?: "regular" | "medium" }
76
82
  | { type: "avatarText"; caption?: string; name: string; src?: string; status?: "top" | "bottom" }
77
83
  | { type: "rating"; max?: 5; value: number }
78
84
  | { type: "progress"; label?: string; tone?: "success" | "brand"; value: number }
79
- | { type: "toggle"; checked: boolean; disabled?: boolean }
85
+ | { type: "toggle"; ariaLabel?: string; checked: boolean; disabled?: boolean; onCheckedChange?: (checked: boolean) => void }
80
86
  | { type: "badges"; items: BadgeItem[]; maxVisible?: number }
81
87
  | { type: "onlyAvatar"; alt: string; src?: string }
82
- | { type: "avatarStack"; avatars: AvatarItem[]; canAdd?: boolean; count?: number }
88
+ | { type: "avatarStack"; addLabel?: string; avatars: AvatarItem[]; canAdd?: boolean; count?: number; onAdd?: () => void }
83
89
  | { type: "tags"; items: string[]; maxVisible?: number }
84
90
  | { type: "file"; label?: string }
85
91
  | { type: "brandLogoText"; label: string; logoSrc?: string }
@@ -185,7 +191,7 @@ function cx(...classes: Array<string | false | undefined>) {
185
191
 
186
192
  export function Table<Row extends TableRowBase>({
187
193
  columns,
188
- dir = "ltr",
194
+ dir,
189
195
  onSelectedRowIdsChange,
190
196
  onSortChange,
191
197
  rows,
@@ -311,7 +317,7 @@ export function DataTable<Row extends TableRowBase>({
311
317
  columns,
312
318
  defaultSort = null,
313
319
  description,
314
- dir = "ltr",
320
+ dir,
315
321
  emptyState,
316
322
  error = false,
317
323
  filters = [],
@@ -752,7 +758,15 @@ function clampNumber(value: number, min: number, max: number) {
752
758
  function renderTableItem(item: TableItem) {
753
759
  switch (item.type) {
754
760
  case "checkbox":
755
- return <SelectionCheckbox checked={item.checked} indeterminate={item.indeterminate} label="Select row" onChange={() => undefined} />;
761
+ return (
762
+ <SelectionCheckbox
763
+ checked={item.checked}
764
+ disabled={item.disabled ?? !item.onCheckedChange}
765
+ indeterminate={item.indeterminate}
766
+ label={item.ariaLabel ?? "Select row"}
767
+ onChange={item.onCheckedChange}
768
+ />
769
+ );
756
770
  case "text":
757
771
  return <span className={`ds-table-item-text ds-table-item-text--${item.tone ?? "default"} ds-table-item-text--${item.weight ?? "regular"}`}>{item.value}</span>;
758
772
  case "avatarText":
@@ -770,13 +784,29 @@ function renderTableItem(item: TableItem) {
770
784
  case "progress":
771
785
  return <Progress value={item.value} label={item.label} tone={item.tone ?? "success"} />;
772
786
  case "toggle":
773
- return <button aria-pressed={item.checked} className="ds-table-toggle" disabled={item.disabled} type="button"><span /></button>;
787
+ return (
788
+ <Toggle
789
+ aria-label={item.ariaLabel ?? "Toggle row value"}
790
+ checked={item.checked}
791
+ disabled={item.disabled ?? !item.onCheckedChange}
792
+ onCheckedChange={item.onCheckedChange}
793
+ size="sm"
794
+ />
795
+ );
774
796
  case "badges":
775
797
  return <BadgeList items={item.items} maxVisible={item.maxVisible} />;
776
798
  case "onlyAvatar":
777
799
  return <Avatar name={item.alt} src={item.src} />;
778
800
  case "avatarStack":
779
- return <AvatarStack avatars={item.avatars} count={item.count} canAdd={item.canAdd} />;
801
+ return (
802
+ <AvatarStack
803
+ addLabel={item.addLabel}
804
+ avatars={item.avatars}
805
+ canAdd={item.canAdd}
806
+ count={item.count}
807
+ onAdd={item.onAdd}
808
+ />
809
+ );
780
810
  case "tags":
781
811
  return <TagList items={item.items} maxVisible={item.maxVisible} />;
782
812
  case "file":
@@ -793,7 +823,7 @@ function renderTableItem(item: TableItem) {
793
823
  return (
794
824
  <span className="ds-table-action-group">
795
825
  {item.actions.map((action) => (
796
- <IconButton key={action.label} icon={action.icon} label={action.label} onClick={action.onAction} />
826
+ <IconButton disabled={action.disabled} key={action.label} icon={action.icon} label={action.label} onClick={action.onAction} />
797
827
  ))}
798
828
  </span>
799
829
  );
@@ -813,31 +843,15 @@ function SelectionCheckbox({
813
843
  disabled?: boolean;
814
844
  indeterminate?: boolean;
815
845
  label: string;
816
- onChange: (checked: boolean) => void;
846
+ onChange?: (checked: boolean) => void;
817
847
  }) {
818
- const inputRef = useRef<HTMLInputElement | null>(null);
819
-
820
- useEffect(() => {
821
- if (inputRef.current) {
822
- inputRef.current.indeterminate = indeterminate;
823
- }
824
- }, [indeterminate]);
825
-
826
848
  return (
827
- <label className="ds-table-checkbox">
828
- <input
829
- aria-checked={indeterminate ? "mixed" : checked}
830
- aria-label={label}
831
- checked={checked}
832
- disabled={disabled}
833
- onChange={(event) => onChange(event.currentTarget.checked)}
834
- ref={inputRef}
835
- type="checkbox"
836
- />
837
- <span aria-hidden="true">
838
- {indeterminate ? <IndeterminateIcon /> : <CheckIcon />}
839
- </span>
840
- </label>
849
+ <Checkbox
850
+ aria-label={label}
851
+ checked={indeterminate ? "indeterminate" : checked}
852
+ disabled={disabled}
853
+ onCheckedChange={(nextChecked) => onChange?.(nextChecked === true)}
854
+ />
841
855
  );
842
856
  }
843
857
 
@@ -849,17 +863,38 @@ function Avatar({ name, src }: { name: string; src?: string }) {
849
863
  .join("")
850
864
  .toUpperCase();
851
865
 
852
- return src ? <img alt="" className="ds-table-avatar" src={src} /> : <span className="ds-table-avatar">{initials}</span>;
866
+ return (
867
+ <AvatarPrimitive className="ds-table-avatar" size="sm">
868
+ {src ? <AvatarImage alt="" src={src} /> : null}
869
+ <AvatarFallback>{initials}</AvatarFallback>
870
+ </AvatarPrimitive>
871
+ );
853
872
  }
854
873
 
855
- function AvatarStack({ avatars, canAdd, count }: { avatars: AvatarItem[]; canAdd?: boolean; count?: number }) {
874
+ function AvatarStack({
875
+ addLabel = "Add person",
876
+ avatars,
877
+ canAdd,
878
+ count,
879
+ onAdd,
880
+ }: {
881
+ addLabel?: string;
882
+ avatars: AvatarItem[];
883
+ canAdd?: boolean;
884
+ count?: number;
885
+ onAdd?: () => void;
886
+ }) {
856
887
  return (
857
888
  <span className="ds-table-avatar-stack">
858
889
  {avatars.slice(0, 3).map((avatar) => (
859
890
  <Avatar key={avatar.alt} name={avatar.alt} src={avatar.src} />
860
891
  ))}
861
892
  {count ? <span className="ds-table-avatar ds-table-avatar--count">+{count}</span> : null}
862
- {canAdd ? <button aria-label="Add person" type="button">+</button> : null}
893
+ {canAdd ? (
894
+ <button aria-label={addLabel} disabled={!onAdd} onClick={onAdd} type="button">
895
+ +
896
+ </button>
897
+ ) : null}
863
898
  </span>
864
899
  );
865
900
  }
@@ -871,12 +906,17 @@ function BadgeList({ items, maxVisible = items.length }: { items: BadgeItem[]; m
871
906
  return (
872
907
  <span className="ds-table-badges">
873
908
  {visible.map((item, index) => (
874
- <span className={`ds-table-badge ds-table-badge--${item.tone ?? "neutral"}`} key={`${item.label}-${index}`}>
875
- {item.dot && <i />}
909
+ <Badge
910
+ badgeStyle="light"
911
+ color={badgeColor(item.tone)}
912
+ key={`${item.label}-${index}`}
913
+ size="xs"
914
+ type={item.dot ? "dot" : "default"}
915
+ >
876
916
  {item.label}
877
- </span>
917
+ </Badge>
878
918
  ))}
879
- {overflow > 0 && <span className="ds-table-badge">+{overflow}</span>}
919
+ {overflow > 0 && <Badge size="xs">+{overflow}</Badge>}
880
920
  </span>
881
921
  );
882
922
  }
@@ -888,23 +928,22 @@ function TagList({ items, maxVisible = items.length }: { items: string[]; maxVis
888
928
  return (
889
929
  <span className="ds-table-tags">
890
930
  {visible.map((item, index) => (
891
- <span key={`${item}-${index}`}>{item}</span>
931
+ <Tag key={`${item}-${index}`} size="xs">{item}</Tag>
892
932
  ))}
893
- {overflow > 0 && <span>+{overflow}</span>}
933
+ {overflow > 0 && <Tag size="xs">+{overflow}</Tag>}
894
934
  </span>
895
935
  );
896
936
  }
897
937
 
898
938
  function Progress({ label, tone, value }: { label?: string; tone: "success" | "brand"; value: number }) {
899
- const safeValue = Math.max(0, Math.min(100, value));
900
-
901
939
  return (
902
- <span className={`ds-table-progress ds-table-progress--${tone}`}>
903
- <span aria-hidden="true">
904
- <i style={{ width: `${safeValue}%` }} />
905
- </span>
906
- <em>{label ?? `${safeValue}%`}</em>
907
- </span>
940
+ <ProgressPrimitive
941
+ className={`ds-table-progress ds-table-progress--${tone}`}
942
+ indicator={label}
943
+ labelPosition="inline"
944
+ size="sm"
945
+ value={value}
946
+ />
908
947
  );
909
948
  }
910
949
 
@@ -927,14 +966,30 @@ function IconLabel({ icon, label }: { icon: ReactNode; label: string }) {
927
966
  );
928
967
  }
929
968
 
930
- function IconButton({ icon, label, onClick }: { icon: TableAction["icon"]; label: string; onClick?: () => void }) {
969
+ function IconButton({
970
+ disabled,
971
+ icon,
972
+ label,
973
+ onClick,
974
+ }: {
975
+ disabled?: boolean;
976
+ icon: TableAction["icon"];
977
+ label: string;
978
+ onClick?: () => void;
979
+ }) {
931
980
  return (
932
- <button aria-label={label} className="ds-table-icon-button" onClick={onClick} type="button">
981
+ <Button aria-label={label} className="ds-table-icon-button" disabled={disabled ?? !onClick} onClick={onClick} size="icon-xs" type="button" variant="ghost">
933
982
  {renderActionIcon(icon)}
934
- </button>
983
+ </Button>
935
984
  );
936
985
  }
937
986
 
987
+ function badgeColor(tone: BadgeItem["tone"]) {
988
+ if (tone === "success") return "green" as const;
989
+ if (tone === "warning") return "amber" as const;
990
+ return tone ?? "neutral";
991
+ }
992
+
938
993
  function renderActionIcon(icon: TableAction["icon"]) {
939
994
  switch (icon) {
940
995
  case "view":
@@ -949,38 +1004,30 @@ function renderActionIcon(icon: TableAction["icon"]) {
949
1004
  }
950
1005
  }
951
1006
 
952
- function CheckIcon() {
953
- return <LucideCheckIcon strokeWidth={2.6} />;
954
- }
955
-
956
- function IndeterminateIcon() {
957
- return <MinusIcon strokeWidth={2.6} />;
958
- }
959
-
960
1007
  function SortIcon({ direction }: { direction?: TableSortDirection }) {
961
1008
  return (
962
- <ArrowUpDownIcon aria-hidden="true" data-direction={direction ?? "none"} strokeWidth={1.9} />
1009
+ <ArrowUpDownIcon aria-hidden="true" data-direction={direction ?? "none"} strokeWidth="var(--bh-icon-stroke-190)" />
963
1010
  );
964
1011
  }
965
1012
 
966
1013
  function MoreIcon() {
967
- return <EllipsisIcon aria-hidden="true" strokeWidth={2.25} />;
1014
+ return <EllipsisIcon aria-hidden="true" strokeWidth="var(--bh-icon-stroke-225)" />;
968
1015
  }
969
1016
 
970
1017
  function ViewIcon() {
971
- return <EyeIcon aria-hidden="true" strokeWidth={1.9} />;
1018
+ return <EyeIcon aria-hidden="true" strokeWidth="var(--bh-icon-stroke-190)" />;
972
1019
  }
973
1020
 
974
1021
  function EditIcon() {
975
- return <LucideEditIcon aria-hidden="true" strokeWidth={1.9} />;
1022
+ return <LucideEditIcon aria-hidden="true" strokeWidth="var(--bh-icon-stroke-190)" />;
976
1023
  }
977
1024
 
978
1025
  function DeleteIcon() {
979
- return <Trash2Icon aria-hidden="true" strokeWidth={1.9} />;
1026
+ return <Trash2Icon aria-hidden="true" strokeWidth="var(--bh-icon-stroke-190)" />;
980
1027
  }
981
1028
 
982
1029
  function FileIcon() {
983
- return <LucideFileIcon strokeWidth={1.9} />;
1030
+ return <LucideFileIcon strokeWidth="var(--bh-icon-stroke-190)" />;
984
1031
  }
985
1032
 
986
1033
  function BrandIcon() {
@@ -103,7 +103,7 @@ export function TimelineItem({
103
103
  caption,
104
104
  className,
105
105
  date,
106
- dir = "ltr",
106
+ dir,
107
107
  icon,
108
108
  label,
109
109
  orientation = "vertical",
@@ -175,7 +175,7 @@ export function TimelineItem({
175
175
  export function Timeline({
176
176
  ariaLabel,
177
177
  className,
178
- dir = "ltr",
178
+ dir,
179
179
  orientation = "vertical",
180
180
  steps = [],
181
181
  variant = "default",
@@ -212,5 +212,5 @@ export function Timeline({
212
212
  }
213
213
 
214
214
  function CheckIcon() {
215
- return <LucideCheckIcon aria-hidden="true" className="ds-timeline__check" strokeWidth={3} />;
215
+ return <LucideCheckIcon aria-hidden="true" className="ds-timeline__check" strokeWidth="var(--bh-icon-stroke-300)" />;
216
216
  }
@@ -30,7 +30,7 @@
30
30
  align-items: flex-start;
31
31
  color: var(--activity-feed-content-default);
32
32
  font-family: var(--bh-font-family);
33
- letter-spacing: 0;
33
+ letter-spacing: var(--bh-text-base-letter-spacing);
34
34
  }
35
35
 
36
36
  .ds-activity-feed *,
@@ -15,7 +15,7 @@
15
15
  font-family: var(--bh-font-family);
16
16
  font-size: var(--bh-text-body-md-font-size);
17
17
  font-weight: var(--bh-font-weight-medium);
18
- letter-spacing: 0;
18
+ letter-spacing: var(--bh-text-base-letter-spacing);
19
19
  line-height: var(--bh-text-body-md-line-height);
20
20
  }
21
21
 
@@ -18,7 +18,7 @@
18
18
  gap: var(--bh-space-md-8);
19
19
  color: var(--bh-content-default);
20
20
  font-family: var(--bh-font-family);
21
- letter-spacing: 0;
21
+ letter-spacing: var(--bh-text-base-letter-spacing);
22
22
  }
23
23
 
24
24
  .ds-content-divider *,
@@ -11,7 +11,7 @@
11
11
  padding: var(--bh-space-6xl-32);
12
12
  color: var(--bh-content-default);
13
13
  font-family: var(--bh-font-family);
14
- letter-spacing: 0;
14
+ letter-spacing: var(--bh-text-base-letter-spacing);
15
15
  text-align: center;
16
16
  }
17
17
 
@@ -7,7 +7,7 @@
7
7
  gap: var(--bh-space-xl-12);
8
8
  color: var(--bh-content-default);
9
9
  font-family: var(--bh-font-family);
10
- letter-spacing: 0;
10
+ letter-spacing: var(--bh-text-base-letter-spacing);
11
11
  }
12
12
 
13
13
  .ds-file-upload *,
@@ -90,7 +90,7 @@
90
90
  .ds-file-upload__icon svg {
91
91
  width: var(--bh-space-5xl-24);
92
92
  height: var(--bh-space-5xl-24);
93
- stroke-width: 2;
93
+ stroke-width: var(--bh-icon-stroke-200);
94
94
  }
95
95
 
96
96
  .ds-file-upload__copy {
@@ -257,7 +257,7 @@
257
257
  font-family: var(--bh-font-family);
258
258
  font-size: calc(var(--bh-space-lg-10) - var(--bh-space-xxxs-1));
259
259
  font-weight: var(--bh-font-weight-bold);
260
- letter-spacing: 0;
260
+ letter-spacing: var(--bh-text-base-letter-spacing);
261
261
  line-height: 1;
262
262
  pointer-events: none;
263
263
  text-rendering: geometricPrecision;
@@ -352,7 +352,7 @@
352
352
  .ds-file-upload-row__status svg {
353
353
  width: var(--bh-space-3xl-16);
354
354
  height: var(--bh-space-3xl-16);
355
- stroke-width: 2.2;
355
+ stroke-width: var(--bh-icon-stroke-220);
356
356
  }
357
357
 
358
358
  .ds-file-upload-row__status--standalone {
@@ -372,7 +372,7 @@
372
372
  }
373
373
 
374
374
  .ds-file-upload-row__status--uploading svg {
375
- animation: ds-file-upload-spin 1s linear infinite;
375
+ animation: ds-file-upload-spin var(--bh-file-upload-spin-duration) linear infinite;
376
376
  }
377
377
 
378
378
  .ds-file-upload-row--error .ds-file-upload-row__state,
@@ -391,7 +391,7 @@
391
391
  font-weight: var(--bh-font-weight-medium);
392
392
  line-height: var(--bh-text-body-md-medium-line-height);
393
393
  text-decoration-line: underline;
394
- text-underline-offset: 0.125em;
394
+ text-underline-offset: var(--bh-underline-offset-default);
395
395
  cursor: pointer;
396
396
  }
397
397