banhaten 0.1.2 → 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 (365) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/CONTRIBUTING.md +44 -0
  3. package/README.md +145 -328
  4. package/SECURITY.md +15 -0
  5. package/banhaten.config.example.json +1 -3
  6. package/docs/design-system/README.md +20 -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 +189 -0
  10. package/docs/design-system/appearances/default.md +94 -0
  11. package/docs/design-system/appearances/rounded.md +95 -0
  12. package/docs/design-system/appearances/sharp.md +95 -0
  13. package/docs/design-system/component-docs-pattern.md +81 -0
  14. package/docs/design-system/component-showcase-consistency-report.md +217 -0
  15. package/docs/design-system/component-token-consistency-audit.md +173 -0
  16. package/docs/design-system/components/README.md +75 -0
  17. package/docs/design-system/components/accordion.md +67 -0
  18. package/docs/design-system/components/activity-feed.md +106 -0
  19. package/docs/design-system/components/alert-dialog.md +87 -0
  20. package/docs/design-system/components/alert.md +111 -0
  21. package/docs/design-system/components/aspect-ratio.md +59 -0
  22. package/docs/design-system/components/attribute.md +103 -0
  23. package/docs/design-system/components/autocomplete.md +93 -0
  24. package/docs/design-system/components/avatar.md +70 -0
  25. package/docs/design-system/components/badge.md +72 -0
  26. package/docs/design-system/components/banner.md +99 -0
  27. package/docs/design-system/components/breadcrumbs.md +188 -0
  28. package/docs/design-system/components/button-group.md +117 -0
  29. package/docs/design-system/components/button.md +95 -0
  30. package/docs/design-system/components/card.md +95 -0
  31. package/docs/design-system/components/carousel.md +61 -0
  32. package/docs/design-system/components/catalog-components.md +59 -0
  33. package/docs/design-system/components/chart.md +58 -0
  34. package/docs/design-system/components/checkbox.md +68 -0
  35. package/docs/design-system/components/collapsible.md +63 -0
  36. package/docs/design-system/components/command.md +75 -0
  37. package/docs/design-system/components/context-menu.md +59 -0
  38. package/docs/design-system/components/date-picker.md +97 -0
  39. package/docs/design-system/components/divider.md +117 -0
  40. package/docs/design-system/components/empty-state.md +72 -0
  41. package/docs/design-system/components/field.md +86 -0
  42. package/docs/design-system/components/file-upload.md +199 -0
  43. package/docs/design-system/components/hover-card.md +61 -0
  44. package/docs/design-system/components/icons.md +48 -0
  45. package/docs/design-system/components/input-group.md +73 -0
  46. package/docs/design-system/components/input-otp.md +73 -0
  47. package/docs/design-system/components/input.md +84 -0
  48. package/docs/design-system/components/item.md +72 -0
  49. package/docs/design-system/components/kbd.md +62 -0
  50. package/docs/design-system/components/label.md +64 -0
  51. package/docs/design-system/components/menu.md +76 -0
  52. package/docs/design-system/components/menubar.md +60 -0
  53. package/docs/design-system/components/modal.md +119 -0
  54. package/docs/design-system/components/native-select.md +70 -0
  55. package/docs/design-system/components/navigation-menu.md +63 -0
  56. package/docs/design-system/components/onboarding-step-list-item.md +94 -0
  57. package/docs/design-system/components/page-header.md +98 -0
  58. package/docs/design-system/components/pagination.md +71 -0
  59. package/docs/design-system/components/popover.md +77 -0
  60. package/docs/design-system/components/progress-slider.md +66 -0
  61. package/docs/design-system/components/progress.md +92 -0
  62. package/docs/design-system/components/radio-card.md +65 -0
  63. package/docs/design-system/components/radio-group.md +72 -0
  64. package/docs/design-system/components/resizable.md +57 -0
  65. package/docs/design-system/components/scroll-area.md +60 -0
  66. package/docs/design-system/components/segmented-control.md +71 -0
  67. package/docs/design-system/components/select.md +87 -0
  68. package/docs/design-system/components/sheet.md +82 -0
  69. package/docs/design-system/components/sidebar.md +83 -0
  70. package/docs/design-system/components/skeleton.md +91 -0
  71. package/docs/design-system/components/slideout.md +77 -0
  72. package/docs/design-system/components/slider.md +81 -0
  73. package/docs/design-system/components/social-button.md +65 -0
  74. package/docs/design-system/components/spinner.md +77 -0
  75. package/docs/design-system/components/steps.md +77 -0
  76. package/docs/design-system/components/table.md +411 -0
  77. package/docs/design-system/components/tabs.md +69 -0
  78. package/docs/design-system/components/tag.md +95 -0
  79. package/docs/design-system/components/textarea.md +64 -0
  80. package/docs/design-system/components/timeline.md +95 -0
  81. package/docs/design-system/components/toast.md +73 -0
  82. package/docs/design-system/components/toggle.md +96 -0
  83. package/docs/design-system/components/toolbar.md +105 -0
  84. package/docs/design-system/components/tooltip.md +107 -0
  85. package/docs/design-system/components/typography.md +18 -0
  86. package/docs/design-system/density-and-elevation.md +44 -0
  87. package/docs/design-system/design-system-test-missing-items.md +368 -0
  88. package/docs/design-system/direction-and-localization.md +23 -0
  89. package/docs/design-system/form-recipes.md +73 -0
  90. package/docs/design-system/gap-promotion-policy.md +21 -0
  91. package/docs/design-system/gap-promotion-report.md +166 -0
  92. package/docs/design-system/icons.md +69 -0
  93. package/docs/design-system/installation.md +68 -0
  94. package/docs/design-system/launch-comparison-shadcn.md +98 -0
  95. package/docs/design-system/registry-and-cli.md +64 -0
  96. package/docs/design-system/release-policy.md +30 -0
  97. package/docs/design-system/roadmap.md +14 -0
  98. package/docs/design-system/support-matrix.md +23 -0
  99. package/docs/design-system/tabs.md +53 -0
  100. package/docs/design-system/token-governance.md +60 -0
  101. package/package.json +97 -65
  102. package/registry/component-contract.json +40 -0
  103. package/registry/components/alert-dialog.tsx +297 -0
  104. package/registry/components/alert.tsx +86 -65
  105. package/registry/components/aspect-ratio.tsx +30 -0
  106. package/registry/components/autocomplete.tsx +23 -9
  107. package/registry/components/avatar.tsx +7 -7
  108. package/registry/components/badge.tsx +1 -1
  109. package/registry/components/button-group.tsx +321 -4
  110. package/registry/components/button.tsx +38 -17
  111. package/registry/components/card.tsx +68 -59
  112. package/registry/components/carousel.tsx +282 -0
  113. package/registry/components/chart.tsx +203 -0
  114. package/registry/components/checkbox.tsx +3 -3
  115. package/registry/components/collapsible.tsx +69 -0
  116. package/registry/components/command.tsx +174 -0
  117. package/registry/components/context-menu.tsx +236 -0
  118. package/registry/components/date-picker.tsx +246 -105
  119. package/registry/components/expanded/ActivityFeed.tsx +6 -15
  120. package/registry/components/expanded/Banner.tsx +3 -3
  121. package/registry/components/expanded/Breadcrumbs.tsx +5 -5
  122. package/registry/components/expanded/CatalogComponentsShowcase.tsx +13 -13
  123. package/registry/components/expanded/CatalogDivider.tsx +1 -1
  124. package/registry/components/expanded/EmptyState.tsx +1 -1
  125. package/registry/components/expanded/FileUpload.tsx +9 -2
  126. package/registry/components/expanded/OnboardingStepListItem.tsx +2 -4
  127. package/registry/components/expanded/PageHeader.tsx +14 -14
  128. package/registry/components/expanded/Slideout.tsx +15 -415
  129. package/registry/components/expanded/Steps.tsx +4 -4
  130. package/registry/components/expanded/Table.tsx +116 -69
  131. package/registry/components/expanded/Timeline.tsx +3 -3
  132. package/registry/components/expanded/activityFeed.css +1 -1
  133. package/registry/components/expanded/breadcrumbs.css +139 -139
  134. package/registry/components/expanded/catalogComponentsShowcase.css +83 -83
  135. package/registry/components/expanded/divider.css +1 -1
  136. package/registry/components/expanded/emptyState.css +1 -1
  137. package/registry/components/expanded/fileUpload.css +6 -6
  138. package/registry/components/expanded/slideout.css +9 -685
  139. package/registry/components/expanded/steps.css +274 -274
  140. package/registry/components/expanded/table.css +2 -2
  141. package/registry/components/expanded/timeline.css +264 -264
  142. package/registry/components/field.tsx +230 -0
  143. package/registry/components/hover-card.tsx +48 -0
  144. package/registry/components/input-content.ts +1 -0
  145. package/registry/components/input-group.tsx +130 -0
  146. package/registry/components/input-otp.tsx +13 -3
  147. package/registry/components/input.tsx +70 -45
  148. package/registry/components/item.tsx +189 -0
  149. package/registry/components/kbd.tsx +151 -0
  150. package/registry/components/label.tsx +78 -0
  151. package/registry/components/menu.tsx +34 -246
  152. package/registry/components/menubar.tsx +226 -0
  153. package/registry/components/modal.tsx +216 -143
  154. package/registry/components/native-select.tsx +205 -0
  155. package/registry/components/navigation-menu.tsx +171 -0
  156. package/registry/components/pagination.tsx +80 -58
  157. package/registry/components/popover.tsx +162 -664
  158. package/registry/components/radio-card.tsx +116 -87
  159. package/registry/components/radio-group.tsx +1 -1
  160. package/registry/components/resizable.tsx +74 -0
  161. package/registry/components/scroll-area.tsx +67 -0
  162. package/registry/components/segmented-control.tsx +87 -0
  163. package/registry/components/select-content.tsx +2 -2
  164. package/registry/components/select.tsx +54 -20
  165. package/registry/components/sheet.tsx +305 -0
  166. package/registry/components/sidebar.tsx +352 -0
  167. package/registry/components/skeleton.css +0 -3
  168. package/registry/components/social-button.tsx +116 -30
  169. package/registry/components/spinner.tsx +18 -55
  170. package/registry/components/{expanded/tabs.css → tabs.css} +127 -106
  171. package/registry/components/tabs.tsx +246 -0
  172. package/registry/components/tag.tsx +2 -2
  173. package/registry/components/textarea.tsx +4 -4
  174. package/registry/components/toast.tsx +136 -0
  175. package/registry/components/toggle.tsx +2 -2
  176. package/registry/components/toolbar.tsx +89 -17
  177. package/registry/components/tooltip.tsx +1 -1
  178. package/registry/examples/alert-demo.tsx +25 -5
  179. package/registry/examples/alert-dialog-demo.tsx +42 -0
  180. package/registry/examples/aspect-ratio-demo.tsx +11 -0
  181. package/registry/examples/attribute-demo.tsx +1 -1
  182. package/registry/examples/autocomplete-demo.tsx +3 -3
  183. package/registry/examples/avatar-demo.tsx +7 -7
  184. package/registry/examples/badge-demo.tsx +1 -1
  185. package/registry/examples/button-demo.tsx +6 -6
  186. package/registry/examples/button-group-demo.tsx +23 -2
  187. package/registry/examples/card-demo.tsx +46 -8
  188. package/registry/examples/carousel-demo.tsx +43 -0
  189. package/registry/examples/chart-demo.tsx +33 -0
  190. package/registry/examples/checkbox-demo.tsx +5 -5
  191. package/registry/examples/collapsible-demo.tsx +16 -0
  192. package/registry/examples/collection-filter-bar-demo.tsx +135 -0
  193. package/registry/examples/command-demo.tsx +42 -0
  194. package/registry/examples/{expanded/command-bar-demo.tsx → command-palette-demo.tsx} +5 -15
  195. package/registry/examples/context-menu-demo.tsx +29 -0
  196. package/registry/examples/control-density-contract-demo.tsx +61 -0
  197. package/registry/examples/date-picker-demo.tsx +12 -12
  198. package/registry/examples/divider-demo.tsx +3 -3
  199. package/registry/examples/expanded/banner-demo.tsx +1 -1
  200. package/registry/examples/expanded/breadcrumbs-demo.tsx +1 -1
  201. package/registry/examples/expanded/empty-state-demo.tsx +1 -1
  202. package/registry/examples/expanded/file-upload-demo.tsx +1 -1
  203. package/registry/examples/expanded/onboarding-step-demo.tsx +1 -1
  204. package/registry/examples/expanded/slideout-demo.tsx +2 -2
  205. package/registry/examples/expanded/steps-demo.tsx +1 -1
  206. package/registry/examples/expanded/tabs-demo.tsx +2 -2
  207. package/registry/examples/expanded/timeline-demo.tsx +1 -1
  208. package/registry/examples/field-demo.tsx +51 -0
  209. package/registry/examples/hover-card-demo.tsx +23 -0
  210. package/registry/examples/input-demo.tsx +6 -6
  211. package/registry/examples/input-group-demo.tsx +16 -0
  212. package/registry/examples/input-otp-demo.tsx +4 -4
  213. package/registry/examples/item-demo.tsx +46 -0
  214. package/registry/examples/kbd-demo.tsx +11 -0
  215. package/registry/examples/label-demo.tsx +20 -0
  216. package/registry/examples/menu-demo.tsx +1 -1
  217. package/registry/examples/menubar-demo.tsx +34 -0
  218. package/registry/examples/modal-demo.tsx +67 -9
  219. package/registry/examples/native-select-demo.tsx +16 -0
  220. package/registry/examples/navigation-menu-demo.tsx +29 -0
  221. package/registry/examples/pagination-demo.tsx +6 -3
  222. package/registry/examples/popover-demo.tsx +19 -19
  223. package/registry/examples/progress-demo.tsx +1 -1
  224. package/registry/examples/progress-slider-demo.tsx +1 -1
  225. package/registry/examples/radio-card-demo.tsx +4 -4
  226. package/registry/examples/radio-group-demo.tsx +2 -2
  227. package/registry/examples/resizable-demo.tsx +22 -0
  228. package/registry/examples/results-toolbar-demo.tsx +44 -0
  229. package/registry/examples/scroll-area-demo.tsx +15 -0
  230. package/registry/examples/segmented-control-demo.tsx +39 -0
  231. package/registry/examples/select-demo.tsx +1 -1
  232. package/registry/examples/sheet-demo.tsx +47 -0
  233. package/registry/examples/sidebar-demo.tsx +55 -0
  234. package/registry/examples/slider-demo.tsx +3 -3
  235. package/registry/examples/social-button-demo.tsx +18 -8
  236. package/registry/examples/spinner-demo.tsx +13 -13
  237. package/registry/examples/tabs-demo.tsx +13 -0
  238. package/registry/examples/tag-demo.tsx +1 -1
  239. package/registry/examples/textarea-demo.tsx +4 -4
  240. package/registry/examples/toast-demo.tsx +35 -0
  241. package/registry/examples/toggle-demo.tsx +6 -6
  242. package/registry/examples/tooltip-demo.tsx +4 -4
  243. package/registry/guidance/USAGE.md +27 -0
  244. package/registry/hooks/use-direction.ts +193 -13
  245. package/registry/index.json +6010 -432
  246. package/registry/styles/globals.css +3112 -4690
  247. package/registry.json +1582 -0
  248. package/schema/config.schema.json +51 -0
  249. package/schema/registry.schema.json +190 -0
  250. package/schema/tokens.schema.json +163 -0
  251. package/src/cli/command-line.js +194 -0
  252. package/src/cli/config-editors.js +9 -0
  253. package/src/cli/doctor.js +399 -0
  254. package/src/cli/file-transaction.js +295 -0
  255. package/src/cli/global-css.js +153 -0
  256. package/src/cli/index.js +639 -1391
  257. package/src/cli/install-plan.js +592 -0
  258. package/src/cli/install-receipt.js +171 -0
  259. package/src/cli/jsonc.js +203 -0
  260. package/src/cli/package-install-state.js +254 -0
  261. package/src/cli/package-manager.js +238 -0
  262. package/src/cli/package-plan.js +185 -0
  263. package/src/cli/package-version.js +97 -0
  264. package/src/cli/registry-query.js +207 -0
  265. package/src/cli/reporting.js +55 -0
  266. package/src/cli/schema-validation.js +19 -0
  267. package/src/cli/source-scanner.js +686 -0
  268. package/src/cli/vite-config.js +478 -0
  269. package/tokens/banhaten.tokens.json +4313 -310
  270. package/registry/assets/avatars/avatar-02.jpg +0 -0
  271. package/registry/assets/avatars/avatar-03.jpg +0 -0
  272. package/registry/assets/avatars/avatar-04.jpg +0 -0
  273. package/registry/assets/avatars/avatar-05.jpg +0 -0
  274. package/registry/assets/avatars/avatar-06.jpg +0 -0
  275. package/registry/assets/avatars/avatar-07.jpg +0 -0
  276. package/registry/assets/avatars/avatar-08.jpg +0 -0
  277. package/registry/assets/avatars/avatar-09.jpg +0 -0
  278. package/registry/assets/avatars/avatar-10.jpg +0 -0
  279. package/registry/assets/avatars/avatar-11.jpg +0 -0
  280. package/registry/assets/avatars/avatar-12.jpg +0 -0
  281. package/registry/assets/avatars/avatar-13.jpg +0 -0
  282. package/registry/assets/avatars/avatar-14.jpg +0 -0
  283. package/registry/assets/avatars/avatar-15.jpg +0 -0
  284. package/registry/assets/avatars/avatar-16.jpg +0 -0
  285. package/registry/assets/avatars/avatar-17.jpg +0 -0
  286. package/registry/assets/avatars/avatar-18.jpg +0 -0
  287. package/registry/assets/avatars/avatar-19.jpg +0 -0
  288. package/registry/assets/avatars/avatar-20.jpg +0 -0
  289. package/registry/assets/avatars/avatar-21.jpg +0 -0
  290. package/registry/assets/avatars/avatar-22.jpg +0 -0
  291. package/registry/assets/avatars/avatar-23.jpg +0 -0
  292. package/registry/assets/avatars/avatar-24.jpg +0 -0
  293. package/registry/assets/avatars/avatar-25.jpg +0 -0
  294. package/registry/assets/avatars/avatar-26.jpg +0 -0
  295. package/registry/assets/avatars/avatar-27.jpg +0 -0
  296. package/registry/assets/avatars/avatar-28.jpg +0 -0
  297. package/registry/assets/avatars/avatar-29.jpg +0 -0
  298. package/registry/assets/avatars/avatar-30.jpg +0 -0
  299. package/registry/assets/avatars/avatar-31.jpg +0 -0
  300. package/registry/assets/avatars/avatar-32.jpg +0 -0
  301. package/registry/assets/avatars/avatar-33.jpg +0 -0
  302. package/registry/assets/avatars/avatar-34.jpg +0 -0
  303. package/registry/assets/avatars/avatar-35.jpg +0 -0
  304. package/registry/assets/image-assets.json +0 -744
  305. package/registry/assets/images/art-02.jpg +0 -0
  306. package/registry/assets/images/art-03.jpg +0 -0
  307. package/registry/assets/images/art-04.jpg +0 -0
  308. package/registry/assets/images/art-05.jpg +0 -0
  309. package/registry/assets/images/art-06.jpg +0 -0
  310. package/registry/assets/images/art-07.jpg +0 -0
  311. package/registry/assets/images/art-08.jpg +0 -0
  312. package/registry/assets/images/art-09.jpg +0 -0
  313. package/registry/assets/images/art-10.jpg +0 -0
  314. package/registry/assets/images/art-11.jpg +0 -0
  315. package/registry/assets/images/art-12.jpg +0 -0
  316. package/registry/assets/images/art-13.jpg +0 -0
  317. package/registry/assets/images/art-14.jpg +0 -0
  318. package/registry/assets/images/art-15.jpg +0 -0
  319. package/registry/assets/images/art-16.jpg +0 -0
  320. package/registry/assets/images/art-17.jpg +0 -0
  321. package/registry/assets/images/art-18.jpg +0 -0
  322. package/registry/assets/images/art-19.jpg +0 -0
  323. package/registry/assets/images/art-20.jpg +0 -0
  324. package/registry/assets/images/art-21.jpg +0 -0
  325. package/registry/assets/images/art-22.jpg +0 -0
  326. package/registry/assets/images/art-23.jpg +0 -0
  327. package/registry/assets/images/art-24.jpg +0 -0
  328. package/registry/assets/images/art-25.jpg +0 -0
  329. package/registry/assets/images/art-26.jpg +0 -0
  330. package/registry/assets/images/art-27.jpg +0 -0
  331. package/registry/assets/images/nature-01.jpg +0 -0
  332. package/registry/assets/images/nature-02.jpg +0 -0
  333. package/registry/assets/images/nature-03.jpg +0 -0
  334. package/registry/assets/images/nature-04.jpg +0 -0
  335. package/registry/assets/images/nature-05.jpg +0 -0
  336. package/registry/assets/images/nature-06.jpg +0 -0
  337. package/registry/assets/images/nature-07.jpg +0 -0
  338. package/registry/assets/images/nature-08.jpg +0 -0
  339. package/registry/assets/images/nature-09.jpg +0 -0
  340. package/registry/assets/images/nature-10.jpg +0 -0
  341. package/registry/assets/images/nature-11.jpg +0 -0
  342. package/registry/assets/images/nature-12.jpg +0 -0
  343. package/registry/assets/images/nature-13.jpg +0 -0
  344. package/registry/assets/images/nature-14.jpg +0 -0
  345. package/registry/assets/images/nature-15.jpg +0 -0
  346. package/registry/assets/images/nature-16.jpg +0 -0
  347. package/registry/assets/images/nature-17.jpg +0 -0
  348. package/registry/assets/images/nature-18.jpg +0 -0
  349. package/registry/assets/images/nature-19.jpg +0 -0
  350. package/registry/assets/images/nature-20.jpg +0 -0
  351. package/registry/components/expanded/BannerBoard.tsx +0 -225
  352. package/registry/components/expanded/CatalogTag.tsx +0 -85
  353. package/registry/components/expanded/CommandBar.tsx +0 -386
  354. package/registry/components/expanded/IconExplorer.tsx +0 -612
  355. package/registry/components/expanded/Tabs.tsx +0 -86
  356. package/registry/components/expanded/TimelineShowcase.tsx +0 -158
  357. package/registry/components/expanded/commandBar.css +0 -470
  358. package/registry/components/expanded/iconExplorer.css +0 -764
  359. package/registry/components/expanded/iconPacks.ts +0 -866
  360. package/registry/components/expanded/tag.css +0 -148
  361. package/registry/examples/expanded/icons-demo.tsx +0 -5
  362. package/tokens/Color mode.zip +0 -0
  363. package/tokens/Numbers.zip +0 -0
  364. package/tokens/Radius.zip +0 -0
  365. package/tokens/Theme.zip +0 -0
