banhaten 0.1.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 (201) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +361 -0
  3. package/banhaten.config.example.json +13 -0
  4. package/package.json +59 -0
  5. package/registry/assets/activity-feed-avatar.png +0 -0
  6. package/registry/assets/avatars/avatar-01.jpg +0 -0
  7. package/registry/assets/avatars/avatar-02.jpg +0 -0
  8. package/registry/assets/avatars/avatar-03.jpg +0 -0
  9. package/registry/assets/avatars/avatar-04.jpg +0 -0
  10. package/registry/assets/avatars/avatar-05.jpg +0 -0
  11. package/registry/assets/avatars/avatar-06.jpg +0 -0
  12. package/registry/assets/avatars/avatar-07.jpg +0 -0
  13. package/registry/assets/avatars/avatar-08.jpg +0 -0
  14. package/registry/assets/avatars/avatar-09.jpg +0 -0
  15. package/registry/assets/avatars/avatar-10.jpg +0 -0
  16. package/registry/assets/avatars/avatar-11.jpg +0 -0
  17. package/registry/assets/avatars/avatar-12.jpg +0 -0
  18. package/registry/assets/avatars/avatar-13.jpg +0 -0
  19. package/registry/assets/avatars/avatar-14.jpg +0 -0
  20. package/registry/assets/avatars/avatar-15.jpg +0 -0
  21. package/registry/assets/avatars/avatar-16.jpg +0 -0
  22. package/registry/assets/avatars/avatar-17.jpg +0 -0
  23. package/registry/assets/avatars/avatar-18.jpg +0 -0
  24. package/registry/assets/avatars/avatar-19.jpg +0 -0
  25. package/registry/assets/avatars/avatar-20.jpg +0 -0
  26. package/registry/assets/avatars/avatar-21.jpg +0 -0
  27. package/registry/assets/avatars/avatar-22.jpg +0 -0
  28. package/registry/assets/avatars/avatar-23.jpg +0 -0
  29. package/registry/assets/avatars/avatar-24.jpg +0 -0
  30. package/registry/assets/avatars/avatar-25.jpg +0 -0
  31. package/registry/assets/avatars/avatar-26.jpg +0 -0
  32. package/registry/assets/avatars/avatar-27.jpg +0 -0
  33. package/registry/assets/avatars/avatar-28.jpg +0 -0
  34. package/registry/assets/avatars/avatar-29.jpg +0 -0
  35. package/registry/assets/avatars/avatar-30.jpg +0 -0
  36. package/registry/assets/avatars/avatar-31.jpg +0 -0
  37. package/registry/assets/avatars/avatar-32.jpg +0 -0
  38. package/registry/assets/avatars/avatar-33.jpg +0 -0
  39. package/registry/assets/avatars/avatar-34.jpg +0 -0
  40. package/registry/assets/avatars/avatar-35.jpg +0 -0
  41. package/registry/assets/image-assets.json +744 -0
  42. package/registry/assets/images/art-01.jpg +0 -0
  43. package/registry/assets/images/art-02.jpg +0 -0
  44. package/registry/assets/images/art-03.jpg +0 -0
  45. package/registry/assets/images/art-04.jpg +0 -0
  46. package/registry/assets/images/art-05.jpg +0 -0
  47. package/registry/assets/images/art-06.jpg +0 -0
  48. package/registry/assets/images/art-07.jpg +0 -0
  49. package/registry/assets/images/art-08.jpg +0 -0
  50. package/registry/assets/images/art-09.jpg +0 -0
  51. package/registry/assets/images/art-10.jpg +0 -0
  52. package/registry/assets/images/art-11.jpg +0 -0
  53. package/registry/assets/images/art-12.jpg +0 -0
  54. package/registry/assets/images/art-13.jpg +0 -0
  55. package/registry/assets/images/art-14.jpg +0 -0
  56. package/registry/assets/images/art-15.jpg +0 -0
  57. package/registry/assets/images/art-16.jpg +0 -0
  58. package/registry/assets/images/art-17.jpg +0 -0
  59. package/registry/assets/images/art-18.jpg +0 -0
  60. package/registry/assets/images/art-19.jpg +0 -0
  61. package/registry/assets/images/art-20.jpg +0 -0
  62. package/registry/assets/images/art-21.jpg +0 -0
  63. package/registry/assets/images/art-22.jpg +0 -0
  64. package/registry/assets/images/art-23.jpg +0 -0
  65. package/registry/assets/images/art-24.jpg +0 -0
  66. package/registry/assets/images/art-25.jpg +0 -0
  67. package/registry/assets/images/art-26.jpg +0 -0
  68. package/registry/assets/images/art-27.jpg +0 -0
  69. package/registry/assets/images/nature-01.jpg +0 -0
  70. package/registry/assets/images/nature-02.jpg +0 -0
  71. package/registry/assets/images/nature-03.jpg +0 -0
  72. package/registry/assets/images/nature-04.jpg +0 -0
  73. package/registry/assets/images/nature-05.jpg +0 -0
  74. package/registry/assets/images/nature-06.jpg +0 -0
  75. package/registry/assets/images/nature-07.jpg +0 -0
  76. package/registry/assets/images/nature-08.jpg +0 -0
  77. package/registry/assets/images/nature-09.jpg +0 -0
  78. package/registry/assets/images/nature-10.jpg +0 -0
  79. package/registry/assets/images/nature-11.jpg +0 -0
  80. package/registry/assets/images/nature-12.jpg +0 -0
  81. package/registry/assets/images/nature-13.jpg +0 -0
  82. package/registry/assets/images/nature-14.jpg +0 -0
  83. package/registry/assets/images/nature-15.jpg +0 -0
  84. package/registry/assets/images/nature-16.jpg +0 -0
  85. package/registry/assets/images/nature-17.jpg +0 -0
  86. package/registry/assets/images/nature-18.jpg +0 -0
  87. package/registry/assets/images/nature-19.jpg +0 -0
  88. package/registry/assets/images/nature-20.jpg +0 -0
  89. package/registry/components/accordion.tsx +119 -0
  90. package/registry/components/alert.tsx +282 -0
  91. package/registry/components/attribute.tsx +452 -0
  92. package/registry/components/avatar.tsx +142 -0
  93. package/registry/components/badge.tsx +567 -0
  94. package/registry/components/button-group.tsx +246 -0
  95. package/registry/components/button.tsx +102 -0
  96. package/registry/components/card.tsx +613 -0
  97. package/registry/components/checkbox.tsx +244 -0
  98. package/registry/components/date-picker.tsx +1143 -0
  99. package/registry/components/divider.tsx +82 -0
  100. package/registry/components/expanded/ActivityFeed.tsx +226 -0
  101. package/registry/components/expanded/Banner.tsx +145 -0
  102. package/registry/components/expanded/BannerBoard.tsx +225 -0
  103. package/registry/components/expanded/Breadcrumbs.tsx +156 -0
  104. package/registry/components/expanded/CatalogComponentsShowcase.tsx +211 -0
  105. package/registry/components/expanded/CatalogDivider.tsx +48 -0
  106. package/registry/components/expanded/CatalogTag.tsx +92 -0
  107. package/registry/components/expanded/CommandBar.tsx +406 -0
  108. package/registry/components/expanded/FileUpload.tsx +231 -0
  109. package/registry/components/expanded/IconExplorer.tsx +612 -0
  110. package/registry/components/expanded/OnboardingStepListItem.tsx +67 -0
  111. package/registry/components/expanded/PageHeader.tsx +184 -0
  112. package/registry/components/expanded/Slideout.tsx +514 -0
  113. package/registry/components/expanded/Steps.tsx +266 -0
  114. package/registry/components/expanded/Table.tsx +1014 -0
  115. package/registry/components/expanded/Tabs.tsx +86 -0
  116. package/registry/components/expanded/Timeline.tsx +235 -0
  117. package/registry/components/expanded/TimelineShowcase.tsx +158 -0
  118. package/registry/components/expanded/activityFeed.css +292 -0
  119. package/registry/components/expanded/banner.css +312 -0
  120. package/registry/components/expanded/breadcrumbs.css +140 -0
  121. package/registry/components/expanded/catalogComponentsShowcase.css +87 -0
  122. package/registry/components/expanded/commandBar.css +473 -0
  123. package/registry/components/expanded/divider.css +75 -0
  124. package/registry/components/expanded/fileUpload.css +228 -0
  125. package/registry/components/expanded/iconExplorer.css +764 -0
  126. package/registry/components/expanded/iconPacks.ts +866 -0
  127. package/registry/components/expanded/onboardingStepListItem.css +126 -0
  128. package/registry/components/expanded/pageHeader.css +287 -0
  129. package/registry/components/expanded/slideout.css +955 -0
  130. package/registry/components/expanded/steps.css +329 -0
  131. package/registry/components/expanded/table.css +607 -0
  132. package/registry/components/expanded/tabs.css +197 -0
  133. package/registry/components/expanded/tag.css +148 -0
  134. package/registry/components/expanded/timeline.css +282 -0
  135. package/registry/components/input-content.ts +106 -0
  136. package/registry/components/input.tsx +866 -0
  137. package/registry/components/menu.tsx +758 -0
  138. package/registry/components/modal.tsx +799 -0
  139. package/registry/components/pagination.tsx +543 -0
  140. package/registry/components/progress-slider.tsx +216 -0
  141. package/registry/components/progress.tsx +367 -0
  142. package/registry/components/radio-card.tsx +654 -0
  143. package/registry/components/radio-group.tsx +570 -0
  144. package/registry/components/select-content.tsx +313 -0
  145. package/registry/components/select.tsx +871 -0
  146. package/registry/components/slider.tsx +380 -0
  147. package/registry/components/social-button.tsx +360 -0
  148. package/registry/components/spinner.tsx +31 -0
  149. package/registry/components/tag.tsx +423 -0
  150. package/registry/components/textarea.tsx +625 -0
  151. package/registry/components/toggle.tsx +272 -0
  152. package/registry/components/toolbar.tsx +467 -0
  153. package/registry/components/tooltip.tsx +427 -0
  154. package/registry/examples/accordion-demo.tsx +34 -0
  155. package/registry/examples/alert-demo.tsx +14 -0
  156. package/registry/examples/attribute-demo.tsx +65 -0
  157. package/registry/examples/avatar-demo.tsx +74 -0
  158. package/registry/examples/badge-demo.tsx +53 -0
  159. package/registry/examples/button-demo.tsx +83 -0
  160. package/registry/examples/button-group-demo.tsx +42 -0
  161. package/registry/examples/card-demo.tsx +48 -0
  162. package/registry/examples/checkbox-demo.tsx +67 -0
  163. package/registry/examples/date-picker-demo.tsx +74 -0
  164. package/registry/examples/divider-demo.tsx +17 -0
  165. package/registry/examples/expanded/activity-feed-demo.tsx +22 -0
  166. package/registry/examples/expanded/banner-demo.tsx +23 -0
  167. package/registry/examples/expanded/catalog-components-demo.tsx +5 -0
  168. package/registry/examples/expanded/command-bar-demo.tsx +10 -0
  169. package/registry/examples/expanded/icons-demo.tsx +5 -0
  170. package/registry/examples/expanded/onboarding-step-demo.tsx +11 -0
  171. package/registry/examples/expanded/page-header-demo.tsx +19 -0
  172. package/registry/examples/expanded/slideout-demo.tsx +15 -0
  173. package/registry/examples/expanded/steps-demo.tsx +18 -0
  174. package/registry/examples/expanded/tabs-demo.tsx +13 -0
  175. package/registry/examples/expanded/timeline-demo.tsx +18 -0
  176. package/registry/examples/input-demo.tsx +87 -0
  177. package/registry/examples/menu-demo.tsx +109 -0
  178. package/registry/examples/modal-demo.tsx +16 -0
  179. package/registry/examples/pagination-demo.tsx +17 -0
  180. package/registry/examples/progress-demo.tsx +37 -0
  181. package/registry/examples/progress-slider-demo.tsx +29 -0
  182. package/registry/examples/radio-card-demo.tsx +51 -0
  183. package/registry/examples/radio-group-demo.tsx +62 -0
  184. package/registry/examples/select-demo.tsx +73 -0
  185. package/registry/examples/slider-demo.tsx +31 -0
  186. package/registry/examples/social-button-demo.tsx +51 -0
  187. package/registry/examples/tag-demo.tsx +29 -0
  188. package/registry/examples/textarea-demo.tsx +79 -0
  189. package/registry/examples/toggle-demo.tsx +59 -0
  190. package/registry/examples/toolbar-demo.tsx +80 -0
  191. package/registry/examples/tooltip-demo.tsx +115 -0
  192. package/registry/hooks/use-direction.ts +27 -0
  193. package/registry/index.json +1213 -0
  194. package/registry/styles/globals.css +4600 -0
  195. package/registry/utils/cn.ts +6 -0
  196. package/src/cli/index.js +826 -0
  197. package/tokens/Color mode.zip +0 -0
  198. package/tokens/Numbers.zip +0 -0
  199. package/tokens/Radius.zip +0 -0
  200. package/tokens/Theme.zip +0 -0
  201. package/tokens/banhaten.tokens.json +5525 -0
