banhaten 0.1.3 → 0.3.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 (275) hide show
  1. package/CHANGELOG.md +73 -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-implementation-ownership-audit.md +244 -0
  12. package/docs/design-system/component-quality-audit-2026-08-20.md +223 -0
  13. package/docs/design-system/component-showcase-consistency-report.md +2 -0
  14. package/docs/design-system/component-token-consistency-audit.md +13 -3
  15. package/docs/design-system/components/README.md +4 -2
  16. package/docs/design-system/components/accordion.md +16 -0
  17. package/docs/design-system/components/activity-feed.md +17 -1
  18. package/docs/design-system/components/activity-heatmap.md +73 -0
  19. package/docs/design-system/components/alert-dialog.md +17 -0
  20. package/docs/design-system/components/alert.md +46 -14
  21. package/docs/design-system/components/aspect-ratio.md +15 -0
  22. package/docs/design-system/components/attribute.md +16 -0
  23. package/docs/design-system/components/autocomplete.md +19 -0
  24. package/docs/design-system/components/avatar.md +18 -0
  25. package/docs/design-system/components/badge.md +19 -0
  26. package/docs/design-system/components/banner.md +19 -1
  27. package/docs/design-system/components/breadcrumbs.md +17 -0
  28. package/docs/design-system/components/button-group.md +35 -0
  29. package/docs/design-system/components/button.md +18 -0
  30. package/docs/design-system/components/card.md +26 -1
  31. package/docs/design-system/components/carousel.md +20 -3
  32. package/docs/design-system/components/catalog-components.md +18 -1
  33. package/docs/design-system/components/chart.md +15 -0
  34. package/docs/design-system/components/checkbox.md +16 -0
  35. package/docs/design-system/components/collapsible.md +15 -0
  36. package/docs/design-system/components/command.md +15 -0
  37. package/docs/design-system/components/context-menu.md +15 -0
  38. package/docs/design-system/components/date-picker.md +21 -1
  39. package/docs/design-system/components/divider.md +16 -0
  40. package/docs/design-system/components/empty-state.md +17 -0
  41. package/docs/design-system/components/field.md +17 -0
  42. package/docs/design-system/components/file-upload.md +18 -0
  43. package/docs/design-system/components/hover-card.md +15 -0
  44. package/docs/design-system/components/input-group.md +17 -0
  45. package/docs/design-system/components/input-otp.md +18 -0
  46. package/docs/design-system/components/input.md +43 -7
  47. package/docs/design-system/components/item.md +72 -0
  48. package/docs/design-system/components/kbd.md +18 -0
  49. package/docs/design-system/components/label.md +16 -0
  50. package/docs/design-system/components/menu.md +17 -0
  51. package/docs/design-system/components/menubar.md +15 -0
  52. package/docs/design-system/components/modal.md +25 -4
  53. package/docs/design-system/components/native-select.md +18 -0
  54. package/docs/design-system/components/navigation-menu.md +15 -0
  55. package/docs/design-system/components/onboarding-step-list-item.md +16 -1
  56. package/docs/design-system/components/page-header.md +17 -1
  57. package/docs/design-system/components/pagination.md +31 -8
  58. package/docs/design-system/components/popover.md +19 -0
  59. package/docs/design-system/components/progress-slider.md +18 -0
  60. package/docs/design-system/components/progress.md +17 -0
  61. package/docs/design-system/components/radio-card.md +16 -0
  62. package/docs/design-system/components/radio-group.md +17 -0
  63. package/docs/design-system/components/resizable.md +15 -0
  64. package/docs/design-system/components/scroll-area.md +20 -1
  65. package/docs/design-system/components/segmented-control.md +71 -0
  66. package/docs/design-system/components/select.md +44 -7
  67. package/docs/design-system/components/sheet.md +17 -0
  68. package/docs/design-system/components/sidebar.md +17 -0
  69. package/docs/design-system/components/skeleton.md +18 -0
  70. package/docs/design-system/components/slideout.md +17 -0
  71. package/docs/design-system/components/slider.md +20 -0
  72. package/docs/design-system/components/social-button.md +21 -3
  73. package/docs/design-system/components/spinner.md +16 -0
  74. package/docs/design-system/components/steps.md +19 -0
  75. package/docs/design-system/components/table.md +36 -4
  76. package/docs/design-system/components/tabs.md +17 -0
  77. package/docs/design-system/components/tag.md +17 -0
  78. package/docs/design-system/components/textarea.md +16 -0
  79. package/docs/design-system/components/timeline.md +17 -0
  80. package/docs/design-system/components/toast.md +17 -0
  81. package/docs/design-system/components/toggle.md +17 -0
  82. package/docs/design-system/components/toolbar.md +21 -1
  83. package/docs/design-system/components/tooltip.md +18 -1
  84. package/docs/design-system/density-and-elevation.md +61 -0
  85. package/docs/design-system/direction-and-localization.md +23 -0
  86. package/docs/design-system/form-recipes.md +73 -0
  87. package/docs/design-system/gap-promotion-policy.md +21 -0
  88. package/docs/design-system/gap-promotion-report.md +100 -0
  89. package/docs/design-system/installation.md +68 -0
  90. package/docs/design-system/launch-comparison-shadcn.md +98 -0
  91. package/docs/design-system/registry-and-cli.md +30 -7
  92. package/docs/design-system/release-policy.md +30 -0
  93. package/docs/design-system/roadmap.md +14 -0
  94. package/docs/design-system/support-matrix.md +23 -0
  95. package/docs/design-system/tabs.md +1 -1
  96. package/docs/design-system/token-governance.md +23 -1
  97. package/package.json +30 -15
  98. package/registry/component-contract.json +40 -0
  99. package/registry/components/alert-dialog.tsx +2 -2
  100. package/registry/components/alert.tsx +101 -76
  101. package/registry/components/autocomplete.tsx +23 -9
  102. package/registry/components/avatar.tsx +14 -10
  103. package/registry/components/badge.tsx +18 -18
  104. package/registry/components/button-group.tsx +324 -5
  105. package/registry/components/button.tsx +38 -17
  106. package/registry/components/card.tsx +87 -62
  107. package/registry/components/carousel.tsx +67 -5
  108. package/registry/components/chart.tsx +36 -3
  109. package/registry/components/checkbox.tsx +3 -3
  110. package/registry/components/collapsible.tsx +1 -1
  111. package/registry/components/command.tsx +38 -4
  112. package/registry/components/context-menu.tsx +1 -1
  113. package/registry/components/date-picker.tsx +312 -135
  114. package/registry/components/expanded/ActivityFeed.tsx +9 -22
  115. package/registry/components/expanded/ActivityHeatmap.tsx +64 -0
  116. package/registry/components/expanded/Banner.tsx +3 -4
  117. package/registry/components/expanded/Breadcrumbs.tsx +8 -5
  118. package/registry/components/expanded/CatalogComponentsShowcase.tsx +16 -17
  119. package/registry/components/expanded/CatalogDivider.tsx +4 -3
  120. package/registry/components/expanded/EmptyState.tsx +1 -1
  121. package/registry/components/expanded/FileUpload.tsx +16 -7
  122. package/registry/components/expanded/OnboardingStepListItem.tsx +2 -6
  123. package/registry/components/expanded/PageHeader.tsx +47 -56
  124. package/registry/components/expanded/Slideout.tsx +29 -424
  125. package/registry/components/expanded/Steps.tsx +151 -13
  126. package/registry/components/expanded/Table.tsx +161 -82
  127. package/registry/components/expanded/Timeline.tsx +14 -27
  128. package/registry/components/expanded/activityFeed.css +9 -9
  129. package/registry/components/expanded/activityHeatmap.css +66 -0
  130. package/registry/components/expanded/banner.css +21 -11
  131. package/registry/components/expanded/breadcrumbs.css +2 -2
  132. package/registry/components/expanded/divider.css +1 -1
  133. package/registry/components/expanded/emptyState.css +1 -1
  134. package/registry/components/expanded/fileUpload.css +7 -7
  135. package/registry/components/expanded/onboardingStepListItem.css +2 -2
  136. package/registry/components/expanded/pageHeader.css +14 -11
  137. package/registry/components/expanded/slideout.css +10 -690
  138. package/registry/components/expanded/steps.css +78 -15
  139. package/registry/components/expanded/table.css +60 -69
  140. package/registry/components/expanded/timeline.css +19 -18
  141. package/registry/components/field.tsx +61 -8
  142. package/registry/components/input-content.ts +1 -0
  143. package/registry/components/input-otp.tsx +13 -3
  144. package/registry/components/input.tsx +68 -43
  145. package/registry/components/item.tsx +189 -0
  146. package/registry/components/kbd.tsx +111 -4
  147. package/registry/components/menu.tsx +87 -251
  148. package/registry/components/menubar.tsx +1 -1
  149. package/registry/components/modal.tsx +143 -103
  150. package/registry/components/native-select.tsx +2 -2
  151. package/registry/components/navigation-menu.tsx +1 -1
  152. package/registry/components/pagination.css +36 -0
  153. package/registry/components/pagination.tsx +88 -64
  154. package/registry/components/popover.tsx +162 -664
  155. package/registry/components/progress-slider.tsx +1 -1
  156. package/registry/components/radio-card.tsx +116 -87
  157. package/registry/components/resizable.tsx +36 -2
  158. package/registry/components/scroll-area.tsx +30 -6
  159. package/registry/components/segmented-control.tsx +87 -0
  160. package/registry/components/select-content.tsx +2 -2
  161. package/registry/components/select.tsx +86 -27
  162. package/registry/components/sheet.tsx +1 -1
  163. package/registry/components/sidebar.tsx +12 -6
  164. package/registry/components/skeleton.css +0 -3
  165. package/registry/components/social-button.tsx +59 -30
  166. package/registry/components/spinner.tsx +18 -55
  167. package/registry/components/table-elements.tsx +128 -0
  168. package/registry/components/tabs.css +1 -1
  169. package/registry/components/tabs.tsx +13 -14
  170. package/registry/components/tag.tsx +3 -3
  171. package/registry/components/textarea.tsx +3 -3
  172. package/registry/components/toast.tsx +16 -11
  173. package/registry/components/toggle.tsx +4 -4
  174. package/registry/components/toolbar.tsx +94 -22
  175. package/registry/components/tooltip.tsx +2 -2
  176. package/registry/examples/alert-demo.tsx +25 -5
  177. package/registry/examples/attribute-demo.tsx +1 -1
  178. package/registry/examples/autocomplete-demo.tsx +3 -3
  179. package/registry/examples/avatar-demo.tsx +14 -11
  180. package/registry/examples/badge-demo.tsx +1 -1
  181. package/registry/examples/button-demo.tsx +6 -6
  182. package/registry/examples/button-group-demo.tsx +23 -2
  183. package/registry/examples/card-demo.tsx +46 -8
  184. package/registry/examples/carousel-demo.tsx +20 -2
  185. package/registry/examples/chart-demo.tsx +1 -1
  186. package/registry/examples/checkbox-demo.tsx +5 -5
  187. package/registry/examples/collection-filter-bar-demo.tsx +135 -0
  188. package/registry/examples/command-demo.tsx +3 -3
  189. package/registry/examples/{expanded/command-bar-demo.tsx → command-palette-demo.tsx} +5 -15
  190. package/registry/examples/context-menu-demo.tsx +1 -1
  191. package/registry/examples/control-density-contract-demo.tsx +61 -0
  192. package/registry/examples/date-picker-demo.tsx +12 -12
  193. package/registry/examples/divider-demo.tsx +3 -3
  194. package/registry/examples/expanded/activity-heatmap-demo.tsx +29 -0
  195. package/registry/examples/expanded/banner-demo.tsx +1 -1
  196. package/registry/examples/expanded/breadcrumbs-demo.tsx +4 -4
  197. package/registry/examples/expanded/empty-state-demo.tsx +1 -1
  198. package/registry/examples/expanded/file-upload-demo.tsx +1 -1
  199. package/registry/examples/expanded/onboarding-step-demo.tsx +1 -1
  200. package/registry/examples/expanded/slideout-demo.tsx +2 -2
  201. package/registry/examples/expanded/steps-demo.tsx +1 -1
  202. package/registry/examples/expanded/tabs-demo.tsx +1 -1
  203. package/registry/examples/expanded/timeline-demo.tsx +1 -1
  204. package/registry/examples/hover-card-demo.tsx +2 -2
  205. package/registry/examples/input-demo.tsx +6 -6
  206. package/registry/examples/input-otp-demo.tsx +4 -4
  207. package/registry/examples/item-demo.tsx +46 -0
  208. package/registry/examples/kbd-demo.tsx +1 -1
  209. package/registry/examples/label-demo.tsx +1 -1
  210. package/registry/examples/menu-demo.tsx +1 -1
  211. package/registry/examples/modal-demo.tsx +67 -9
  212. package/registry/examples/navigation-menu-demo.tsx +1 -1
  213. package/registry/examples/pagination-demo.tsx +10 -7
  214. package/registry/examples/popover-demo.tsx +19 -19
  215. package/registry/examples/progress-demo.tsx +1 -1
  216. package/registry/examples/progress-slider-demo.tsx +1 -1
  217. package/registry/examples/radio-card-demo.tsx +4 -4
  218. package/registry/examples/radio-group-demo.tsx +2 -2
  219. package/registry/examples/resizable-demo.tsx +1 -1
  220. package/registry/examples/results-toolbar-demo.tsx +44 -0
  221. package/registry/examples/scroll-area-demo.tsx +3 -3
  222. package/registry/examples/segmented-control-demo.tsx +39 -0
  223. package/registry/examples/select-demo.tsx +1 -1
  224. package/registry/examples/sidebar-demo.tsx +5 -3
  225. package/registry/examples/slider-demo.tsx +3 -3
  226. package/registry/examples/social-button-demo.tsx +18 -8
  227. package/registry/examples/spinner-demo.tsx +13 -13
  228. package/registry/examples/tabs-demo.tsx +1 -1
  229. package/registry/examples/tag-demo.tsx +1 -1
  230. package/registry/examples/textarea-demo.tsx +4 -4
  231. package/registry/examples/toast-demo.tsx +1 -1
  232. package/registry/examples/toggle-demo.tsx +6 -6
  233. package/registry/examples/tooltip-demo.tsx +4 -4
  234. package/registry/guidance/USAGE.md +27 -0
  235. package/registry/hooks/use-direction.ts +193 -13
  236. package/registry/index.json +5668 -375
  237. package/registry/styles/globals.css +2404 -3999
  238. package/registry.json +156 -149
  239. package/schema/config.schema.json +11 -8
  240. package/schema/registry.schema.json +150 -45
  241. package/schema/tokens.schema.json +134 -34
  242. package/src/cli/command-line.js +194 -0
  243. package/src/cli/config-editors.js +9 -0
  244. package/src/cli/doctor.js +399 -0
  245. package/src/cli/file-transaction.js +295 -0
  246. package/src/cli/global-css.js +153 -0
  247. package/src/cli/index.js +567 -1613
  248. package/src/cli/install-plan.js +592 -0
  249. package/src/cli/install-receipt.js +171 -0
  250. package/src/cli/jsonc.js +203 -0
  251. package/src/cli/package-install-state.js +254 -0
  252. package/src/cli/package-manager.js +238 -0
  253. package/src/cli/package-plan.js +185 -0
  254. package/src/cli/package-version.js +97 -0
  255. package/src/cli/registry-query.js +207 -0
  256. package/src/cli/reporting.js +55 -0
  257. package/src/cli/schema-validation.js +19 -0
  258. package/src/cli/source-scanner.js +686 -0
  259. package/src/cli/vite-config.js +478 -0
  260. package/tokens/banhaten.tokens.json +4444 -331
  261. package/docs/design-system/components/command-bar.md +0 -57
  262. package/registry/components/expanded/BannerBoard.tsx +0 -225
  263. package/registry/components/expanded/CatalogTag.tsx +0 -85
  264. package/registry/components/expanded/CommandBar.tsx +0 -386
  265. package/registry/components/expanded/IconExplorer.tsx +0 -612
  266. package/registry/components/expanded/TimelineShowcase.tsx +0 -158
  267. package/registry/components/expanded/commandBar.css +0 -470
  268. package/registry/components/expanded/iconExplorer.css +0 -764
  269. package/registry/components/expanded/iconPacks.ts +0 -866
  270. package/registry/components/expanded/tag.css +0 -148
  271. package/registry/examples/expanded/icons-demo.tsx +0 -5
  272. package/tokens/Color mode.zip +0 -0
  273. package/tokens/Numbers.zip +0 -0
  274. package/tokens/Radius.zip +0 -0
  275. package/tokens/Theme.zip +0 -0
