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
|
@@ -30,8 +30,15 @@ type InputNativeProps = Omit<
|
|
|
30
30
|
"className" | "dir" | "size"
|
|
31
31
|
>
|
|
32
32
|
|
|
33
|
+
type InputActionButtonProps = Omit<React.ComponentProps<"button">, "children">
|
|
34
|
+
type InputStepperButtonProps = Omit<InputActionButtonProps, "type">
|
|
35
|
+
|
|
33
36
|
type InputModeRenderProps = {
|
|
34
37
|
buttonLabel?: React.ReactNode
|
|
38
|
+
/** Native props for the button or dropdown segment, including events and ARIA. */
|
|
39
|
+
buttonProps?: InputActionButtonProps
|
|
40
|
+
decreaseButtonProps?: InputStepperButtonProps
|
|
41
|
+
increaseButtonProps?: InputStepperButtonProps
|
|
35
42
|
inlineLeadingAddon?: React.ReactNode
|
|
36
43
|
inlineTagsClassName?: string
|
|
37
44
|
inlineTrailingAddon?: React.ReactNode
|
|
@@ -77,6 +84,7 @@ type InputCommonProps = InputNativeProps & {
|
|
|
77
84
|
hasLeadingIcon?: boolean
|
|
78
85
|
hasLabel?: boolean
|
|
79
86
|
isOptional?: boolean
|
|
87
|
+
/** Shows the marker and exposes aria-required without enabling native validation. */
|
|
80
88
|
isRequired?: boolean
|
|
81
89
|
label?: React.ReactNode
|
|
82
90
|
leadingIcon?: React.ReactNode | false
|
|
@@ -100,14 +108,14 @@ const inputSurface = cva(
|
|
|
100
108
|
[
|
|
101
109
|
"group/input-surface relative flex w-full overflow-hidden rounded-[var(--bh-input-radius)]",
|
|
102
110
|
"transition-[background-color,box-shadow]",
|
|
103
|
-
"[--bh-input-border:var(--bh-border-input)] [--
|
|
104
|
-
"[--
|
|
105
|
-
"[--
|
|
106
|
-
"[--
|
|
107
|
-
"[--
|
|
108
|
-
"[--
|
|
109
|
-
"after:pointer-events-none after:absolute after:inset-0 after:z-[var(--bh-z-raised)] after:rounded-[inherit] after:[box-shadow:var(--
|
|
110
|
-
"focus-within:shadow-[var(--
|
|
111
|
+
"[--bh-input-border:var(--bh-border-input)] [--elevation-input:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-input-border,var(--bh-border-input)),var(--elevation-component-default)]",
|
|
112
|
+
"[--elevation-input-surface:var(--elevation-component-default)]",
|
|
113
|
+
"[--elevation-input-overlay:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-input-border,var(--bh-border-input))]",
|
|
114
|
+
"[--elevation-input-focus-surface:var(--elevation-input-focus-ring)]",
|
|
115
|
+
"[--elevation-input-focus-overlay:none]",
|
|
116
|
+
"[--elevation-input-disabled-overlay:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-border-disabled)]",
|
|
117
|
+
"after:pointer-events-none after:absolute after:inset-0 after:z-[var(--bh-z-raised)] after:rounded-[inherit] after:[box-shadow:var(--elevation-input-overlay)] after:content-['']",
|
|
118
|
+
"focus-within:shadow-[var(--elevation-input-focus-surface)] focus-within:after:[box-shadow:var(--elevation-input-focus-overlay)]",
|
|
111
119
|
],
|
|
112
120
|
{
|
|
113
121
|
variants: {
|
|
@@ -122,13 +130,13 @@ const inputSurface = cva(
|
|
|
122
130
|
},
|
|
123
131
|
state: {
|
|
124
132
|
default:
|
|
125
|
-
"shadow-[var(--
|
|
133
|
+
"shadow-[var(--elevation-input-surface)]",
|
|
126
134
|
filled:
|
|
127
|
-
"shadow-[var(--
|
|
135
|
+
"shadow-[var(--elevation-input-surface)]",
|
|
128
136
|
error:
|
|
129
|
-
"[--bh-input-border:var(--bh-border-danger-strong)] shadow-[var(--
|
|
137
|
+
"[--bh-input-border:var(--bh-border-danger-strong)] shadow-[var(--elevation-input-surface)] focus-within:shadow-[var(--elevation-input-surface)] focus-within:after:[box-shadow:var(--elevation-input-overlay)]",
|
|
130
138
|
disabled:
|
|
131
|
-
"[--bh-input-border:var(--bh-border-disabled)] bg-[var(--bh-interactive-input-disabled)] shadow-none after:[box-shadow:var(--
|
|
139
|
+
"[--bh-input-border:var(--bh-border-disabled)] bg-[var(--bh-interactive-input-disabled)] shadow-none after:[box-shadow:var(--elevation-input-disabled-overlay)]",
|
|
132
140
|
},
|
|
133
141
|
},
|
|
134
142
|
compoundVariants: [
|
|
@@ -151,8 +159,10 @@ const inputContent = cva(
|
|
|
151
159
|
{
|
|
152
160
|
variants: {
|
|
153
161
|
size: {
|
|
154
|
-
|
|
155
|
-
|
|
162
|
+
// Library Input frame: 8px content padding, and the value starts 4px further in when nothing precedes it,
|
|
163
|
+
// so text sits 12px from the edge and trailing icons 8px.
|
|
164
|
+
md: "px-[var(--bh-input-content-padding-x)] [&>[data-slot=input-control]:first-child]:ps-[var(--bh-input-value-inset)]",
|
|
165
|
+
lg: "px-[var(--bh-input-content-padding-x)] [&>[data-slot=input-control]:first-child]:ps-[var(--bh-input-value-inset)]",
|
|
156
166
|
comfortable: "px-[var(--bh-input-comfortable-padding-x)]",
|
|
157
167
|
},
|
|
158
168
|
},
|
|
@@ -266,6 +276,8 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
266
276
|
labelClassName,
|
|
267
277
|
surfaceClassName,
|
|
268
278
|
buttonLabel,
|
|
279
|
+
buttonProps,
|
|
280
|
+
decreaseButtonProps,
|
|
269
281
|
defaultValue,
|
|
270
282
|
density,
|
|
271
283
|
dir,
|
|
@@ -276,6 +288,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
276
288
|
hasLeadingIcon,
|
|
277
289
|
hasLabel,
|
|
278
290
|
id,
|
|
291
|
+
increaseButtonProps,
|
|
279
292
|
inlineLeadingAddon,
|
|
280
293
|
inlineTrailingAddon,
|
|
281
294
|
isOptional = false,
|
|
@@ -299,6 +312,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
299
312
|
tags,
|
|
300
313
|
trailingAddon,
|
|
301
314
|
trailingIcon,
|
|
315
|
+
type,
|
|
302
316
|
value,
|
|
303
317
|
valueText,
|
|
304
318
|
variant = "default",
|
|
@@ -315,7 +329,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
315
329
|
const visualState = disabled ? "disabled" : state
|
|
316
330
|
const isDisabled = visualState === "disabled"
|
|
317
331
|
const isInvalid = visualState === "error" && !isDisabled
|
|
332
|
+
const isSemanticallyRequired = isRequired || Boolean(required)
|
|
318
333
|
const isTagInput = kind === "tags" || kind === "inline-tags"
|
|
334
|
+
const isQuantity = kind === "quantity" || kind === "quantity-2"
|
|
319
335
|
const selectedLabel = label
|
|
320
336
|
const selectedOptionalText = optionalText
|
|
321
337
|
const inferredPlaceholder = getInputPlaceholder({
|
|
@@ -347,8 +363,32 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
347
363
|
(hasRenderableContent(trailingIcon) || showInfo || Boolean(hasInformationIcon))
|
|
348
364
|
)
|
|
349
365
|
|
|
350
|
-
function focusInput() {
|
|
351
|
-
if (
|
|
366
|
+
function focusInput(event: React.MouseEvent<HTMLDivElement>) {
|
|
367
|
+
if (isDisabled || event.defaultPrevented) return
|
|
368
|
+
if (event.target instanceof Element && event.target.closest("button, input, a, [tabindex]")) return
|
|
369
|
+
inputRef.current?.focus()
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function stepInput(direction: -1 | 1) {
|
|
373
|
+
const input = inputRef.current
|
|
374
|
+
if (!input || input.disabled || input.readOnly) return
|
|
375
|
+
const previousValue = input.value
|
|
376
|
+
const hasAnyStep = input.step === "any"
|
|
377
|
+
// Native stepping owns min/max, decimal precision, and the step base.
|
|
378
|
+
// `any` permits free entry; its buttons move by one unit.
|
|
379
|
+
if (hasAnyStep) input.step = "1"
|
|
380
|
+
try {
|
|
381
|
+
if (direction === 1) input.stepUp()
|
|
382
|
+
else input.stepDown()
|
|
383
|
+
} finally {
|
|
384
|
+
if (hasAnyStep) input.step = "any"
|
|
385
|
+
}
|
|
386
|
+
if (input.value !== previousValue) {
|
|
387
|
+
// stepUp/stepDown do not emit input events. Dispatch through the native
|
|
388
|
+
// event path so React onChange and controlled-value restoration work.
|
|
389
|
+
const EventConstructor = input.ownerDocument.defaultView?.Event ?? Event
|
|
390
|
+
input.dispatchEvent(new EventConstructor("input", { bubbles: true, composed: true }))
|
|
391
|
+
}
|
|
352
392
|
}
|
|
353
393
|
|
|
354
394
|
function setInputRef(node: HTMLInputElement | null) {
|
|
@@ -361,6 +401,21 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
361
401
|
}
|
|
362
402
|
}
|
|
363
403
|
|
|
404
|
+
const segmentContext = {
|
|
405
|
+
buttonLabel,
|
|
406
|
+
buttonProps,
|
|
407
|
+
decreaseButtonProps,
|
|
408
|
+
increaseButtonProps,
|
|
409
|
+
disabled: isDisabled,
|
|
410
|
+
kind,
|
|
411
|
+
leadingAddon,
|
|
412
|
+
quantityLabel,
|
|
413
|
+
readOnly: Boolean(readOnly),
|
|
414
|
+
onStep: stepInput,
|
|
415
|
+
size: resolvedSize,
|
|
416
|
+
trailingAddon,
|
|
417
|
+
}
|
|
418
|
+
|
|
364
419
|
return (
|
|
365
420
|
<div
|
|
366
421
|
data-kind={kind}
|
|
@@ -377,7 +432,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
377
432
|
className={labelClassName}
|
|
378
433
|
htmlFor={inputId}
|
|
379
434
|
isOptional={isOptional}
|
|
380
|
-
isRequired={
|
|
435
|
+
isRequired={isSemanticallyRequired}
|
|
381
436
|
label={selectedLabel}
|
|
382
437
|
optionalText={selectedOptionalText}
|
|
383
438
|
/>
|
|
@@ -407,15 +462,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
407
462
|
)}
|
|
408
463
|
onClick={focusInput}
|
|
409
464
|
>
|
|
410
|
-
{
|
|
411
|
-
buttonLabel,
|
|
412
|
-
disabled: isDisabled,
|
|
413
|
-
kind,
|
|
414
|
-
leadingAddon,
|
|
415
|
-
quantityLabel,
|
|
416
|
-
size: resolvedSize,
|
|
417
|
-
trailingAddon,
|
|
418
|
-
})}
|
|
465
|
+
{renderInputSegment({ ...segmentContext, side: "leading" })}
|
|
419
466
|
|
|
420
467
|
<span
|
|
421
468
|
data-slot="input-content"
|
|
@@ -444,6 +491,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
444
491
|
<input
|
|
445
492
|
aria-describedby={shouldRenderHelperText ? helperId : undefined}
|
|
446
493
|
aria-invalid={isInvalid || undefined}
|
|
494
|
+
aria-required={isSemanticallyRequired || undefined}
|
|
447
495
|
data-slot="input-control"
|
|
448
496
|
data-state={visualState}
|
|
449
497
|
defaultValue={inferredDefaultValue}
|
|
@@ -453,8 +501,13 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
453
501
|
readOnly={readOnly}
|
|
454
502
|
ref={setInputRef}
|
|
455
503
|
required={required}
|
|
504
|
+
type={isQuantity ? "number" : type}
|
|
456
505
|
value={value}
|
|
457
|
-
className={cn(
|
|
506
|
+
className={cn(
|
|
507
|
+
inputControl(),
|
|
508
|
+
isQuantity && "[appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
|
|
509
|
+
controlClassName
|
|
510
|
+
)}
|
|
458
511
|
{...props}
|
|
459
512
|
/>
|
|
460
513
|
|
|
@@ -482,15 +535,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
|
482
535
|
) : null}
|
|
483
536
|
</span>
|
|
484
537
|
|
|
485
|
-
{
|
|
486
|
-
buttonLabel,
|
|
487
|
-
disabled: isDisabled,
|
|
488
|
-
kind,
|
|
489
|
-
leadingAddon,
|
|
490
|
-
quantityLabel,
|
|
491
|
-
size: resolvedSize,
|
|
492
|
-
trailingAddon,
|
|
493
|
-
})}
|
|
538
|
+
{renderInputSegment({ ...segmentContext, side: "trailing" })}
|
|
494
539
|
</div>
|
|
495
540
|
|
|
496
541
|
{selectedTags.inline.length > 0 ? (
|
|
@@ -730,60 +775,75 @@ function InputTagList({
|
|
|
730
775
|
}
|
|
731
776
|
|
|
732
777
|
function InputSegment({
|
|
778
|
+
buttonProps,
|
|
733
779
|
children,
|
|
734
780
|
disabled,
|
|
735
781
|
interactive = false,
|
|
736
782
|
side,
|
|
737
783
|
}: {
|
|
784
|
+
buttonProps?: InputActionButtonProps
|
|
738
785
|
children: React.ReactNode
|
|
739
786
|
disabled: boolean
|
|
740
787
|
interactive?: boolean
|
|
741
788
|
side: "leading" | "trailing"
|
|
742
789
|
}) {
|
|
743
|
-
const
|
|
790
|
+
const isDisabled = disabled || Boolean(interactive && buttonProps?.disabled)
|
|
791
|
+
const className = cn(
|
|
792
|
+
inputSegment({ disabled: isDisabled, interactive, side }),
|
|
793
|
+
interactive && buttonProps?.className
|
|
794
|
+
)
|
|
795
|
+
|
|
796
|
+
if (!interactive) {
|
|
797
|
+
return <span data-slot="input-segment" className={className}>{children}</span>
|
|
798
|
+
}
|
|
744
799
|
|
|
745
800
|
return (
|
|
746
|
-
<
|
|
801
|
+
<button
|
|
802
|
+
{...buttonProps}
|
|
747
803
|
data-slot="input-segment"
|
|
748
|
-
disabled={
|
|
749
|
-
type={
|
|
750
|
-
className={
|
|
751
|
-
onClick={(event) => {
|
|
752
|
-
if (interactive) event.stopPropagation()
|
|
753
|
-
}}
|
|
804
|
+
disabled={isDisabled}
|
|
805
|
+
type={buttonProps?.type ?? "button"}
|
|
806
|
+
className={className}
|
|
754
807
|
>
|
|
755
808
|
{children}
|
|
756
|
-
</
|
|
809
|
+
</button>
|
|
757
810
|
)
|
|
758
811
|
}
|
|
759
812
|
|
|
760
813
|
function InputStepperButton({
|
|
814
|
+
buttonProps,
|
|
761
815
|
children,
|
|
762
816
|
disabled,
|
|
763
817
|
label,
|
|
818
|
+
onStep,
|
|
764
819
|
side,
|
|
765
820
|
size,
|
|
766
821
|
}: {
|
|
822
|
+
buttonProps?: InputStepperButtonProps
|
|
767
823
|
children: React.ReactNode
|
|
768
824
|
disabled: boolean
|
|
769
825
|
label: string
|
|
826
|
+
onStep: () => void
|
|
770
827
|
side: "leading" | "trailing"
|
|
771
828
|
size: InputSize
|
|
772
829
|
}) {
|
|
773
830
|
return (
|
|
774
831
|
<button
|
|
775
|
-
|
|
832
|
+
{...buttonProps}
|
|
833
|
+
aria-label={buttonProps?.["aria-label"] ?? label}
|
|
776
834
|
data-side={side}
|
|
777
835
|
data-slot="input-stepper-button"
|
|
778
|
-
disabled={disabled}
|
|
836
|
+
disabled={disabled || buttonProps?.disabled}
|
|
779
837
|
type="button"
|
|
780
838
|
className={cn(
|
|
781
839
|
inputStepperButton({ side }),
|
|
782
840
|
size === "md" && "w-[var(--bh-input-md-height)]",
|
|
783
|
-
size === "comfortable" && "w-[var(--bh-input-comfortable-height)]"
|
|
841
|
+
size === "comfortable" && "w-[var(--bh-input-comfortable-height)]",
|
|
842
|
+
buttonProps?.className
|
|
784
843
|
)}
|
|
785
844
|
onClick={(event) => {
|
|
786
|
-
event
|
|
845
|
+
buttonProps?.onClick?.(event)
|
|
846
|
+
if (!event.defaultPrevented) onStep()
|
|
787
847
|
}}
|
|
788
848
|
>
|
|
789
849
|
{children}
|
|
@@ -793,106 +853,57 @@ function InputStepperButton({
|
|
|
793
853
|
|
|
794
854
|
type InputSegmentRenderContext = {
|
|
795
855
|
buttonLabel?: React.ReactNode
|
|
856
|
+
buttonProps?: InputActionButtonProps
|
|
857
|
+
decreaseButtonProps?: InputStepperButtonProps
|
|
858
|
+
increaseButtonProps?: InputStepperButtonProps
|
|
796
859
|
disabled: boolean
|
|
797
860
|
kind: InputKind
|
|
798
861
|
leadingAddon?: React.ReactNode
|
|
799
862
|
quantityLabel?: React.ReactNode
|
|
863
|
+
readOnly: boolean
|
|
864
|
+
onStep: (direction: -1 | 1) => void
|
|
865
|
+
side: "leading" | "trailing"
|
|
800
866
|
size: InputSize
|
|
801
867
|
trailingAddon?: React.ReactNode
|
|
802
868
|
}
|
|
803
869
|
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
870
|
+
function renderInputSegment({
|
|
871
|
+
buttonLabel, buttonProps, decreaseButtonProps, increaseButtonProps,
|
|
872
|
+
disabled, kind, leadingAddon, onStep, quantityLabel, readOnly, side, size, trailingAddon,
|
|
873
|
+
}: InputSegmentRenderContext) {
|
|
874
|
+
if (kind === "quantity" || kind === "quantity-2") {
|
|
875
|
+
const isDecrease = side === "leading"
|
|
876
|
+
return (
|
|
877
|
+
<InputStepperButton
|
|
878
|
+
buttonProps={isDecrease ? decreaseButtonProps : increaseButtonProps}
|
|
879
|
+
disabled={disabled || readOnly}
|
|
880
|
+
label={formatStepperLabel(isDecrease ? "Decrease" : "Increase", quantityLabel)}
|
|
881
|
+
onStep={() => onStep(isDecrease ? -1 : 1)}
|
|
882
|
+
side={side}
|
|
883
|
+
size={size}
|
|
884
|
+
>
|
|
885
|
+
{isDecrease ? <MinusIcon /> : <PlusIcon />}
|
|
886
|
+
</InputStepperButton>
|
|
887
|
+
)
|
|
888
|
+
}
|
|
807
889
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
hasRenderableContent(
|
|
811
|
-
<InputSegment disabled={disabled} side=
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
) : null,
|
|
815
|
-
"leading-button": ({ buttonLabel, disabled }) =>
|
|
816
|
-
hasRenderableContent(buttonLabel) ? (
|
|
817
|
-
<InputSegment disabled={disabled} interactive side="leading">
|
|
818
|
-
{buttonLabel}
|
|
819
|
-
</InputSegment>
|
|
820
|
-
) : null,
|
|
821
|
-
"leading-dropdown": ({ buttonLabel, disabled }) => (
|
|
822
|
-
<InputSegment disabled={disabled} interactive side="leading">
|
|
823
|
-
{buttonLabel}
|
|
824
|
-
<ChevronIcon />
|
|
825
|
-
</InputSegment>
|
|
826
|
-
),
|
|
827
|
-
quantity: ({ disabled, quantityLabel, size }) => (
|
|
828
|
-
<InputStepperButton
|
|
829
|
-
disabled={disabled}
|
|
830
|
-
label={formatStepperLabel("Decrease", quantityLabel)}
|
|
831
|
-
side="leading"
|
|
832
|
-
size={size}
|
|
833
|
-
>
|
|
834
|
-
<MinusIcon />
|
|
835
|
-
</InputStepperButton>
|
|
836
|
-
),
|
|
837
|
-
"quantity-2": ({ disabled, quantityLabel, size }) => (
|
|
838
|
-
<InputStepperButton
|
|
839
|
-
disabled={disabled}
|
|
840
|
-
label={formatStepperLabel("Decrease", quantityLabel)}
|
|
841
|
-
side="leading"
|
|
842
|
-
size={size}
|
|
843
|
-
>
|
|
844
|
-
<MinusIcon />
|
|
845
|
-
</InputStepperButton>
|
|
846
|
-
),
|
|
847
|
-
}
|
|
890
|
+
if (kind === "add-on") {
|
|
891
|
+
const addon = side === "leading" ? leadingAddon : trailingAddon
|
|
892
|
+
return hasRenderableContent(addon) ? (
|
|
893
|
+
<InputSegment disabled={disabled} side={side}>{addon}</InputSegment>
|
|
894
|
+
) : null
|
|
895
|
+
}
|
|
848
896
|
|
|
849
|
-
const
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
<InputSegment disabled={disabled} side=
|
|
853
|
-
{trailingAddon}
|
|
854
|
-
</InputSegment>
|
|
855
|
-
) : null,
|
|
856
|
-
"trailing-button": ({ buttonLabel, disabled }) =>
|
|
857
|
-
hasRenderableContent(buttonLabel) ? (
|
|
858
|
-
<InputSegment disabled={disabled} interactive side="trailing">
|
|
897
|
+
const isDropdown = kind === `${side}-dropdown`
|
|
898
|
+
if (isDropdown || (kind === `${side}-button` && hasRenderableContent(buttonLabel))) {
|
|
899
|
+
return (
|
|
900
|
+
<InputSegment buttonProps={buttonProps} disabled={disabled} interactive side={side}>
|
|
859
901
|
{buttonLabel}
|
|
902
|
+
{isDropdown ? <ChevronIcon /> : null}
|
|
860
903
|
</InputSegment>
|
|
861
|
-
)
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
{buttonLabel}
|
|
865
|
-
<ChevronIcon />
|
|
866
|
-
</InputSegment>
|
|
867
|
-
),
|
|
868
|
-
quantity: ({ disabled, quantityLabel, size }) => (
|
|
869
|
-
<InputStepperButton
|
|
870
|
-
disabled={disabled}
|
|
871
|
-
label={formatStepperLabel("Increase", quantityLabel)}
|
|
872
|
-
side="trailing"
|
|
873
|
-
size={size}
|
|
874
|
-
>
|
|
875
|
-
<PlusIcon />
|
|
876
|
-
</InputStepperButton>
|
|
877
|
-
),
|
|
878
|
-
"quantity-2": ({ disabled, quantityLabel, size }) => (
|
|
879
|
-
<InputStepperButton
|
|
880
|
-
disabled={disabled}
|
|
881
|
-
label={formatStepperLabel("Increase", quantityLabel)}
|
|
882
|
-
side="trailing"
|
|
883
|
-
size={size}
|
|
884
|
-
>
|
|
885
|
-
<PlusIcon />
|
|
886
|
-
</InputStepperButton>
|
|
887
|
-
),
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
function renderLeadingSegment(context: InputSegmentRenderContext) {
|
|
891
|
-
return leadingSegmentRenderers[context.kind]?.(context) ?? null
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
function renderTrailingSegment(context: InputSegmentRenderContext) {
|
|
895
|
-
return trailingSegmentRenderers[context.kind]?.(context) ?? null
|
|
904
|
+
)
|
|
905
|
+
}
|
|
906
|
+
return null
|
|
896
907
|
}
|
|
897
908
|
|
|
898
909
|
function formatStepperLabel(action: "Decrease" | "Increase", quantityLabel?: React.ReactNode) {
|
|
@@ -970,9 +981,11 @@ function resolveInputSize(
|
|
|
970
981
|
export { Input, inputContent, inputControl, inputRoot, inputSurface }
|
|
971
982
|
export type {
|
|
972
983
|
ControlDensity,
|
|
984
|
+
InputActionButtonProps,
|
|
973
985
|
InputKind,
|
|
974
986
|
InputProps,
|
|
975
987
|
InputSize,
|
|
988
|
+
InputStepperButtonProps,
|
|
976
989
|
InputTag,
|
|
977
990
|
InputVariant,
|
|
978
991
|
InputVisualState,
|
|
@@ -8,7 +8,7 @@ const itemVariants = cva(
|
|
|
8
8
|
[
|
|
9
9
|
"group/item flex min-w-0 items-center gap-[var(--bh-item-gap)] rounded-[var(--bh-item-radius)]",
|
|
10
10
|
"px-[var(--bh-item-padding-x)] py-[var(--bh-item-padding-y)] text-start text-[var(--bh-content-default)]",
|
|
11
|
-
"outline-none transition-[background-color,box-shadow] focus-visible:shadow-[var(--
|
|
11
|
+
"outline-none transition-[background-color,box-shadow] focus-visible:shadow-[var(--elevation-button-focus)]",
|
|
12
12
|
"aria-disabled:pointer-events-none aria-disabled:text-[var(--bh-content-disabled)]",
|
|
13
13
|
],
|
|
14
14
|
{
|
|
@@ -10,7 +10,7 @@ const kbdVariants = cva(
|
|
|
10
10
|
"inline-flex min-w-[var(--bh-space-5xl-24)] items-center justify-center whitespace-nowrap rounded-[var(--bh-radius-md-6)]",
|
|
11
11
|
"border border-[var(--bh-border-default)] bg-[var(--bh-interactive-soft-default)] text-[var(--bh-content-subtle)]",
|
|
12
12
|
"[font-family:var(--bh-font-family)] text-[length:var(--bh-text-body-xs-medium-font-size)] font-[var(--bh-text-body-xs-medium-font-weight)]",
|
|
13
|
-
"leading-[var(--bh-text-body-xs-medium-line-height)] tracking-[var(--bh-text-body-xs-medium-letter-spacing)] shadow-[var(--
|
|
13
|
+
"leading-[var(--bh-text-body-xs-medium-line-height)] tracking-[var(--bh-text-body-xs-medium-letter-spacing)] shadow-[var(--elevation-button-soft)]",
|
|
14
14
|
"data-[disabled=true]:border-[var(--bh-border-disabled)] data-[disabled=true]:bg-[var(--bh-interactive-soft-disabled)] data-[disabled=true]:text-[var(--bh-content-disabled)] data-[disabled=true]:shadow-none",
|
|
15
15
|
],
|
|
16
16
|
{
|
|
@@ -40,13 +40,14 @@ type KbdProps = React.ComponentProps<"kbd"> &
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const Kbd = React.forwardRef<HTMLElement, KbdProps>(function Kbd(
|
|
43
|
-
{ className, disabled = false, size, ...props },
|
|
43
|
+
{ className, dir = "ltr", disabled = false, size, ...props },
|
|
44
44
|
ref
|
|
45
45
|
) {
|
|
46
46
|
return (
|
|
47
47
|
<kbd
|
|
48
48
|
data-disabled={disabled ? "true" : undefined}
|
|
49
49
|
data-slot="kbd"
|
|
50
|
+
dir={dir}
|
|
50
51
|
ref={ref}
|
|
51
52
|
className={cn(kbdVariants({ size, className }))}
|
|
52
53
|
{...props}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from "react"
|
|
2
2
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
|
3
3
|
import { Slot } from "@radix-ui/react-slot"
|
|
4
|
+
import { CheckIcon } from "lucide-react"
|
|
4
5
|
import { cva, type VariantProps } from "class-variance-authority"
|
|
5
6
|
|
|
6
7
|
import { cn } from "@/lib/utils"
|
|
@@ -21,7 +22,7 @@ const MENU_COLLISION_PADDING_PX = 8
|
|
|
21
22
|
const MENU_SUBCONTENT_SIDE_OFFSET_PX = 4
|
|
22
23
|
|
|
23
24
|
const menuVariants = cva(
|
|
24
|
-
"flex flex-col items-start gap-[var(--bh-menu-gap)] overflow-hidden rounded-[var(--bh-menu-radius)] bg-[var(--bh-menu-bg)] py-[var(--bh-menu-padding-y)] shadow-[var(--
|
|
25
|
+
"flex flex-col items-start gap-[var(--bh-menu-gap)] overflow-hidden rounded-[var(--bh-menu-radius)] bg-[var(--bh-menu-bg)] py-[var(--bh-menu-padding-y)] shadow-[var(--elevation-menu)]",
|
|
25
26
|
{
|
|
26
27
|
variants: {
|
|
27
28
|
width: {
|
|
@@ -117,6 +118,8 @@ const MenuRoot = DropdownMenuPrimitive.Root
|
|
|
117
118
|
const MenuSub = DropdownMenuPrimitive.Sub
|
|
118
119
|
const MenuTrigger = DropdownMenuPrimitive.Trigger
|
|
119
120
|
const MenuStaticContext = React.createContext(false)
|
|
121
|
+
// The chosen value of the MenuRadioGroup around an item in a static MenuPreview (Radix tracks it in a live menu).
|
|
122
|
+
const MenuRadioStaticContext = React.createContext<string | undefined>(undefined)
|
|
120
123
|
|
|
121
124
|
function Menu({ dir, ...props }: MenuProps) {
|
|
122
125
|
const directionBoundaryRef = React.useRef<HTMLSpanElement | null>(null)
|
|
@@ -258,17 +261,9 @@ function getMenuItemTextValue(children: React.ReactNode) {
|
|
|
258
261
|
return undefined
|
|
259
262
|
}
|
|
260
263
|
|
|
261
|
-
type
|
|
262
|
-
React.
|
|
263
|
-
|
|
264
|
-
>
|
|
265
|
-
|
|
266
|
-
type MenuItemProps = React.ComponentProps<"div"> &
|
|
267
|
-
VariantProps<typeof menuItemVariants> &
|
|
268
|
-
MenuItemPrimitiveProps & {
|
|
269
|
-
asChild?: boolean
|
|
270
|
-
disabled?: boolean
|
|
271
|
-
}
|
|
264
|
+
type MenuItemProps =
|
|
265
|
+
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> &
|
|
266
|
+
VariantProps<typeof menuItemVariants>
|
|
272
267
|
|
|
273
268
|
type MenuSubTriggerPrimitiveProps = Pick<
|
|
274
269
|
React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger>,
|
|
@@ -356,6 +351,112 @@ const MenuItem = React.forwardRef<HTMLDivElement, MenuItemProps>(function MenuIt
|
|
|
356
351
|
|
|
357
352
|
MenuItem.displayName = "MenuItem"
|
|
358
353
|
|
|
354
|
+
type MenuRadioGroupProps = React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioGroup>
|
|
355
|
+
|
|
356
|
+
// One choice among MenuRadioItems: value is the chosen item's value, onValueChange receives the new one. The group
|
|
357
|
+
// is a full-width column with the menu's item gap, so its items stretch and space as the menu's other items do.
|
|
358
|
+
const menuRadioGroupClassName = "flex w-full flex-col gap-[var(--bh-menu-gap)]"
|
|
359
|
+
|
|
360
|
+
function MenuRadioGroup({ children, className, onValueChange, value, ...props }: MenuRadioGroupProps) {
|
|
361
|
+
const isStaticMenu = React.useContext(MenuStaticContext)
|
|
362
|
+
|
|
363
|
+
if (isStaticMenu) {
|
|
364
|
+
return (
|
|
365
|
+
<MenuRadioStaticContext.Provider value={value}>
|
|
366
|
+
<div data-slot="menu-radio-group" role="group" className={cn(menuRadioGroupClassName, className)} {...props}>
|
|
367
|
+
{children}
|
|
368
|
+
</div>
|
|
369
|
+
</MenuRadioStaticContext.Provider>
|
|
370
|
+
)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return (
|
|
374
|
+
<DropdownMenuPrimitive.RadioGroup
|
|
375
|
+
data-slot="menu-radio-group"
|
|
376
|
+
className={cn(menuRadioGroupClassName, className)}
|
|
377
|
+
onValueChange={onValueChange}
|
|
378
|
+
value={value}
|
|
379
|
+
{...props}
|
|
380
|
+
>
|
|
381
|
+
{children}
|
|
382
|
+
</DropdownMenuPrimitive.RadioGroup>
|
|
383
|
+
)
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
type MenuRadioItemProps =
|
|
387
|
+
Omit<React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>, "asChild"> &
|
|
388
|
+
VariantProps<typeof menuItemVariants>
|
|
389
|
+
|
|
390
|
+
// A menu item that is one of a MenuRadioGroup's choices: role menuitemradio with aria-checked, and a trailing check
|
|
391
|
+
// on the chosen one. Radix sets the role and checked state in a live menu; a static MenuPreview sets them here.
|
|
392
|
+
const MenuRadioItem = React.forwardRef<HTMLDivElement, MenuRadioItemProps>(function MenuRadioItem({
|
|
393
|
+
className,
|
|
394
|
+
kind = "default",
|
|
395
|
+
disabled = false,
|
|
396
|
+
children,
|
|
397
|
+
onSelect,
|
|
398
|
+
textValue,
|
|
399
|
+
value,
|
|
400
|
+
...props
|
|
401
|
+
}, ref) {
|
|
402
|
+
const isStaticMenu = React.useContext(MenuStaticContext)
|
|
403
|
+
const staticValue = React.useContext(MenuRadioStaticContext)
|
|
404
|
+
const selectedKind: MenuItemKind = kind ?? "default"
|
|
405
|
+
const staticChecked = staticValue === value
|
|
406
|
+
const indicator = (
|
|
407
|
+
<MenuItemIcon data-slot="menu-radio-item-indicator" position="trailing">
|
|
408
|
+
<CheckIcon aria-hidden="true" focusable={false} strokeWidth="var(--bh-icon-stroke-200)" />
|
|
409
|
+
</MenuItemIcon>
|
|
410
|
+
)
|
|
411
|
+
// In a live menu, role, aria-checked and data-state come from Radix and must not be overridden.
|
|
412
|
+
const staticSemantics = isStaticMenu
|
|
413
|
+
? {
|
|
414
|
+
"aria-checked": staticChecked,
|
|
415
|
+
"data-state": staticChecked ? "checked" : "unchecked",
|
|
416
|
+
role: "menuitemradio",
|
|
417
|
+
}
|
|
418
|
+
: {}
|
|
419
|
+
|
|
420
|
+
const item = (
|
|
421
|
+
<div
|
|
422
|
+
{...staticSemantics}
|
|
423
|
+
aria-disabled={disabled ? true : undefined}
|
|
424
|
+
data-disabled={disabled ? "true" : "false"}
|
|
425
|
+
data-kind={selectedKind}
|
|
426
|
+
data-slot="menu-item"
|
|
427
|
+
ref={ref}
|
|
428
|
+
tabIndex={disabled ? -1 : 0}
|
|
429
|
+
className={cn(menuItemVariants({ kind: selectedKind, className }))}
|
|
430
|
+
{...props}
|
|
431
|
+
>
|
|
432
|
+
<MenuItemContent kind={selectedKind}>
|
|
433
|
+
<MenuItemChildren kind={selectedKind}>{children}</MenuItemChildren>
|
|
434
|
+
{isStaticMenu ? (
|
|
435
|
+
staticChecked ? indicator : null
|
|
436
|
+
) : (
|
|
437
|
+
<DropdownMenuPrimitive.ItemIndicator asChild>{indicator}</DropdownMenuPrimitive.ItemIndicator>
|
|
438
|
+
)}
|
|
439
|
+
</MenuItemContent>
|
|
440
|
+
</div>
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
if (isStaticMenu) return item
|
|
444
|
+
|
|
445
|
+
return (
|
|
446
|
+
<DropdownMenuPrimitive.RadioItem
|
|
447
|
+
asChild
|
|
448
|
+
disabled={disabled}
|
|
449
|
+
onSelect={onSelect}
|
|
450
|
+
textValue={textValue ?? getMenuItemTextValue(children)}
|
|
451
|
+
value={value}
|
|
452
|
+
>
|
|
453
|
+
{item}
|
|
454
|
+
</DropdownMenuPrimitive.RadioItem>
|
|
455
|
+
)
|
|
456
|
+
})
|
|
457
|
+
|
|
458
|
+
MenuRadioItem.displayName = "MenuRadioItem"
|
|
459
|
+
|
|
359
460
|
function findMenuItemSwitchState(children: React.ReactNode): boolean | undefined {
|
|
360
461
|
let state: boolean | undefined
|
|
361
462
|
|
|
@@ -951,6 +1052,8 @@ export {
|
|
|
951
1052
|
MenuProgress,
|
|
952
1053
|
MenuPreview,
|
|
953
1054
|
MenuPortal,
|
|
1055
|
+
MenuRadioGroup,
|
|
1056
|
+
MenuRadioItem,
|
|
954
1057
|
MenuRoot,
|
|
955
1058
|
MenuSeparator,
|
|
956
1059
|
MenuSub,
|
|
@@ -981,6 +1084,8 @@ export type {
|
|
|
981
1084
|
MenuProgressProps,
|
|
982
1085
|
MenuProps,
|
|
983
1086
|
MenuPreviewProps,
|
|
1087
|
+
MenuRadioGroupProps,
|
|
1088
|
+
MenuRadioItemProps,
|
|
984
1089
|
MenuSurfaceProps,
|
|
985
1090
|
MenuWidth,
|
|
986
1091
|
}
|