banhaten 0.1.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +73 -0
- package/CONTRIBUTING.md +44 -0
- package/README.md +65 -13
- package/SECURITY.md +15 -0
- package/banhaten.config.example.json +0 -2
- package/docs/design-system/README.md +9 -0
- package/docs/design-system/adoption-quality-remediation.md +87 -0
- package/docs/design-system/agent-usage.md +13 -0
- package/docs/design-system/appearance-presets.md +6 -1
- package/docs/design-system/component-docs-pattern.md +81 -0
- package/docs/design-system/component-implementation-ownership-audit.md +244 -0
- package/docs/design-system/component-quality-audit-2026-08-20.md +223 -0
- package/docs/design-system/component-showcase-consistency-report.md +2 -0
- package/docs/design-system/component-token-consistency-audit.md +13 -3
- package/docs/design-system/components/README.md +4 -2
- package/docs/design-system/components/accordion.md +16 -0
- package/docs/design-system/components/activity-feed.md +17 -1
- package/docs/design-system/components/activity-heatmap.md +73 -0
- package/docs/design-system/components/alert-dialog.md +17 -0
- package/docs/design-system/components/alert.md +46 -14
- package/docs/design-system/components/aspect-ratio.md +15 -0
- package/docs/design-system/components/attribute.md +16 -0
- package/docs/design-system/components/autocomplete.md +19 -0
- package/docs/design-system/components/avatar.md +18 -0
- package/docs/design-system/components/badge.md +19 -0
- package/docs/design-system/components/banner.md +19 -1
- package/docs/design-system/components/breadcrumbs.md +17 -0
- package/docs/design-system/components/button-group.md +35 -0
- package/docs/design-system/components/button.md +18 -0
- package/docs/design-system/components/card.md +26 -1
- package/docs/design-system/components/carousel.md +20 -3
- package/docs/design-system/components/catalog-components.md +18 -1
- package/docs/design-system/components/chart.md +15 -0
- package/docs/design-system/components/checkbox.md +16 -0
- package/docs/design-system/components/collapsible.md +15 -0
- package/docs/design-system/components/command.md +15 -0
- package/docs/design-system/components/context-menu.md +15 -0
- package/docs/design-system/components/date-picker.md +21 -1
- package/docs/design-system/components/divider.md +16 -0
- package/docs/design-system/components/empty-state.md +17 -0
- package/docs/design-system/components/field.md +17 -0
- package/docs/design-system/components/file-upload.md +18 -0
- package/docs/design-system/components/hover-card.md +15 -0
- package/docs/design-system/components/input-group.md +17 -0
- package/docs/design-system/components/input-otp.md +18 -0
- package/docs/design-system/components/input.md +43 -7
- package/docs/design-system/components/item.md +72 -0
- package/docs/design-system/components/kbd.md +18 -0
- package/docs/design-system/components/label.md +16 -0
- package/docs/design-system/components/menu.md +17 -0
- package/docs/design-system/components/menubar.md +15 -0
- package/docs/design-system/components/modal.md +25 -4
- package/docs/design-system/components/native-select.md +18 -0
- package/docs/design-system/components/navigation-menu.md +15 -0
- package/docs/design-system/components/onboarding-step-list-item.md +16 -1
- package/docs/design-system/components/page-header.md +17 -1
- package/docs/design-system/components/pagination.md +31 -8
- package/docs/design-system/components/popover.md +19 -0
- package/docs/design-system/components/progress-slider.md +18 -0
- package/docs/design-system/components/progress.md +17 -0
- package/docs/design-system/components/radio-card.md +16 -0
- package/docs/design-system/components/radio-group.md +17 -0
- package/docs/design-system/components/resizable.md +15 -0
- package/docs/design-system/components/scroll-area.md +20 -1
- package/docs/design-system/components/segmented-control.md +71 -0
- package/docs/design-system/components/select.md +44 -7
- package/docs/design-system/components/sheet.md +17 -0
- package/docs/design-system/components/sidebar.md +17 -0
- package/docs/design-system/components/skeleton.md +18 -0
- package/docs/design-system/components/slideout.md +17 -0
- package/docs/design-system/components/slider.md +20 -0
- package/docs/design-system/components/social-button.md +21 -3
- package/docs/design-system/components/spinner.md +16 -0
- package/docs/design-system/components/steps.md +19 -0
- package/docs/design-system/components/table.md +36 -4
- package/docs/design-system/components/tabs.md +17 -0
- package/docs/design-system/components/tag.md +17 -0
- package/docs/design-system/components/textarea.md +16 -0
- package/docs/design-system/components/timeline.md +17 -0
- package/docs/design-system/components/toast.md +17 -0
- package/docs/design-system/components/toggle.md +17 -0
- package/docs/design-system/components/toolbar.md +21 -1
- package/docs/design-system/components/tooltip.md +18 -1
- package/docs/design-system/density-and-elevation.md +61 -0
- package/docs/design-system/direction-and-localization.md +23 -0
- package/docs/design-system/form-recipes.md +73 -0
- package/docs/design-system/gap-promotion-policy.md +21 -0
- package/docs/design-system/gap-promotion-report.md +100 -0
- package/docs/design-system/installation.md +68 -0
- package/docs/design-system/launch-comparison-shadcn.md +98 -0
- package/docs/design-system/registry-and-cli.md +30 -7
- package/docs/design-system/release-policy.md +30 -0
- package/docs/design-system/roadmap.md +14 -0
- package/docs/design-system/support-matrix.md +23 -0
- package/docs/design-system/tabs.md +1 -1
- package/docs/design-system/token-governance.md +23 -1
- package/package.json +30 -15
- package/registry/component-contract.json +40 -0
- package/registry/components/alert-dialog.tsx +2 -2
- package/registry/components/alert.tsx +101 -76
- package/registry/components/autocomplete.tsx +23 -9
- package/registry/components/avatar.tsx +14 -10
- package/registry/components/badge.tsx +18 -18
- package/registry/components/button-group.tsx +324 -5
- package/registry/components/button.tsx +38 -17
- package/registry/components/card.tsx +87 -62
- package/registry/components/carousel.tsx +67 -5
- package/registry/components/chart.tsx +36 -3
- package/registry/components/checkbox.tsx +3 -3
- package/registry/components/collapsible.tsx +1 -1
- package/registry/components/command.tsx +38 -4
- package/registry/components/context-menu.tsx +1 -1
- package/registry/components/date-picker.tsx +312 -135
- package/registry/components/expanded/ActivityFeed.tsx +9 -22
- package/registry/components/expanded/ActivityHeatmap.tsx +64 -0
- package/registry/components/expanded/Banner.tsx +3 -4
- package/registry/components/expanded/Breadcrumbs.tsx +8 -5
- package/registry/components/expanded/CatalogComponentsShowcase.tsx +16 -17
- package/registry/components/expanded/CatalogDivider.tsx +4 -3
- package/registry/components/expanded/EmptyState.tsx +1 -1
- package/registry/components/expanded/FileUpload.tsx +16 -7
- package/registry/components/expanded/OnboardingStepListItem.tsx +2 -6
- package/registry/components/expanded/PageHeader.tsx +47 -56
- package/registry/components/expanded/Slideout.tsx +29 -424
- package/registry/components/expanded/Steps.tsx +151 -13
- package/registry/components/expanded/Table.tsx +161 -82
- package/registry/components/expanded/Timeline.tsx +14 -27
- package/registry/components/expanded/activityFeed.css +9 -9
- package/registry/components/expanded/activityHeatmap.css +66 -0
- package/registry/components/expanded/banner.css +21 -11
- package/registry/components/expanded/breadcrumbs.css +2 -2
- package/registry/components/expanded/divider.css +1 -1
- package/registry/components/expanded/emptyState.css +1 -1
- package/registry/components/expanded/fileUpload.css +7 -7
- package/registry/components/expanded/onboardingStepListItem.css +2 -2
- package/registry/components/expanded/pageHeader.css +14 -11
- package/registry/components/expanded/slideout.css +10 -690
- package/registry/components/expanded/steps.css +78 -15
- package/registry/components/expanded/table.css +60 -69
- package/registry/components/expanded/timeline.css +19 -18
- package/registry/components/field.tsx +61 -8
- package/registry/components/input-content.ts +1 -0
- package/registry/components/input-otp.tsx +13 -3
- package/registry/components/input.tsx +68 -43
- package/registry/components/item.tsx +189 -0
- package/registry/components/kbd.tsx +111 -4
- package/registry/components/menu.tsx +87 -251
- package/registry/components/menubar.tsx +1 -1
- package/registry/components/modal.tsx +143 -103
- package/registry/components/native-select.tsx +2 -2
- package/registry/components/navigation-menu.tsx +1 -1
- package/registry/components/pagination.css +36 -0
- package/registry/components/pagination.tsx +88 -64
- package/registry/components/popover.tsx +162 -664
- package/registry/components/progress-slider.tsx +1 -1
- package/registry/components/radio-card.tsx +116 -87
- package/registry/components/resizable.tsx +36 -2
- package/registry/components/scroll-area.tsx +30 -6
- package/registry/components/segmented-control.tsx +87 -0
- package/registry/components/select-content.tsx +2 -2
- package/registry/components/select.tsx +86 -27
- package/registry/components/sheet.tsx +1 -1
- package/registry/components/sidebar.tsx +12 -6
- package/registry/components/skeleton.css +0 -3
- package/registry/components/social-button.tsx +59 -30
- package/registry/components/spinner.tsx +18 -55
- package/registry/components/table-elements.tsx +128 -0
- package/registry/components/tabs.css +1 -1
- package/registry/components/tabs.tsx +13 -14
- package/registry/components/tag.tsx +3 -3
- package/registry/components/textarea.tsx +3 -3
- package/registry/components/toast.tsx +16 -11
- package/registry/components/toggle.tsx +4 -4
- package/registry/components/toolbar.tsx +94 -22
- package/registry/components/tooltip.tsx +2 -2
- package/registry/examples/alert-demo.tsx +25 -5
- package/registry/examples/attribute-demo.tsx +1 -1
- package/registry/examples/autocomplete-demo.tsx +3 -3
- package/registry/examples/avatar-demo.tsx +14 -11
- package/registry/examples/badge-demo.tsx +1 -1
- package/registry/examples/button-demo.tsx +6 -6
- package/registry/examples/button-group-demo.tsx +23 -2
- package/registry/examples/card-demo.tsx +46 -8
- package/registry/examples/carousel-demo.tsx +20 -2
- package/registry/examples/chart-demo.tsx +1 -1
- package/registry/examples/checkbox-demo.tsx +5 -5
- package/registry/examples/collection-filter-bar-demo.tsx +135 -0
- package/registry/examples/command-demo.tsx +3 -3
- package/registry/examples/{expanded/command-bar-demo.tsx → command-palette-demo.tsx} +5 -15
- package/registry/examples/context-menu-demo.tsx +1 -1
- package/registry/examples/control-density-contract-demo.tsx +61 -0
- package/registry/examples/date-picker-demo.tsx +12 -12
- package/registry/examples/divider-demo.tsx +3 -3
- package/registry/examples/expanded/activity-heatmap-demo.tsx +29 -0
- package/registry/examples/expanded/banner-demo.tsx +1 -1
- package/registry/examples/expanded/breadcrumbs-demo.tsx +4 -4
- package/registry/examples/expanded/empty-state-demo.tsx +1 -1
- package/registry/examples/expanded/file-upload-demo.tsx +1 -1
- package/registry/examples/expanded/onboarding-step-demo.tsx +1 -1
- package/registry/examples/expanded/slideout-demo.tsx +2 -2
- package/registry/examples/expanded/steps-demo.tsx +1 -1
- package/registry/examples/expanded/tabs-demo.tsx +1 -1
- package/registry/examples/expanded/timeline-demo.tsx +1 -1
- package/registry/examples/hover-card-demo.tsx +2 -2
- package/registry/examples/input-demo.tsx +6 -6
- package/registry/examples/input-otp-demo.tsx +4 -4
- package/registry/examples/item-demo.tsx +46 -0
- package/registry/examples/kbd-demo.tsx +1 -1
- package/registry/examples/label-demo.tsx +1 -1
- package/registry/examples/menu-demo.tsx +1 -1
- package/registry/examples/modal-demo.tsx +67 -9
- package/registry/examples/navigation-menu-demo.tsx +1 -1
- package/registry/examples/pagination-demo.tsx +10 -7
- package/registry/examples/popover-demo.tsx +19 -19
- package/registry/examples/progress-demo.tsx +1 -1
- package/registry/examples/progress-slider-demo.tsx +1 -1
- package/registry/examples/radio-card-demo.tsx +4 -4
- package/registry/examples/radio-group-demo.tsx +2 -2
- package/registry/examples/resizable-demo.tsx +1 -1
- package/registry/examples/results-toolbar-demo.tsx +44 -0
- package/registry/examples/scroll-area-demo.tsx +3 -3
- package/registry/examples/segmented-control-demo.tsx +39 -0
- package/registry/examples/select-demo.tsx +1 -1
- package/registry/examples/sidebar-demo.tsx +5 -3
- package/registry/examples/slider-demo.tsx +3 -3
- package/registry/examples/social-button-demo.tsx +18 -8
- package/registry/examples/spinner-demo.tsx +13 -13
- package/registry/examples/tabs-demo.tsx +1 -1
- package/registry/examples/tag-demo.tsx +1 -1
- package/registry/examples/textarea-demo.tsx +4 -4
- package/registry/examples/toast-demo.tsx +1 -1
- package/registry/examples/toggle-demo.tsx +6 -6
- package/registry/examples/tooltip-demo.tsx +4 -4
- package/registry/guidance/USAGE.md +27 -0
- package/registry/hooks/use-direction.ts +193 -13
- package/registry/index.json +5668 -375
- package/registry/styles/globals.css +2404 -3999
- package/registry.json +156 -149
- package/schema/config.schema.json +11 -8
- package/schema/registry.schema.json +150 -45
- package/schema/tokens.schema.json +134 -34
- package/src/cli/command-line.js +194 -0
- package/src/cli/config-editors.js +9 -0
- package/src/cli/doctor.js +399 -0
- package/src/cli/file-transaction.js +295 -0
- package/src/cli/global-css.js +153 -0
- package/src/cli/index.js +567 -1613
- package/src/cli/install-plan.js +592 -0
- package/src/cli/install-receipt.js +171 -0
- package/src/cli/jsonc.js +203 -0
- package/src/cli/package-install-state.js +254 -0
- package/src/cli/package-manager.js +238 -0
- package/src/cli/package-plan.js +185 -0
- package/src/cli/package-version.js +97 -0
- package/src/cli/registry-query.js +207 -0
- package/src/cli/reporting.js +55 -0
- package/src/cli/schema-validation.js +19 -0
- package/src/cli/source-scanner.js +686 -0
- package/src/cli/vite-config.js +478 -0
- package/tokens/banhaten.tokens.json +4444 -331
- package/docs/design-system/components/command-bar.md +0 -57
- package/registry/components/expanded/BannerBoard.tsx +0 -225
- package/registry/components/expanded/CatalogTag.tsx +0 -85
- package/registry/components/expanded/CommandBar.tsx +0 -386
- package/registry/components/expanded/IconExplorer.tsx +0 -612
- package/registry/components/expanded/TimelineShowcase.tsx +0 -158
- package/registry/components/expanded/commandBar.css +0 -470
- package/registry/components/expanded/iconExplorer.css +0 -764
- package/registry/components/expanded/iconPacks.ts +0 -866
- package/registry/components/expanded/tag.css +0 -148
- package/registry/examples/expanded/icons-demo.tsx +0 -5
- package/tokens/Color mode.zip +0 -0
- package/tokens/Numbers.zip +0 -0
- package/tokens/Radius.zip +0 -0
- package/tokens/Theme.zip +0 -0
|
@@ -58,7 +58,7 @@ const cardVariants = cva(
|
|
|
58
58
|
orientation: "horizontal",
|
|
59
59
|
breakpoint: "desktop",
|
|
60
60
|
class:
|
|
61
|
-
"min-h-[var(--bh-card-horizontal-min-height)] w-[min(100%,var(--bh-card-horizontal-width))]",
|
|
61
|
+
"min-h-[var(--bh-card-horizontal-min-height)] w-[min(100%,var(--bh-card-horizontal-width))] flex-wrap",
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
64
|
orientation: "horizontal",
|
|
@@ -109,6 +109,20 @@ type CardActionsProps = React.ComponentProps<"div"> & {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
type CardFooterProps = React.ComponentProps<"div">
|
|
112
|
+
type CardSurfaceProps = React.ComponentPropsWithoutRef<"article">
|
|
113
|
+
|
|
114
|
+
const CardSurface = React.forwardRef<HTMLElement, CardSurfaceProps>(
|
|
115
|
+
function CardSurface({ className, ...props }, ref) {
|
|
116
|
+
return (
|
|
117
|
+
<article
|
|
118
|
+
data-slot="card-surface"
|
|
119
|
+
ref={ref}
|
|
120
|
+
className={cn(cardVariants(), className)}
|
|
121
|
+
{...props}
|
|
122
|
+
/>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
)
|
|
112
126
|
|
|
113
127
|
const Card = React.forwardRef<HTMLElement, CardProps>(function Card({
|
|
114
128
|
actions,
|
|
@@ -121,15 +135,15 @@ const Card = React.forwardRef<HTMLElement, CardProps>(function Card({
|
|
|
121
135
|
moreButtonLabel = "Open card menu",
|
|
122
136
|
onMoreClick,
|
|
123
137
|
orientation = "vertical",
|
|
124
|
-
primaryActionLabel
|
|
138
|
+
primaryActionLabel,
|
|
125
139
|
primaryActionProps,
|
|
126
|
-
secondaryActionLabel
|
|
140
|
+
secondaryActionLabel,
|
|
127
141
|
secondaryActionProps,
|
|
128
|
-
showDescription
|
|
129
|
-
showFooter
|
|
130
|
-
showImage
|
|
131
|
-
showMoreButton
|
|
132
|
-
showSubtitle
|
|
142
|
+
showDescription,
|
|
143
|
+
showFooter,
|
|
144
|
+
showImage,
|
|
145
|
+
showMoreButton,
|
|
146
|
+
showSubtitle,
|
|
133
147
|
subtitle,
|
|
134
148
|
title,
|
|
135
149
|
type = "leading-image",
|
|
@@ -142,13 +156,15 @@ const Card = React.forwardRef<HTMLElement, CardProps>(function Card({
|
|
|
142
156
|
? "leading-image"
|
|
143
157
|
: type ?? "leading-image"
|
|
144
158
|
const fullImage = cardOrientation === "vertical" && cardType === "full-image"
|
|
145
|
-
const
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
159
|
+
const shouldShowDescription = showDescription ?? description !== undefined
|
|
160
|
+
const shouldShowFooter =
|
|
161
|
+
showFooter ??
|
|
162
|
+
Boolean(footer || actions || primaryActionLabel || secondaryActionLabel)
|
|
163
|
+
const shouldShowImage = showImage ?? Boolean(imageSrc)
|
|
164
|
+
const shouldShowMoreButton = showMoreButton ?? Boolean(onMoreClick)
|
|
165
|
+
const shouldShowSubtitle = showSubtitle ?? subtitle !== undefined
|
|
150
166
|
|
|
151
|
-
const media =
|
|
167
|
+
const media = shouldShowImage ? (
|
|
152
168
|
<CardMedia
|
|
153
169
|
imageAlt={imageAlt}
|
|
154
170
|
imageSrc={imageSrc}
|
|
@@ -160,7 +176,7 @@ const Card = React.forwardRef<HTMLElement, CardProps>(function Card({
|
|
|
160
176
|
<CardBody
|
|
161
177
|
actions={actions}
|
|
162
178
|
breakpoint={cardBreakpoint}
|
|
163
|
-
description={
|
|
179
|
+
description={description}
|
|
164
180
|
footer={footer}
|
|
165
181
|
moreButtonLabel={moreButtonLabel}
|
|
166
182
|
onMoreClick={onMoreClick}
|
|
@@ -169,12 +185,12 @@ const Card = React.forwardRef<HTMLElement, CardProps>(function Card({
|
|
|
169
185
|
primaryActionProps={primaryActionProps}
|
|
170
186
|
secondaryActionLabel={secondaryActionLabel}
|
|
171
187
|
secondaryActionProps={secondaryActionProps}
|
|
172
|
-
showDescription={
|
|
173
|
-
showFooter={
|
|
174
|
-
showMoreButton={
|
|
175
|
-
showSubtitle={
|
|
176
|
-
subtitle={
|
|
177
|
-
title={
|
|
188
|
+
showDescription={shouldShowDescription}
|
|
189
|
+
showFooter={shouldShowFooter && !fullImage}
|
|
190
|
+
showMoreButton={shouldShowMoreButton}
|
|
191
|
+
showSubtitle={shouldShowSubtitle}
|
|
192
|
+
subtitle={subtitle}
|
|
193
|
+
title={title}
|
|
178
194
|
/>
|
|
179
195
|
)
|
|
180
196
|
|
|
@@ -206,10 +222,10 @@ const Card = React.forwardRef<HTMLElement, CardProps>(function Card({
|
|
|
206
222
|
breakpoint={cardBreakpoint}
|
|
207
223
|
moreButtonLabel={moreButtonLabel}
|
|
208
224
|
onMoreClick={onMoreClick}
|
|
209
|
-
showMoreButton={
|
|
210
|
-
showSubtitle={
|
|
211
|
-
subtitle={
|
|
212
|
-
title={
|
|
225
|
+
showMoreButton={shouldShowMoreButton}
|
|
226
|
+
showSubtitle={shouldShowSubtitle}
|
|
227
|
+
subtitle={subtitle}
|
|
228
|
+
title={title}
|
|
213
229
|
/>
|
|
214
230
|
</>
|
|
215
231
|
) : cardOrientation === "horizontal" &&
|
|
@@ -275,9 +291,9 @@ const CardActions = React.forwardRef<HTMLDivElement, CardActionsProps>(
|
|
|
275
291
|
function CardActions({
|
|
276
292
|
children,
|
|
277
293
|
className,
|
|
278
|
-
primaryLabel
|
|
294
|
+
primaryLabel,
|
|
279
295
|
primaryProps,
|
|
280
|
-
secondaryLabel
|
|
296
|
+
secondaryLabel,
|
|
281
297
|
secondaryProps,
|
|
282
298
|
...props
|
|
283
299
|
}, ref) {
|
|
@@ -286,23 +302,28 @@ const CardActions = React.forwardRef<HTMLDivElement, CardActionsProps>(
|
|
|
286
302
|
data-slot="card-actions"
|
|
287
303
|
ref={ref}
|
|
288
304
|
className={cn(
|
|
289
|
-
"grid w-full max-w-[var(--bh-card-actions-max-width)]
|
|
305
|
+
"grid w-full max-w-[var(--bh-card-actions-max-width)] gap-[var(--bh-space-xl-12)]",
|
|
306
|
+
primaryLabel && secondaryLabel ? "grid-cols-2" : "grid-cols-1",
|
|
290
307
|
className
|
|
291
308
|
)}
|
|
292
309
|
{...props}
|
|
293
310
|
>
|
|
294
311
|
{children ?? (
|
|
295
312
|
<>
|
|
296
|
-
|
|
297
|
-
{
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
313
|
+
{primaryLabel ? (
|
|
314
|
+
<Button {...primaryProps} className={cn("min-w-0", primaryProps?.className)}>
|
|
315
|
+
{primaryLabel}
|
|
316
|
+
</Button>
|
|
317
|
+
) : null}
|
|
318
|
+
{secondaryLabel ? (
|
|
319
|
+
<Button
|
|
320
|
+
variant="soft"
|
|
321
|
+
{...secondaryProps}
|
|
322
|
+
className={cn("min-w-0", secondaryProps?.className)}
|
|
323
|
+
>
|
|
324
|
+
{secondaryLabel}
|
|
325
|
+
</Button>
|
|
326
|
+
) : null}
|
|
306
327
|
</>
|
|
307
328
|
)}
|
|
308
329
|
</div>
|
|
@@ -331,21 +352,21 @@ function CardBody({
|
|
|
331
352
|
}: {
|
|
332
353
|
actions?: React.ReactNode
|
|
333
354
|
breakpoint: CardBreakpoint
|
|
334
|
-
description
|
|
355
|
+
description?: React.ReactNode
|
|
335
356
|
footer?: React.ReactNode
|
|
336
357
|
moreButtonLabel: string
|
|
337
358
|
onMoreClick?: React.MouseEventHandler<HTMLButtonElement>
|
|
338
359
|
orientation: CardOrientation
|
|
339
|
-
primaryActionLabel
|
|
360
|
+
primaryActionLabel?: React.ReactNode
|
|
340
361
|
primaryActionProps?: ButtonProps
|
|
341
|
-
secondaryActionLabel
|
|
362
|
+
secondaryActionLabel?: React.ReactNode
|
|
342
363
|
secondaryActionProps?: ButtonProps
|
|
343
364
|
showDescription: boolean
|
|
344
365
|
showFooter: boolean
|
|
345
366
|
showMoreButton: boolean
|
|
346
367
|
showSubtitle: boolean
|
|
347
|
-
subtitle
|
|
348
|
-
title
|
|
368
|
+
subtitle?: React.ReactNode
|
|
369
|
+
title?: React.ReactNode
|
|
349
370
|
}) {
|
|
350
371
|
const horizontal = orientation === "horizontal"
|
|
351
372
|
|
|
@@ -355,7 +376,7 @@ function CardBody({
|
|
|
355
376
|
className={cn(
|
|
356
377
|
"flex min-w-0 flex-col",
|
|
357
378
|
horizontal
|
|
358
|
-
? "flex-
|
|
379
|
+
? "min-w-[min(100%,var(--bh-card-vertical-width))] flex-[1_1_var(--bh-card-vertical-width)] gap-[var(--bh-space-5xl-24)] p-[var(--bh-card-horizontal-padding)]"
|
|
359
380
|
: "w-full gap-[var(--bh-space-5xl-24)] p-[var(--bh-card-content-padding)]"
|
|
360
381
|
)}
|
|
361
382
|
>
|
|
@@ -378,7 +399,7 @@ function CardBody({
|
|
|
378
399
|
title={title}
|
|
379
400
|
subtitleClassName={getSubtitleClassName(breakpoint)}
|
|
380
401
|
/>
|
|
381
|
-
{showDescription ? (
|
|
402
|
+
{showDescription && description !== undefined ? (
|
|
382
403
|
<p
|
|
383
404
|
data-slot="card-description"
|
|
384
405
|
dir="auto"
|
|
@@ -423,8 +444,8 @@ function CardFullImageContent({
|
|
|
423
444
|
onMoreClick?: React.MouseEventHandler<HTMLButtonElement>
|
|
424
445
|
showMoreButton: boolean
|
|
425
446
|
showSubtitle: boolean
|
|
426
|
-
subtitle
|
|
427
|
-
title
|
|
447
|
+
subtitle?: React.ReactNode
|
|
448
|
+
title?: React.ReactNode
|
|
428
449
|
}) {
|
|
429
450
|
return (
|
|
430
451
|
<div
|
|
@@ -475,20 +496,22 @@ function CardHeader({
|
|
|
475
496
|
className="flex min-w-0 items-start gap-[var(--bh-space-3xl-16)]"
|
|
476
497
|
>
|
|
477
498
|
<div className="flex min-w-0 flex-1 flex-col gap-[var(--bh-space-xxs-2)]">
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
499
|
+
{title !== undefined ? (
|
|
500
|
+
<h3
|
|
501
|
+
data-slot="card-title"
|
|
502
|
+
dir="auto"
|
|
503
|
+
className={cn(
|
|
504
|
+
"min-w-0 break-words text-[length:var(--bh-text-heading-sm-semibold-font-size)]",
|
|
505
|
+
"font-[var(--bh-text-heading-sm-semibold-font-weight)]",
|
|
506
|
+
"leading-[var(--bh-text-heading-sm-semibold-line-height)]",
|
|
507
|
+
"tracking-[var(--bh-text-heading-sm-semibold-letter-spacing)]",
|
|
508
|
+
onImage ? "text-[var(--bh-content-on-color)]" : "text-[var(--bh-content-default)]"
|
|
509
|
+
)}
|
|
510
|
+
>
|
|
511
|
+
{title}
|
|
512
|
+
</h3>
|
|
513
|
+
) : null}
|
|
514
|
+
{showSubtitle && subtitle !== undefined ? (
|
|
492
515
|
<p
|
|
493
516
|
data-slot="card-subtitle"
|
|
494
517
|
dir="auto"
|
|
@@ -557,7 +580,7 @@ function getCardMediaClassName(
|
|
|
557
580
|
breakpoint: CardBreakpoint
|
|
558
581
|
) {
|
|
559
582
|
if (orientation === "horizontal" && breakpoint === "desktop") {
|
|
560
|
-
return "h-
|
|
583
|
+
return "min-h-[var(--bh-card-media-height)] w-[min(100%,var(--bh-card-horizontal-media-width))] shrink flex-[1_1_var(--bh-card-horizontal-media-width)]"
|
|
561
584
|
}
|
|
562
585
|
|
|
563
586
|
return "h-[var(--bh-card-media-height)] w-full"
|
|
@@ -602,6 +625,7 @@ export {
|
|
|
602
625
|
CardActions,
|
|
603
626
|
CardFooter,
|
|
604
627
|
CardMedia,
|
|
628
|
+
CardSurface,
|
|
605
629
|
cardVariants,
|
|
606
630
|
type CardActionsProps,
|
|
607
631
|
type CardBreakpoint,
|
|
@@ -609,5 +633,6 @@ export {
|
|
|
609
633
|
type CardMediaProps,
|
|
610
634
|
type CardOrientation,
|
|
611
635
|
type CardProps,
|
|
636
|
+
type CardSurfaceProps,
|
|
612
637
|
type CardType,
|
|
613
638
|
}
|
|
@@ -8,6 +8,7 @@ import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react"
|
|
|
8
8
|
|
|
9
9
|
import { Button } from "@/components/ui/button"
|
|
10
10
|
import { cn } from "@/lib/utils"
|
|
11
|
+
import { useResolvedDirection, type Direction } from "@/hooks/use-direction"
|
|
11
12
|
|
|
12
13
|
type CarouselApi = UseEmblaCarouselType[1]
|
|
13
14
|
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
|
|
@@ -15,7 +16,29 @@ type CarouselOptions = UseCarouselParameters[0]
|
|
|
15
16
|
type CarouselPlugin = UseCarouselParameters[1]
|
|
16
17
|
type CarouselOrientation = "horizontal" | "vertical"
|
|
17
18
|
|
|
19
|
+
type CarouselMessages = {
|
|
20
|
+
carouselLabel: string
|
|
21
|
+
carouselRoleDescription: string
|
|
22
|
+
nextSlide: string
|
|
23
|
+
previousSlide: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const defaultCarouselMessages: CarouselMessages = {
|
|
27
|
+
carouselLabel: "Carousel",
|
|
28
|
+
carouselRoleDescription: "carousel",
|
|
29
|
+
nextSlide: "Next slide",
|
|
30
|
+
previousSlide: "Previous slide",
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const arabicCarouselMessages: CarouselMessages = {
|
|
34
|
+
carouselLabel: "\u0639\u0627\u0631\u0636 \u0627\u0644\u0634\u0631\u0627\u0626\u062d",
|
|
35
|
+
carouselRoleDescription: "\u0639\u0627\u0631\u0636 \u0634\u0631\u0627\u0626\u062d",
|
|
36
|
+
nextSlide: "\u0627\u0644\u0634\u0631\u064a\u062d\u0629 \u0627\u0644\u062a\u0627\u0644\u064a\u0629",
|
|
37
|
+
previousSlide: "\u0627\u0644\u0634\u0631\u064a\u062d\u0629 \u0627\u0644\u0633\u0627\u0628\u0642\u0629",
|
|
38
|
+
}
|
|
39
|
+
|
|
18
40
|
type CarouselProps = React.ComponentProps<"div"> & {
|
|
41
|
+
messages?: Partial<CarouselMessages>
|
|
19
42
|
opts?: CarouselOptions
|
|
20
43
|
orientation?: CarouselOrientation
|
|
21
44
|
plugins?: CarouselPlugin
|
|
@@ -29,6 +52,8 @@ type CarouselContextValue = {
|
|
|
29
52
|
api: CarouselApi
|
|
30
53
|
canScrollNext: boolean
|
|
31
54
|
canScrollPrev: boolean
|
|
55
|
+
direction: Direction
|
|
56
|
+
messages: CarouselMessages
|
|
32
57
|
orientation: CarouselOrientation
|
|
33
58
|
scrollNext: () => void
|
|
34
59
|
scrollPrev: () => void
|
|
@@ -39,8 +64,13 @@ const CarouselContext = React.createContext<CarouselContextValue | null>(null)
|
|
|
39
64
|
const Carousel = React.forwardRef<HTMLDivElement, CarouselProps>(
|
|
40
65
|
function Carousel(
|
|
41
66
|
{
|
|
67
|
+
"aria-label": ariaLabel,
|
|
68
|
+
"aria-labelledby": ariaLabelledBy,
|
|
69
|
+
"aria-roledescription": ariaRoleDescription,
|
|
42
70
|
children,
|
|
43
71
|
className,
|
|
72
|
+
dir,
|
|
73
|
+
messages: messageOverrides,
|
|
44
74
|
opts,
|
|
45
75
|
orientation = "horizontal",
|
|
46
76
|
plugins,
|
|
@@ -49,15 +79,33 @@ const Carousel = React.forwardRef<HTMLDivElement, CarouselProps>(
|
|
|
49
79
|
},
|
|
50
80
|
ref
|
|
51
81
|
) {
|
|
82
|
+
const rootRef = React.useRef<HTMLDivElement | null>(null)
|
|
83
|
+
const direction = useResolvedDirection(
|
|
84
|
+
dir === "ltr" || dir === "rtl" ? dir : undefined,
|
|
85
|
+
rootRef
|
|
86
|
+
)
|
|
87
|
+
const setRootRef = React.useCallback(
|
|
88
|
+
(node: HTMLDivElement | null) => {
|
|
89
|
+
rootRef.current = node
|
|
90
|
+
if (typeof ref === "function") ref(node)
|
|
91
|
+
else if (ref) ref.current = node
|
|
92
|
+
},
|
|
93
|
+
[ref]
|
|
94
|
+
)
|
|
52
95
|
const [carouselRef, api] = useEmblaCarousel(
|
|
53
96
|
{
|
|
54
97
|
...opts,
|
|
55
98
|
axis: orientation === "horizontal" ? "x" : "y",
|
|
99
|
+
direction,
|
|
56
100
|
},
|
|
57
101
|
plugins
|
|
58
102
|
)
|
|
59
103
|
const [canScrollPrev, setCanScrollPrev] = React.useState(false)
|
|
60
104
|
const [canScrollNext, setCanScrollNext] = React.useState(false)
|
|
105
|
+
const messages = React.useMemo(
|
|
106
|
+
() => ({ ...defaultCarouselMessages, ...messageOverrides }),
|
|
107
|
+
[messageOverrides]
|
|
108
|
+
)
|
|
61
109
|
|
|
62
110
|
const onSelect = React.useCallback((nextApi: CarouselApi) => {
|
|
63
111
|
if (!nextApi) return
|
|
@@ -86,6 +134,8 @@ const Carousel = React.forwardRef<HTMLDivElement, CarouselProps>(
|
|
|
86
134
|
api,
|
|
87
135
|
canScrollNext,
|
|
88
136
|
canScrollPrev,
|
|
137
|
+
direction,
|
|
138
|
+
messages,
|
|
89
139
|
orientation,
|
|
90
140
|
scrollNext,
|
|
91
141
|
scrollPrev,
|
|
@@ -94,8 +144,14 @@ const Carousel = React.forwardRef<HTMLDivElement, CarouselProps>(
|
|
|
94
144
|
<div
|
|
95
145
|
data-orientation={orientation}
|
|
96
146
|
data-slot="carousel"
|
|
97
|
-
|
|
147
|
+
dir={direction}
|
|
148
|
+
ref={setRootRef}
|
|
98
149
|
role="region"
|
|
150
|
+
aria-label={ariaLabelledBy ? undefined : (ariaLabel ?? messages.carouselLabel)}
|
|
151
|
+
aria-labelledby={ariaLabelledBy}
|
|
152
|
+
aria-roledescription={
|
|
153
|
+
ariaRoleDescription ?? messages.carouselRoleDescription
|
|
154
|
+
}
|
|
99
155
|
className={cn("relative", className)}
|
|
100
156
|
{...props}
|
|
101
157
|
>
|
|
@@ -153,11 +209,13 @@ const CarouselItem = React.forwardRef<HTMLDivElement, CarouselItemProps>(
|
|
|
153
209
|
|
|
154
210
|
const CarouselPrevious = React.forwardRef<HTMLButtonElement, CarouselButtonProps>(
|
|
155
211
|
function CarouselPrevious({ className, variant = "outline", size = "icon", ...props }, ref) {
|
|
156
|
-
const { canScrollPrev, orientation, scrollPrev } = useCarousel()
|
|
212
|
+
const { canScrollPrev, messages, orientation, scrollPrev } = useCarousel()
|
|
157
213
|
|
|
158
214
|
return (
|
|
159
215
|
<Button
|
|
160
|
-
aria-label=
|
|
216
|
+
aria-label={
|
|
217
|
+
props["aria-label"] ?? messages.previousSlide
|
|
218
|
+
}
|
|
161
219
|
className={cn(
|
|
162
220
|
"absolute size-[var(--bh-space-7xl-40)] rounded-[var(--bh-radius-full)]",
|
|
163
221
|
orientation === "horizontal"
|
|
@@ -181,11 +239,13 @@ const CarouselPrevious = React.forwardRef<HTMLButtonElement, CarouselButtonProps
|
|
|
181
239
|
|
|
182
240
|
const CarouselNext = React.forwardRef<HTMLButtonElement, CarouselButtonProps>(
|
|
183
241
|
function CarouselNext({ className, variant = "outline", size = "icon", ...props }, ref) {
|
|
184
|
-
const { canScrollNext, orientation, scrollNext } = useCarousel()
|
|
242
|
+
const { canScrollNext, messages, orientation, scrollNext } = useCarousel()
|
|
185
243
|
|
|
186
244
|
return (
|
|
187
245
|
<Button
|
|
188
|
-
aria-label=
|
|
246
|
+
aria-label={
|
|
247
|
+
props["aria-label"] ?? messages.nextSlide
|
|
248
|
+
}
|
|
189
249
|
className={cn(
|
|
190
250
|
"absolute size-[var(--bh-space-7xl-40)] rounded-[var(--bh-radius-full)]",
|
|
191
251
|
orientation === "horizontal"
|
|
@@ -216,6 +276,7 @@ function useCarousel() {
|
|
|
216
276
|
}
|
|
217
277
|
|
|
218
278
|
export {
|
|
279
|
+
arabicCarouselMessages,
|
|
219
280
|
Carousel,
|
|
220
281
|
CarouselContent,
|
|
221
282
|
CarouselItem,
|
|
@@ -227,6 +288,7 @@ export type {
|
|
|
227
288
|
CarouselButtonProps,
|
|
228
289
|
CarouselContentProps,
|
|
229
290
|
CarouselItemProps,
|
|
291
|
+
CarouselMessages,
|
|
230
292
|
CarouselOptions,
|
|
231
293
|
CarouselOrientation,
|
|
232
294
|
CarouselPlugin,
|
|
@@ -37,6 +37,17 @@ type ChartLegendContentProps = React.ComponentProps<"div"> & {
|
|
|
37
37
|
payload?: ChartPayloadItem[]
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
const chartCategoricalTokens = [
|
|
41
|
+
"--bh-chart-categorical-brand",
|
|
42
|
+
"--bh-chart-categorical-success",
|
|
43
|
+
"--bh-chart-categorical-warning",
|
|
44
|
+
"--bh-chart-categorical-danger",
|
|
45
|
+
"--bh-chart-categorical-information",
|
|
46
|
+
"--bh-chart-categorical-purple",
|
|
47
|
+
"--bh-chart-categorical-aqua",
|
|
48
|
+
"--bh-chart-categorical-fuchsia",
|
|
49
|
+
] as const
|
|
50
|
+
|
|
40
51
|
function ChartContainer({
|
|
41
52
|
children,
|
|
42
53
|
className,
|
|
@@ -62,6 +73,26 @@ function ChartContainer({
|
|
|
62
73
|
const ChartTooltip = RechartsTooltip
|
|
63
74
|
const ChartLegend = RechartsLegend
|
|
64
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Recharts clones the element passed as `content` and injects its own internal
|
|
78
|
+
* props (`iconSize`, `verticalAlign`, `chartWidth`, `itemSorter`, …). Those are
|
|
79
|
+
* not valid DOM attributes, so forward only what a presentational element can
|
|
80
|
+
* legitimately receive.
|
|
81
|
+
*/
|
|
82
|
+
function forwardableDomProps(props: Record<string, unknown>) {
|
|
83
|
+
return Object.fromEntries(
|
|
84
|
+
Object.entries(props).filter(
|
|
85
|
+
([key]) =>
|
|
86
|
+
key === "id" ||
|
|
87
|
+
key === "role" ||
|
|
88
|
+
key === "style" ||
|
|
89
|
+
key === "tabIndex" ||
|
|
90
|
+
key.startsWith("aria-") ||
|
|
91
|
+
key.startsWith("data-")
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
65
96
|
function ChartTooltipContent({
|
|
66
97
|
active,
|
|
67
98
|
className,
|
|
@@ -79,7 +110,7 @@ function ChartTooltipContent({
|
|
|
79
110
|
"grid min-w-[var(--bh-space-17xl-288)] gap-[var(--bh-space-sm-6)] rounded-[var(--bh-radius-lg-8)] bg-[var(--bh-bg-raised)] p-[var(--bh-space-xl-12)] text-[length:var(--bh-text-body-xs-regular-font-size)] font-[var(--bh-text-body-xs-regular-font-weight)] leading-[var(--bh-text-body-xs-regular-line-height)] tracking-[var(--bh-text-body-xs-regular-letter-spacing)] text-[var(--bh-content-default)] shadow-[var(--shadow-popover)]",
|
|
80
111
|
className
|
|
81
112
|
)}
|
|
82
|
-
{...props}
|
|
113
|
+
{...forwardableDomProps(props)}
|
|
83
114
|
>
|
|
84
115
|
{!hideLabel && label ? (
|
|
85
116
|
<div className="font-[var(--bh-text-body-xs-medium-font-weight)]">
|
|
@@ -121,7 +152,7 @@ function ChartLegendContent({
|
|
|
121
152
|
<div
|
|
122
153
|
data-slot="chart-legend"
|
|
123
154
|
className={cn("flex flex-wrap items-center justify-center gap-[var(--bh-space-3xl-16)]", className)}
|
|
124
|
-
{...props}
|
|
155
|
+
{...forwardableDomProps(props)}
|
|
125
156
|
>
|
|
126
157
|
{payload.map((item, index) => (
|
|
127
158
|
<div
|
|
@@ -146,7 +177,9 @@ function getChartStyle(config?: ChartConfig): React.CSSProperties {
|
|
|
146
177
|
return Object.entries(config).reduce<React.CSSProperties>(
|
|
147
178
|
(style, [key, value], index) => ({
|
|
148
179
|
...style,
|
|
149
|
-
[`--color-${key}`]:
|
|
180
|
+
[`--color-${key}`]:
|
|
181
|
+
value.color ??
|
|
182
|
+
`var(${chartCategoricalTokens[index % chartCategoricalTokens.length]})`,
|
|
150
183
|
}),
|
|
151
184
|
{}
|
|
152
185
|
)
|
|
@@ -63,13 +63,13 @@ const Checkbox = React.forwardRef<
|
|
|
63
63
|
aria-hidden="true"
|
|
64
64
|
className="size-[var(--bh-checkbox-icon-size)] group-data-[state=indeterminate]/checkbox:hidden"
|
|
65
65
|
focusable="false"
|
|
66
|
-
strokeWidth=
|
|
66
|
+
strokeWidth="var(--bh-icon-stroke-300)"
|
|
67
67
|
/>
|
|
68
68
|
<MinusIcon
|
|
69
69
|
aria-hidden="true"
|
|
70
70
|
className="hidden size-[var(--bh-checkbox-icon-size)] group-data-[state=indeterminate]/checkbox:block"
|
|
71
71
|
focusable="false"
|
|
72
|
-
strokeWidth=
|
|
72
|
+
strokeWidth="var(--bh-icon-stroke-300)"
|
|
73
73
|
/>
|
|
74
74
|
</CheckboxPrimitive.Indicator>
|
|
75
75
|
</CheckboxPrimitive.Root>
|
|
@@ -231,7 +231,7 @@ function CheckboxCardIndicator({
|
|
|
231
231
|
aria-hidden="true"
|
|
232
232
|
className="absolute top-1/2 left-1/2 size-[var(--bh-checkbox-icon-size)] -translate-x-1/2 -translate-y-1/2 text-[var(--bh-content-on-color)]"
|
|
233
233
|
focusable="false"
|
|
234
|
-
strokeWidth=
|
|
234
|
+
strokeWidth="var(--bh-icon-stroke-300)"
|
|
235
235
|
/>
|
|
236
236
|
) : null}
|
|
237
237
|
</span>
|
|
@@ -38,7 +38,7 @@ const CollapsibleTrigger = React.forwardRef<
|
|
|
38
38
|
<ChevronDownIcon
|
|
39
39
|
aria-hidden="true"
|
|
40
40
|
className="size-[var(--bh-space-3xl-16)] shrink-0 text-[var(--bh-content-subtle)] transition-transform group-data-[state=open]/collapsible-trigger:rotate-180"
|
|
41
|
-
strokeWidth=
|
|
41
|
+
strokeWidth="var(--bh-icon-stroke-200)"
|
|
42
42
|
/>
|
|
43
43
|
</CollapsiblePrimitive.Trigger>
|
|
44
44
|
)
|
|
@@ -44,7 +44,7 @@ const CommandInput = React.forwardRef<HTMLInputElement, CommandInputProps>(
|
|
|
44
44
|
<SearchIcon
|
|
45
45
|
aria-hidden="true"
|
|
46
46
|
className="size-[var(--bh-space-5xl-24)] shrink-0 text-[var(--bh-content-muted)]"
|
|
47
|
-
strokeWidth=
|
|
47
|
+
strokeWidth="var(--bh-icon-stroke-200)"
|
|
48
48
|
/>
|
|
49
49
|
<CommandPrimitive.Input
|
|
50
50
|
data-slot="command-input"
|
|
@@ -63,10 +63,27 @@ const CommandInput = React.forwardRef<HTMLInputElement, CommandInputProps>(
|
|
|
63
63
|
|
|
64
64
|
const CommandList = React.forwardRef<HTMLDivElement, CommandListProps>(
|
|
65
65
|
function CommandList({ className, ...props }, ref) {
|
|
66
|
+
const listRef = React.useRef<HTMLDivElement | null>(null)
|
|
67
|
+
React.useLayoutEffect(() => {
|
|
68
|
+
listRef.current
|
|
69
|
+
?.querySelector<HTMLElement>("[cmdk-list-sizer]")
|
|
70
|
+
?.setAttribute("role", "presentation")
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
const setListRef = React.useCallback(
|
|
74
|
+
(node: HTMLDivElement | null) => {
|
|
75
|
+
listRef.current = node
|
|
76
|
+
|
|
77
|
+
if (typeof ref === "function") ref(node)
|
|
78
|
+
else if (ref) ref.current = node
|
|
79
|
+
},
|
|
80
|
+
[ref]
|
|
81
|
+
)
|
|
82
|
+
|
|
66
83
|
return (
|
|
67
84
|
<CommandPrimitive.List
|
|
68
85
|
data-slot="command-list"
|
|
69
|
-
ref={
|
|
86
|
+
ref={setListRef}
|
|
70
87
|
className={cn(
|
|
71
88
|
"max-h-[calc(var(--bh-space-19xl-384)+var(--bh-space-8xl-48))] overflow-y-auto overflow-x-hidden p-[var(--bh-space-md-8)]",
|
|
72
89
|
className
|
|
@@ -79,10 +96,25 @@ const CommandList = React.forwardRef<HTMLDivElement, CommandListProps>(
|
|
|
79
96
|
|
|
80
97
|
const CommandEmpty = React.forwardRef<HTMLDivElement, CommandEmptyProps>(
|
|
81
98
|
function CommandEmpty({ className, ...props }, ref) {
|
|
99
|
+
const emptyRef = React.useRef<HTMLDivElement | null>(null)
|
|
100
|
+
React.useLayoutEffect(() => {
|
|
101
|
+
emptyRef.current?.setAttribute("role", "option")
|
|
102
|
+
emptyRef.current?.setAttribute("aria-disabled", "true")
|
|
103
|
+
emptyRef.current?.setAttribute("aria-selected", "false")
|
|
104
|
+
})
|
|
105
|
+
const setEmptyRef = React.useCallback(
|
|
106
|
+
(node: HTMLDivElement | null) => {
|
|
107
|
+
emptyRef.current = node
|
|
108
|
+
if (typeof ref === "function") ref(node)
|
|
109
|
+
else if (ref) ref.current = node
|
|
110
|
+
},
|
|
111
|
+
[ref]
|
|
112
|
+
)
|
|
113
|
+
|
|
82
114
|
return (
|
|
83
115
|
<CommandPrimitive.Empty
|
|
84
116
|
data-slot="command-empty"
|
|
85
|
-
ref={
|
|
117
|
+
ref={setEmptyRef}
|
|
86
118
|
className={cn(
|
|
87
119
|
"py-[var(--bh-space-8xl-48)] text-center 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-subtle)]",
|
|
88
120
|
className
|
|
@@ -130,9 +162,11 @@ const CommandSeparator = React.forwardRef<
|
|
|
130
162
|
CommandSeparatorProps
|
|
131
163
|
>(function CommandSeparator({ className, ...props }, ref) {
|
|
132
164
|
return (
|
|
133
|
-
<
|
|
165
|
+
<div
|
|
134
166
|
data-slot="command-separator"
|
|
135
167
|
ref={ref}
|
|
168
|
+
role="presentation"
|
|
169
|
+
aria-hidden="true"
|
|
136
170
|
className={cn("-mx-[var(--bh-space-md-8)] my-[var(--bh-space-md-8)] h-[var(--bh-border-width-default)] bg-[var(--bh-border-subtle)]", className)}
|
|
137
171
|
{...props}
|
|
138
172
|
/>
|
|
@@ -53,7 +53,7 @@ const menuContentClassName =
|
|
|
53
53
|
"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)]"
|
|
54
54
|
|
|
55
55
|
const menuItemClassName =
|
|
56
|
-
"relative flex min-h-[var(--bh-menu-item-
|
|
56
|
+
"relative flex min-h-[var(--bh-menu-item-default-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)]"
|
|
57
57
|
|
|
58
58
|
const ContextMenuContent = React.forwardRef<
|
|
59
59
|
React.ElementRef<typeof ContextMenuPrimitive.Content>,
|