@@ -40,7 +40,7 @@ function SpinnerBase({ className, motion, ...props }: SpinnerBaseProps) {
40
40
  r="10"
41
41
  fill="none"
42
42
  stroke="currentColor"
43
- strokeWidth="4"
43
+ strokeWidth="var(--bh-spinner-stroke-width)"
44
44
  opacity="var(--bh-opacity-25)"
45
45
  />
46
46
  <circle
@@ -50,64 +50,27 @@ function SpinnerBase({ className, motion, ...props }: SpinnerBaseProps) {
50
50
  r="10"
51
51
  fill="none"
52
52
  stroke="currentColor"
53
- strokeWidth="4"
53
+ strokeWidth="var(--bh-spinner-stroke-width)"
54
54
  strokeLinecap="round"
55
55
  pathLength="100"
56
56
  strokeDasharray="30 70"
57
- >
58
- {motion === "dynamic" ? (
59
- <DynamicSpinnerMotion />
60
- ) : (
61
- <SteadySpinnerMotion />
62
- )}
63
- </circle>
64
- </svg>
65
- )
66
- }
67
-
68
- function DynamicSpinnerMotion() {
69
- return (
70
- <>
71
- <animate
72
- attributeName="stroke-dasharray"
73
- calcMode="spline"
74
- dur="6s"
75
- keySplines="0.45 0 0.55 1; 0.45 0 0.55 1; 0.45 0 0.55 1; 0.45 0 0.55 1"
76
- keyTimes="0; 0.25; 0.5; 0.75; 1"
77
- repeatCount="indefinite"
78
- values="22 78; 38 62; 30 70; 42 58; 22 78"
79
- />
80
- <animate
81
- attributeName="stroke-dashoffset"
82
- calcMode="spline"
83
- dur="6s"
84
- keySplines="0.45 0 0.55 1; 0.45 0 0.55 1; 0.45 0 0.55 1; 0.45 0 0.55 1"
85
- keyTimes="0; 0.25; 0.5; 0.75; 1"
86
- repeatCount="indefinite"
87
- values="0; -16; -44; -72; -100"
57
+ style={{
58
+ animationDuration:
59
+ motion === "dynamic"
60
+ ? "var(--bh-spinner-duration-dynamic)"
61
+ : "var(--bh-spinner-duration-steady)",
62
+ animationIterationCount: "infinite",
63
+ animationName:
64
+ motion === "dynamic"
65
+ ? "bh-spinner-dynamic"
66
+ : "bh-spinner-steady",
67
+ animationTimingFunction:
68
+ motion === "dynamic" ? "var(--bh-spinner-easing)" : "linear",
69
+ transformBox: "fill-box",
70
+ transformOrigin: "center",
71
+ }}
88
72
  />
89
- <animateTransform
90
- attributeName="transform"
91
- dur="6s"
92
- from="0 12 12"
93
- repeatCount="indefinite"
94
- to="1080 12 12"
95
- type="rotate"
96
- />
97
- </>
98
- )
99
- }
100
-
101
- function SteadySpinnerMotion() {
102
- return (
103
- <animateTransform
104
- attributeName="transform"
105
- dur="1.5s"
106
- from="0 12 12"
107
- repeatCount="indefinite"
108
- to="360 12 12"
109
- type="rotate"
110
- />
73
+ </svg>
111
74
  )
112
75
  }