@@ -10,6 +10,7 @@ import {
10
10
  } from "lucide-react"
11
11
 
12
12
  import { cn } from "@/lib/utils"
13
+ import { useResolvedDirection } from "@/hooks/use-direction"
13
14
 
14
15
  const alertVariants = cva(
15
16
  [
@@ -35,11 +36,11 @@ const alertVariants = cva(
35
36
  false:
36
37
  "h-[var(--bh-alert-compact-height)] w-[var(--bh-alert-compact-width)] items-center gap-[var(--bh-space-xl-12)] rounded-[var(--bh-alert-compact-radius)] p-[var(--bh-alert-compact-padding)]",
37
38
  true:
38
- "h-[var(--bh-alert-expanded-height)] w-[var(--bh-alert-expanded-width)] items-start gap-[var(--bh-space-xl-12)] rounded-[var(--bh-alert-expanded-radius)] px-[var(--bh-alert-expanded-padding-x)] py-[var(--bh-alert-expanded-padding-y)]",
39
+ "w-[var(--bh-alert-expanded-width)] items-start gap-[var(--bh-space-xl-12)] rounded-[var(--bh-alert-expanded-radius)] px-[var(--bh-alert-expanded-padding-x)] py-[var(--bh-alert-expanded-padding-y)]",
39
40
  },
40
41
  },
41
42
  defaultVariants: {
42
- status: "danger",
43
+ status: "neutral",
43
44
  isExpandable: false,
44
45
  },
45
46
  }
