banhaten 0.1.2 → 0.1.3

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 (231) hide show
  1. package/README.md +93 -328
  2. package/banhaten.config.example.json +1 -1
  3. package/docs/design-system/README.md +11 -0
  4. package/docs/design-system/appearance-presets.md +184 -0
  5. package/docs/design-system/appearances/default.md +94 -0
  6. package/docs/design-system/appearances/rounded.md +95 -0
  7. package/docs/design-system/appearances/sharp.md +95 -0
  8. package/docs/design-system/component-showcase-consistency-report.md +217 -0
  9. package/docs/design-system/component-token-consistency-audit.md +163 -0
  10. package/docs/design-system/components/README.md +74 -0
  11. package/docs/design-system/components/accordion.md +51 -0
  12. package/docs/design-system/components/activity-feed.md +92 -0
  13. package/docs/design-system/components/alert-dialog.md +70 -0
  14. package/docs/design-system/components/alert.md +79 -0
  15. package/docs/design-system/components/aspect-ratio.md +44 -0
  16. package/docs/design-system/components/attribute.md +87 -0
  17. package/docs/design-system/components/autocomplete.md +74 -0
  18. package/docs/design-system/components/avatar.md +52 -0
  19. package/docs/design-system/components/badge.md +53 -0
  20. package/docs/design-system/components/banner.md +85 -0
  21. package/docs/design-system/components/breadcrumbs.md +174 -0
  22. package/docs/design-system/components/button-group.md +83 -0
  23. package/docs/design-system/components/button.md +77 -0
  24. package/docs/design-system/components/card.md +78 -0
  25. package/docs/design-system/components/carousel.md +44 -0
  26. package/docs/design-system/components/catalog-components.md +45 -0
  27. package/docs/design-system/components/chart.md +43 -0
  28. package/docs/design-system/components/checkbox.md +52 -0
  29. package/docs/design-system/components/collapsible.md +48 -0
  30. package/docs/design-system/components/command-bar.md +57 -0
  31. package/docs/design-system/components/command.md +60 -0
  32. package/docs/design-system/components/context-menu.md +44 -0
  33. package/docs/design-system/components/date-picker.md +77 -0
  34. package/docs/design-system/components/divider.md +101 -0
  35. package/docs/design-system/components/empty-state.md +55 -0
  36. package/docs/design-system/components/field.md +69 -0
  37. package/docs/design-system/components/file-upload.md +185 -0
  38. package/docs/design-system/components/hover-card.md +46 -0
  39. package/docs/design-system/components/icons.md +48 -0
  40. package/docs/design-system/components/input-group.md +56 -0
  41. package/docs/design-system/components/input-otp.md +55 -0
  42. package/docs/design-system/components/input.md +48 -0
  43. package/docs/design-system/components/kbd.md +44 -0
  44. package/docs/design-system/components/label.md +48 -0
  45. package/docs/design-system/components/menu.md +59 -0
  46. package/docs/design-system/components/menubar.md +45 -0
  47. package/docs/design-system/components/modal.md +98 -0
  48. package/docs/design-system/components/native-select.md +52 -0
  49. package/docs/design-system/components/navigation-menu.md +48 -0
  50. package/docs/design-system/components/onboarding-step-list-item.md +80 -0
  51. package/docs/design-system/components/page-header.md +84 -0
  52. package/docs/design-system/components/pagination.md +49 -0
  53. package/docs/design-system/components/popover.md +58 -0
  54. package/docs/design-system/components/progress-slider.md +48 -0
  55. package/docs/design-system/components/progress.md +75 -0
  56. package/docs/design-system/components/radio-card.md +49 -0
  57. package/docs/design-system/components/radio-group.md +55 -0
  58. package/docs/design-system/components/resizable.md +42 -0
  59. package/docs/design-system/components/scroll-area.md +45 -0
  60. package/docs/design-system/components/select.md +50 -0
  61. package/docs/design-system/components/sheet.md +65 -0
  62. package/docs/design-system/components/sidebar.md +68 -0
  63. package/docs/design-system/components/skeleton.md +73 -0
  64. package/docs/design-system/components/slideout.md +63 -0
  65. package/docs/design-system/components/slider.md +61 -0
  66. package/docs/design-system/components/social-button.md +47 -0
  67. package/docs/design-system/components/spinner.md +61 -0
  68. package/docs/design-system/components/steps.md +63 -0
  69. package/docs/design-system/components/table.md +397 -0
  70. package/docs/design-system/components/tabs.md +52 -0
  71. package/docs/design-system/components/tag.md +78 -0
  72. package/docs/design-system/components/textarea.md +48 -0
  73. package/docs/design-system/components/timeline.md +81 -0
  74. package/docs/design-system/components/toast.md +56 -0
  75. package/docs/design-system/components/toggle.md +79 -0
  76. package/docs/design-system/components/toolbar.md +85 -0
  77. package/docs/design-system/components/tooltip.md +90 -0
  78. package/docs/design-system/components/typography.md +18 -0
  79. package/docs/design-system/design-system-test-missing-items.md +368 -0
  80. package/docs/design-system/icons.md +69 -0
  81. package/docs/design-system/registry-and-cli.md +41 -0
  82. package/docs/design-system/tabs.md +53 -0
  83. package/docs/design-system/token-governance.md +38 -0
  84. package/package.json +83 -65
  85. package/registry/components/alert-dialog.tsx +297 -0
  86. package/registry/components/aspect-ratio.tsx +30 -0
  87. package/registry/components/carousel.tsx +234 -0
  88. package/registry/components/chart.tsx +170 -0
  89. package/registry/components/collapsible.tsx +69 -0
  90. package/registry/components/command.tsx +174 -0
  91. package/registry/components/context-menu.tsx +236 -0
  92. package/registry/components/date-picker.tsx +1 -1
  93. package/registry/components/expanded/PageHeader.tsx +1 -1
  94. package/registry/components/expanded/breadcrumbs.css +139 -139
  95. package/registry/components/expanded/catalogComponentsShowcase.css +83 -83
  96. package/registry/components/expanded/steps.css +274 -274
  97. package/registry/components/expanded/timeline.css +264 -264
  98. package/registry/components/field.tsx +230 -0
  99. package/registry/components/hover-card.tsx +48 -0
  100. package/registry/components/input-group.tsx +130 -0
  101. package/registry/components/input.tsx +2 -2
  102. package/registry/components/kbd.tsx +44 -0
  103. package/registry/components/label.tsx +78 -0
  104. package/registry/components/menu.tsx +3 -1
  105. package/registry/components/menubar.tsx +226 -0
  106. package/registry/components/modal.tsx +109 -76
  107. package/registry/components/native-select.tsx +205 -0
  108. package/registry/components/navigation-menu.tsx +171 -0
  109. package/registry/components/radio-group.tsx +1 -1
  110. package/registry/components/resizable.tsx +74 -0
  111. package/registry/components/scroll-area.tsx +67 -0
  112. package/registry/components/select.tsx +2 -4
  113. package/registry/components/sheet.tsx +305 -0
  114. package/registry/components/sidebar.tsx +352 -0
  115. package/registry/components/social-button.tsx +74 -10
  116. package/registry/components/{expanded/tabs.css → tabs.css} +127 -106
  117. package/registry/components/tabs.tsx +242 -0
  118. package/registry/components/textarea.tsx +1 -1
  119. package/registry/components/toast.tsx +131 -0
  120. package/registry/examples/alert-dialog-demo.tsx +42 -0
  121. package/registry/examples/aspect-ratio-demo.tsx +11 -0
  122. package/registry/examples/carousel-demo.tsx +25 -0
  123. package/registry/examples/chart-demo.tsx +33 -0
  124. package/registry/examples/collapsible-demo.tsx +16 -0
  125. package/registry/examples/command-demo.tsx +42 -0
  126. package/registry/examples/context-menu-demo.tsx +29 -0
  127. package/registry/examples/expanded/tabs-demo.tsx +1 -1
  128. package/registry/examples/field-demo.tsx +51 -0
  129. package/registry/examples/hover-card-demo.tsx +23 -0
  130. package/registry/examples/input-group-demo.tsx +16 -0
  131. package/registry/examples/kbd-demo.tsx +11 -0
  132. package/registry/examples/label-demo.tsx +20 -0
  133. package/registry/examples/menubar-demo.tsx +34 -0
  134. package/registry/examples/native-select-demo.tsx +16 -0
  135. package/registry/examples/navigation-menu-demo.tsx +29 -0
  136. package/registry/examples/resizable-demo.tsx +22 -0
  137. package/registry/examples/scroll-area-demo.tsx +15 -0
  138. package/registry/examples/sheet-demo.tsx +47 -0
  139. package/registry/examples/sidebar-demo.tsx +55 -0
  140. package/registry/examples/tabs-demo.tsx +13 -0
  141. package/registry/examples/toast-demo.tsx +35 -0
  142. package/registry/index.json +655 -11
  143. package/registry/styles/globals.css +4733 -4690
  144. package/registry.json +1612 -0
  145. package/schema/config.schema.json +48 -0
  146. package/schema/registry.schema.json +85 -0
  147. package/schema/tokens.schema.json +63 -0
  148. package/src/cli/index.js +312 -18
  149. package/tokens/banhaten.tokens.json +1 -1
  150. package/registry/assets/avatars/avatar-02.jpg +0 -0
  151. package/registry/assets/avatars/avatar-03.jpg +0 -0
  152. package/registry/assets/avatars/avatar-04.jpg +0 -0
  153. package/registry/assets/avatars/avatar-05.jpg +0 -0
  154. package/registry/assets/avatars/avatar-06.jpg +0 -0
  155. package/registry/assets/avatars/avatar-07.jpg +0 -0
  156. package/registry/assets/avatars/avatar-08.jpg +0 -0
  157. package/registry/assets/avatars/avatar-09.jpg +0 -0
  158. package/registry/assets/avatars/avatar-10.jpg +0 -0
  159. package/registry/assets/avatars/avatar-11.jpg +0 -0
  160. package/registry/assets/avatars/avatar-12.jpg +0 -0
  161. package/registry/assets/avatars/avatar-13.jpg +0 -0
  162. package/registry/assets/avatars/avatar-14.jpg +0 -0
  163. package/registry/assets/avatars/avatar-15.jpg +0 -0
  164. package/registry/assets/avatars/avatar-16.jpg +0 -0
  165. package/registry/assets/avatars/avatar-17.jpg +0 -0
  166. package/registry/assets/avatars/avatar-18.jpg +0 -0
  167. package/registry/assets/avatars/avatar-19.jpg +0 -0
  168. package/registry/assets/avatars/avatar-20.jpg +0 -0
  169. package/registry/assets/avatars/avatar-21.jpg +0 -0
  170. package/registry/assets/avatars/avatar-22.jpg +0 -0
  171. package/registry/assets/avatars/avatar-23.jpg +0 -0
  172. package/registry/assets/avatars/avatar-24.jpg +0 -0
  173. package/registry/assets/avatars/avatar-25.jpg +0 -0
  174. package/registry/assets/avatars/avatar-26.jpg +0 -0
  175. package/registry/assets/avatars/avatar-27.jpg +0 -0
  176. package/registry/assets/avatars/avatar-28.jpg +0 -0
  177. package/registry/assets/avatars/avatar-29.jpg +0 -0
  178. package/registry/assets/avatars/avatar-30.jpg +0 -0
  179. package/registry/assets/avatars/avatar-31.jpg +0 -0
  180. package/registry/assets/avatars/avatar-32.jpg +0 -0
  181. package/registry/assets/avatars/avatar-33.jpg +0 -0
  182. package/registry/assets/avatars/avatar-34.jpg +0 -0
  183. package/registry/assets/avatars/avatar-35.jpg +0 -0
  184. package/registry/assets/image-assets.json +0 -744
  185. package/registry/assets/images/art-02.jpg +0 -0
  186. package/registry/assets/images/art-03.jpg +0 -0
  187. package/registry/assets/images/art-04.jpg +0 -0
  188. package/registry/assets/images/art-05.jpg +0 -0
  189. package/registry/assets/images/art-06.jpg +0 -0
  190. package/registry/assets/images/art-07.jpg +0 -0
  191. package/registry/assets/images/art-08.jpg +0 -0
  192. package/registry/assets/images/art-09.jpg +0 -0
  193. package/registry/assets/images/art-10.jpg +0 -0
  194. package/registry/assets/images/art-11.jpg +0 -0
  195. package/registry/assets/images/art-12.jpg +0 -0
  196. package/registry/assets/images/art-13.jpg +0 -0
  197. package/registry/assets/images/art-14.jpg +0 -0
  198. package/registry/assets/images/art-15.jpg +0 -0
  199. package/registry/assets/images/art-16.jpg +0 -0
  200. package/registry/assets/images/art-17.jpg +0 -0
  201. package/registry/assets/images/art-18.jpg +0 -0
  202. package/registry/assets/images/art-19.jpg +0 -0
  203. package/registry/assets/images/art-20.jpg +0 -0
  204. package/registry/assets/images/art-21.jpg +0 -0
  205. package/registry/assets/images/art-22.jpg +0 -0
  206. package/registry/assets/images/art-23.jpg +0 -0
  207. package/registry/assets/images/art-24.jpg +0 -0
  208. package/registry/assets/images/art-25.jpg +0 -0
  209. package/registry/assets/images/art-26.jpg +0 -0
  210. package/registry/assets/images/art-27.jpg +0 -0
  211. package/registry/assets/images/nature-01.jpg +0 -0
  212. package/registry/assets/images/nature-02.jpg +0 -0
  213. package/registry/assets/images/nature-03.jpg +0 -0
  214. package/registry/assets/images/nature-04.jpg +0 -0
  215. package/registry/assets/images/nature-05.jpg +0 -0
  216. package/registry/assets/images/nature-06.jpg +0 -0
  217. package/registry/assets/images/nature-07.jpg +0 -0
  218. package/registry/assets/images/nature-08.jpg +0 -0
  219. package/registry/assets/images/nature-09.jpg +0 -0
  220. package/registry/assets/images/nature-10.jpg +0 -0
  221. package/registry/assets/images/nature-11.jpg +0 -0
  222. package/registry/assets/images/nature-12.jpg +0 -0
  223. package/registry/assets/images/nature-13.jpg +0 -0
  224. package/registry/assets/images/nature-14.jpg +0 -0
  225. package/registry/assets/images/nature-15.jpg +0 -0
  226. package/registry/assets/images/nature-16.jpg +0 -0
  227. package/registry/assets/images/nature-17.jpg +0 -0
  228. package/registry/assets/images/nature-18.jpg +0 -0
  229. package/registry/assets/images/nature-19.jpg +0 -0
  230. package/registry/assets/images/nature-20.jpg +0 -0
  231. package/registry/components/expanded/Tabs.tsx +0 -86