113
76
 
@@ -0,0 +1,128 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ type TableRootProps = React.ComponentPropsWithoutRef<"table">
8
+ type TableSectionProps = React.ComponentPropsWithoutRef<"thead">
9
+ type TableBodyProps = React.ComponentPropsWithoutRef<"tbody">
10
+ type TableRowElementProps = React.ComponentPropsWithoutRef<"tr">
11
+ type TableHeadProps = React.ComponentPropsWithoutRef<"th">
12
+ type TableCellProps = React.ComponentPropsWithoutRef<"td">
13
+ type DataTableSurfaceProps = React.ComponentPropsWithoutRef<"div">
14
+
15
+ const DataTableSurface = React.forwardRef<
16
+ HTMLDivElement,
17
+ DataTableSurfaceProps
18
+ >(function DataTableSurface({ className, role = "table", ...props }, ref) {
19
+ return (
20
+ <div
21
+ data-slot="data-table-surface"
22
+ ref={ref}
23
+ role={role}
24
+ className={cn("min-w-0", className)}
25
+ {...props}
26
+ />
27
+ )
28
+ })
29
+
30
+ const TableRoot = React.forwardRef<HTMLTableElement, TableRootProps>(
31
+ function TableRoot({ className, ...props }, ref) {
32
+ return (
33
+ <table
34
+ data-slot="table-root"
35
+ ref={ref}
36
+ className={cn("w-full border-collapse text-start", className)}
37
+ {...props}
38
+ />
39
+ )
40
+ }
41
+ )
42
+
43
+ const TableHeader = React.forwardRef<
44
+ HTMLTableSectionElement,
45
+ TableSectionProps
46
+ >(function TableHeader({ className, ...props }, ref) {
47
+ return (
48
+ <thead
49
+ data-slot="table-header"
50
+ ref={ref}
51
+ className={cn("text-start", className)}
52
+ {...props}
53
+ />
54
+ )
55
+ })
56
+
57
+ const TableBody = React.forwardRef<HTMLTableSectionElement, TableBodyProps>(
58
+ function TableBody({ className, ...props }, ref) {
59
+ return (
60
+ <tbody
61
+ data-slot="table-body"
62
+ ref={ref}
63
+ className={className}
64
+ {...props}
65
+ />
66
+ )
67
+ }
68
+ )
69
+
70
+ const TableRowElement = React.forwardRef<
71
+ HTMLTableRowElement,
72
+ TableRowElementProps
73
+ >(function TableRowElement({ className, ...props }, ref) {
74
+ return (
75
+ <tr
76
+ data-slot="table-row"
77
+ ref={ref}
78
+ className={className}
79
+ {...props}
80
+ />
81
+ )
82
+ })
83
+
84
+ const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(
85
+ function TableHead({ className, scope = "col", ...props }, ref) {
86
+ return (
87
+ <th
88
+ data-slot="table-head"
89
+ ref={ref}
90
+ className={cn("text-start", className)}
91
+ scope={scope}
92
+ {...props}
93
+ />
94
+ )
95
+ }
96
+ )
97
+
98
+ const TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps>(
99
+ function TableCell({ className, ...props }, ref) {
100
+ return (
101
+ <td
102
+ data-slot="table-cell"
103
+ ref={ref}
104
+ className={className}
105
+ {...props}
106
+ />
107
+ )
108
+ }
109
+ )
110
+
111
+ export {
112
+ DataTableSurface,
113
+ TableBody,
114
+ TableCell,
115
+ TableHead,
116
+ TableHeader,
117
+ TableRoot,
118
+ TableRowElement,
119
+ }
120
+ export type {
121
+ DataTableSurfaceProps,
122
+ TableBodyProps,
123
+ TableCellProps,
124
+ TableHeadProps,
125
+ TableRootProps,
126
+ TableRowElementProps,
127
+ TableSectionProps,
128
+ }
@@ -93,7 +93,7 @@
93
93
  .ds-tabs__tab:disabled,