@@ -48,9 +49,21 @@ const alertVariants = cva(
48
49
  type AlertStatus = "danger" | "success" | "warning" | "info" | "neutral"
49
50
  type AlertDirection = "ltr" | "rtl"
50
51
 
52
+ type AlertMessages = {
53
+ close: string
54
+ }
55
+
56
+ const defaultAlertMessages: AlertMessages = {
57
+ close: "Close alert",
58
+ }
59
+
60
+ const arabicAlertMessages: AlertMessages = {
61
+ close: "\u0625\u063a\u0644\u0627\u0642 \u0627\u0644\u062a\u0646\u0628\u064a\u0647",
62
+ }
63
+
51
64
  type AlertAction = {
52
65
  label: React.ReactNode
53
- onClick?: () => void
66
+ onClick: () => void
54
67
  }
55
68
 
56
69
  type AlertProps = Omit<
@@ -62,6 +75,7 @@ type AlertProps = Omit<
62
75
  closeLabel?: string
63
76
  description?: React.ReactNode
64
77
  dir?: AlertDirection
78
+ messages?: Partial<AlertMessages>
65
79
  onClose?: () => void
66
80
  showActions?: boolean
67
81
  showCloseButton?: boolean
@@ -69,28 +83,6 @@ type AlertProps = Omit<
69
83
  title?: React.ReactNode
70
84
  }