@@ -0,0 +1,226 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as MenubarPrimitive from "@radix-ui/react-menubar"
5
+ import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
6
+
7
+ import { cn } from "@/lib/utils"
8
+
9
+ type MenubarProps = React.ComponentProps<typeof MenubarPrimitive.Root>
10
+ type MenubarTriggerProps = React.ComponentPropsWithoutRef<
11
+ typeof MenubarPrimitive.Trigger
12
+ >
13
+ type MenubarContentProps = React.ComponentPropsWithoutRef<
14
+ typeof MenubarPrimitive.Content
15
+ >
16
+ type MenubarItemProps = React.ComponentPropsWithoutRef<
17
+ typeof MenubarPrimitive.Item
18
+ > & {
19
+ inset?: boolean
20
+ }
21
+ type MenubarCheckboxItemProps = React.ComponentPropsWithoutRef<
22
+ typeof MenubarPrimitive.CheckboxItem
23
+ >
24
+ type MenubarRadioItemProps = React.ComponentPropsWithoutRef<
25
+ typeof MenubarPrimitive.RadioItem
26
+ >
27
+ type MenubarLabelProps = React.ComponentPropsWithoutRef<
28
+ typeof MenubarPrimitive.Label
29
+ > & {
30
+ inset?: boolean
31
+ }
32
+ type MenubarSeparatorProps = React.ComponentPropsWithoutRef<
33
+ typeof MenubarPrimitive.Separator
34
+ >
35
+ type MenubarShortcutProps = React.ComponentProps<"span">
36
+
37
+ const MenubarMenu = MenubarPrimitive.Menu
38
+ const MenubarGroup = MenubarPrimitive.Group
39
+ const MenubarPortal = MenubarPrimitive.Portal
40
+ const MenubarSub = MenubarPrimitive.Sub
41
+ const MenubarRadioGroup = MenubarPrimitive.RadioGroup
42
+
43
+ const Menubar = React.forwardRef<
44
+ React.ElementRef<typeof MenubarPrimitive.Root>,
45
+ MenubarProps
46
+ >(function Menubar({ className, ...props }, ref) {
47
+ return (
48
+ <MenubarPrimitive.Root
49
+ data-slot="menubar"
50
+ ref={ref}
51
+ className={cn(
52
+ "flex h-[var(--bh-space-7xl-40)] items-center gap-[var(--bh-space-xs-4)] rounded-[var(--bh-radius-lg-8)] border border-[var(--bh-border-subtle)] bg-[var(--bh-bg-raised)] p-[var(--bh-space-xs-4)] shadow-[var(--shadow-component-default)]",
53
+ className
54
+ )}
55
+ {...props}
56
+ />
57
+ )
58
+ })
59
+
60
+ const MenubarTrigger = React.forwardRef<
61
+ React.ElementRef<typeof MenubarPrimitive.Trigger>,
62
+ MenubarTriggerProps
63
+ >(function MenubarTrigger({ className, ...props }, ref) {
64
+ return (
65
+ <MenubarPrimitive.Trigger
66
+ data-slot="menubar-trigger"
67
+ ref={ref}
68
+ className={cn(
69
+ "flex h-[var(--bh-space-6xl-32)] items-center rounded-[var(--bh-radius-md-6)] px-[var(--bh-space-md-8)] text-[length:var(--bh-text-body-sm-medium-font-size)] font-[var(--bh-text-body-sm-medium-font-weight)] leading-[var(--bh-text-body-sm-medium-line-height)] tracking-[var(--bh-text-body-sm-medium-letter-spacing)] text-[var(--bh-content-default)] outline-none data-[highlighted]:bg-[var(--bh-interactive-ghost-hover)] data-[state=open]:bg-[var(--bh-interactive-soft-default)]",
70
+ className
71
+ )}
72
+ {...props}
73
+ />
74
+ )
75
+ })
76
+
77
+ const menuContentClassName =
78
+ "z-[var(--bh-z-popover)] min-w-[var(--bh-menu-width)] overflow-hidden rounded-[var(--bh-radius-xl-10)] bg-[var(--bh-bg-raised)] p-[var(--bh-space-xs-4)] text-[var(--bh-content-default)] shadow-[var(--shadow-menu)]"
79
+
80
+ const menuItemClassName =
81
+ "relative flex min-h-[var(--bh-menu-item-min-height)] cursor-default select-none items-center gap-[var(--bh-space-md-8)] rounded-[var(--bh-radius-md-6)] px-[var(--bh-space-md-8)] py-[var(--bh-space-sm-6)] text-start text-[length:var(--bh-text-body-sm-regular-font-size)] font-[var(--bh-text-body-sm-regular-font-weight)] leading-[var(--bh-text-body-sm-regular-line-height)] tracking-[var(--bh-text-body-sm-regular-letter-spacing)] text-[var(--bh-content-default)] outline-none data-[disabled]:pointer-events-none data-[disabled]:text-[var(--bh-content-disabled)] data-[highlighted]:bg-[var(--bh-menu-item-hover-bg)]"
82
+
83
+ const MenubarContent = React.forwardRef<
84
+ React.ElementRef<typeof MenubarPrimitive.Content>,
85
+ MenubarContentProps
86
+ >(function MenubarContent({ align = "start", className, ...props }, ref) {
87
+ return (
88
+ <MenubarPortal>
89
+ <MenubarPrimitive.Content
90
+ align={align}
91
+ data-slot="menubar-content"
92
+ ref={ref}
93
+ className={cn(menuContentClassName, className)}
94
+ {...props}
95
+ />
96
+ </MenubarPortal>
97
+ )
98
+ })
99
+
100
+ const MenubarItem = React.forwardRef<
101
+ React.ElementRef<typeof MenubarPrimitive.Item>,
102
+ MenubarItemProps
103
+ >(function MenubarItem({ className, inset, ...props }, ref) {
104
+ return (
105
+ <MenubarPrimitive.Item
106
+ data-inset={inset ? "true" : undefined}
107
+ data-slot="menubar-item"
108
+ ref={ref}
109
+ className={cn(menuItemClassName, inset && "ps-[var(--bh-space-8xl-48)]", className)}
110
+ {...props}
111
+ />
112
+ )
113
+ })
114
+
115
+ const MenubarCheckboxItem = React.forwardRef<
116
+ React.ElementRef<typeof MenubarPrimitive.CheckboxItem>,
117
+ MenubarCheckboxItemProps
118
+ >(function MenubarCheckboxItem({ children, className, checked, ...props }, ref) {
119
+ return (
120
+ <MenubarPrimitive.CheckboxItem
121
+ checked={checked}
122
+ data-slot="menubar-checkbox-item"
123
+ ref={ref}
124
+ className={cn(menuItemClassName, "ps-[var(--bh-space-8xl-48)]", className)}
125
+ {...props}
126
+ >
127
+ <span className="absolute start-[var(--bh-space-md-8)] inline-flex size-[var(--bh-space-5xl-24)] items-center justify-center">
128
+ <MenubarPrimitive.ItemIndicator>
129
+ <CheckIcon className="size-[var(--bh-space-3xl-16)]" />
130
+ </MenubarPrimitive.ItemIndicator>
131
+ </span>
132
+ {children}
133
+ </MenubarPrimitive.CheckboxItem>
134
+ )
135
+ })
136
+
137
+ const MenubarRadioItem = React.forwardRef<
138
+ React.ElementRef<typeof MenubarPrimitive.RadioItem>,
139
+ MenubarRadioItemProps
140
+ >(function MenubarRadioItem({ children, className, ...props }, ref) {
141
+ return (
142
+ <MenubarPrimitive.RadioItem
143
+ data-slot="menubar-radio-item"
144
+ ref={ref}
145
+ className={cn(menuItemClassName, "ps-[var(--bh-space-8xl-48)]", className)}
146
+ {...props}
147
+ >
148
+ <span className="absolute start-[var(--bh-space-md-8)] inline-flex size-[var(--bh-space-5xl-24)] items-center justify-center">
149
+ <MenubarPrimitive.ItemIndicator>
150
+ <CircleIcon className="size-[var(--bh-space-md-8)] fill-current" />
151
+ </MenubarPrimitive.ItemIndicator>
152
+ </span>
153
+ {children}
154
+ </MenubarPrimitive.RadioItem>
155
+ )
156
+ })
157
+
158
+ const MenubarLabel = React.forwardRef<
159
+ React.ElementRef<typeof MenubarPrimitive.Label>,
160
+ MenubarLabelProps
161
+ >(function MenubarLabel({ className, inset, ...props }, ref) {
162
+ return (
163
+ <MenubarPrimitive.Label
164
+ data-slot="menubar-label"
165
+ ref={ref}
166
+ className={cn(
167
+ "px-[var(--bh-space-md-8)] py-[var(--bh-space-sm-6)] text-[length:var(--bh-text-body-xs-medium-font-size)] font-[var(--bh-text-body-xs-medium-font-weight)] leading-[var(--bh-text-body-xs-medium-line-height)] tracking-[var(--bh-text-body-xs-medium-letter-spacing)] text-[var(--bh-content-muted)]",
168
+ inset && "ps-[var(--bh-space-8xl-48)]",
169
+ className
170
+ )}
171
+ {...props}
172
+ />
173
+ )
174
+ })
175
+
176
+ const MenubarSeparator = React.forwardRef<
177
+ React.ElementRef<typeof MenubarPrimitive.Separator>,
178
+ MenubarSeparatorProps
179
+ >(function MenubarSeparator({ className, ...props }, ref) {
180
+ return (
181
+ <MenubarPrimitive.Separator
182
+ data-slot="menubar-separator"
183
+ ref={ref}
184
+ className={cn("my-[var(--bh-space-xs-4)] h-[var(--bh-border-width-default)] bg-[var(--bh-border-subtle)]", className)}
185
+ {...props}
186
+ />
187
+ )
188
+ })
189
+
190
+ function MenubarShortcut({ className, ...props }: MenubarShortcutProps) {
191
+ return (
192
+ <span
193
+ data-slot="menubar-shortcut"
194
+ className={cn("ms-auto text-[length:var(--bh-text-body-xs-medium-font-size)] font-[var(--bh-text-body-xs-medium-font-weight)] text-[var(--bh-content-muted)]", className)}
195
+ {...props}
196
+ />
197
+ )
198
+ }
199
+
200
+ export {
201
+ Menubar,
202
+ MenubarCheckboxItem,
203
+ MenubarContent,
204
+ MenubarGroup,
205
+ MenubarItem,
206
+ MenubarLabel,
207
+ MenubarMenu,
208
+ MenubarPortal,
209
+ MenubarRadioGroup,
210
+ MenubarRadioItem,
211
+ MenubarSeparator,
212
+ MenubarShortcut,
213
+ MenubarSub,
214
+ MenubarTrigger,
215
+ }
216
+ export type {
217
+ MenubarCheckboxItemProps,
218
+ MenubarContentProps,
219
+ MenubarItemProps,
220
+ MenubarLabelProps,
221
+ MenubarProps,
222
+ MenubarRadioItemProps,
223
+ MenubarSeparatorProps,
224
+ MenubarShortcutProps,
225
+ MenubarTriggerProps,
226
+ }
@@ -5,6 +5,15 @@ import * as DialogPrimitive from "@radix-ui/react-dialog"
5
5
  import { cva, type VariantProps } from "class-variance-authority"