@@ -0,0 +1,467 @@
1
+ import * as React from "react"
2
+ import { Slot } from "@radix-ui/react-slot"
3
+ import { cva, type VariantProps } from "class-variance-authority"
4
+ import {
5
+ ChevronDownIcon,
6
+ FilterIcon,
7
+ MoreVerticalIcon,
8
+ SearchIcon,
9
+ } from "lucide-react"
10
+
11
+ import { cn } from "@/lib/utils"
12
+
13
+ const toolbarVariants = cva(
14
+ "flex w-full max-w-full min-w-0 gap-[var(--bh-space-3xl-16)] text-[var(--bh-content-default)]",
15
+ {
16
+ variants: {
17
+ layout: {
18
+ inline: "items-start",
19
+ split: "items-start justify-between",
20
+ stack: "flex-col items-stretch",
21
+ wrap: "flex-wrap items-center",
22
+ },
23
+ wrap: {
24
+ true: "flex-wrap",
25
+ false: "",
26
+ },
27
+ },
28
+ defaultVariants: {
29
+ layout: "inline",
30
+ wrap: false,
31
+ },
32
+ }
33
+ )
34
+
35
+ const toolbarSectionVariants = cva(
36
+ "flex min-w-0 items-center gap-[var(--bh-space-xl-12)]",
37
+ {
38
+ variants: {
39
+ align: {
40
+ start: "justify-start",
41
+ center: "justify-center",
42
+ end: "justify-end",
43
+ between: "justify-between",
44
+ },
45
+ grow: {
46
+ true: "flex-1",
47
+ false: "shrink-0",
48
+ },
49
+ stack: {
50
+ true: "flex-col items-stretch",
51
+ false: "",
52
+ },
53
+ wrap: {
54
+ true: "flex-wrap",
55
+ false: "",
56
+ },
57
+ },
58
+ defaultVariants: {
59
+ align: "start",
60
+ grow: false,
61
+ stack: false,
62
+ wrap: false,
63
+ },
64
+ }
65
+ )
66
+
67
+ const toolbarButtonVariants = cva(
68
+ "group/toolbar-button inline-flex min-w-0 items-center justify-center whitespace-nowrap rounded-[var(--bh-control-default)] text-[length:var(--bh-text-button-font-size)] font-[var(--bh-text-button-font-weight)] leading-[var(--bh-text-button-line-height)] tracking-[var(--bh-text-button-letter-spacing)] outline-none transition-[background-color,border-color,color,box-shadow] focus-visible:shadow-[var(--shadow-button-focus)] disabled:pointer-events-none disabled:shadow-none aria-invalid:border aria-invalid:border-destructive aria-invalid:shadow-[var(--shadow-button-danger-focus)] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-[var(--bh-button-icon-size)] [&_svg[data-icon='inline-start']]:ms-[var(--bh-button-icon-offset)] [&_svg[data-icon='inline-end']]:me-[var(--bh-button-icon-offset)] rtl:[&_svg[data-rtl-flip='true']]:-scale-x-100",
69
+ {
70
+ variants: {
71
+ variant: {
72
+ default:
73
+ "bg-primary text-primary-foreground shadow-[var(--shadow-button-raised)] hover:bg-[var(--primary-hover)] active:bg-[var(--primary-pressed)] disabled:bg-[var(--bh-interactive-brand-disabled)] disabled:text-[var(--bh-content-disabled)]",
74
+ soft: "border border-transparent bg-[var(--soft)] text-foreground shadow-[var(--shadow-button-soft)] hover:bg-[var(--soft-hover)] active:bg-[var(--soft-pressed)] focus-visible:border-[var(--bh-border-brand-strong)] disabled:bg-[var(--bh-interactive-soft-disabled)] disabled:text-[var(--bh-content-disabled)]",
75
+ outline:
76
+ "border border-[var(--bh-border-default)] bg-[var(--outline)] text-foreground hover:bg-[var(--outline-hover)] active:bg-[var(--outline-pressed)] focus-visible:border-[var(--bh-border-brand-strong)] disabled:border-[var(--bh-border-disabled)] disabled:bg-[var(--bh-interactive-outlined-disabled)] disabled:text-[var(--bh-content-disabled)]",
77
+ ghost:
78
+ "border border-transparent bg-[var(--ghost)] text-foreground hover:bg-[var(--ghost-hover)] active:bg-[var(--ghost-pressed)] focus-visible:border-[var(--bh-border-brand-strong)] disabled:bg-[var(--bh-interactive-ghost-disabled)] disabled:text-[var(--bh-content-disabled)]",
79
+ link: "border border-transparent bg-[var(--ghost)] text-[var(--bh-content-brand-default)] hover:bg-[var(--ghost-hover)] active:bg-[var(--ghost-pressed)] focus-visible:border-[var(--bh-border-brand-strong)] disabled:bg-[var(--bh-interactive-ghost-disabled)] disabled:text-[var(--bh-content-disabled)]",
80
+ },
81
+ size: {
82
+ sm: "h-[var(--bh-button-sm-height)] gap-[var(--bh-button-gap)] px-[var(--bh-button-sm-padding-x)] py-[var(--bh-button-sm-padding-y)] has-[>svg]:px-[var(--bh-button-sm-padding-x)]",
83
+ default: "h-[var(--bh-button-md-height)] gap-[var(--bh-button-gap)] px-[var(--bh-button-md-padding-x)] py-[var(--bh-button-sm-padding-y)] has-[>svg]:px-[var(--bh-button-md-padding-x)]",
84
+ "icon-sm": "size-[var(--bh-button-sm-height)] gap-[var(--bh-space-none)] p-[var(--bh-space-none)]",
85
+ icon: "size-[var(--bh-button-md-height)] gap-[var(--bh-space-none)] p-[var(--bh-space-none)]",
86
+ },
87
+ },
88
+ defaultVariants: {
89
+ variant: "soft",
90
+ size: "default",
91
+ },
92
+ }
93
+ )
94
+
95
+ const toolbarSearchVariants = cva(
96
+ "flex h-[var(--bh-input-lg-height)] max-w-full min-w-0 items-center gap-[var(--bh-input-content-gap)] rounded-[var(--bh-input-radius)] bg-[var(--bh-interactive-input-default)] px-[var(--bh-input-lg-padding-x)] text-[var(--bh-content-default)] shadow-[var(--shadow-input)] transition-[background-color,box-shadow] focus-within:shadow-[var(--shadow-input-focus-ring)] data-[disabled=true]:pointer-events-none data-[disabled=true]:bg-[var(--bh-interactive-input-disabled)] data-[disabled=true]:text-[var(--bh-content-disabled)]",
97
+ {
98
+ variants: {
99
+ width: {
100
+ compact: "w-[calc(var(--bh-input-width)/2)]",
101
+ default: "w-[var(--bh-input-width)]",
102
+ full: "w-full",
103
+ auto: "w-auto",
104
+ },
105
+ },
106
+ defaultVariants: {
107
+ width: "default",
108
+ },
109
+ }
110
+ )
111
+
112
+ const toolbarSelectVariants = cva(
113
+ "inline-flex h-[var(--bh-input-lg-height)] max-w-full min-w-0 items-center justify-between gap-[var(--bh-space-md-8)] rounded-[var(--bh-input-radius)] bg-[var(--bh-interactive-input-default)] px-[var(--bh-select-trigger-padding-x)] 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-default)] shadow-[var(--shadow-select-trigger)] outline-none transition-[background-color,box-shadow] hover:bg-[var(--bh-interactive-input-hover)] focus-visible:shadow-[var(--shadow-input-focus-ring)] disabled:pointer-events-none disabled:bg-[var(--bh-interactive-input-disabled)] disabled:text-[var(--bh-content-disabled)]",
114
+ {
115
+ variants: {
116
+ width: {
117
+ compact: "w-[calc(var(--bh-select-width)/2)]",
118
+ default: "w-[var(--bh-select-width)]",
119
+ full: "w-full",
120
+ auto: "w-auto",
121
+ },
122
+ },
123
+ defaultVariants: {
124
+ width: "compact",
125
+ },
126
+ }
127
+ )
128
+
129
+ const toolbarBadgeVariants = cva(
130
+ "inline-flex h-[calc(var(--bh-space-5xl-24)+var(--bh-space-xs-4))] min-w-0 items-center gap-[var(--bh-space-xs-4)] rounded-[var(--bh-radius-full)] px-[var(--bh-space-xl-12)] text-[length:var(--bh-text-body-2xs-medium-font-size)] font-[var(--bh-text-body-2xs-medium-font-weight)] leading-[var(--bh-text-body-2xs-medium-line-height)] tracking-[var(--bh-text-body-2xs-medium-letter-spacing)]",
131
+ {
132
+ variants: {
133
+ variant: {
134
+ neutral:
135
+ "bg-[var(--bh-bg-neutral-subtle)] text-[var(--bh-content-default)]",
136
+ brand:
137
+ "bg-[var(--bh-bg-brand-subtle)] text-[var(--bh-content-brand-default)]",
138
+ },
139
+ },
140
+ defaultVariants: {
141
+ variant: "neutral",
142
+ },
143
+ }
144
+ )
145
+
146
+ type ToolbarProps = React.ComponentProps<"div"> &
147
+ VariantProps<typeof toolbarVariants>
148
+
149
+ const Toolbar = React.forwardRef<HTMLDivElement, ToolbarProps>(function Toolbar(
150
+ { className, layout, wrap, role = "toolbar", ...props },
151
+ ref
152
+ ) {
153
+ return (
154
+ <div
155
+ data-slot="toolbar"
156
+ ref={ref}
157
+ role={role}
158
+ className={cn(toolbarVariants({ layout, wrap, className }))}
159
+ {...props}
160
+ />
161
+ )
162
+ })
163
+
164
+ type ToolbarSectionProps = React.ComponentProps<"div"> &
165
+ VariantProps<typeof toolbarSectionVariants>
166
+
167
+ const ToolbarSection = React.forwardRef<HTMLDivElement, ToolbarSectionProps>(
168
+ function ToolbarSection(
169
+ { className, align, grow, stack, wrap, ...props },
170
+ ref
171
+ ) {
172
+ return (
173
+ <div
174
+ data-slot="toolbar-section"
175
+ ref={ref}
176
+ className={cn(
177
+ toolbarSectionVariants({ align, grow, stack, wrap, className })
178
+ )}
179
+ {...props}
180
+ />
181
+ )
182
+ }
183
+ )
184
+
185
+ type ToolbarSpacerProps = React.ComponentProps<"div">
186
+
187
+ const ToolbarSpacer = React.forwardRef<HTMLDivElement, ToolbarSpacerProps>(
188
+ function ToolbarSpacer({ className, ...props }, ref) {
189
+ return (
190
+ <div
191
+ aria-hidden="true"
192
+ data-slot="toolbar-spacer"
193
+ ref={ref}
194
+ className={cn("min-w-[var(--bh-space-xl-12)] flex-1", className)}
195
+ {...props}
196
+ />
197
+ )
198
+ }
199
+ )
200
+
201
+ type ToolbarButtonProps = React.ComponentProps<"button"> &
202
+ VariantProps<typeof toolbarButtonVariants> & {
203
+ asChild?: boolean
204
+ }
205
+
206
+ const ToolbarButton = React.forwardRef<HTMLButtonElement, ToolbarButtonProps>(
207
+ function ToolbarButton(
208
+ { className, variant, size, asChild = false, children, type = "button", ...props },
209
+ ref
210
+ ) {
211
+ const Comp = asChild ? Slot : "button"
212
+
213
+ return (
214
+ <Comp
215
+ data-slot="toolbar-button"
216
+ ref={ref}
217
+ className={cn(toolbarButtonVariants({ variant, size, className }))}
218
+ {...(!asChild ? { type } : {})}
219
+ {...props}
220
+ >
221
+ {asChild ? children : <ToolbarButtonChildren>{children}</ToolbarButtonChildren>}
222
+ </Comp>
223
+ )
224
+ }
225
+ )
226
+
227
+ function ToolbarButtonChildren({ children }: { children: React.ReactNode }) {
228
+ return React.Children.map(children, (child) => {
229
+ if (typeof child === "string" || typeof child === "number") {
230
+ return (
231
+ <span data-slot="toolbar-button-label" dir="auto" className="min-w-0 px-[var(--bh-button-label-padding-x)]">
232
+ {child}
233
+ </span>
234
+ )
235
+ }
236
+
237
+ return child
238
+ })
239
+ }
240
+
241
+ type ToolbarIconButtonProps = Omit<ToolbarButtonProps, "children"> & {
242
+ children: React.ReactNode
243
+ }
244
+
245
+ const ToolbarIconButton = React.forwardRef<HTMLButtonElement, ToolbarIconButtonProps>(
246
+ function ToolbarIconButton({ size = "icon-sm", variant = "soft", ...props }, ref) {
247
+ return <ToolbarButton ref={ref} size={size} variant={variant} {...props} />
248
+ }
249
+ )
250
+
251
+ type ToolbarFilterButtonProps = Omit<ToolbarButtonProps, "children"> & {
252
+ label?: string
253
+ }
254
+
255
+ const ToolbarFilterButton = React.forwardRef<
256
+ HTMLButtonElement,
257
+ ToolbarFilterButtonProps
258
+ >(function ToolbarFilterButton({ label = "Filters", ...props }, ref) {
259
+ return (
260
+ <ToolbarIconButton aria-label={label} ref={ref} {...props}>
261
+ <FilterIcon />
262
+ </ToolbarIconButton>
263
+ )
264
+ })
265
+
266
+ type ToolbarMoreButtonProps = Omit<ToolbarButtonProps, "children"> & {
267
+ label?: string
268
+ }
269
+
270
+ const ToolbarMoreButton = React.forwardRef<
271
+ HTMLButtonElement,
272
+ ToolbarMoreButtonProps
273
+ >(function ToolbarMoreButton(
274
+ { label = "More actions", size = "icon", ...props },
275
+ ref
276
+ ) {
277
+ return (
278
+ <ToolbarIconButton aria-label={label} ref={ref} size={size} {...props}>
279
+ <MoreVerticalIcon />
280
+ </ToolbarIconButton>
281
+ )
282
+ })
283
+
284
+ type ToolbarSearchProps = Omit<
285
+ React.ComponentProps<"input">,
286
+ "className" | "size" | "width"
287
+ > &
288
+ VariantProps<typeof toolbarSearchVariants> & {
289
+ className?: string
290
+ inputClassName?: string
291
+ icon?: React.ReactNode
292
+ }
293
+
294
+ const ToolbarSearch = React.forwardRef<HTMLInputElement, ToolbarSearchProps>(
295
+ function ToolbarSearch(
296
+ {
297
+ className,
298
+ disabled,
299
+ icon,
300
+ inputClassName,
301
+ placeholder = "Search...",
302
+ type = "search",
303
+ width,
304
+ ...props
305
+ },
306
+ ref
307
+ ) {
308
+ return (
309
+ <div
310
+ data-disabled={disabled ? "true" : undefined}
311
+ data-slot="toolbar-search"
312
+ className={cn(toolbarSearchVariants({ width, className }))}
313
+ >
314
+ <span
315
+ aria-hidden="true"
316
+ data-slot="toolbar-search-icon"
317
+ className="flex size-[var(--bh-select-icon-slot-size)] shrink-0 items-center justify-center text-[var(--bh-content-muted)] [&_svg]:size-[var(--bh-select-icon-size)]"
318
+ >
319
+ {icon || <SearchIcon />}
320
+ </span>
321
+ <input
322
+ ref={ref}
323
+ className={cn(
324
+ "h-full min-w-0 flex-1 bg-transparent 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-default)] outline-none placeholder:text-[var(--bh-content-muted)] disabled:cursor-not-allowed disabled:text-[var(--bh-content-disabled)]",
325
+ inputClassName
326
+ )}
327
+ disabled={disabled}
328
+ placeholder={placeholder}
329
+ type={type}
330
+ {...props}
331
+ />
332
+ </div>
333
+ )
334
+ }
335
+ )
336
+
337
+ type ToolbarSelectProps = Omit<React.ComponentProps<"button">, "children"> &
338
+ VariantProps<typeof toolbarSelectVariants> & {
339
+ icon?: React.ReactNode | false
340
+ placeholder?: React.ReactNode
341
+ value?: React.ReactNode
342
+ }
343
+
344
+ const ToolbarSelect = React.forwardRef<HTMLButtonElement, ToolbarSelectProps>(
345
+ function ToolbarSelect(
346
+ {
347
+ className,
348
+ icon,
349
+ placeholder = "Select",
350
+ type = "button",
351
+ value,
352
+ width,
353
+ ...props
354
+ },
355
+ ref
356
+ ) {
357
+ return (
358
+ <button
359
+ aria-haspopup="listbox"
360
+ data-slot="toolbar-select"
361
+ ref={ref}
362
+ type={type}
363
+ className={cn(toolbarSelectVariants({ width, className }))}
364
+ {...props}
365
+ >
366
+ <span
367
+ data-slot="toolbar-select-value"
368
+ dir="auto"
369
+ className="min-w-0 flex-1 truncate"
370
+ >
371
+ {value || placeholder}
372
+ </span>
373
+ {icon !== false && (
374
+ <span
375
+ aria-hidden="true"
376
+ data-slot="toolbar-select-icon"
377
+ className="flex size-[var(--bh-select-icon-slot-size)] shrink-0 items-center justify-center text-[var(--bh-content-muted)] [&_svg]:size-[var(--bh-select-icon-size)]"
378
+ >
379
+ {icon || <ChevronDownIcon />}
380
+ </span>
381
+ )}
382
+ </button>
383
+ )
384
+ }
385
+ )
386
+
387
+ type ToolbarBadgeProps = React.ComponentProps<"span"> &
388
+ VariantProps<typeof toolbarBadgeVariants> & {
389
+ asChild?: boolean
390
+ }
391
+
392
+ const ToolbarBadge = React.forwardRef<HTMLSpanElement, ToolbarBadgeProps>(
393
+ function ToolbarBadge(
394
+ { asChild = false, className, variant, children, ...props },
395
+ ref
396
+ ) {
397
+ const Comp = asChild ? Slot : "span"
398
+
399
+ return (
400
+ <Comp
401
+ data-slot="toolbar-badge"
402
+ ref={ref}
403
+ className={cn(toolbarBadgeVariants({ variant, className }))}
404
+ {...props}
405
+ >
406
+ {asChild ? (
407
+ children
408
+ ) : (
409
+ <span data-slot="toolbar-badge-label" dir="auto" className="min-w-0 truncate">
410
+ {children}
411
+ </span>
412
+ )}
413
+ </Comp>
414
+ )
415
+ }
416
+ )
417
+
418
+ type ToolbarTextProps = React.ComponentProps<"span">
419
+
420
+ const ToolbarText = React.forwardRef<HTMLSpanElement, ToolbarTextProps>(
421
+ function ToolbarText({ className, ...props }, ref) {
422
+ return (
423
+ <span
424
+ data-slot="toolbar-text"
425
+ ref={ref}
426
+ className={cn(
427
+ "inline-flex h-[var(--bh-input-lg-height)] min-w-0 items-center 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)]",
428
+ className
429
+ )}
430
+ {...props}
431
+ />
432
+ )
433
+ }
434
+ )
435
+
436
+ export {
437
+ Toolbar,
438
+ ToolbarBadge,
439
+ ToolbarButton,
440
+ ToolbarFilterButton,
441
+ ToolbarIconButton,
442
+ ToolbarMoreButton,
443
+ ToolbarSearch,
444
+ ToolbarSection,
445
+ ToolbarSelect,
446
+ ToolbarSpacer,
447
+ ToolbarText,
448
+ toolbarBadgeVariants,
449
+ toolbarButtonVariants,
450
+ toolbarSearchVariants,
451
+ toolbarSectionVariants,
452
+ toolbarSelectVariants,
453
+ toolbarVariants,
454
+ }
455
+ export type {
456
+ ToolbarBadgeProps,
457
+ ToolbarButtonProps,
458
+ ToolbarFilterButtonProps,
459
+ ToolbarIconButtonProps,
460
+ ToolbarMoreButtonProps,
461
+ ToolbarProps,
462
+ ToolbarSearchProps,
463
+ ToolbarSectionProps,
464
+ ToolbarSelectProps,
465
+ ToolbarSpacerProps,
466
+ ToolbarTextProps,
467
+ }