94
94
  .ds-tabs__tab[data-disabled] {
95
95
  cursor: not-allowed;
96
- opacity: var(--bh-opacity-disabled);
96
+ opacity: var(--bh-opacity-60);
97
97
  }
98
98
 
99
99
  .ds-tabs__tab:focus-visible {
@@ -4,6 +4,7 @@ import * as React from "react"
4
4
  import * as TabsPrimitive from "@radix-ui/react-tabs"
5
5
 
6
6
  import { cn } from "@/lib/utils"
7
+ import { useResolvedDirection } from "@/hooks/use-direction"
7
8
 
8
9
  import "./tabs.css"
9
10
 
@@ -84,7 +85,7 @@ const TabsList = React.forwardRef<
84
85
  `ds-tabs--${variant}`,
85
86
  `ds-tabs--${size}`,
86
87
  fullWidth ? "ds-tabs--full" : "ds-tabs--hug",
87
- isRtl ? "ds-tabs--rtl" : "ds-tabs--ltr",
88
+ isRtl ? "ds-tabs--rtl" : dir === "ltr" ? "ds-tabs--ltr" : undefined,
88
89
  className
89
90
  )}
90
91
  {...props}
@@ -133,7 +134,7 @@ function Tabs({
133
134
  className = "",
134
135
  defaultActiveIndex = 0,
135
136
  defaultValue,
136
- dir = "ltr",
137
+ dir,
137
138
  fullWidth = false,
138
139
  items = [],
139
140
  onActiveIndexChange,
@@ -144,6 +145,8 @@ function Tabs({
144
145
  variant = "underline",
145
146
  ...props
146
147
  }: TabsProps) {
148
+ const rootRef = React.useRef<React.ElementRef<typeof TabsPrimitive.Root>>(null)
149
+ const resolvedDirection = useResolvedDirection(dir, rootRef)
147
150
  const normalizedItems = items.map(normalizeTabsItem)
148
151
  const activeValue =
149
152
  value ?? (activeIndex === undefined ? undefined : normalizedItems[activeIndex]?.value)
@@ -151,7 +154,6 @@ function Tabs({
151
154
  defaultValue ??
152
155
  normalizedItems[defaultActiveIndex]?.value ??
153
156
  normalizedItems[0]?.value
154
- const hasPanels = normalizedItems.some((item) => item.content !== undefined)
155
157
 
156
158
  function handleValueChange(nextValue: string) {
157
159
  onValueChange?.(nextValue)
@@ -166,7 +168,8 @@ function Tabs({
166
168
  <TabsRoot
167
169
  data-slot="tabs-root"
168
170
  defaultValue={activeValue === undefined ? uncontrolledDefaultValue : undefined}
169
- dir={dir}
171
+ dir={resolvedDirection}
172
+ ref={rootRef}
170
173
  value={activeValue}
171
174
  onValueChange={handleValueChange}
172
175
  className={rootClassName}
@@ -175,7 +178,7 @@ function Tabs({
175
178
  <TabsList
176
179
  aria-label={ariaLabel}
177
180
  className={className}
178
- dir={dir}
181
+ dir={resolvedDirection}
179
182
  fullWidth={fullWidth}
180
183
  size={size}
181
184
  variant={variant}
@@ -190,15 +193,11 @@ function Tabs({
190
193
  </TabsTrigger>
191
194
  ))}
192
195
  </TabsList>
193
- {hasPanels
194
- ? normalizedItems.map((item) =>
195
- item.content === undefined ? null : (
196
- <TabsContent key={`${item.value}-panel`} value={item.value}>
197
- {item.content}
198
- </TabsContent>
199
- )
200
- )
201
- : null}
196
+ {normalizedItems.map((item) => (
197
+ <TabsContent key={`${item.value}-panel`} value={item.value}>
198
+ {item.content ?? null}
199
+ </TabsContent>
200
+ ))}
202
201
  {children}
203
202
  </TabsRoot>
204
203
  )
@@ -348,7 +348,7 @@ function TagAvatar({
348
348
  <span
349
349
  data-slot="tag-avatar"
350
350
  className={cn(
351
- "flex size-[var(--bh-space-4xl-20)] shrink-0 items-center justify-center overflow-hidden rounded-[var(--bh-radius-full)] border border-[var(--bh-border-subtle)] bg-[var(--bh-bg-neutral-default)] text-[length:var(--bh-text-body-3xs-semibold-font-size)] font-[var(--bh-text-body-3xs-semibold-font-weight)] leading-[var(--bh-text-body-3xs-semibold-line-height)] text-[var(--bh-content-on-color)]",
351
+ "flex size-[var(--bh-space-4xl-20)] shrink-0 items-center justify-center overflow-hidden rounded-[var(--bh-radius-full)] border border-[var(--bh-border-subtle)] bg-[var(--bh-bg-neutral-bold)] text-[length:var(--bh-text-body-3xs-semibold-font-size)] font-[var(--bh-text-body-3xs-semibold-font-weight)] leading-[var(--bh-text-body-3xs-semibold-line-height)] text-[var(--bh-content-on-neutral)]",
352
352
  className
353
353
  )}
354
354
  {...props}
@@ -372,7 +372,7 @@ function TagIcon({
372
372
  )}
373
373
  {...props}
374
374
  >
375
- {children ?? <PlusIcon aria-hidden="true" strokeWidth={2.25} />}
375
+ {children ?? <PlusIcon aria-hidden="true" strokeWidth="var(--bh-icon-stroke-225)" />}
376
376
  </span>
377
377
  )
378
378
  }
@@ -405,7 +405,7 @@ function TagCloseButton({
405
405
  <XIcon
406
406
  aria-hidden="true"
407
407
  className="size-[var(--bh-space-xl-12)]"
408
- strokeWidth={2}
408
+ strokeWidth="var(--bh-icon-stroke-200)"
409
409
  />
410
410
  </button>
411
411
  )
@@ -539,14 +539,14 @@ function TextareaIcon({
539
539
  aria-hidden="true"
540
540
  className="size-[var(--bh-textarea-helper-icon-size)]"
541
541
  focusable="false"
542
- strokeWidth={2.25}
542
+ strokeWidth="var(--bh-icon-stroke-225)"
543
543
  />
544
544
  ) : (
545
545
  <InfoIcon
546
546
  aria-hidden="true"
547
547
  className="size-[var(--bh-textarea-helper-icon-size)]"
548
548
  focusable="false"
549
- strokeWidth={2.25}
549
+ strokeWidth="var(--bh-icon-stroke-225)"
550
550
  />
551
551
  )}
552
552
  </span>
@@ -563,7 +563,7 @@ function CloseIcon() {
563
563
  aria-hidden="true"
564
564
  className="size-[var(--bh-textarea-close-icon-size)]"
565
565
  focusable="false"
566
- strokeWidth={2.5}
566
+ strokeWidth="var(--bh-icon-stroke-250)"
567
567
  />
568
568
  </span>
569
569
  )
@@ -9,6 +9,7 @@ import {
9
9
  } from "sonner"
10
10
 
11
11
  import { cn } from "@/lib/utils"
12
+ import { useResolvedDirection } from "@/hooks/use-direction"
12
13
 
13
14
  type ToastIntent = "default" | "success" | "danger" | "warning" | "info"
14
15
  type ToastSide = "start" | "end"
@@ -54,7 +55,9 @@ function Toaster({
54
55
  toastOptions,
55
56
  ...props
56
57
  }: ToasterProps) {
57
- const resolvedPosition = position ?? getToastPosition(dir, side)
58
+ const directionBoundaryRef = React.useRef<HTMLSpanElement | null>(null)
59
+ const resolvedDirection = useResolvedDirection(dir, directionBoundaryRef)
60
+ const resolvedPosition = position ?? getToastPosition(resolvedDirection, side)
58
61
  const mergedToastOptions: ToasterProps["toastOptions"] = {
59
62
  ...toastOptions,
60
63
  classNames: {
@@ -69,7 +72,7 @@ function Toaster({
69
72
  toastOptions?.classNames?.description
70
73
  ),
71
74
  actionButton: cn(
72
- "rounded-[var(--bh-control-default)] bg-[var(--bh-interactive-primary-default)] px-[var(--bh-space-lg-10)] py-[var(--bh-space-xs-4)] text-[var(--bh-content-on-color)]",
75
+ "rounded-[var(--bh-control-default)] bg-[var(--bh-interactive-brand-default)] px-[var(--bh-space-lg-10)] py-[var(--bh-space-xs-4)] text-[var(--bh-content-on-brand)]",
73
76
  toastOptions?.classNames?.actionButton
74
77
  ),
75
78
  cancelButton: cn(
@@ -80,15 +83,17 @@ function Toaster({
80
83
  }
81
84
 
82
85
  return (
83
- <SonnerToaster
84
- className={cn("toaster group", className)}
85
- closeButton={closeButton}
86
- dir={dir}
87
- position={resolvedPosition}
88
- richColors={richColors}
89
- toastOptions={mergedToastOptions}
90
- {...props}
91
- />
86
+ <span className="contents" data-slot="toaster-direction-boundary" ref={directionBoundaryRef}>
87
+ <SonnerToaster
88
+ className={cn("toaster group", className)}
89
+ closeButton={closeButton}
90
+ dir={resolvedDirection}
91
+ position={resolvedPosition}
92
+ richColors={richColors}
93
+ toastOptions={mergedToastOptions}
94
+ {...props}
95
+ />
96
+ </span>
92
97
  )
93
98
  }
94
99
 
@@ -78,7 +78,7 @@ const Toggle = React.forwardRef<
78
78
  >
79
79
  <SwitchPrimitive.Thumb
80
80
  data-slot="toggle-thumb"
81
- className="pointer-events-none flex size-[var(--bh-toggle-handle-size)] translate-x-0 items-center justify-center rounded-[var(--bh-radius-full)] bg-[var(--bh-interactive-switch-handle)] text-[var(--bh-content-on-light)] shadow-[var(--shadow-component-default)] transition-[background-color,transform] group-data-[disabled]/toggle:bg-[var(--bh-interactive-switch-handle-disabled)] group-data-[state=checked]/toggle:translate-x-[var(--bh-toggle-offset)] rtl:group-data-[state=checked]/toggle:-translate-x-[var(--bh-toggle-offset)]"
81
+ className="pointer-events-none flex size-[var(--bh-toggle-handle-size)] translate-x-0 items-center justify-center rounded-[var(--bh-radius-full)] bg-[var(--bh-interactive-switch-handle)] text-[var(--bh-content-on-light)] shadow-[var(--shadow-md)] transition-[background-color,transform] group-data-[disabled]/toggle:bg-[var(--bh-interactive-switch-handle-disabled)] group-data-[state=checked]/toggle:translate-x-[var(--bh-toggle-offset)] rtl:group-data-[state=checked]/toggle:-translate-x-[var(--bh-toggle-offset)]"
82
82
  >
83
83
  {showIcon ? (
84
84
  <span
@@ -190,7 +190,7 @@ const ToggleField = React.forwardRef<HTMLDivElement, ToggleFieldProps>(
190
190
  data-slot="toggle-field-description"
191
191
  dir="auto"
192
192
  id={descriptionId}
193
- className="w-full min-w-0 break-words text-[length:var(--bh-text-body-xs-regular-font-size)] font-[var(--bh-text-body-xs-regular-font-weight)] leading-[var(--bh-text-body-xs-regular-line-height)] tracking-[var(--bh-text-body-xs-regular-letter-spacing)] text-[var(--bh-content-subtle)] group-data-[disabled=true]/toggle-field:text-[var(--bh-content-disabled)]"
193
+ className="w-full min-w-0 break-words text-[length:var(--bh-text-body-xs-regular-font-size)] font-[var(--bh-text-body-xs-regular-font-weight)] leading-[var(--bh-text-body-xs-regular-line-height)] tracking-[var(--bh-text-body-xs-regular-letter-spacing)] text-[var(--bh-content-subtle)]"
194
194
  >
195
195
  {description}
196
196
  </span>
@@ -231,7 +231,7 @@ function ToggleCheckIcon({ className }: { className?: string }) {
231
231
  aria-hidden="true"
232
232
  className={className}
233
233
  focusable="false"
234
- strokeWidth={2.5}
234
+ strokeWidth="var(--bh-icon-stroke-250)"
235
235
  />
236
236
  )
237
237
  }
@@ -242,7 +242,7 @@ function ToggleCloseIcon({ className }: { className?: string }) {
242
242
  aria-hidden="true"
243
243
  className={className}
244
244
  focusable="false"
245
- strokeWidth={2.5}
245
+ strokeWidth="var(--bh-icon-stroke-250)"
246
246
  />
247
247
  )
248
248
  }