6
6
  import { InfoIcon, TriangleAlertIcon, XIcon } from "lucide-react"
7
7
 
8
+ import {
9
+ AlertDialog,
10
+ AlertDialogAction,
11
+ AlertDialogCancel,
12
+ AlertDialogContent,
13
+ AlertDialogDescription,
14
+ AlertDialogTitle,
15
+ type AlertDialogContentProps,
16
+ } from "@/components/ui/alert-dialog"
8
17
  import { Button, type ButtonProps } from "@/components/ui/button"
9
18
  import { Checkbox, type CheckboxProps } from "@/components/ui/checkbox"
10
19
  import { Spinner } from "@/components/ui/spinner"
@@ -57,6 +66,12 @@ const modalHeaderIconIntentClassNames: Record<ModalIntent, string> = {
57
66
  "rounded-[var(--bh-radius-full)] bg-[var(--bh-bg-warning-subtle)] text-[var(--bh-content-warning-default)]",
58
67
  }
59
68
 
69
+ const modalTitleClassName =
70
+ "min-w-0 flex-1 text-start text-[length:var(--bh-text-heading-sm-semibold-font-size)] font-[var(--bh-text-heading-sm-semibold-font-weight)] leading-[var(--bh-text-heading-sm-semibold-line-height)] tracking-[var(--bh-text-heading-sm-semibold-letter-spacing)] text-[var(--bh-content-default)]"
71
+
72
+ const modalDescriptionClassName =
73
+ "min-w-0 flex-1 text-start text-[length:var(--bh-text-body-md-regular-font-size)] font-[var(--bh-text-body-md-regular-font-weight)] leading-[var(--bh-text-body-md-regular-line-height)] tracking-[var(--bh-text-body-md-regular-letter-spacing)] text-[var(--bh-content-subtle)]"
74
+
60
75
  type ModalRootProps = React.ComponentProps<typeof DialogPrimitive.Root>