71
85
 
72
- const defaultActions: Record<AlertDirection, AlertAction[]> = {
73
- ltr: [{ label: "Action" }, { label: "Action" }],
74
- rtl: [
75
- { label: "\u0632\u0631 \u0627\u0644\u0631\u0627\u0628\u0637" },
76
- { label: "\u0632\u0631 \u0627\u0644\u0631\u0627\u0628\u0637" },
77
- ],
78
- }
79
-
80
- const defaultCopy = {
81
- ltr: {
82
- title: "Alert title",
83
- description:
84
- "Lorem ipsum dolor sit amet consectetur. Libero feugiat velit risus egestas blandit eget curabitur.",
85
- },
86
- rtl: {
87
- title:
88
- "\u0623\u062f\u062e\u0644 \u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u062a\u0646\u0628\u064a\u0647 \u0627\u0644\u062e\u0627\u0635 \u0628\u0643 \u0647\u0646\u0627!",
89
- description:
90
- "\u0623\u062f\u062e\u0644 \u0648\u0635\u0641 \u0627\u0644\u062a\u0646\u0628\u064a\u0647 \u0647\u0646\u0627\u060c \u0633\u064a\u0628\u062f\u0648 \u0623\u0641\u0636\u0644 \u0643\u0633\u0637\u0631\u064a\u0646 \u0645\u0646 \u0627\u0644\u0646\u0635.",
91
- },
92
- }
93
-
94
86
  const Alert = React.forwardRef<HTMLElement, AlertProps>(function Alert(
95
87
  {
96
88
  actions,
@@ -98,37 +90,57 @@ const Alert = React.forwardRef<HTMLElement, AlertProps>(function Alert(
98
90
  className,
99
91
  closeLabel,
100
92
  description,
101
- dir = "ltr",
93
+ dir,
102
94
  isExpandable = false,
95
+ messages: messageOverrides,
103
96
  onClose,
104
- showActions = true,
105
- showCloseButton = true,
106
- status = "danger",
97
+ role,
98
+ showActions,
99
+ showCloseButton,
100
+ status = "neutral",
107
101
  title,
108
102
  ...props
109
103
  },
110
104
  ref
111
105
  ) {
112
- const expanded = Boolean(isExpandable)
113
- const resolvedStatus = status ?? "danger"
114
- const copy = defaultCopy[dir]
115
- const renderedTitle = title ?? children ?? copy.title
116
- const renderedDescription = description ?? copy.description
117
- const actionItems = actions ?? defaultActions[dir]
118
- const visibleActions = showActions ? actionItems.slice(0, expanded ? 2 : 1) : []
106
+ const rootRef = React.useRef<HTMLElement | null>(null)
107
+ const resolvedDirection = useResolvedDirection(dir, rootRef)
108
+ const setRootRef = React.useCallback(
109
+ (node: HTMLElement | null) => {
110
+ rootRef.current = node
111
+ if (typeof ref === "function") ref(node)
112
+ else if (ref) ref.current = node
113
+ },
114
+ [ref]
115
+ )
116
+ const resolvedStatus = status ?? "neutral"
117
+ const renderedTitle = title ?? children
118
+ const requestedActions = (showActions ?? Boolean(actions?.length))
119
+ ? (actions ?? [])
120
+ : []
121
+ const expanded = Boolean(isExpandable && requestedActions.length > 0)
122
+ const visibleActions = requestedActions.slice(0, expanded ? 2 : 1)
123
+ const visibleCloseButton = showCloseButton ?? Boolean(onClose)
124
+ const resolvedCloseLabel =
125
+ closeLabel ?? messageOverrides?.close ?? defaultAlertMessages.close
126
+ const resolvedRole =
127
+ role ??
128
+ (resolvedStatus === "danger" || resolvedStatus === "warning"
129
+ ? "alert"
130
+ : "status")
119
131
 
120
132
  return (
121
133
  <section
122
134
  data-slot="alert"
123
135
  data-status={resolvedStatus}
124
136
  data-expandable={expanded ? "true" : "false"}
125
- dir={dir}
126
- ref={ref}
137
+ dir={resolvedDirection}
138
+ ref={setRootRef}
139
+ role={resolvedRole}
127
140
  className={cn(
128
141
  alertVariants({ status: resolvedStatus, isExpandable: expanded }),
129
- expanded && dir === "rtl" && "h-[var(--bh-alert-expanded-rtl-height)]",
130
142
  expanded &&
131
- dir === "ltr" &&
143
+ resolvedDirection === "ltr" &&
132
144
  resolvedStatus === "neutral" &&
133
145
  "[--alert-border:var(--bh-border-default)]",
134
146
  className
@@ -154,36 +166,39 @@ const Alert = React.forwardRef<HTMLElement, AlertProps>(function Alert(
154
166
  data-slot="alert-copy"
155
167
  className={cn(
156
168
  "flex flex-[1_0_0] min-w-0 text-start",
157
- expanded && "flex-col justify-center gap-[var(--bh-space-xl-12)]",
158
- dir === "rtl" && "text-right"
169
+ expanded && "flex-col gap-[var(--bh-space-xl-12)]",
170
+ resolvedDirection === "rtl" && "text-right"
159
171
  )}
160
172
  >
161
173
  <div
162
174
  data-slot="alert-info"
163
175
  className={cn(
164
176
  "flex w-full min-w-0 flex-[1_0_0] flex-col justify-center gap-[var(--bh-space-xs-4)]",
165
- dir === "rtl" && "items-end text-right"
177
+ expanded && "flex-none",
178
+ resolvedDirection === "rtl" && "items-end text-right"
166
179
  )}
167
180
  >
168
- <p
169
- data-slot="alert-title"
170
- dir="auto"
171
- className={cn(
172
- "m-0 min-w-0 w-full break-words text-[length:var(--bh-text-body-md-medium-font-size)] font-[var(--bh-font-weight-medium)] leading-[var(--bh-text-body-md-medium-line-height)] tracking-[var(--bh-text-body-md-medium-letter-spacing)] text-[var(--alert-title)]",
173
- dir === "rtl" && "[direction:rtl] text-right leading-[var(--bh-text-body-sm-regular-line-height)]"
174
- )}
175
- >
176
- {renderedTitle}
177
- </p>
178
- {expanded && (
181
+ {renderedTitle !== undefined ? (
182
+ <p
183
+ data-slot="alert-title"
184
+ dir="auto"
185
+ className={cn(
186
+ "m-0 min-w-0 w-full break-words text-[length:var(--bh-text-body-md-medium-font-size)] font-[var(--bh-font-weight-medium)] leading-[var(--bh-text-body-md-medium-line-height)] tracking-[var(--bh-text-body-md-medium-letter-spacing)] text-[var(--alert-title)]",
187
+ resolvedDirection === "rtl" && "[direction:rtl] text-right leading-[var(--bh-text-body-sm-regular-line-height)]"
188
+ )}
189
+ >
190
+ {renderedTitle}
191
+ </p>
192
+ ) : null}
193
+ {expanded && description !== undefined ? (
179
194
  <p
180
195
  data-slot="alert-description"
181
196
  dir="auto"
182
197
  className="m-0 w-full break-words text-[length:var(--bh-text-body-sm-regular-font-size)] font-[var(--bh-font-weight-regular)] leading-[var(--bh-text-body-sm-regular-line-height)] tracking-[var(--bh-text-body-sm-regular-letter-spacing)] text-[var(--alert-description)] opacity-[var(--bh-opacity-80)]"
183
198
  >
184
- {renderedDescription}
199
+ {description}
185
200
  </p>
186
- )}
201
+ ) : null}
187
202
  </div>
188
203
 
189
204
  {expanded && visibleActions.length > 0 && (
@@ -196,10 +211,10 @@ const Alert = React.forwardRef<HTMLElement, AlertProps>(function Alert(
196
211
  <AlertActions actions={visibleActions} />
197
212
  )}
198
213
 
199
- {showCloseButton && (
214
+ {visibleCloseButton && (
200
215
  <button
201
216
  data-slot="alert-close"
202
- aria-label={closeLabel}
217
+ aria-label={resolvedCloseLabel}
203
218
  className="inline-flex size-[var(--bh-alert-icon-size)] shrink-0 cursor-pointer items-center justify-center rounded-[var(--bh-radius-full)] border-0 bg-transparent p-0 text-[var(--bh-content-subtle)] outline-none focus-visible:shadow-[var(--shadow-button-focus)]"
204
219
  onClick={onClose}
205
220
  type="button"
@@ -211,7 +226,11 @@ const Alert = React.forwardRef<HTMLElement, AlertProps>(function Alert(
211
226
  )
212
227
  })
213
228
 
214
- function AlertActions({ actions }: { actions: AlertAction[] }) {
229
+ function AlertActions({
230
+ actions,
231
+ }: {
232
+ actions: AlertAction[]
233
+ }) {
215
234
  return (
216
235
  <div
217
236
  data-slot="alert-actions"
@@ -234,35 +253,37 @@ function AlertActions({ actions }: { actions: AlertAction[] }) {
234
253
 
235
254
  function AlertStatusIcon({ status }: { status: AlertStatus }) {
236
255
  if (status === "success") {
237
- return <CircleCheckIcon aria-hidden="true" className="size-[var(--bh-alert-icon-size)]" strokeWidth={2.25} />
256
+ return <CircleCheckIcon aria-hidden="true" className="size-[var(--bh-alert-icon-size)]" strokeWidth="var(--bh-icon-stroke-225)" />
238
257
  }
239
258
 
240
259
  if (status === "warning") {
241
- return <TriangleAlertIcon aria-hidden="true" className="size-[var(--bh-alert-icon-size)]" strokeWidth={2.25} />
260
+ return <TriangleAlertIcon aria-hidden="true" className="size-[var(--bh-alert-icon-size)]" strokeWidth="var(--bh-icon-stroke-225)" />
242
261
  }
243
262
 
244
263
  if (status === "info") {
245
- return <InfoIcon aria-hidden="true" className="size-[var(--bh-alert-icon-size)]" strokeWidth={2.25} />
264
+ return <InfoIcon aria-hidden="true" className="size-[var(--bh-alert-icon-size)]" strokeWidth="var(--bh-icon-stroke-225)" />
246
265
  }
247
266
 
248
267
  if (status === "neutral") {
249
- return <StarIcon aria-hidden="true" className="size-[var(--bh-alert-icon-size)]" strokeWidth={2.25} />
268
+ return <StarIcon aria-hidden="true" className="size-[var(--bh-alert-icon-size)]" strokeWidth="var(--bh-icon-stroke-225)" />
250
269
  }
251
270
 
252
- return <CircleAlertIcon aria-hidden="true" className="size-[var(--bh-alert-icon-size)]" strokeWidth={2.25} />
271
+ return <CircleAlertIcon aria-hidden="true" className="size-[var(--bh-alert-icon-size)]" strokeWidth="var(--bh-icon-stroke-225)" />
253
272
  }
254
273
 
255
274
  function CloseIcon() {
256
275
  return (
257
- <XIcon aria-hidden="true" className="size-[var(--bh-alert-icon-size)]" strokeWidth={2.25} />
276
+ <XIcon aria-hidden="true" className="size-[var(--bh-alert-icon-size)]" strokeWidth="var(--bh-icon-stroke-225)" />
258
277
  )
259
278
  }
260
279
 
261
280
  export {
281
+ arabicAlertMessages,
262
282
  Alert,
263
283
  alertVariants,
264
284
  type AlertAction,
265
285
  type AlertDirection,
286
+ type AlertMessages,
266
287
  type AlertProps,
267
288
  type AlertStatus,
268
289
  }
@@ -0,0 +1,30 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ type AspectRatioProps = React.ComponentPropsWithoutRef<
9
+ typeof AspectRatioPrimitive.Root
10
+ >
11
+
12
+ const AspectRatio = React.forwardRef<
13
+ React.ElementRef<typeof AspectRatioPrimitive.Root>,
14
+ AspectRatioProps
15
+ >(function AspectRatio({ className, ...props }, ref) {
16
+ return (
17
+ <AspectRatioPrimitive.Root
18
+ data-slot="aspect-ratio"
19
+ ref={ref}
20
+ className={cn(
21
+ "overflow-hidden rounded-[var(--bh-radius-xl-10)] bg-[var(--bh-bg-neutral-subtle)]",
22
+ className
23
+ )}
24
+ {...props}
25
+ />
26
+ )
27
+ })
28
+
29
+ export { AspectRatio }
30
+ export type { AspectRatioProps }
@@ -13,6 +13,7 @@ import {
13
13
  type SelectItemType,
14
14
  } from "./select"
15
15
  import { Tag, type TagSize } from "./tag"
16
+ import { Popover, PopoverAnchor, PopoverContent } from "./popover"
16
17
 
17
18
  import { cn } from "@/lib/utils"
18
19
 
@@ -404,8 +405,13 @@ const Autocomplete = React.forwardRef<HTMLDivElement, AutocompleteProps>(
404
405
  </div>
405
406
  ) : null}
406
407
 
407
- <div data-slot="autocomplete-control" className="relative w-full">
408
- <Input
408
+ <Popover
409
+ className="w-full"
410
+ open={menuOpen}
411
+ onOpenChange={setMenuOpen}
412
+ >
413
+ <PopoverAnchor asChild>
414
+ <Input
409
415
  aria-activedescendant={activeOptionId}
410
416
  aria-autocomplete="list"
411
417
  aria-controls={menuOpen ? listboxId : undefined}
@@ -424,7 +430,7 @@ const Autocomplete = React.forwardRef<HTMLDivElement, AutocompleteProps>(
424
430
  aria-hidden="true"
425
431
  className="size-[var(--bh-input-icon-size)]"
426
432
  focusable="false"
427
- strokeWidth={2.25}
433
+ strokeWidth="var(--bh-icon-stroke-225)"
428
434
  />
429
435
  }
430
436
  placeholder={placeholder}
@@ -439,14 +445,22 @@ const Autocomplete = React.forwardRef<HTMLDivElement, AutocompleteProps>(
439
445
  onClick={handleInputClick}
440
446
  onFocus={handleInputFocus}
441
447
  onKeyDown={handleInputKeyDown}
442
- />
443
-
444
- {menuOpen ? (
448
+ />
449
+ </PopoverAnchor>
450
+
451
+ <PopoverContent
452
+ align="start"
453
+ role="presentation"
454
+ showArrow={false}
455
+ size="auto"
456
+ className="w-[var(--bh-select-menu-width)] bg-transparent p-0 shadow-none"
457
+ onOpenAutoFocus={(event) => event.preventDefault()}
458
+ >
445
459
  <SelectMenu
446
460
  aria-multiselectable={isMultiple || undefined}
447
461
  id={listboxId}
448
462
  className={cn(
449
- "absolute start-0 top-[calc(100%+var(--bh-select-menu-offset))] z-[var(--bh-z-popover)] max-h-[var(--bh-autocomplete-menu-max-height,var(--bh-space-18xl-320))] overflow-y-auto",
463
+ "max-h-[var(--bh-autocomplete-menu-max-height,var(--bh-space-18xl-320))] overflow-y-auto",
450
464
  menuClassName
451
465
  )}
452
466
  >
@@ -486,8 +500,8 @@ const Autocomplete = React.forwardRef<HTMLDivElement, AutocompleteProps>(
486
500
  </div>
487
501
  )}
488
502
  </SelectMenu>
489
- ) : null}
490
- </div>
503
+ </PopoverContent>
504
+ </Popover>
491
505
 
492
506
  {shouldRenderHelper ? (
493
507
  <SelectHelperText
@@ -212,7 +212,7 @@ function AvatarIcon({
212
212
  <UserIcon
213
213
  aria-hidden="true"
214
214
  className="size-[var(--bh-avatar-icon-size)]"
215
- strokeWidth={2.1}
215
+ strokeWidth="var(--bh-icon-stroke-210)"
216
216
  />
217
217
  )}
218
218
  </span>
@@ -253,7 +253,7 @@ function AvatarStatus({
253
253
  <BanIcon
254
254
  aria-hidden="true"
255
255
  className="size-full"
256
- strokeWidth={2.4}
256
+ strokeWidth="var(--bh-icon-stroke-240)"
257
257
  />
258
258
  ) : null}
259
259
  </span>
@@ -298,7 +298,7 @@ function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) {
298
298
  function AvatarGroupCount({
299
299
  className,
300
300
  children,
301
- dir = "ltr",
301
+ dir,
302
302
  size,
303
303
  ...props
304
304
  }: React.ComponentProps<"span"> & VariantProps<typeof avatarVariants>) {
@@ -327,7 +327,7 @@ function AvatarActionIcon({
327
327
  <PencilIcon
328
328
  aria-hidden="true"
329
329
  className="size-[var(--bh-avatar-action-icon-size)]"
330
- strokeWidth={2.6}
330
+ strokeWidth="var(--bh-icon-stroke-260)"
331
331
  />
332
332
  )
333
333
  }
@@ -337,7 +337,7 @@ function AvatarActionIcon({
337
337
  <XIcon
338
338
  aria-hidden="true"
339
339
  className="size-[var(--bh-avatar-action-icon-size)]"
340
- strokeWidth={2.8}
340
+ strokeWidth="var(--bh-icon-stroke-280)"
341
341
  />
342
342
  )
343
343
  }
@@ -347,7 +347,7 @@ function AvatarActionIcon({
347
347
  <BadgeCheckIcon
348
348
  aria-hidden="true"
349
349
  className="size-[var(--bh-avatar-action-size)] fill-current text-[var(--bh-bg-accent-sky-base)] [stroke:var(--bh-content-on-brand)]"
350
- strokeWidth={2.4}
350
+ strokeWidth="var(--bh-icon-stroke-240)"
351
351
  />
352
352
  )
353
353
  }
@@ -356,7 +356,7 @@ function AvatarActionIcon({
356
356
  <PlusIcon
357
357
  aria-hidden="true"
358
358
  className="size-[var(--bh-avatar-action-icon-size)]"
359
- strokeWidth={2.6}
359
+ strokeWidth="var(--bh-icon-stroke-260)"
360
360
  />
361
361
  )
362
362
  }
@@ -60,7 +60,7 @@ const legacyVariantMap: Record<
60
60
  badgeStyle: "light",
61
61
  color: "blue",
62
62
  className:
63
- "bg-[var(--bh-interactive-ghost-default)] px-[var(--bh-space-none)] text-[var(--bh-content-link)] underline-offset-4 [a&]:hover:underline",
63
+ "bg-[var(--bh-interactive-ghost-default)] px-[var(--bh-space-none)] text-[var(--bh-content-link)] underline-offset-[var(--bh-space-xs-4)] [a&]:hover:underline",
64
64
  },
65
65
  }
66
66