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
@@ -12,7 +12,7 @@ type ProgressSliderSize = "default" | "lg"
12
12
  const progressSliderVariants = cva(
13
13
  [
14
14
  "group/progress-slider relative flex touch-none select-none items-center",
15
- "w-[var(--bh-progress-slider-width-current)] max-w-full",
15
+ "w-full max-w-[var(--bh-progress-slider-width-current)] min-w-0",
16
16
  "data-[disabled]:pointer-events-none data-[disabled]:opacity-[var(--bh-opacity-60)]",
17
17
  "[--bh-progress-slider-width-current:var(--bh-progress-slider-width-md)]",
18
18
  "[--bh-progress-slider-height-current:var(--bh-progress-slider-height-md)]",
@@ -2,6 +2,7 @@ import * as React from "react"
2
2
  import { cva, type VariantProps } from "class-variance-authority"
3
3
  import { Building2Icon, CreditCardIcon, UserIcon } from "lucide-react"
4
4
 
5
+ import { useResolvedDirection, type Direction } from "@/hooks/use-direction"
5
6
  import { cn } from "@/lib/utils"
6
7
 
7
8
  type RadioCardType =
@@ -14,7 +15,7 @@ type RadioCardType =
14
15
  | "radio-label"
15
16
 
16
17
  type RadioCardState = "default" | "active" | "disabled"
17
- type RadioCardDirection = "ltr" | "rtl"
18
+ type RadioCardDirection = Direction
18
19
 
19
20
  const radioCardVariants = cva(
20
21
  [
@@ -69,91 +70,119 @@ type RadioCardProps = Omit<
69
70
  inputProps?: Omit<React.ComponentProps<"input">, "type">
70
71
  }
71
72
 
72
- function RadioCard({
73
- className,
74
- type = "with-icon",
75
- state = "default",
76
- direction = "ltr",
77
- checked,
78
- disabled,
79
- label,
80
- description,
81
- supportLabel,
82
- supportDescription,
83
- showDescription = true,
84
- showSupportItems = true,
85
- showSupportDescription = true,
86
- icon,
87
- media,
88
- inputProps,
89
- ...props
90
- }: RadioCardProps) {
91
- const hasControlledChecked =
92
- checked !== undefined || inputProps?.checked !== undefined
93
- const controlledChecked = checked ?? inputProps?.checked
94
- const inputChecked =
95
- controlledChecked ?? Boolean(inputProps?.defaultChecked)
96
- const inputReadOnly =
97
- inputProps?.readOnly ??
98
- (hasControlledChecked && inputProps?.onChange === undefined
99
- ? true
100
- : undefined)
101
- const isDisabled = disabled ?? inputProps?.disabled ?? state === "disabled"
102
- const visualState: RadioCardState = isDisabled
103
- ? "disabled"
104
- : inputChecked || state === "active"
105
- ? "active"
106
- : state ?? "default"
107
- const isRtl = direction === "rtl"
108
- const textLabel = label
109
- const textDescription = description
73
+ const RadioCard = React.forwardRef<HTMLLabelElement, RadioCardProps>(
74
+ function RadioCard(
75
+ {
76
+ className,
77
+ type = "with-icon",
78
+ state = "default",
79
+ direction,
80
+ dir,
81
+ checked,
82
+ disabled,
83
+ label,
84
+ description,
85
+ supportLabel,
86
+ supportDescription,
87
+ showDescription = true,
88
+ showSupportItems = true,
89
+ showSupportDescription = true,
90
+ icon,
91
+ media,
92
+ inputProps,
93
+ ...props
94
+ },
95
+ forwardedRef
96
+ ) {
97
+ const directionBoundaryRef = React.useRef<HTMLLabelElement | null>(null)
98
+ const explicitDirection =
99
+ direction ?? (dir === "ltr" || dir === "rtl" ? dir : undefined)
100
+ const resolvedDirection = useResolvedDirection(
101
+ explicitDirection,
102
+ directionBoundaryRef
103
+ )
104
+ const setDirectionBoundaryRef = React.useCallback(
105
+ (node: HTMLLabelElement | null) => {
106
+ directionBoundaryRef.current = node
107
+
108
+ if (typeof forwardedRef === "function") {
109
+ forwardedRef(node)
110
+ } else if (forwardedRef) {
111
+ forwardedRef.current = node
112
+ }
113
+ },
114
+ [forwardedRef]
115
+ )
116
+ const hasControlledChecked =
117
+ checked !== undefined || inputProps?.checked !== undefined
118
+ const controlledChecked = checked ?? inputProps?.checked
119
+ const inputChecked =
120
+ controlledChecked ?? Boolean(inputProps?.defaultChecked)
121
+ const inputReadOnly =
122
+ inputProps?.readOnly ??
123
+ (hasControlledChecked && inputProps?.onChange === undefined
124
+ ? true
125
+ : undefined)
126
+ const isDisabled = disabled ?? inputProps?.disabled ?? state === "disabled"
127
+ const visualState: RadioCardState = isDisabled
128
+ ? "disabled"
129
+ : inputChecked || state === "active"
130
+ ? "active"
131
+ : state ?? "default"
132
+ const isRtl = resolvedDirection === "rtl"
133
+ const textLabel = label
134
+ const textDescription = description
110
135
 
111
- return (
112
- <label
113
- data-slot="radio-card"
114
- data-state={visualState}
115
- data-type={type}
116
- data-direction={direction}
117
- {...props}
118
- dir="ltr"
119
- className={cn(radioCardVariants({ state: visualState }), className)}
120
- >
121
- <input
122
- aria-label={typeof textLabel === "string" ? textLabel : undefined}
123
- {...inputProps}
124
- checked={hasControlledChecked ? controlledChecked : undefined}
125
- className={cn("sr-only", inputProps?.className)}
126
- defaultChecked={hasControlledChecked ? undefined : inputProps?.defaultChecked}
127
- disabled={isDisabled}
128
- readOnly={inputReadOnly}
129
- type="radio"
130
- />
131
- <span
132
- data-slot="radio-card-layout"
133
- className={cn(
134
- "flex min-w-0 items-start [direction:ltr]",
135
- type === "radio-label" && "items-center",
136
- getCardGapClass(type, isRtl)
137
- )}
136
+ return (
137
+ <label
138
+ data-slot="radio-card"
139
+ data-state={visualState}
140
+ data-type={type}
141
+ {...props}
142
+ ref={setDirectionBoundaryRef}
143
+ data-direction={resolvedDirection}
144
+ dir={resolvedDirection}
145
+ className={cn(radioCardVariants({ state: visualState }), className)}
138
146
  >
139
- {renderRadioCardContent({
140
- type,
141
- direction,
142
- state: visualState,
143
- label: textLabel,
144
- description: textDescription,
145
- supportLabel,
146
- supportDescription,
147
- showDescription,
148
- showSupportItems,
149
- showSupportDescription,
150
- icon,
151
- media,
152
- })}
153
- </span>
154
- </label>
155
- )
156
- }
147
+ <input
148
+ aria-label={typeof textLabel === "string" ? textLabel : undefined}
149
+ {...inputProps}
150
+ checked={hasControlledChecked ? controlledChecked : undefined}
151
+ className={cn("sr-only", inputProps?.className)}
152
+ defaultChecked={
153
+ hasControlledChecked ? undefined : inputProps?.defaultChecked
154
+ }
155
+ disabled={isDisabled}
156
+ readOnly={inputReadOnly}
157
+ type="radio"
158
+ />
159
+ <span
160
+ data-slot="radio-card-layout"
161
+ className={cn(
162
+ "flex min-w-0 items-start [direction:ltr]",
163
+ type === "radio-label" && "items-center",
164
+ getCardGapClass(type, isRtl)
165
+ )}
166
+ >
167
+ {renderRadioCardContent({
168
+ type,
169
+ direction: resolvedDirection,
170
+ state: visualState,
171
+ label: textLabel,
172
+ description: textDescription,
173
+ supportLabel,
174
+ supportDescription,
175
+ showDescription,
176
+ showSupportItems,
177
+ showSupportDescription,
178
+ icon,
179
+ media,
180
+ })}
181
+ </span>
182
+ </label>
183
+ )
184
+ }
185
+ )
157
186
 
158
187
  function renderRadioCardContent({
159
188
  type,
@@ -564,7 +593,7 @@ function RadioCardUserIcon() {
564
593
  <UserIcon
565
594
  aria-hidden="true"
566
595
  className="size-[var(--bh-space-4xl-20)]"
567
- strokeWidth={2}
596
+ strokeWidth="var(--bh-icon-stroke-200)"
568
597
  />
569
598
  )
570
599
  }
@@ -578,7 +607,7 @@ function RadioCardPaymentIcon() {
578
607
  <CreditCardIcon
579
608
  aria-hidden="true"
580
609
  className="h-[var(--bh-radio-card-payment-logo-height)] w-[var(--bh-radio-card-payment-logo-width)]"
581
- strokeWidth={2}
610
+ strokeWidth="var(--bh-icon-stroke-200)"
582
611
  />
583
612
  </span>
584
613
  )
@@ -610,7 +639,7 @@ function RadioCardCompanyIcon({ disabled }: { disabled: boolean }) {
610
639
  <Building2Icon
611
640
  aria-hidden="true"
612
641
  className="size-[var(--bh-space-5xl-24)] text-[var(--bh-radio-card-company-mark-color)]"
613
- strokeWidth={1.8}
642
+ strokeWidth="var(--bh-icon-stroke-180)"
614
643
  />
615
644
  </span>
616
645
  )
@@ -17,7 +17,9 @@ import { cn } from "@/lib/utils"
17
17
  type ResizablePanelGroupProps = Omit<GroupProps, "orientation"> & {
18
18
  direction?: Orientation
19
19
  }
20
- type ResizablePanelProps = PanelProps
20
+ type ResizablePanelProps = PanelProps & {
21
+ contentTabIndex?: number
22
+ }
21
23
  type ResizableHandleProps = SeparatorProps & {
22
24
  withHandle?: boolean
23
25
  }
@@ -41,7 +43,39 @@ function ResizablePanelGroup({
41
43
  )
42
44
  }
43
45
 
44
- const ResizablePanel = Panel
46
+ function ResizablePanel({
47
+ className,
48
+ contentTabIndex = 0,
49
+ elementRef,
50
+ ...props
51
+ }: ResizablePanelProps) {
52
+ const setElementRef = React.useCallback(
53
+ (node: HTMLDivElement | null) => {
54
+ const content = node?.firstElementChild
55
+ if (content instanceof HTMLElement) {
56
+ content.tabIndex = contentTabIndex
57
+ content.setAttribute("data-slot", "resizable-panel-content")
58
+ }
59
+
60
+ if (typeof elementRef === "function") elementRef(node)
61
+ else if (elementRef) {
62
+ ;(elementRef as React.MutableRefObject<HTMLDivElement | null>).current = node
63
+ }
64
+ },
65
+ [contentTabIndex, elementRef]
66
+ )
67
+
68
+ return (
69
+ <Panel
70
+ className={cn(
71
+ "outline-none focus-visible:shadow-[var(--shadow-component-focus-ring)]",
72
+ className
73
+ )}
74
+ elementRef={setElementRef}
75
+ {...props}
76
+ />
77
+ )
78
+ }
45
79
 
46
80
  function ResizableHandle({
47
81
  className,
@@ -5,9 +5,15 @@ import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
5
5
 
6
6
  import { cn } from "@/lib/utils"
7
7
 
8
+ type ScrollAreaOrientation = "vertical" | "horizontal" | "both"
8
9
  type ScrollAreaProps = React.ComponentPropsWithoutRef<
9
10
  typeof ScrollAreaPrimitive.Root
10
- >
11
+ > & {
12
+ orientation?: ScrollAreaOrientation
13
+ viewportProps?: React.ComponentPropsWithoutRef<
14
+ typeof ScrollAreaPrimitive.Viewport
15
+ >
16
+ }
11
17
  type ScrollBarProps = React.ComponentPropsWithoutRef<
12
18
  typeof ScrollAreaPrimitive.ScrollAreaScrollbar
13
19
  >
@@ -15,9 +21,24 @@ type ScrollBarProps = React.ComponentPropsWithoutRef<
15
21
  const ScrollArea = React.forwardRef<
16
22
  React.ElementRef<typeof ScrollAreaPrimitive.Root>,
17
23
  ScrollAreaProps
18
- >(function ScrollArea({ children, className, ...props }, ref) {
24
+ >(function ScrollArea(
25
+ {
26
+ children,
27
+ className,
28
+ orientation = "vertical",
29
+ viewportProps,
30
+ ...props
31
+ },
32
+ ref
33
+ ) {
34
+ const hasVerticalScrollbar =
35
+ orientation === "vertical" || orientation === "both"
36
+ const hasHorizontalScrollbar =
37
+ orientation === "horizontal" || orientation === "both"
38
+
19
39
  return (
20
40
  <ScrollAreaPrimitive.Root
41
+ data-orientation={orientation}
21
42
  data-slot="scroll-area"
22
43
  ref={ref}
23
44
  className={cn("relative overflow-hidden", className)}
@@ -25,12 +46,15 @@ const ScrollArea = React.forwardRef<
25
46
  >
26
47
  <ScrollAreaPrimitive.Viewport
27
48
  data-slot="scroll-area-viewport"
28
- className="size-full rounded-[inherit]"
49
+ {...viewportProps}
50
+ tabIndex={viewportProps?.tabIndex ?? 0}
51
+ className={cn("size-full rounded-[inherit] outline-none focus-visible:shadow-[var(--shadow-component-focus-ring)]", viewportProps?.className)}
29
52
  >
30
53
  {children}
31
54
  </ScrollAreaPrimitive.Viewport>
32
- <ScrollBar />
33
- <ScrollAreaPrimitive.Corner />
55
+ {hasVerticalScrollbar ? <ScrollBar orientation="vertical" /> : null}
56
+ {hasHorizontalScrollbar ? <ScrollBar orientation="horizontal" /> : null}
57
+ {orientation === "both" ? <ScrollAreaPrimitive.Corner /> : null}
34
58
  </ScrollAreaPrimitive.Root>
35
59
  )
36
60
  })
@@ -64,4 +88,4 @@ const ScrollBar = React.forwardRef<
64
88
  })
65
89
 
66
90
  export { ScrollArea, ScrollBar }
67
- export type { ScrollAreaProps, ScrollBarProps }
91
+ export type { ScrollAreaOrientation, ScrollAreaProps, ScrollBarProps }
@@ -0,0 +1,87 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+
5
+ import {
6
+ ButtonGroupLabel,
7
+ ToggleGroup,
8
+ ToggleGroupItem,
9
+ type ButtonGroupLabelProps,
10
+ type ControlDensity,
11
+ type ToggleGroupItemProps,
12
+ type ToggleGroupProps,
13
+ } from "@/components/ui/button-group"
14
+
15
+ type SegmentedControlProps = Omit<
16
+ ToggleGroupProps,
17
+ "itemWidth" | "mode"
18
+ > & {
19
+ "aria-label": string
20
+ density?: ControlDensity
21
+ }
22
+
23
+ const SegmentedControl = React.forwardRef<
24
+ HTMLDivElement,
25
+ SegmentedControlProps
26
+ >(function SegmentedControl(
27
+ { density = "default", type = "single", ...props },
28
+ ref
29
+ ) {
30
+ return (
31
+ <ToggleGroup
32
+ data-slot="segmented-control"
33
+ density={density}
34
+ itemWidth="content"
35
+ mode="default"
36
+ ref={ref}
37
+ type={type}
38
+ {...props}
39
+ />
40
+ )
41
+ })
42
+
43
+ type SegmentedControlItemProps = ToggleGroupItemProps
44
+
45
+ const SegmentedControlItem = React.forwardRef<
46
+ HTMLButtonElement,
47
+ SegmentedControlItemProps
48
+ >(function SegmentedControlItem(props, ref) {
49
+ return (
50
+ <ToggleGroupItem
51
+ data-slot="segmented-control-item"
52
+ itemWidth="content"
53
+ ref={ref}
54
+ {...props}
55
+ />
56
+ )
57
+ })
58
+
59
+ type SegmentedControlLabelProps = Omit<
60
+ ButtonGroupLabelProps,
61
+ "itemWidth"
62
+ >
63
+
64
+ const SegmentedControlLabel = React.forwardRef<
65
+ HTMLSpanElement,
66
+ SegmentedControlLabelProps
67
+ >(function SegmentedControlLabel(props, ref) {
68
+ return (
69
+ <ButtonGroupLabel
70
+ data-slot="segmented-control-label"
71
+ itemWidth="content"
72
+ ref={ref}
73
+ {...props}
74
+ />
75
+ )
76
+ })
77
+
78
+ export {
79
+ SegmentedControl,
80
+ SegmentedControlItem,
81
+ SegmentedControlLabel,
82
+ }
83
+ export type {
84
+ SegmentedControlItemProps,
85
+ SegmentedControlLabelProps,
86
+ SegmentedControlProps,
87
+ }
@@ -104,7 +104,7 @@ function SelectItemCompanyLogo({
104
104
  aria-hidden="true"
105
105
  className="size-[var(--bh-select-company-icon-size)]"
106
106
  focusable="false"
107
- strokeWidth={2.2}
107
+ strokeWidth="var(--bh-icon-stroke-220)"
108
108
  />
109
109
  </span>
110
110
  )
@@ -177,7 +177,7 @@ function SelectIcon({
177
177
  "aria-hidden": true,
178
178
  className: iconClassName,
179
179
  focusable: false,
180
- strokeWidth: 2,
180
+ strokeWidth: "var(--bh-icon-stroke-200)",
181
181
  } as const
182
182
 
183
183
  if (name === "user") {