61
76
  type ModalContentProps = React.ComponentPropsWithoutRef<
62
77
  typeof DialogPrimitive.Content
@@ -79,6 +94,7 @@ type ModalHeaderIconProps = React.ComponentProps<"span"> & {
79
94
  type ModalCloseButtonProps = React.ComponentProps<"button"> & {
80
95
  label?: string
81
96
  }
97
+ type ConfirmModalContentProps = AlertDialogContentProps
82
98
  type ModalFooterCheckboxProps = Omit<React.ComponentProps<"div">, "children"> & {
83
99
  checked?: CheckboxProps["checked"]
84
100
  defaultChecked?: CheckboxProps["defaultChecked"]
@@ -238,13 +254,10 @@ const ModalTitle = React.forwardRef<
238
254
  >(function ModalTitle({ className, dir = "auto", ...props }, ref) {
239
255
  return (
240
256
  <DialogPrimitive.Title
241
- data-slot="modal-title"
242
- dir={dir}
243
- ref={ref}
244
- className={cn(
245
- "min-w-0 flex-1 text-start text-[length:var(--bh-text-heading-sm-semibold-font-size)] font-[var(--bh-text-heading-sm-semibold-font-weight)] leading-[var(--bh-text-heading-sm-semibold-line-height)] tracking-[var(--bh-text-heading-sm-semibold-letter-spacing)] text-[var(--bh-content-default)]",
246
- className
247
- )}
257
+ data-slot="modal-title"
258
+ dir={dir}
259
+ ref={ref}
260
+ className={cn(modalTitleClassName, className)}
248
261
  {...props}
249
262
  />
250
263
  )
@@ -256,18 +269,47 @@ const ModalDescription = React.forwardRef<
256
269
  >(function ModalDescription({ className, dir = "auto", ...props }, ref) {
257
270
  return (
258
271
  <DialogPrimitive.Description
259
- data-slot="modal-description"
260
- dir={dir}
261
- ref={ref}
262
- className={cn(
263
- "min-w-0 flex-1 text-start text-[length:var(--bh-text-body-md-regular-font-size)] font-[var(--bh-text-body-md-regular-font-weight)] leading-[var(--bh-text-body-md-regular-line-height)] tracking-[var(--bh-text-body-md-regular-letter-spacing)] text-[var(--bh-content-subtle)]",
264
- className
265
- )}
272
+ data-slot="modal-description"
273
+ dir={dir}
274
+ ref={ref}
275
+ className={cn(modalDescriptionClassName, className)}
266
276
  {...props}
267
277
  />
268
278
  )
269
279
  })
270
280
 
281
+ const ConfirmModalCloseButton = React.forwardRef<
282
+ HTMLButtonElement,
283
+ ModalCloseButtonProps
284
+ >(function ConfirmModalCloseButton(
285
+ { children, className, label = "Close modal", type = "button", ...props },
286
+ ref
287
+ ) {
288
+ return (
289
+ <AlertDialogCancel asChild>
290
+ <button
291
+ aria-label={label}
292
+ data-slot="modal-close"
293
+ ref={ref}
294
+ type={type}
295
+ className={cn(
296
+ "absolute end-[var(--bh-space-3xl-16)] top-1/2 inline-flex size-[var(--bh-space-6xl-32)] -translate-y-1/2 items-center justify-center rounded-[var(--bh-radius-full)] border-0 bg-transparent p-0 text-[var(--bh-content-subtle)] outline-none transition-[background-color,box-shadow,color] hover:bg-[var(--bh-interactive-ghost-hover)] hover:text-[var(--bh-content-default)] focus-visible:shadow-[var(--shadow-button-focus)]",
297
+ className
298
+ )}
299
+ {...props}
300
+ >
301
+ {children ?? (
302
+ <XIcon
303
+ aria-hidden="true"
304
+ className="size-[var(--bh-space-5xl-24)]"
305
+ strokeWidth={2}
306
+ />
307
+ )}
308
+ </button>
309
+ </AlertDialogCancel>
310
+ )
311
+ })
312
+
271
313
  const ModalBody = React.forwardRef<HTMLDivElement, ModalBodyProps>(function ModalBody({
272
314
  className,
273
315
  ...props
@@ -539,18 +581,18 @@ function ConfirmModal({
539
581
  description,
540
582
  dir,
541
583
  intent = "danger",
542
- modal = true,
584
+ modal: _modal = true,
543
585
  onCancel,
544
586
  onConfirm,
545
587
  onEscapeKeyDown,
546
- onInteractOutside,
547
588
  onOpenAutoFocus,
548
589
  onOpenChange,
549
- onPointerDownOutside,
590
+ onInteractOutside: _onInteractOutside,
591
+ onPointerDownOutside: _onPointerDownOutside,
550
592
  open,
551
593
  overlayClassName,
552
594
  preventEscapeDismiss = false,
553
- preventOutsideDismiss = true,
595
+ preventOutsideDismiss: _preventOutsideDismiss = true,
554
596
  showCancelButton = true,
555
597
  showCloseButton = false,
556
598
  showDivider = true,
@@ -565,8 +607,8 @@ function ConfirmModal({
565
607
  const isRtl = dir === "rtl"
566
608
  const rootProps =
567
609
  open === undefined
568
- ? { defaultOpen, modal, onOpenChange }
569
- : { modal, onOpenChange, open }
610
+ ? { defaultOpen, onOpenChange }
611
+ : { onOpenChange, open }
570
612
  const resolvedTitle = title ?? (isRtl ? defaultRtlConfirmTitle : defaultConfirmTitle)
571
613
  const resolvedDescription =
572
614
  description ?? (isRtl ? defaultRtlConfirmDescription : defaultConfirmDescription)
@@ -592,57 +634,36 @@ function ConfirmModal({
592
634
  } = confirmButtonProps ?? {}
593
635
  const isConfirmDisabled = confirmDisabled || confirmLoading || confirmButtonDisabled
594
636
 
595
- const handleOpenAutoFocus: NonNullable<ModalContentProps["onOpenAutoFocus"]> =
596
- React.useCallback(
597
- (event) => {
598
- onOpenAutoFocus?.(event)
599
- if (event.defaultPrevented) return
637
+ const handleOpenAutoFocus: NonNullable<
638
+ ConfirmModalContentProps["onOpenAutoFocus"]
639
+ > = React.useCallback(
640
+ (event) => {
641
+ onOpenAutoFocus?.(event)
642
+ if (event.defaultPrevented) return
600
643
 
601
- const focusTarget = showCancelButton
602
- ? cancelButtonRef.current
603
- : confirmButtonRef.current
604
- if (!focusTarget) return
644
+ const focusTarget = showCancelButton
645
+ ? cancelButtonRef.current
646
+ : confirmButtonRef.current
647
+ if (!focusTarget) return
605
648
 
606
- event.preventDefault()
607
- focusTarget.focus()
608
- },
609
- [onOpenAutoFocus, showCancelButton]
610
- )
649
+ event.preventDefault()
650
+ focusTarget.focus()
651
+ },
652
+ [onOpenAutoFocus, showCancelButton]
653
+ )
611
654
 
612
- const handlePointerDownOutside: NonNullable<
613
- ModalContentProps["onPointerDownOutside"]
655
+ const handleEscapeKeyDown: NonNullable<
656
+ ConfirmModalContentProps["onEscapeKeyDown"]
614
657
  > = React.useCallback(
615
658
  (event) => {
616
- onPointerDownOutside?.(event)
617
- if (!event.defaultPrevented && preventOutsideDismiss) {
659
+ onEscapeKeyDown?.(event)
660
+ if (!event.defaultPrevented && preventEscapeDismiss) {
618
661
  event.preventDefault()
619
662
  }
620
663
  },
621
- [onPointerDownOutside, preventOutsideDismiss]
664
+ [onEscapeKeyDown, preventEscapeDismiss]
622
665
  )
623
666
 
624
- const handleInteractOutside: NonNullable<ModalContentProps["onInteractOutside"]> =
625
- React.useCallback(
626
- (event) => {
627
- onInteractOutside?.(event)
628
- if (!event.defaultPrevented && preventOutsideDismiss) {
629
- event.preventDefault()
630
- }
631
- },
632
- [onInteractOutside, preventOutsideDismiss]
633
- )
634
-
635
- const handleEscapeKeyDown: NonNullable<ModalContentProps["onEscapeKeyDown"]> =
636
- React.useCallback(
637
- (event) => {
638
- onEscapeKeyDown?.(event)
639
- if (!event.defaultPrevented && preventEscapeDismiss) {
640
- event.preventDefault()
641
- }
642
- },
643
- [onEscapeKeyDown, preventEscapeDismiss]
644
- )
645
-
646
667
  const handleCancel: React.MouseEventHandler<HTMLButtonElement> = (event) => {
647
668
  cancelButtonOnClick?.(event)
648
669
  if (!event.defaultPrevented) {
@@ -691,26 +712,26 @@ function ConfirmModal({
691
712
  )
692
713
 
693
714
  return (
694
- <ModalRoot {...rootProps}>
695
- <ModalContent
715
+ <AlertDialog {...rootProps}>
716
+ <AlertDialogContent
696
717
  data-intent={intent}
718
+ data-size={size}
697
719
  data-slot="confirm-modal"
698
720
  dir={dir}
721
+ className={cn(modalContentVariants({ size, className }))}
699
722
  overlayClassName={overlayClassName}
700
- role="alertdialog"
701
- size={size}
702
- className={className}
703
723
  onEscapeKeyDown={handleEscapeKeyDown}
704
- onInteractOutside={handleInteractOutside}
705
724
  onOpenAutoFocus={handleOpenAutoFocus}
706
- onPointerDownOutside={handlePointerDownOutside}
707
725
  {...props}
708
726
  >
709
727
  <ModalHeader>
710
728
  {showIcon ? (
711
729
  <ModalHeaderIcon intent={intent}>
712
730
  {intent === "default" ? (
713
- <InfoIcon className="size-[var(--bh-space-3xl-16)]" strokeWidth={2} />
731
+ <InfoIcon
732
+ className="size-[var(--bh-space-3xl-16)]"
733
+ strokeWidth={2}
734
+ />
714
735
  ) : (
715
736
  <TriangleAlertIcon
716
737
  className="size-[var(--bh-space-3xl-16)]"
@@ -719,31 +740,43 @@ function ConfirmModal({
719
740
  )}
720
741
  </ModalHeaderIcon>
721
742
  ) : null}
722
- <ModalTitle>{resolvedTitle}</ModalTitle>
723
- {showCloseButton ? <ModalCloseButton /> : null}
743
+ <AlertDialogTitle
744
+ data-slot="modal-title"
745
+ className={modalTitleClassName}
746
+ >
747
+ {resolvedTitle}
748
+ </AlertDialogTitle>
749
+ {showCloseButton ? <ConfirmModalCloseButton /> : null}
724
750
  </ModalHeader>
725
751
  <ModalBody>
726
- {children ?? <ModalDescription>{resolvedDescription}</ModalDescription>}
752
+ {children ?? (
753
+ <AlertDialogDescription
754
+ data-slot="modal-description"
755
+ className={modalDescriptionClassName}
756
+ >
757
+ {resolvedDescription}
758
+ </AlertDialogDescription>
759
+ )}
727
760
  </ModalBody>
728
761
  {showDivider ? <ModalDivider /> : null}
729
762
  {showFooter ? (
730
763
  <ModalFooter>
731
764
  <ModalActions>
732
765
  {cancelAction && closeOnCancel ? (
733
- <ModalClose asChild>{cancelAction}</ModalClose>
766
+ <AlertDialogCancel asChild>{cancelAction}</AlertDialogCancel>
734
767
  ) : (
735
768
  cancelAction
736
769
  )}
737
770
  {closeOnConfirm ? (
738
- <ModalClose asChild>{confirmAction}</ModalClose>
771
+ <AlertDialogAction asChild>{confirmAction}</AlertDialogAction>
739
772
  ) : (
740
773
  confirmAction
741
774
  )}
742
775
  </ModalActions>
743
776
  </ModalFooter>
744
777
  ) : null}
745
- </ModalContent>
746
- </ModalRoot>
778
+ </AlertDialogContent>
779
+ </AlertDialog>
747
780
  )
748
781
  }
749
782