banhaten 0.4.0 → 0.6.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 +78 -1
- package/CONTRIBUTING.md +6 -4
- package/README.md +4 -2
- package/docs/design-spacing.md +13 -0
- package/docs/design-system/README.md +2 -0
- package/docs/design-system/appearances/default.md +1 -1
- package/docs/design-system/appearances/rounded.md +1 -1
- package/docs/design-system/appearances/sharp.md +1 -1
- package/docs/design-system/component-showcase-consistency-report.md +5 -5
- package/docs/design-system/components/README.md +15 -0
- package/docs/design-system/components/accordion.md +1 -1
- package/docs/design-system/components/activity-feed.md +1 -1
- package/docs/design-system/components/activity-heatmap.md +1 -1
- package/docs/design-system/components/agent-input.md +85 -0
- package/docs/design-system/components/alert-dialog.md +1 -1
- package/docs/design-system/components/alert.md +10 -4
- package/docs/design-system/components/app-header.md +97 -0
- package/docs/design-system/components/approval-card.md +134 -0
- package/docs/design-system/components/attribute.md +14 -2
- package/docs/design-system/components/avatar.md +1 -1
- package/docs/design-system/components/badge.md +1 -1
- package/docs/design-system/components/banner.md +1 -1
- package/docs/design-system/components/breadcrumbs.md +8 -3
- package/docs/design-system/components/button-group.md +1 -1
- package/docs/design-system/components/button.md +8 -5
- package/docs/design-system/components/card.md +15 -1
- package/docs/design-system/components/catalog-components.md +1 -1
- package/docs/design-system/components/chart.md +95 -24
- package/docs/design-system/components/checkbox.md +1 -1
- package/docs/design-system/components/collapsible.md +20 -6
- package/docs/design-system/components/command.md +1 -1
- package/docs/design-system/components/context-menu.md +1 -1
- package/docs/design-system/components/date-picker.md +1 -1
- package/docs/design-system/components/file-upload.md +1 -1
- package/docs/design-system/components/hover-card.md +1 -1
- package/docs/design-system/components/inline-citations.md +93 -0
- package/docs/design-system/components/input-group.md +1 -1
- package/docs/design-system/components/input.md +59 -3
- package/docs/design-system/components/item.md +1 -1
- package/docs/design-system/components/kbd.md +6 -4
- package/docs/design-system/components/menu.md +35 -4
- package/docs/design-system/components/menubar.md +1 -1
- package/docs/design-system/components/modal.md +2 -2
- package/docs/design-system/components/native-select.md +1 -1
- package/docs/design-system/components/navigation-menu.md +1 -1
- package/docs/design-system/components/onboarding-step-list-item.md +1 -1
- package/docs/design-system/components/page-header.md +58 -17
- package/docs/design-system/components/pagination.md +2 -2
- package/docs/design-system/components/popover.md +1 -1
- package/docs/design-system/components/progress-slider.md +1 -1
- package/docs/design-system/components/radio-card.md +1 -1
- package/docs/design-system/components/radio-group.md +1 -1
- package/docs/design-system/components/resizable.md +1 -1
- package/docs/design-system/components/rolling-count.md +61 -0
- package/docs/design-system/components/scroll-area.md +1 -1
- package/docs/design-system/components/select.md +12 -2
- package/docs/design-system/components/sheet.md +1 -1
- package/docs/design-system/components/shimmer-text.md +67 -0
- package/docs/design-system/components/sidebar.md +75 -8
- package/docs/design-system/components/skeleton.md +2 -2
- package/docs/design-system/components/slideout.md +1 -1
- package/docs/design-system/components/slider.md +2 -2
- package/docs/design-system/components/social-button.md +2 -2
- package/docs/design-system/components/streaming-text.md +82 -0
- package/docs/design-system/components/table.md +103 -21
- package/docs/design-system/components/tabs.md +25 -6
- package/docs/design-system/components/tag.md +1 -1
- package/docs/design-system/components/task-list.md +95 -0
- package/docs/design-system/components/textarea.md +1 -1
- package/docs/design-system/components/thinking-reasoning.md +72 -0
- package/docs/design-system/components/thinking-state.md +67 -0
- package/docs/design-system/components/timeline.md +1 -1
- package/docs/design-system/components/toast.md +1 -1
- package/docs/design-system/components/toggle.md +2 -2
- package/docs/design-system/components/toolbar.md +11 -6
- package/docs/design-system/components/tooltip.md +6 -4
- package/docs/design-system/density-and-elevation.md +16 -16
- package/docs/design-system/design-system-test-missing-items.md +8 -8
- package/docs/design-system/installation.md +2 -0
- package/docs/design-system/tabs.md +2 -1
- package/docs/design-system/template-gap-audit.md +32 -0
- package/docs/design-system/templates.md +59 -0
- package/docs/design-system/token-governance.md +15 -2
- package/package.json +2 -2
- package/registry/components/accordion.tsx +2 -2
- package/registry/components/agent-input-parts.tsx +552 -0
- package/registry/components/agent-input-state.ts +156 -0
- package/registry/components/agent-input.css +307 -0
- package/registry/components/agent-input.tsx +382 -0
- package/registry/components/alert-dialog.tsx +2 -2
- package/registry/components/alert.tsx +23 -7
- package/registry/components/app-header.tsx +151 -0
- package/registry/components/approval-card.css +409 -0
- package/registry/components/approval-card.tsx +401 -0
- package/registry/components/approval-frame.tsx +108 -0
- package/registry/components/approval-questions.tsx +559 -0
- package/registry/components/attribute.tsx +48 -13
- package/registry/components/autocomplete.tsx +15 -68
- package/registry/components/avatar.tsx +2 -2
- package/registry/components/badge.tsx +8 -7
- package/registry/components/button-group.tsx +2 -2
- package/registry/components/button.tsx +19 -14
- package/registry/components/card.tsx +18 -5
- package/registry/components/chart-block-data.ts +177 -0
- package/registry/components/chart-block.css +171 -0
- package/registry/components/chart-block.tsx +260 -0
- package/registry/components/chart-interactions.ts +123 -0
- package/registry/components/chart-options.cartesian.ts +162 -0
- package/registry/components/chart-options.paint.ts +99 -0
- package/registry/components/chart-options.parts.ts +72 -0
- package/registry/components/chart-options.radial.ts +109 -0
- package/registry/components/chart-options.ts +44 -0
- package/registry/components/chart-options.types.ts +67 -0
- package/registry/components/chart.tsx +1 -1
- package/registry/components/checkbox.tsx +6 -6
- package/registry/components/collapsible.tsx +43 -3
- package/registry/components/command.tsx +1 -1
- package/registry/components/context-menu.tsx +1 -1
- package/registry/components/data-chart.tsx +40 -0
- package/registry/components/date-picker.tsx +9 -9
- package/registry/components/echart-theme.ts +246 -0
- package/registry/components/echart.css +49 -0
- package/registry/components/echart.tsx +178 -0
- package/registry/components/expanded/Breadcrumbs.tsx +5 -1
- package/registry/components/expanded/PageHeader.tsx +67 -24
- package/registry/components/expanded/Table.tsx +60 -22
- package/registry/components/expanded/activityFeed.css +2 -2
- package/registry/components/expanded/activityHeatmap.css +1 -1
- package/registry/components/expanded/banner.css +2 -2
- package/registry/components/expanded/breadcrumbs.css +19 -2
- package/registry/components/expanded/catalogComponentsShowcase.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 +38 -44
- package/registry/components/expanded/slideout.css +4 -4
- package/registry/components/expanded/table.css +58 -9
- package/registry/components/expanded/timeline.css +1 -1
- package/registry/components/hover-card.tsx +1 -1
- package/registry/components/inline-citations.css +126 -0
- package/registry/components/inline-citations.tsx +292 -0
- package/registry/components/input-group.tsx +4 -4
- package/registry/components/input.tsx +150 -137
- package/registry/components/item.tsx +1 -1
- package/registry/components/kbd.tsx +3 -2
- package/registry/components/menu.tsx +117 -12
- package/registry/components/menubar.tsx +2 -2
- package/registry/components/modal.tsx +3 -3
- package/registry/components/native-select.tsx +4 -4
- package/registry/components/navigation-menu.tsx +2 -2
- package/registry/components/pagination.tsx +4 -4
- package/registry/components/popover.tsx +3 -3
- package/registry/components/progress-slider.tsx +1 -1
- package/registry/components/radio-card.tsx +7 -7
- package/registry/components/radio-group.tsx +2 -2
- package/registry/components/resizable.tsx +2 -2
- package/registry/components/rolling-count.css +37 -0
- package/registry/components/rolling-count.tsx +110 -0
- package/registry/components/scroll-area.tsx +1 -1
- package/registry/components/select.tsx +15 -10
- package/registry/components/sheet.tsx +2 -2
- package/registry/components/shimmer-text.css +69 -0
- package/registry/components/shimmer-text.tsx +43 -0
- package/registry/components/sidebar.tsx +528 -223
- package/registry/components/skeleton.tsx +1 -1
- package/registry/components/slider.tsx +2 -2
- package/registry/components/social-button.tsx +1 -1
- package/registry/components/streaming-text.css +45 -0
- package/registry/components/streaming-text.tsx +165 -0
- package/registry/components/table-elements.tsx +164 -5
- package/registry/components/tabs.css +32 -4
- package/registry/components/tabs.tsx +5 -1
- package/registry/components/tag.tsx +1 -1
- package/registry/components/task-list.css +328 -0
- package/registry/components/task-list.tsx +429 -0
- package/registry/components/textarea.tsx +4 -4
- package/registry/components/thinking-reasoning.css +178 -0
- package/registry/components/thinking-reasoning.tsx +253 -0
- package/registry/components/thinking-state.css +8 -0
- package/registry/components/thinking-state.tsx +46 -0
- package/registry/components/toast.tsx +1 -1
- package/registry/components/toggle.tsx +2 -2
- package/registry/components/toolbar.tsx +6 -6
- package/registry/components/tooltip.tsx +6 -4
- package/registry/examples/agent-input-demo.tsx +90 -0
- package/registry/examples/app-header-demo.tsx +40 -0
- package/registry/examples/approval-card-demo.tsx +83 -0
- package/registry/examples/button-demo.tsx +3 -0
- package/registry/examples/chart-block-demo.tsx +5 -0
- package/registry/examples/chart-demo.tsx +6 -21
- package/registry/examples/collection-filter-bar-demo.tsx +1 -1
- package/registry/examples/control-density-contract-demo.tsx +5 -1
- package/registry/examples/inline-citations-demo.tsx +31 -0
- package/registry/examples/input-actions-demo.tsx +36 -0
- package/registry/examples/menu-demo.tsx +1 -1
- package/registry/examples/popover-demo.tsx +1 -0
- package/registry/examples/rolling-count-demo.tsx +39 -0
- package/registry/examples/shimmer-text-demo.tsx +20 -0
- package/registry/examples/streaming-text-demo.tsx +28 -0
- package/registry/examples/task-list-demo.tsx +74 -0
- package/registry/examples/thinking-reasoning-demo.tsx +74 -0
- package/registry/examples/thinking-state-demo.tsx +13 -0
- package/registry/guidance/charts.LICENSE.txt +24 -0
- package/registry/hooks/use-controllable-state.ts +33 -0
- package/registry/hooks/use-listbox-navigation.ts +73 -0
- package/registry/hooks/use-motion-end.ts +55 -0
- package/registry/hooks/use-reduced-motion.ts +28 -0
- package/registry/index.json +1808 -190
- package/registry/styles/globals.css +992 -1088
- package/registry.json +385 -10
- package/schema/registry.schema.json +5 -1
- package/schema/tokens.schema.json +8 -4
- package/src/cli/file-transaction.js +15 -8
- package/src/cli/index.js +22 -29
- package/tokens/banhaten.tokens.json +490 -192
|
@@ -49,7 +49,7 @@ const Menubar = React.forwardRef<
|
|
|
49
49
|
data-slot="menubar"
|
|
50
50
|
ref={ref}
|
|
51
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(--
|
|
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(--elevation-component-default)]",
|
|
53
53
|
className
|
|
54
54
|
)}
|
|
55
55
|
{...props}
|
|
@@ -75,7 +75,7 @@ const MenubarTrigger = React.forwardRef<
|
|
|
75
75
|
})
|
|
76
76
|
|
|
77
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(--
|
|
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(--elevation-menu)]"
|
|
79
79
|
|
|
80
80
|
const menuItemClassName =
|
|
81
81
|
"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)]"
|
|
@@ -38,8 +38,8 @@ type ConfirmModalMessages = {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
const modalSurfaceBaseClassName = [
|
|
41
|
-
"flex max-h-[calc(100vh-(var(--bh-space-8xl-48)*2))] w-[var(--bh-modal-width)] max-w-[calc(100vw-(var(--bh-space-4xl-20)*2))] flex-col overflow-hidden rounded-[var(--bh-radius-2xl-12)] bg-[var(--bh-bg-raised)] text-[var(--bh-content-default)] shadow-[var(--
|
|
42
|
-
"[--bh-modal-border:var(--bh-border-subtle)] [--
|
|
41
|
+
"flex max-h-[calc(100vh-(var(--bh-space-8xl-48)*2))] w-[var(--bh-modal-width)] max-w-[calc(100vw-(var(--bh-space-4xl-20)*2))] flex-col overflow-hidden rounded-[var(--bh-radius-2xl-12)] bg-[var(--bh-bg-raised)] text-[var(--bh-content-default)] shadow-[var(--elevation-modal)] outline-none",
|
|
42
|
+
"[--bh-modal-border:var(--bh-border-subtle)] [--elevation-modal:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-modal-border),var(--elevation-06)]",
|
|
43
43
|
]
|
|
44
44
|
|
|
45
45
|
const modalSizeVariants = {
|
|
@@ -334,7 +334,7 @@ const ModalCloseButtonSurface = React.forwardRef<
|
|
|
334
334
|
ref={ref}
|
|
335
335
|
type={type}
|
|
336
336
|
className={cn(
|
|
337
|
-
"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(--
|
|
337
|
+
"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(--elevation-button-focus)]",
|
|
338
338
|
className
|
|
339
339
|
)}
|
|
340
340
|
{...props}
|
|
@@ -46,9 +46,9 @@ const nativeSelectRootVariants = cva(
|
|
|
46
46
|
const nativeSelectControlVariants = cva(
|
|
47
47
|
[
|
|
48
48
|
"relative grid w-full rounded-[var(--bh-select-trigger-radius)]",
|
|
49
|
-
"[--bh-select-trigger-border-current:var(--bh-select-trigger-border)] [--
|
|
50
|
-
"bg-[var(--bh-select-trigger-bg)] shadow-[var(--
|
|
51
|
-
"focus-within:[--bh-select-trigger-border-current:var(--bh-select-trigger-border-focus)] focus-within:shadow-[var(--
|
|
49
|
+
"[--bh-select-trigger-border-current:var(--bh-select-trigger-border)] [--elevation-select-trigger:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-select-trigger-border-current,var(--bh-select-trigger-border)),var(--elevation-component-default)]",
|
|
50
|
+
"bg-[var(--bh-select-trigger-bg)] shadow-[var(--elevation-select-trigger)] transition-[background-color,box-shadow]",
|
|
51
|
+
"focus-within:[--bh-select-trigger-border-current:var(--bh-select-trigger-border-focus)] focus-within:shadow-[var(--elevation-select-focus-ring)]",
|
|
52
52
|
],
|
|
53
53
|
{
|
|
54
54
|
variants: {
|
|
@@ -60,7 +60,7 @@ const nativeSelectControlVariants = cva(
|
|
|
60
60
|
default: "",
|
|
61
61
|
filled: "",
|
|
62
62
|
error:
|
|
63
|
-
"[--bh-select-trigger-border-current:var(--bh-select-trigger-border-error)] shadow-[var(--
|
|
63
|
+
"[--bh-select-trigger-border-current:var(--bh-select-trigger-border-error)] shadow-[var(--elevation-select-trigger)] focus-within:shadow-[var(--elevation-select-danger-focus-ring)]",
|
|
64
64
|
disabled:
|
|
65
65
|
"pointer-events-none bg-[var(--bh-select-trigger-bg-disabled)] shadow-[inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-select-trigger-border-disabled)]",
|
|
66
66
|
},
|
|
@@ -90,7 +90,7 @@ const NavigationMenuContent = React.forwardRef<
|
|
|
90
90
|
data-slot="navigation-menu-content"
|
|
91
91
|
ref={ref}
|
|
92
92
|
className={cn(
|
|
93
|
-
"start-0 top-0 w-full rounded-[var(--bh-radius-2xl-12)] bg-[var(--bh-bg-raised)] p-[var(--bh-space-3xl-16)] text-[var(--bh-content-default)] shadow-[var(--
|
|
93
|
+
"start-0 top-0 w-full rounded-[var(--bh-radius-2xl-12)] bg-[var(--bh-bg-raised)] p-[var(--bh-space-3xl-16)] text-[var(--bh-content-default)] shadow-[var(--elevation-popover)] md:absolute md:w-[var(--bh-space-19xl-384)]",
|
|
94
94
|
className
|
|
95
95
|
)}
|
|
96
96
|
{...props}
|
|
@@ -125,7 +125,7 @@ const NavigationMenuViewport = React.forwardRef<
|
|
|
125
125
|
data-slot="navigation-menu-viewport"
|
|
126
126
|
ref={ref}
|
|
127
127
|
className={cn(
|
|
128
|
-
"origin-top-center relative mt-[var(--bh-space-xs-4)] h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-[var(--bh-radius-2xl-12)] bg-[var(--bh-bg-raised)] shadow-[var(--
|
|
128
|
+
"origin-top-center relative mt-[var(--bh-space-xs-4)] h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-[var(--bh-radius-2xl-12)] bg-[var(--bh-bg-raised)] shadow-[var(--elevation-popover)] md:w-[var(--radix-navigation-menu-viewport-width)]",
|
|
129
129
|
className
|
|
130
130
|
)}
|
|
131
131
|
{...props}
|
|
@@ -109,7 +109,7 @@ const paginationControlVariants = cva(
|
|
|
109
109
|
"text-[length:var(--bh-pagination-font-size)] font-[var(--bh-pagination-label-font-weight)]",
|
|
110
110
|
"leading-[var(--bh-pagination-line-height)] tracking-[var(--bh-pagination-letter-spacing)]",
|
|
111
111
|
"outline-none transition-[background-color,border-color,color,box-shadow]",
|
|
112
|
-
"focus-visible:shadow-[var(--
|
|
112
|
+
"focus-visible:shadow-[var(--elevation-pagination-focus)]",
|
|
113
113
|
"disabled:pointer-events-none disabled:text-[var(--bh-content-disabled)]",
|
|
114
114
|
"[&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
115
115
|
"rtl:[&_svg[data-rtl-flip='true']]:-scale-x-100",
|
|
@@ -118,7 +118,7 @@ const paginationControlVariants = cva(
|
|
|
118
118
|
variants: {
|
|
119
119
|
variant: {
|
|
120
120
|
soft:
|
|
121
|
-
"bg-[var(--bh-pagination-control-soft-bg)] shadow-[var(--
|
|
121
|
+
"bg-[var(--bh-pagination-control-soft-bg)] shadow-[var(--elevation-pagination-control)] hover:bg-[var(--bh-pagination-control-soft-hover)] active:bg-[var(--bh-pagination-control-soft-pressed)]",
|
|
122
122
|
ghost:
|
|
123
123
|
"bg-[var(--bh-pagination-control-ghost-bg)] hover:bg-[var(--bh-pagination-control-ghost-hover)] active:bg-[var(--bh-pagination-control-ghost-pressed)]",
|
|
124
124
|
},
|
|
@@ -164,9 +164,9 @@ const paginationItemVariants = cva(
|
|
|
164
164
|
variants: {
|
|
165
165
|
active: {
|
|
166
166
|
true:
|
|
167
|
-
"border-[var(--bh-pagination-active-border)] bg-[var(--bh-pagination-active-bg)] text-[var(--bh-pagination-active-content)] shadow-[var(--
|
|
167
|
+
"border-[var(--bh-pagination-active-border)] bg-[var(--bh-pagination-active-bg)] text-[var(--bh-pagination-active-content)] shadow-[var(--elevation-pagination-active)]",
|
|
168
168
|
false:
|
|
169
|
-
"bg-[var(--bh-pagination-page-bg)] text-[var(--bh-pagination-page-content)] hover:bg-[var(--bh-pagination-page-hover)] active:bg-[var(--bh-pagination-page-pressed)] focus-visible:border-[var(--bh-border-brand-strong)] focus-visible:shadow-[var(--
|
|
169
|
+
"bg-[var(--bh-pagination-page-bg)] text-[var(--bh-pagination-page-content)] hover:bg-[var(--bh-pagination-page-hover)] active:bg-[var(--bh-pagination-page-pressed)] focus-visible:border-[var(--bh-border-brand-strong)] focus-visible:shadow-[var(--elevation-pagination-focus)]",
|
|
170
170
|
},
|
|
171
171
|
},
|
|
172
172
|
defaultVariants: {
|
|
@@ -24,7 +24,7 @@ const popoverContentVariants = cva(
|
|
|
24
24
|
[
|
|
25
25
|
"z-[var(--bh-z-popover)] grid max-w-[var(--bh-popover-max-width)] gap-[var(--bh-popover-content-gap)]",
|
|
26
26
|
"rounded-[var(--bh-popover-radius)] bg-[var(--bh-popover-bg)] p-[var(--bh-popover-padding)]",
|
|
27
|
-
"text-start text-[var(--bh-content-default)] shadow-[var(--
|
|
27
|
+
"text-start text-[var(--bh-content-default)] shadow-[var(--elevation-popover)] outline-none",
|
|
28
28
|
"font-[var(--bh-font-family)] tracking-[var(--bh-text-base-letter-spacing)]",
|
|
29
29
|
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
30
30
|
],
|
|
@@ -185,7 +185,7 @@ const PopoverTrigger = React.forwardRef<
|
|
|
185
185
|
className={cn(
|
|
186
186
|
"inline-flex min-w-0 items-center justify-center gap-[var(--bh-popover-trigger-gap)]",
|
|
187
187
|
"rounded-[var(--bh-control-default)] text-start outline-none transition-[background-color,border-color,box-shadow]",
|
|
188
|
-
"focus-visible:shadow-[var(--
|
|
188
|
+
"focus-visible:shadow-[var(--elevation-button-focus)] disabled:pointer-events-none disabled:text-[var(--bh-content-disabled)]",
|
|
189
189
|
className
|
|
190
190
|
)}
|
|
191
191
|
data-slot="popover-trigger"
|
|
@@ -290,7 +290,7 @@ const PopoverClose = React.forwardRef<HTMLButtonElement, PopoverCloseProps>(
|
|
|
290
290
|
className={cn(
|
|
291
291
|
"inline-flex size-[var(--bh-popover-close-size)] shrink-0 items-center justify-center rounded-[var(--bh-radius-full)]",
|
|
292
292
|
"border-0 bg-transparent p-0 text-[var(--bh-content-subtle)] outline-none transition-[background-color,box-shadow,color]",
|
|
293
|
-
"hover:bg-[var(--bh-interactive-ghost-hover)] hover:text-[var(--bh-content-default)] focus-visible:shadow-[var(--
|
|
293
|
+
"hover:bg-[var(--bh-interactive-ghost-hover)] hover:text-[var(--bh-content-default)] focus-visible:shadow-[var(--elevation-button-focus)]",
|
|
294
294
|
className
|
|
295
295
|
)}
|
|
296
296
|
data-slot="popover-close"
|
|
@@ -186,7 +186,7 @@ function ProgressSlider({
|
|
|
186
186
|
<SliderPrimitive.Thumb
|
|
187
187
|
aria-label={props["aria-label"]}
|
|
188
188
|
aria-valuetext={getProgressAriaValueText(ariaValueText, currentValue)}
|
|
189
|
-
className="relative z-[var(--bh-z-overlay)] flex h-[var(--bh-progress-slider-height-current)] w-[var(--bh-progress-slider-handle-width-current)] shrink-0 items-center justify-center rounded-[var(--bh-progress-slider-radius)] bg-transparent outline-none transition-[box-shadow] focus-visible:shadow-[var(--
|
|
189
|
+
className="relative z-[var(--bh-z-overlay)] flex h-[var(--bh-progress-slider-height-current)] w-[var(--bh-progress-slider-handle-width-current)] shrink-0 items-center justify-center rounded-[var(--bh-progress-slider-radius)] bg-transparent outline-none transition-[box-shadow] focus-visible:shadow-[var(--elevation-progress-slider-thumb-focus)]"
|
|
190
190
|
data-slot="progress-slider-thumb"
|
|
191
191
|
>
|
|
192
192
|
<span
|
|
@@ -21,15 +21,15 @@ const radioCardVariants = cva(
|
|
|
21
21
|
[
|
|
22
22
|
"group/radio-card relative inline-block w-[var(--bh-radio-card-width)] max-w-full shrink-0",
|
|
23
23
|
"rounded-[var(--bh-radius-xl-10)] p-[var(--bh-space-3xl-16)]",
|
|
24
|
-
"bg-[var(--bh-radio-card-bg)] text-start shadow-[var(--
|
|
24
|
+
"bg-[var(--bh-radio-card-bg)] text-start shadow-[var(--elevation-radio-card-current)] outline-none",
|
|
25
25
|
"transition-[background-color,box-shadow]",
|
|
26
26
|
"[--bh-radio-card-bg:var(--bh-bg-raised)]",
|
|
27
27
|
"[--bh-radio-card-border:var(--bh-border-default)]",
|
|
28
|
-
"[--
|
|
28
|
+
"[--elevation-radio-card-current:var(--elevation-radio-card)]",
|
|
29
29
|
"has-[:focus-visible]:[--bh-radio-card-border:var(--bh-border-brand-strong)]",
|
|
30
30
|
"has-[:disabled]:pointer-events-none",
|
|
31
31
|
"has-[:disabled]:[--bh-radio-card-border:var(--bh-border-disabled)]",
|
|
32
|
-
"has-[:disabled]:[--
|
|
32
|
+
"has-[:disabled]:[--elevation-radio-card-current:var(--elevation-radio-card-disabled)]",
|
|
33
33
|
"has-[:disabled]:[--bh-radio-card-bg:var(--bh-bg-raised)]",
|
|
34
34
|
],
|
|
35
35
|
{
|
|
@@ -40,7 +40,7 @@ const radioCardVariants = cva(
|
|
|
40
40
|
active:
|
|
41
41
|
"[--bh-radio-card-border:var(--bh-border-brand-strong)] [--bh-radio-card-border-width:var(--bh-radio-card-border-width-active)]",
|
|
42
42
|
disabled:
|
|
43
|
-
"pointer-events-none [--bh-radio-card-bg:var(--bh-bg-raised)] [--bh-radio-card-border:var(--bh-border-disabled)] [--
|
|
43
|
+
"pointer-events-none [--bh-radio-card-bg:var(--bh-bg-raised)] [--bh-radio-card-border:var(--bh-border-disabled)] [--elevation-radio-card-current:var(--elevation-radio-card-disabled)]",
|
|
44
44
|
},
|
|
45
45
|
},
|
|
46
46
|
defaultVariants: {
|
|
@@ -528,12 +528,12 @@ function RadioCardIndicator({
|
|
|
528
528
|
>
|
|
529
529
|
<span
|
|
530
530
|
className={cn(
|
|
531
|
-
"flex size-[var(--bh-space-3xl-16)] items-center justify-center rounded-[var(--bh-radius-full)] [--
|
|
531
|
+
"flex size-[var(--bh-space-3xl-16)] items-center justify-center rounded-[var(--bh-radius-full)] [--elevation-radio-control:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-radio-control-border,var(--bh-border-input)),var(--elevation-component-default)]",
|
|
532
532
|
checked
|
|
533
|
-
? "bg-[var(--bh-interactive-radiobutton-default)] shadow-[var(--
|
|
533
|
+
? "bg-[var(--bh-interactive-radiobutton-default)] shadow-[var(--elevation-radio-control)] [--bh-radio-control-border:transparent]"
|
|
534
534
|
: disabled
|
|
535
535
|
? "bg-[var(--bh-bg-raised)] shadow-[inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-border-disabled)]"
|
|
536
|
-
: "bg-[var(--bh-bg-raised)] shadow-[var(--
|
|
536
|
+
: "bg-[var(--bh-bg-raised)] shadow-[var(--elevation-radio-control)] [--bh-radio-control-border:var(--bh-border-input)]"
|
|
537
537
|
)}
|
|
538
538
|
>
|
|
539
539
|
{checked ? (
|
|
@@ -15,12 +15,12 @@ const radioRoot = cva(
|
|
|
15
15
|
|
|
16
16
|
const radioControl = cva([
|
|
17
17
|
"pointer-events-none flex size-[var(--bh-space-3xl-16)] items-center justify-center rounded-[var(--bh-radius-full)]",
|
|
18
|
-
"bg-[var(--bh-bg-default)] shadow-[var(--
|
|
18
|
+
"bg-[var(--bh-bg-default)] shadow-[var(--elevation-radio-control)] transition-[background-color,box-shadow]",
|
|
19
19
|
"[--bh-radio-control-border:var(--bh-border-input)]",
|
|
20
20
|
"group-data-[invalid=true]/radio:[--bh-radio-control-border:var(--bh-border-danger-strong)]",
|
|
21
21
|
"group-hover/radio-field:[--bh-radio-control-border:var(--bh-border-brand-strong)]",
|
|
22
22
|
"peer-checked:bg-[var(--bh-interactive-radiobutton-default)] peer-checked:[--bh-radio-control-border:transparent]",
|
|
23
|
-
"peer-focus-visible:shadow-[var(--
|
|
23
|
+
"peer-focus-visible:shadow-[var(--elevation-radio-control),var(--elevation-button-focus)]",
|
|
24
24
|
"peer-disabled:bg-[var(--bh-bg-disabled)] peer-disabled:shadow-[inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-border-disabled)]",
|
|
25
25
|
])
|
|
26
26
|
|
|
@@ -68,7 +68,7 @@ function ResizablePanel({
|
|
|
68
68
|
return (
|
|
69
69
|
<Panel
|
|
70
70
|
className={cn(
|
|
71
|
-
"outline-none focus-visible:shadow-[var(--
|
|
71
|
+
"outline-none focus-visible:shadow-[var(--elevation-component-focus-ring)]",
|
|
72
72
|
className
|
|
73
73
|
)}
|
|
74
74
|
elementRef={setElementRef}
|
|
@@ -86,7 +86,7 @@ function ResizableHandle({
|
|
|
86
86
|
<Separator
|
|
87
87
|
data-slot="resizable-handle"
|
|
88
88
|
className={cn(
|
|
89
|
-
"relative flex w-[var(--bh-border-width-default)] items-center justify-center bg-[var(--bh-border-subtle)] outline-none transition-[background-color,box-shadow] after:absolute after:inset-y-0 after:start-1/2 after:w-[var(--bh-space-5xl-24)] after:-translate-x-1/2 focus-visible:shadow-[var(--
|
|
89
|
+
"relative flex w-[var(--bh-border-width-default)] items-center justify-center bg-[var(--bh-border-subtle)] outline-none transition-[background-color,box-shadow] after:absolute after:inset-y-0 after:start-1/2 after:w-[var(--bh-space-5xl-24)] after:-translate-x-1/2 focus-visible:shadow-[var(--elevation-button-focus)] aria-[orientation=horizontal]:h-[var(--bh-border-width-default)] aria-[orientation=horizontal]:w-full aria-[orientation=horizontal]:after:start-0 aria-[orientation=horizontal]:after:h-[var(--bh-space-5xl-24)] aria-[orientation=horizontal]:after:w-full aria-[orientation=horizontal]:after:-translate-y-1/2 aria-[orientation=horizontal]:after:translate-x-0",
|
|
90
90
|
className
|
|
91
91
|
)}
|
|
92
92
|
{...props}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/* Rolling digits: the old glyph slides out as the new one slides in. */
|
|
2
|
+
[data-slot="rolling-count"] {
|
|
3
|
+
font-variant-numeric: tabular-nums;
|
|
4
|
+
unicode-bidi: isolate;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
[data-slot="rolling-count-digits"] {
|
|
8
|
+
display: inline-flex;
|
|
9
|
+
align-items: baseline;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
[data-slot="rolling-digit"] {
|
|
13
|
+
block-size: 1em;
|
|
14
|
+
display: inline-block;
|
|
15
|
+
line-height: 1em;
|
|
16
|
+
overflow: hidden;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
[data-slot="rolling-digit-track"] {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
transition: transform var(--bh-duration-slow) var(--bh-easing-standard);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
[data-slot="rolling-digit-track"] > span {
|
|
26
|
+
block-size: 1em;
|
|
27
|
+
line-height: 1em;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
[data-slot="rolling-digit-track"][data-direction="up"][data-shifted="true"],
|
|
31
|
+
[data-slot="rolling-digit-track"][data-direction="down"][data-shifted="false"] {
|
|
32
|
+
transform: translateY(-1em);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
[data-slot="rolling-digit-track"][data-direction="down"][data-shifted="true"] {
|
|
36
|
+
transform: translateY(0);
|
|
37
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
import { useMotionEnd } from "@/hooks/use-motion-end"
|
|
7
|
+
|
|
8
|
+
import "./rolling-count.css"
|
|
9
|
+
|
|
10
|
+
/** One character slot that rolls the old glyph out and the new one in. */
|
|
11
|
+
function RollingDigit({ char }: { char: string }) {
|
|
12
|
+
const previous = React.useRef(char)
|
|
13
|
+
const [roll, setRoll] = React.useState<{
|
|
14
|
+
direction: "up" | "down"
|
|
15
|
+
from: string
|
|
16
|
+
to: string
|
|
17
|
+
} | null>(null)
|
|
18
|
+
const [shifted, setShifted] = React.useState(false)
|
|
19
|
+
const trackRef = React.useRef<HTMLSpanElement>(null)
|
|
20
|
+
|
|
21
|
+
// Swap back to the plain glyph once the roll transition has finished.
|
|
22
|
+
useMotionEnd(trackRef, roll !== null && shifted, () => setRoll(null))
|
|
23
|
+
|
|
24
|
+
React.useEffect(() => {
|
|
25
|
+
if (char === previous.current) return
|
|
26
|
+
const from = previous.current
|
|
27
|
+
previous.current = char
|
|
28
|
+
const fromNumber = Number.parseInt(from, 10)
|
|
29
|
+
const toNumber = Number.parseInt(char, 10)
|
|
30
|
+
// Digits roll like an odometer: 9 → 0 keeps rolling up, 0 → 9 rolls down.
|
|
31
|
+
const numeric = Number.isFinite(fromNumber) && Number.isFinite(toNumber)
|
|
32
|
+
const wrapsUp = numeric && fromNumber === 9 && toNumber === 0
|
|
33
|
+
const wrapsDown = numeric && fromNumber === 0 && toNumber === 9
|
|
34
|
+
const direction =
|
|
35
|
+
wrapsDown || (numeric && !wrapsUp && toNumber < fromNumber)
|
|
36
|
+
? "down"
|
|
37
|
+
: "up"
|
|
38
|
+
setRoll({ direction, from, to: char })
|
|
39
|
+
setShifted(false)
|
|
40
|
+
let second = 0
|
|
41
|
+
const first = window.requestAnimationFrame(() => {
|
|
42
|
+
second = window.requestAnimationFrame(() => setShifted(true))
|
|
43
|
+
})
|
|
44
|
+
return () => {
|
|
45
|
+
window.cancelAnimationFrame(first)
|
|
46
|
+
window.cancelAnimationFrame(second)
|
|
47
|
+
}
|
|
48
|
+
}, [char])
|
|
49
|
+
|
|
50
|
+
if (!roll) {
|
|
51
|
+
return <span data-slot="rolling-digit">{char}</span>
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const top = roll.direction === "down" ? roll.to : roll.from
|
|
55
|
+
const bottom = roll.direction === "down" ? roll.from : roll.to
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<span data-slot="rolling-digit">
|
|
59
|
+
<span
|
|
60
|
+
data-direction={roll.direction}
|
|
61
|
+
data-shifted={shifted ? "true" : "false"}
|
|
62
|
+
data-slot="rolling-digit-track"
|
|
63
|
+
ref={trackRef}
|
|
64
|
+
>
|
|
65
|
+
<span>{top}</span>
|
|
66
|
+
<span>{bottom}</span>
|
|
67
|
+
</span>
|
|
68
|
+
</span>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
type RollingCountProps = Omit<React.ComponentProps<"span">, "children"> & {
|
|
73
|
+
value: string
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Tabular figures where each changed character rolls into place. Assistive
|
|
78
|
+
* technology reads the plain value; the rolling glyphs are presentational.
|
|
79
|
+
*/
|
|
80
|
+
const RollingCount = React.forwardRef<HTMLSpanElement, RollingCountProps>(
|
|
81
|
+
function RollingCount(
|
|
82
|
+
{ "aria-label": ariaLabel, className, dir = "ltr", value, ...props },
|
|
83
|
+
ref
|
|
84
|
+
) {
|
|
85
|
+
// Digits stay in reading order for numbers even inside RTL copy; each
|
|
86
|
+
// glyph is its own box, so without an explicit direction bidi reorders
|
|
87
|
+
// them around the separator.
|
|
88
|
+
return (
|
|
89
|
+
<span
|
|
90
|
+
data-slot="rolling-count"
|
|
91
|
+
dir={dir}
|
|
92
|
+
ref={ref}
|
|
93
|
+
className={cn("inline-flex items-baseline", className)}
|
|
94
|
+
{...props}
|
|
95
|
+
>
|
|
96
|
+
<span className="sr-only">{ariaLabel ?? value}</span>
|
|
97
|
+
<span aria-hidden="true" data-slot="rolling-count-digits">
|
|
98
|
+
{/* Keyed from the end so a value that grows a digit (9/11 → 10/11)
|
|
99
|
+
rolls the existing glyphs in place instead of shifting them. */}
|
|
100
|
+
{Array.from(value).map((char, index, chars) => (
|
|
101
|
+
<RollingDigit char={char} key={chars.length - 1 - index} />
|
|
102
|
+
))}
|
|
103
|
+
</span>
|
|
104
|
+
</span>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
export { RollingCount }
|
|
110
|
+
export type { RollingCountProps }
|
|
@@ -48,7 +48,7 @@ const ScrollArea = React.forwardRef<
|
|
|
48
48
|
data-slot="scroll-area-viewport"
|
|
49
49
|
{...viewportProps}
|
|
50
50
|
tabIndex={viewportProps?.tabIndex ?? 0}
|
|
51
|
-
className={cn("size-full rounded-[inherit] outline-none focus-visible:shadow-[var(--
|
|
51
|
+
className={cn("size-full rounded-[inherit] outline-none focus-visible:shadow-[var(--elevation-component-focus-ring)]", viewportProps?.className)}
|
|
52
52
|
>
|
|
53
53
|
{children}
|
|
54
54
|
</ScrollAreaPrimitive.Viewport>
|
|
@@ -31,8 +31,8 @@ const selectTrigger = cva(
|
|
|
31
31
|
"group/select-trigger relative flex w-full items-center gap-[var(--bh-select-trigger-gap)] rounded-[var(--bh-select-trigger-radius)]",
|
|
32
32
|
"select-none px-[var(--bh-select-trigger-padding-x)] text-start outline-none",
|
|
33
33
|
"transition-[background-color,box-shadow]",
|
|
34
|
-
"[--bh-select-trigger-border-current:var(--bh-select-trigger-border)] [--
|
|
35
|
-
"focus-visible:[--bh-select-trigger-border-current:var(--bh-select-trigger-border-focus)] focus-visible:shadow-[var(--
|
|
34
|
+
"[--bh-select-trigger-border-current:var(--bh-select-trigger-border)] [--elevation-select-trigger:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-select-trigger-border-current,var(--bh-select-trigger-border)),var(--elevation-component-default)]",
|
|
35
|
+
"focus-visible:[--bh-select-trigger-border-current:var(--bh-select-trigger-border-focus)] focus-visible:shadow-[var(--elevation-select-focus-ring)]",
|
|
36
36
|
"aria-invalid:[--bh-select-trigger-border-current:var(--bh-select-trigger-border-error)]",
|
|
37
37
|
"disabled:pointer-events-none disabled:bg-[var(--bh-select-trigger-bg-disabled)] disabled:shadow-[inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-select-trigger-border-disabled)]",
|
|
38
38
|
"[&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
@@ -46,7 +46,7 @@ const selectTrigger = cva(
|
|
|
46
46
|
},
|
|
47
47
|
variant: {
|
|
48
48
|
default:
|
|
49
|
-
"bg-[var(--bh-select-trigger-bg)] shadow-[var(--
|
|
49
|
+
"bg-[var(--bh-select-trigger-bg)] shadow-[var(--elevation-select-trigger)]",
|
|
50
50
|
soft:
|
|
51
51
|
"bg-[var(--bh-select-trigger-bg-soft)] shadow-none",
|
|
52
52
|
},
|
|
@@ -54,7 +54,7 @@ const selectTrigger = cva(
|
|
|
54
54
|
default: "",
|
|
55
55
|
filled: "",
|
|
56
56
|
error:
|
|
57
|
-
"[--bh-select-trigger-border-current:var(--bh-select-trigger-border-error)] shadow-[var(--
|
|
57
|
+
"[--bh-select-trigger-border-current:var(--bh-select-trigger-border-error)] shadow-[var(--elevation-select-trigger)] focus-visible:shadow-[var(--elevation-select-danger-focus-ring)]",
|
|
58
58
|
disabled:
|
|
59
59
|
"pointer-events-none bg-[var(--bh-select-trigger-bg-disabled)] shadow-[inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-select-trigger-border-disabled)]",
|
|
60
60
|
},
|
|
@@ -71,7 +71,7 @@ const selectMenu = cva(
|
|
|
71
71
|
[
|
|
72
72
|
"w-[var(--radix-popper-anchor-width,var(--bh-select-menu-width))] max-w-[var(--radix-popper-available-width,100vw)] overflow-hidden rounded-[var(--bh-select-menu-radius)]",
|
|
73
73
|
"select-none bg-[var(--bh-select-menu-bg)] py-[var(--bh-select-menu-padding-y)]",
|
|
74
|
-
"shadow-[var(--
|
|
74
|
+
"shadow-[var(--elevation-select-menu)]",
|
|
75
75
|
].join(" ")
|
|
76
76
|
)
|
|
77
77
|
|
|
@@ -167,6 +167,8 @@ type SelectProps = Omit<React.ComponentProps<"div">, "children" | "dir"> & {
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
const Select = React.forwardRef<HTMLDivElement, SelectProps>(function Select({
|
|
170
|
+
"aria-label": ariaLabel,
|
|
171
|
+
"aria-labelledby": ariaLabelledBy,
|
|
170
172
|
children,
|
|
171
173
|
className,
|
|
172
174
|
defaultSelectValue,
|
|
@@ -224,9 +226,11 @@ const Select = React.forwardRef<HTMLDivElement, SelectProps>(function Select({
|
|
|
224
226
|
const shouldRenderMenu = React.Children.count(children) > 0
|
|
225
227
|
const selectId = triggerId || generatedId
|
|
226
228
|
const helperId = `${selectId}-helper`
|
|
227
|
-
const triggerAccessibleLabel =
|
|
228
|
-
|
|
229
|
-
|
|
229
|
+
const triggerAccessibleLabel =
|
|
230
|
+
ariaLabel ??
|
|
231
|
+
(!shouldRenderLabel && !ariaLabelledBy
|
|
232
|
+
? getAccessibleText(selectedLabel)
|
|
233
|
+
: undefined)
|
|
230
234
|
const rootOpenProps =
|
|
231
235
|
open === undefined ? { onOpenChange } : { open, onOpenChange }
|
|
232
236
|
|
|
@@ -265,6 +269,7 @@ const Select = React.forwardRef<HTMLDivElement, SelectProps>(function Select({
|
|
|
265
269
|
<SelectPrimitive.Trigger asChild>
|
|
266
270
|
<SelectTrigger
|
|
267
271
|
aria-label={triggerAccessibleLabel}
|
|
272
|
+
aria-labelledby={ariaLabelledBy}
|
|
268
273
|
aria-describedby={shouldRenderHelperText ? helperId : undefined}
|
|
269
274
|
aria-haspopup="listbox"
|
|
270
275
|
aria-invalid={isError || undefined}
|
|
@@ -882,7 +887,7 @@ function SelectCheckboxIndicator({
|
|
|
882
887
|
<span
|
|
883
888
|
data-slot="select-checkbox-control"
|
|
884
889
|
className={cn(
|
|
885
|
-
"pointer-events-none absolute left-1/2 top-1/2 size-[var(--bh-select-checkbox-size)] -translate-x-1/2 -translate-y-1/2 rounded-[var(--bh-select-checkbox-radius)] shadow-[var(--
|
|
890
|
+
"pointer-events-none absolute left-1/2 top-1/2 size-[var(--bh-select-checkbox-size)] -translate-x-1/2 -translate-y-1/2 rounded-[var(--bh-select-checkbox-radius)] shadow-[var(--elevation-select-checkbox)] [--bh-select-checkbox-border:var(--bh-border-input)] [--elevation-select-checkbox:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-select-checkbox-border,var(--bh-border-input)),var(--elevation-component-default)]",
|
|
886
891
|
checked
|
|
887
892
|
? "bg-[var(--bh-interactive-checkbox-default)] [--bh-select-checkbox-border:transparent]"
|
|
888
893
|
: "bg-[var(--bh-bg-default)]",
|
|
@@ -891,7 +896,7 @@ function SelectCheckboxIndicator({
|
|
|
891
896
|
)}
|
|
892
897
|
/>
|
|
893
898
|
{checked ? (
|
|
894
|
-
<span className="absolute left-1/2 top-1/2 flex size-[var(--bh-select-checkbox-icon-size)] -translate-x-1/2 -translate-y-1/2 items-center justify-center text-[var(--bh-
|
|
899
|
+
<span className="absolute left-1/2 top-1/2 flex size-[var(--bh-select-checkbox-icon-size)] -translate-x-1/2 -translate-y-1/2 items-center justify-center text-[var(--bh-interactive-checkbox-content)]">
|
|
895
900
|
<SelectIcon name="check-fill" />
|
|
896
901
|
</span>
|
|
897
902
|
) : null}
|
|
@@ -13,7 +13,7 @@ type SheetSize = "sm" | "default" | "lg"
|
|
|
13
13
|
const sheetContentVariants = cva(
|
|
14
14
|
[
|
|
15
15
|
"fixed z-[var(--bh-z-overlay)] flex flex-col overflow-hidden bg-[var(--bh-bg-raised)] text-[var(--bh-content-default)]",
|
|
16
|
-
"shadow-[var(--
|
|
16
|
+
"shadow-[var(--elevation-component-default)] outline-none",
|
|
17
17
|
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
18
18
|
],
|
|
19
19
|
{
|
|
@@ -255,7 +255,7 @@ const SheetCloseButton = React.forwardRef<
|
|
|
255
255
|
ref={ref}
|
|
256
256
|
type={type}
|
|
257
257
|
className={cn(
|
|
258
|
-
"absolute end-[var(--bh-space-3xl-16)] top-[var(--bh-space-3xl-16)] inline-flex size-[var(--bh-space-6xl-32)] 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(--
|
|
258
|
+
"absolute end-[var(--bh-space-3xl-16)] top-[var(--bh-space-3xl-16)] inline-flex size-[var(--bh-space-6xl-32)] 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(--elevation-button-focus)]",
|
|
259
259
|
className
|
|
260
260
|
)}
|
|
261
261
|
{...props}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
[data-slot="shimmer-text"] {
|
|
2
|
+
--shimmer-text-color: var(--bh-content-subtle);
|
|
3
|
+
--shimmer-text-valley: var(--bh-content-disabled);
|
|
4
|
+
|
|
5
|
+
color: var(--shimmer-text-color);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
[data-slot="shimmer-text"][data-tone="default"] {
|
|
9
|
+
--shimmer-text-color: var(--bh-content-default);
|
|
10
|
+
--shimmer-text-valley: var(--bh-content-subtle);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* The shine is a wide gradient clipped to the glyphs and slid across them. */
|
|
14
|
+
[data-slot="shimmer-text"][data-animated="true"] {
|
|
15
|
+
animation: bh-shimmer-text var(--bh-shimmer-text-duration)
|
|
16
|
+
var(--bh-easing-standard) infinite;
|
|
17
|
+
background-clip: text;
|
|
18
|
+
-webkit-background-clip: text;
|
|
19
|
+
background-image: linear-gradient(
|
|
20
|
+
90deg,
|
|
21
|
+
var(--shimmer-text-color) 0%,
|
|
22
|
+
var(--shimmer-text-color) 30%,
|
|
23
|
+
var(--shimmer-text-valley) 45%,
|
|
24
|
+
var(--shimmer-text-valley) 55%,
|
|
25
|
+
var(--shimmer-text-color) 70%,
|
|
26
|
+
var(--shimmer-text-color) 100%
|
|
27
|
+
);
|
|
28
|
+
background-size: 300% 100%;
|
|
29
|
+
color: transparent;
|
|
30
|
+
-webkit-text-fill-color: transparent;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
[dir="rtl"] [data-slot="shimmer-text"][data-animated="true"],
|
|
34
|
+
[data-slot="shimmer-text"][dir="rtl"][data-animated="true"] {
|
|
35
|
+
animation-name: bh-shimmer-text-rtl;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@keyframes bh-shimmer-text {
|
|
39
|
+
0%,
|
|
40
|
+
18% {
|
|
41
|
+
background-position: 100% 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
82%,
|
|
45
|
+
100% {
|
|
46
|
+
background-position: 0% 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@keyframes bh-shimmer-text-rtl {
|
|
51
|
+
0%,
|
|
52
|
+
18% {
|
|
53
|
+
background-position: 0% 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
82%,
|
|
57
|
+
100% {
|
|
58
|
+
background-position: 100% 0;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@media (prefers-reduced-motion: reduce) {
|
|
63
|
+
[data-slot="shimmer-text"][data-animated="true"] {
|
|
64
|
+
animation: none;
|
|
65
|
+
background-image: none;
|
|
66
|
+
color: var(--shimmer-text-color);
|
|
67
|
+
-webkit-text-fill-color: var(--shimmer-text-color);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
|
|
7
|
+
import "./shimmer-text.css"
|
|
8
|
+
|
|
9
|
+
type ShimmerTextTone = "subtle" | "default"
|
|
10
|
+
|
|
11
|
+
type ShimmerTextProps = React.ComponentProps<"span"> & {
|
|
12
|
+
/** Set false to freeze the sweep while keeping the same color contract. */
|
|
13
|
+
animated?: boolean
|
|
14
|
+
/** `subtle` reads as secondary copy; `default` matches primary text. */
|
|
15
|
+
tone?: ShimmerTextTone
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Text with a soft brightness valley sweeping through it. The sweep direction
|
|
20
|
+
* follows the inherited writing direction, so Arabic labels shine start-to-end.
|
|
21
|
+
*/
|
|
22
|
+
const ShimmerText = React.forwardRef<HTMLSpanElement, ShimmerTextProps>(
|
|
23
|
+
function ShimmerText(
|
|
24
|
+
{ animated = true, className, tone = "subtle", ...props },
|
|
25
|
+
ref
|
|
26
|
+
) {
|
|
27
|
+
// The slot is what the shimmer styles key on, so it is pinned after the
|
|
28
|
+
// spread: a consumer that needs its own hook wraps the primitive instead.
|
|
29
|
+
return (
|
|
30
|
+
<span
|
|
31
|
+
data-animated={animated ? "true" : "false"}
|
|
32
|
+
data-tone={tone}
|
|
33
|
+
ref={ref}
|
|
34
|
+
className={cn("inline-block min-w-0", className)}
|
|
35
|
+
{...props}
|
|
36
|
+
data-slot="shimmer-text"
|
|
37
|
+
/>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
export { ShimmerText }
|
|
43
|
+
export type { ShimmerTextProps, ShimmerTextTone }
|