@dashforge/tw 1.5.1 → 1.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/dist/index.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import { useMemo, forwardRef, useContext, useState, useEffect, useRef, useId, useCallback, Fragment as Fragment$1, createContext, Children, isValidElement, memo, cloneElement, useLayoutEffect } from 'react';
3
3
  import { Slot } from '@radix-ui/react-slot';
4
- import { DashFormContext, useEngineVisibility } from '@dashforge/ui-core';
4
+ import { DashFormContext, useEngineVisibility, useWarnIfControlledInFormMode } from '@dashforge/ui-core';
5
5
  import { useComponentDefaults } from '@dashforge/tw-theme';
6
6
  import clsx from 'clsx';
7
7
  import { twMerge } from 'tailwind-merge';
@@ -13,8 +13,8 @@ import * as RadixTooltip from '@radix-ui/react-tooltip';
13
13
  import * as RadixCheckbox from '@radix-ui/react-checkbox';
14
14
  import * as RadixSwitch from '@radix-ui/react-switch';
15
15
  import * as RadixRadioGroup from '@radix-ui/react-radio-group';
16
- import { useCalendar, resolveCalendarKey, formatLongDate, parseISODate, formatTime, generateTimeOptions, timeStringToMinutes, getTodayISODate, useDateRange } from '@dashforge/calendar-core';
17
16
  import * as RadixPopover from '@radix-ui/react-popover';
17
+ import { useCalendar, resolveCalendarKey, formatLongDate, parseISODate, formatTime, generateTimeOptions, timeStringToMinutes, getTodayISODate, useDateRange } from '@dashforge/calendar-core';
18
18
  import * as RadixDialog from '@radix-ui/react-dialog';
19
19
  import * as RadixSlider from '@radix-ui/react-slider';
20
20
  import * as RadixMenu from '@radix-ui/react-dropdown-menu';
@@ -350,6 +350,12 @@ Spinner.displayName = 'Spinner';
350
350
  'inline-flex items-center justify-center gap-2',
351
351
  'font-medium',
352
352
  'rounded-md',
353
+ // Pointer affordance — the browser UA cursor for `<button>` is
354
+ // `default`, not `pointer`. Applies to every non-disabled state
355
+ // (disabled + loading override below); `variant='link'` inherits
356
+ // this cursor too, matching what browsers show for anchors. See
357
+ // README-BUG § BUG 13.
358
+ 'cursor-pointer',
353
359
  'select-none whitespace-nowrap',
354
360
  'transition-colors',
355
361
  'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2',
@@ -1033,7 +1039,14 @@ const tooltipVariants = tv({
1033
1039
  const themeSlotProps = themeDefaults == null ? void 0 : themeDefaults.slotProps;
1034
1040
  // Option C deep-merge: instance `tooltip` over `theme…defaults.tooltip`.
1035
1041
  const tooltipConfig = resolveFieldTooltip(props.tooltip, themeDefaults == null ? void 0 : (_themeDefaults_defaults = themeDefaults.defaults) == null ? void 0 : _themeDefaults_defaults.tooltip);
1036
- const { name, rules, visibleWhen, layout = 'stacked', size, label, helperText, required, error, disabled, fullWidth, access, sx, slotProps, placeholder, type, onChange: userOnChange, onBlur: userOnBlur, value: userValue, defaultValue } = merged, rest = _object_without_properties_loose(merged, [
1042
+ const { name, rules, visibleWhen, layout = 'stacked', size, label, helperText, required, error, disabled, fullWidth, access, sx, slotProps, placeholder, type, onChange: userOnChange, onBlur: userOnBlur, value: userValue, defaultValue, // Consume `tooltip` here so it does not leak into `...rest` and
1043
+ // end up as an unknown HTML attribute on the rendered <input>.
1044
+ // React 19 passes lowercase unknown attrs through silently, so
1045
+ // the value would ship as `tooltip="…"` on the DOM without any
1046
+ // console signal. Also strips the object form (`{ content, side, … }`)
1047
+ // whose default stringification is `[object Object]`.
1048
+ // See README-BUG § BUG 9.
1049
+ tooltip: _tooltip } = merged, rest = _object_without_properties_loose(merged, [
1037
1050
  "name",
1038
1051
  "rules",
1039
1052
  "visibleWhen",
@@ -1053,7 +1066,8 @@ const tooltipVariants = tv({
1053
1066
  "onChange",
1054
1067
  "onBlur",
1055
1068
  "value",
1056
- "defaultValue"
1069
+ "defaultValue",
1070
+ "tooltip"
1057
1071
  ]);
1058
1072
  // ───── Hooks (unconditional) ─────
1059
1073
  const bridge = useContext(DashFormContext);
@@ -1230,6 +1244,11 @@ const tooltipVariants = tv({
1230
1244
  'rounded border bg-neutral-50',
1231
1245
  'border-neutral-300',
1232
1246
  'transition-colors',
1247
+ // Radix.Checkbox.Root renders a `<button>`, whose UA cursor is
1248
+ // `default`. The label already reads `cursor-pointer`, but the
1249
+ // control itself needs the same affordance when the pointer
1250
+ // sits directly on the box. See README-BUG § BUG 13.
1251
+ 'cursor-pointer',
1233
1252
  'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-primary-500',
1234
1253
  // Radix data-state hooks
1235
1254
  'data-[state=checked]:bg-primary-500 data-[state=checked]:border-primary-500',
@@ -1754,6 +1773,11 @@ const tooltipVariants = tv({
1754
1773
  'rounded-full border bg-neutral-50',
1755
1774
  'border-neutral-300',
1756
1775
  'transition-colors',
1776
+ // Radix.RadioGroup.Item renders a `<button>`, whose UA cursor
1777
+ // is `default`. optionLabel already reads `cursor-pointer`, but
1778
+ // the control itself needs the same affordance when the pointer
1779
+ // sits directly on the circle. See README-BUG § BUG 13.
1780
+ 'cursor-pointer',
1757
1781
  'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-primary-500',
1758
1782
  'data-[state=checked]:border-primary-500',
1759
1783
  'data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed'
@@ -1889,6 +1913,15 @@ const tooltipVariants = tv({
1889
1913
  // must run before the visibility early-returns so hook ordering is
1890
1914
  // consistent across renders. See #113 / useStandaloneFieldWarning.
1891
1915
  useStandaloneFieldWarning('RadioGroup', name, Boolean(bridge == null ? void 0 : bridge.register), explicitValue, onValueChange);
1916
+ // Mirror of the above: warn if under a <DashFormProvider> AND the
1917
+ // consumer passed controlled-mode props (silently ignored in form
1918
+ // mode). See BUG 2 in libs/dashforge/README-BUG.md. Zero cost in
1919
+ // production.
1920
+ useWarnIfControlledInFormMode('RadioGroup', name, {
1921
+ value: explicitValue,
1922
+ defaultValue,
1923
+ onValueChange
1924
+ });
1892
1925
  // ───── Early returns ─────
1893
1926
  if (!isVisible) return null;
1894
1927
  if (!groupAccessState.visible) return null;
@@ -2136,7 +2169,11 @@ const tooltipVariants = tv({
2136
2169
  const themeSlotProps = themeDefaults == null ? void 0 : themeDefaults.slotProps;
2137
2170
  // Option C deep-merge: instance `tooltip` over `theme…defaults.tooltip`.
2138
2171
  const tooltipConfig = resolveFieldTooltip(props.tooltip, themeDefaults == null ? void 0 : (_themeDefaults_defaults = themeDefaults.defaults) == null ? void 0 : _themeDefaults_defaults.tooltip);
2139
- const { name, rules, visibleWhen, layout = 'stacked', size, resize, label, helperText, required, error, disabled, fullWidth, access, sx, slotProps, placeholder, rows = 3, onChange: userOnChange, onBlur: userOnBlur, value: userValue, defaultValue } = merged, rest = _object_without_properties_loose(merged, [
2172
+ const { name, rules, visibleWhen, layout = 'stacked', size, resize, label, helperText, required, error, disabled, fullWidth, access, sx, slotProps, placeholder, rows = 3, onChange: userOnChange, onBlur: userOnBlur, value: userValue, defaultValue, // Consume `tooltip` here so it does not leak into `...rest` and
2173
+ // end up as an unknown HTML attribute on the rendered <textarea>
2174
+ // (React 19 forwards lowercase unknown attrs silently). See
2175
+ // README-BUG § BUG 9.
2176
+ tooltip: _tooltip } = merged, rest = _object_without_properties_loose(merged, [
2140
2177
  "name",
2141
2178
  "rules",
2142
2179
  "visibleWhen",
@@ -2157,7 +2194,8 @@ const tooltipVariants = tv({
2157
2194
  "onChange",
2158
2195
  "onBlur",
2159
2196
  "value",
2160
- "defaultValue"
2197
+ "defaultValue",
2198
+ "tooltip"
2161
2199
  ]);
2162
2200
  // ───── Hooks (unconditional) ─────
2163
2201
  const bridge = useContext(DashFormContext);
@@ -2436,7 +2474,11 @@ const tooltipVariants = tv({
2436
2474
  const themeSlotProps = themeDefaults == null ? void 0 : themeDefaults.slotProps;
2437
2475
  // Option C deep-merge: instance `tooltip` over `theme…defaults.tooltip`.
2438
2476
  const tooltipConfig = resolveFieldTooltip(props.tooltip, themeDefaults == null ? void 0 : (_themeDefaults_defaults = themeDefaults.defaults) == null ? void 0 : _themeDefaults_defaults.tooltip);
2439
- const { name, rules, visibleWhen, layout = 'stacked', size, label, helperText, required, error, disabled, fullWidth, access, sx, slotProps, placeholder, min, max, step = 1, showStepper = false, onChange: userOnChange, onBlur: userOnBlur, value: userValue, defaultValue } = merged, rest = _object_without_properties_loose(merged, [
2477
+ const { name, rules, visibleWhen, layout = 'stacked', size, label, helperText, required, error, disabled, fullWidth, access, sx, slotProps, placeholder, min, max, step = 1, showStepper = false, onChange: userOnChange, onBlur: userOnBlur, value: userValue, defaultValue, // Consume `tooltip` here so it does not leak into `...rest` and
2478
+ // end up as an unknown HTML attribute on the rendered <input>
2479
+ // (React 19 forwards lowercase unknown attrs silently). See
2480
+ // README-BUG § BUG 9.
2481
+ tooltip: _tooltip } = merged, rest = _object_without_properties_loose(merged, [
2440
2482
  "name",
2441
2483
  "rules",
2442
2484
  "visibleWhen",
@@ -2459,7 +2501,8 @@ const tooltipVariants = tv({
2459
2501
  "onChange",
2460
2502
  "onBlur",
2461
2503
  "value",
2462
- "defaultValue"
2504
+ "defaultValue",
2505
+ "tooltip"
2463
2506
  ]);
2464
2507
  // ───── Hooks (unconditional) ─────
2465
2508
  const bridge = useContext(DashFormContext);
@@ -3185,14 +3228,51 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
3185
3228
  * (case-insensitive). Multi-select, free-solo text, generic option
3186
3229
  * shapes, and async runtime options (`optionsFromFieldData`) are
3187
3230
  * deferred to F5-A-bis.
3188
- */ function Autocomplete(props) {
3189
- var _themeDefaults_defaults, _themeSlotProps_root, _slotProps_root, _themeSlotProps_label, _slotProps_label, _themeSlotProps_requiredMark, _slotProps_requiredMark, _themeSlotProps_inputWrapper, _slotProps_inputWrapper, _themeSlotProps_chipsList, _slotProps_chipsList, _themeSlotProps_input, _slotProps_input, _themeSlotProps_clearButton, _slotProps_clearButton, _themeSlotProps_trigger, _slotProps_trigger, _themeSlotProps_popover, _slotProps_popover, _themeSlotProps_listBox, _slotProps_listBox, _themeSlotProps_emptyState, _slotProps_emptyState, _themeSlotProps_emptyState1, _slotProps_emptyState1, _themeSlotProps_errorText, _slotProps_errorText, _themeSlotProps_helperText, _slotProps_helperText;
3231
+ */ /**
3232
+ * Is this event ours?
3233
+ *
3234
+ * "Ours" is the root PLUS the listbox, and the second half is the whole
3235
+ * point. Since the listbox was portaled to `document.body` it is no
3236
+ * longer inside the component's DOM subtree, so `root.contains(target)`
3237
+ * answers FALSE for the options themselves — and two separate pieces of
3238
+ * code used that question to mean "is this mine?":
3239
+ *
3240
+ * the click-outside handler, which closed the popover and reset the
3241
+ * input on a mousedown over an option, before the option's own
3242
+ * `onClick` could run (mouse selection broken, keyboard fine);
3243
+ *
3244
+ * Radix's `DismissableLayer`, which dismissed on the focus that the
3245
+ * combobox input itself receives.
3246
+ *
3247
+ * Both are BUG 7 and BUG 8 in `libs/dashforge/README-BUG.md`. The
3248
+ * predicate exists so the rule has ONE definition and a test can pin
3249
+ * it — `rootRef` does not span the whole widget any more, and anything
3250
+ * here that reasons about containment has to say so out loud.
3251
+ */ function isWithinCombobox(target, root, listbox) {
3252
+ if (!target) return false;
3253
+ return Boolean(root == null ? void 0 : root.contains(target)) || Boolean(listbox == null ? void 0 : listbox.contains(target));
3254
+ }
3255
+ function Autocomplete(props) {
3256
+ var _themeDefaults_defaults, _themeSlotProps_root, _slotProps_root, _themeSlotProps_label, _slotProps_label, _themeSlotProps_requiredMark, _slotProps_requiredMark, _themeSlotProps_inputWrapper, _slotProps_inputWrapper, _themeSlotProps_chipsList, _slotProps_chipsList, _themeSlotProps_input, _slotProps_input, _themeSlotProps_clearButton, _slotProps_clearButton, _themeSlotProps_trigger, _slotProps_trigger, _themeSlotProps_input1, _slotProps_input1, _themeSlotProps_clearButton1, _slotProps_clearButton1, _themeSlotProps_trigger1, _slotProps_trigger1, _themeSlotProps_popover, _slotProps_popover, _themeSlotProps_listBox, _slotProps_listBox, _themeSlotProps_emptyState, _slotProps_emptyState, _themeSlotProps_emptyState1, _slotProps_emptyState1, _themeSlotProps_errorText, _slotProps_errorText, _themeSlotProps_helperText, _slotProps_helperText;
3190
3257
  const themeDefaults = useComponentDefaults('Autocomplete');
3191
3258
  const merged = _extends({}, themeDefaults == null ? void 0 : themeDefaults.defaults, props);
3192
3259
  const themeSlotProps = themeDefaults == null ? void 0 : themeDefaults.slotProps;
3193
3260
  // Option C deep-merge: instance `tooltip` over `theme…defaults.tooltip`.
3194
3261
  const tooltipConfig = resolveFieldTooltip(props.tooltip, themeDefaults == null ? void 0 : (_themeDefaults_defaults = themeDefaults.defaults) == null ? void 0 : _themeDefaults_defaults.tooltip);
3195
3262
  const { name, rules, options, visibleWhen, layout = 'stacked', size, label, helperText, required, error, disabled, fullWidth, access, sx, slotProps, placeholder, value: explicitValue, defaultValue, onValueChange, emptyMessage = 'No matching options', getOptionValue = defaultGetOptionValue, getOptionLabel = defaultGetOptionLabel, getOptionDisabled = defaultGetOptionDisabled, getOptionKey, multiple, freeSolo, loadOptions, loadDebounceMs = 250, loadingMessage = 'Loading…' } = merged;
3263
+ // Dev-mode warning: if this Autocomplete is running under a
3264
+ // <DashFormProvider> AND the consumer has passed any of the
3265
+ // controlled / uncontrolled value props, warn once per
3266
+ // (component, name, prop) that those props are silently ignored
3267
+ // in form mode. See BUG 2 in libs/dashforge/README-BUG.md — the
3268
+ // type-side split can only catch the `rules + defaultValue` combo
3269
+ // at compile time; this runtime rete covers the common case where
3270
+ // consumers pass no `rules`. Zero cost in production.
3271
+ useWarnIfControlledInFormMode('Autocomplete', name, {
3272
+ value: explicitValue,
3273
+ defaultValue,
3274
+ onValueChange
3275
+ });
3196
3276
  const isMulti = Boolean(multiple);
3197
3277
  // Default the React-key accessor to `getOptionValue` (typical case:
3198
3278
  // value is unique). Consumers override only when distinct option
@@ -3510,7 +3590,9 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
3510
3590
  const handlePointerDown = (event)=>{
3511
3591
  const root = rootRef.current;
3512
3592
  if (!root) return;
3513
- if (root.contains(event.target)) return;
3593
+ // The listbox counts as ours even though it is portaled out of
3594
+ // the root — see `isWithinCombobox`.
3595
+ if (isWithinCombobox(event.target, root, listboxRef.current)) return;
3514
3596
  closePopover();
3515
3597
  // Multi mode: just clear the filter query (chips remain).
3516
3598
  // Single + free-solo: commit the typed text as the value (the
@@ -3789,127 +3871,254 @@ const defaultGetOptionDisabled = (option)=>Boolean(option.disabled);
3789
3871
  children: "*"
3790
3872
  }))
3791
3873
  }),
3792
- jsxs("div", {
3793
- className: cn(v.inputWrapper(), // Multi mode: let chips wrap and replace the fixed `h-*`
3794
- // with `min-h-*` so the wrapper grows with selections.
3795
- isMulti && 'flex-wrap min-h-[var(--ac-min-h,2.5rem)] !h-auto py-1', themeSlotProps == null ? void 0 : (_themeSlotProps_inputWrapper = themeSlotProps.inputWrapper) == null ? void 0 : _themeSlotProps_inputWrapper.className, slotProps == null ? void 0 : (_slotProps_inputWrapper = slotProps.inputWrapper) == null ? void 0 : _slotProps_inputWrapper.className),
3874
+ jsxs(RadixPopover.Root, {
3875
+ open: isOpen,
3876
+ onOpenChange: (next)=>{
3877
+ if (!next) setIsOpen(false);
3878
+ },
3879
+ modal: false,
3796
3880
  children: [
3797
- isMulti && selectedKeys.size > 0 && jsx("div", {
3798
- className: cn(v.chipsList(), themeSlotProps == null ? void 0 : (_themeSlotProps_chipsList = themeSlotProps.chipsList) == null ? void 0 : _themeSlotProps_chipsList.className, slotProps == null ? void 0 : (_slotProps_chipsList = slotProps.chipsList) == null ? void 0 : _slotProps_chipsList.className),
3799
- children: Array.from(selectedKeys).map((key)=>{
3800
- var _labelAsString;
3801
- var _themeSlotProps_chip, _slotProps_chip, _themeSlotProps_chipRemove, _slotProps_chipRemove;
3802
- const opt = options.find((o)=>getOptionValue(o) === key);
3803
- const labelNode = opt ? getOptionLabel(opt) : key;
3804
- const labelText = opt ? (_labelAsString = labelAsString(opt)) != null ? _labelAsString : key : key;
3805
- return jsxs("span", {
3806
- className: cn(v.chip(), themeSlotProps == null ? void 0 : (_themeSlotProps_chip = themeSlotProps.chip) == null ? void 0 : _themeSlotProps_chip.className, slotProps == null ? void 0 : (_slotProps_chip = slotProps.chip) == null ? void 0 : _slotProps_chip.className),
3807
- "data-chip-key": key,
3808
- children: [
3809
- labelNode,
3810
- !effectiveDisabled && !effectiveReadOnly && jsx("button", {
3811
- type: "button",
3812
- onMouseDown: preventBlur,
3813
- onClick: ()=>{
3814
- var _inputRef_current;
3815
- commitSelection(key); // toggle removes
3816
- (_inputRef_current = inputRef.current) == null ? void 0 : _inputRef_current.focus();
3817
- },
3818
- "aria-label": `Remove ${labelText}`,
3819
- tabIndex: -1,
3820
- className: cn(v.chipRemove(), themeSlotProps == null ? void 0 : (_themeSlotProps_chipRemove = themeSlotProps.chipRemove) == null ? void 0 : _themeSlotProps_chipRemove.className, slotProps == null ? void 0 : (_slotProps_chipRemove = slotProps.chipRemove) == null ? void 0 : _slotProps_chipRemove.className),
3821
- children: jsx(CloseIcon, {})
3881
+ jsx(RadixPopover.Anchor, {
3882
+ asChild: true,
3883
+ children: jsxs("div", {
3884
+ className: cn(v.inputWrapper(), // Multi mode: let chips wrap and replace the fixed `h-*`
3885
+ // with `min-h-*` so the wrapper grows with selections.
3886
+ isMulti && 'flex-wrap min-h-[var(--ac-min-h,2.5rem)] !h-auto py-1', themeSlotProps == null ? void 0 : (_themeSlotProps_inputWrapper = themeSlotProps.inputWrapper) == null ? void 0 : _themeSlotProps_inputWrapper.className, slotProps == null ? void 0 : (_slotProps_inputWrapper = slotProps.inputWrapper) == null ? void 0 : _slotProps_inputWrapper.className),
3887
+ children: [
3888
+ isMulti && selectedKeys.size > 0 && jsx("div", {
3889
+ className: cn(v.chipsList(), themeSlotProps == null ? void 0 : (_themeSlotProps_chipsList = themeSlotProps.chipsList) == null ? void 0 : _themeSlotProps_chipsList.className, slotProps == null ? void 0 : (_slotProps_chipsList = slotProps.chipsList) == null ? void 0 : _slotProps_chipsList.className),
3890
+ children: Array.from(selectedKeys).map((key)=>{
3891
+ var _labelAsString;
3892
+ var _themeSlotProps_chip, _slotProps_chip, _themeSlotProps_chipRemove, _slotProps_chipRemove;
3893
+ const opt = options.find((o)=>getOptionValue(o) === key);
3894
+ const labelNode = opt ? getOptionLabel(opt) : key;
3895
+ const labelText = opt ? (_labelAsString = labelAsString(opt)) != null ? _labelAsString : key : key;
3896
+ return jsxs("span", {
3897
+ className: cn(v.chip(), themeSlotProps == null ? void 0 : (_themeSlotProps_chip = themeSlotProps.chip) == null ? void 0 : _themeSlotProps_chip.className, slotProps == null ? void 0 : (_slotProps_chip = slotProps.chip) == null ? void 0 : _slotProps_chip.className),
3898
+ "data-chip-key": key,
3899
+ children: [
3900
+ labelNode,
3901
+ !effectiveDisabled && !effectiveReadOnly && jsx("button", {
3902
+ type: "button",
3903
+ onMouseDown: preventBlur,
3904
+ onClick: ()=>{
3905
+ var _inputRef_current;
3906
+ commitSelection(key); // toggle removes
3907
+ (_inputRef_current = inputRef.current) == null ? void 0 : _inputRef_current.focus();
3908
+ },
3909
+ "aria-label": `Remove ${labelText}`,
3910
+ tabIndex: -1,
3911
+ className: cn(v.chipRemove(), themeSlotProps == null ? void 0 : (_themeSlotProps_chipRemove = themeSlotProps.chipRemove) == null ? void 0 : _themeSlotProps_chipRemove.className, slotProps == null ? void 0 : (_slotProps_chipRemove = slotProps.chipRemove) == null ? void 0 : _slotProps_chipRemove.className),
3912
+ children: jsx(CloseIcon, {})
3913
+ })
3914
+ ]
3915
+ }, key);
3822
3916
  })
3823
- ]
3824
- }, key);
3917
+ }),
3918
+ isMulti ? jsxs("div", {
3919
+ className: cn(// `min-w-0` on the controls group (and on the input
3920
+ // below) so the input can shrink when chips have taken
3921
+ // most of the outer wrapper's width. Without it, the
3922
+ // group's intrinsic min-content-size (input floor +
3923
+ // shrink-0 buttons) pushed the chevron past the right
3924
+ // edge by ~6px, which turned into a horizontal scrollbar
3925
+ // inside a `<Dialog>` (whose body is `overflow-y-auto`
3926
+ // and so computes `overflow-x: auto`). See BUG 5 in
3927
+ // README-BUG.md — the regression from the BUG 3 fix.
3928
+ 'flex items-center flex-nowrap flex-1 min-w-0', // The gap keeps the clear × visually separated from the
3929
+ // chevron when both are present.
3930
+ hasAnySelection && !effectiveDisabled && !effectiveReadOnly && 'gap-0.5'),
3931
+ children: [
3932
+ jsx("input", {
3933
+ ref: inputRef,
3934
+ id: `${baseId}-input`,
3935
+ name: name,
3936
+ type: "text",
3937
+ role: "combobox",
3938
+ "aria-autocomplete": "list",
3939
+ "aria-expanded": isOpen,
3940
+ "aria-controls": isOpen ? listboxId : undefined,
3941
+ "aria-activedescendant": activeOptionId,
3942
+ "aria-labelledby": label ? labelId : undefined,
3943
+ "aria-describedby": resolvedHelperText ? helperId : undefined,
3944
+ "aria-invalid": resolvedError ? true : undefined,
3945
+ "aria-required": required ? true : undefined,
3946
+ placeholder: // In multi mode hide the placeholder once the user has
3947
+ // at least one chip — chips already convey "something
3948
+ // is selected".
3949
+ selectedKeys.size > 0 ? undefined : placeholder,
3950
+ value: displayInputValue,
3951
+ onChange: handleInputChange,
3952
+ onKeyDown: handleKeyDown,
3953
+ onFocus: openPopover,
3954
+ onBlur: handleBlur,
3955
+ disabled: effectiveDisabled,
3956
+ readOnly: effectiveReadOnly,
3957
+ autoComplete: "off",
3958
+ // `flex-1` inside the non-wrap controls row: the input
3959
+ // expands to consume whatever the controls-row has left
3960
+ // after the two buttons. `basis-24` is the *preferred*
3961
+ // starting size; `min-w-0` lets the input shrink below
3962
+ // that when chips have consumed most of the outer
3963
+ // wrapper — same BUG 5 rationale as the group's
3964
+ // `min-w-0`. Buttons stay `shrink-0` and always
3965
+ // reachable; the input becomes narrow but still usable.
3966
+ className: cn(v.input(), 'min-w-0 flex-1 basis-24', themeSlotProps == null ? void 0 : (_themeSlotProps_input = themeSlotProps.input) == null ? void 0 : _themeSlotProps_input.className, slotProps == null ? void 0 : (_slotProps_input = slotProps.input) == null ? void 0 : _slotProps_input.className)
3967
+ }),
3968
+ hasAnySelection && !effectiveDisabled && !effectiveReadOnly && jsx("button", {
3969
+ type: "button",
3970
+ onMouseDown: preventBlur,
3971
+ onClick: handleClearClick,
3972
+ "aria-label": "Clear selection",
3973
+ tabIndex: -1,
3974
+ className: cn(v.clearButton(), themeSlotProps == null ? void 0 : (_themeSlotProps_clearButton = themeSlotProps.clearButton) == null ? void 0 : _themeSlotProps_clearButton.className, slotProps == null ? void 0 : (_slotProps_clearButton = slotProps.clearButton) == null ? void 0 : _slotProps_clearButton.className),
3975
+ children: jsx(CloseIcon, {})
3976
+ }),
3977
+ jsx("button", {
3978
+ type: "button",
3979
+ onMouseDown: preventBlur,
3980
+ onClick: handleTriggerClick,
3981
+ "aria-label": "Open",
3982
+ "aria-haspopup": "listbox",
3983
+ "aria-expanded": isOpen,
3984
+ tabIndex: -1,
3985
+ disabled: effectiveDisabled,
3986
+ className: cn(v.trigger(), themeSlotProps == null ? void 0 : (_themeSlotProps_trigger = themeSlotProps.trigger) == null ? void 0 : _themeSlotProps_trigger.className, slotProps == null ? void 0 : (_slotProps_trigger = slotProps.trigger) == null ? void 0 : _slotProps_trigger.className),
3987
+ children: jsx(ChevronDownIcon$1, {})
3988
+ })
3989
+ ]
3990
+ }) : jsxs(Fragment, {
3991
+ children: [
3992
+ jsx("input", {
3993
+ ref: inputRef,
3994
+ id: `${baseId}-input`,
3995
+ name: name,
3996
+ type: "text",
3997
+ role: "combobox",
3998
+ "aria-autocomplete": "list",
3999
+ "aria-expanded": isOpen,
4000
+ "aria-controls": isOpen ? listboxId : undefined,
4001
+ "aria-activedescendant": activeOptionId,
4002
+ "aria-labelledby": label ? labelId : undefined,
4003
+ "aria-describedby": resolvedHelperText ? helperId : undefined,
4004
+ "aria-invalid": resolvedError ? true : undefined,
4005
+ "aria-required": required ? true : undefined,
4006
+ placeholder: placeholder,
4007
+ value: displayInputValue,
4008
+ onChange: handleInputChange,
4009
+ onKeyDown: handleKeyDown,
4010
+ onFocus: openPopover,
4011
+ onBlur: handleBlur,
4012
+ disabled: effectiveDisabled,
4013
+ readOnly: effectiveReadOnly,
4014
+ autoComplete: "off",
4015
+ className: cn(v.input(), themeSlotProps == null ? void 0 : (_themeSlotProps_input1 = themeSlotProps.input) == null ? void 0 : _themeSlotProps_input1.className, slotProps == null ? void 0 : (_slotProps_input1 = slotProps.input) == null ? void 0 : _slotProps_input1.className)
4016
+ }),
4017
+ hasAnySelection && !effectiveDisabled && !effectiveReadOnly && jsx("button", {
4018
+ type: "button",
4019
+ onMouseDown: preventBlur,
4020
+ onClick: handleClearClick,
4021
+ "aria-label": "Clear selection",
4022
+ tabIndex: -1,
4023
+ className: cn(v.clearButton(), themeSlotProps == null ? void 0 : (_themeSlotProps_clearButton1 = themeSlotProps.clearButton) == null ? void 0 : _themeSlotProps_clearButton1.className, slotProps == null ? void 0 : (_slotProps_clearButton1 = slotProps.clearButton) == null ? void 0 : _slotProps_clearButton1.className),
4024
+ children: jsx(CloseIcon, {})
4025
+ }),
4026
+ jsx("button", {
4027
+ type: "button",
4028
+ onMouseDown: preventBlur,
4029
+ onClick: handleTriggerClick,
4030
+ "aria-label": "Open",
4031
+ "aria-haspopup": "listbox",
4032
+ "aria-expanded": isOpen,
4033
+ tabIndex: -1,
4034
+ disabled: effectiveDisabled,
4035
+ className: cn(v.trigger(), themeSlotProps == null ? void 0 : (_themeSlotProps_trigger1 = themeSlotProps.trigger) == null ? void 0 : _themeSlotProps_trigger1.className, slotProps == null ? void 0 : (_slotProps_trigger1 = slotProps.trigger) == null ? void 0 : _slotProps_trigger1.className),
4036
+ children: jsx(ChevronDownIcon$1, {})
4037
+ })
4038
+ ]
4039
+ })
4040
+ ]
3825
4041
  })
3826
4042
  }),
3827
- jsx("input", {
3828
- ref: inputRef,
3829
- id: `${baseId}-input`,
3830
- name: name,
3831
- type: "text",
3832
- role: "combobox",
3833
- "aria-autocomplete": "list",
3834
- "aria-expanded": isOpen,
3835
- "aria-controls": isOpen ? listboxId : undefined,
3836
- "aria-activedescendant": activeOptionId,
3837
- "aria-labelledby": label ? labelId : undefined,
3838
- "aria-describedby": resolvedHelperText ? helperId : undefined,
3839
- "aria-invalid": resolvedError ? true : undefined,
3840
- "aria-required": required ? true : undefined,
3841
- placeholder: // In multi mode hide the placeholder once the user has at
3842
- // least one chip — the chips already convey "something is
3843
- // selected" and the placeholder would clutter the UI.
3844
- isMulti && selectedKeys.size > 0 ? undefined : placeholder,
3845
- value: displayInputValue,
3846
- onChange: handleInputChange,
3847
- onKeyDown: handleKeyDown,
3848
- onFocus: openPopover,
3849
- onBlur: handleBlur,
3850
- disabled: effectiveDisabled,
3851
- readOnly: effectiveReadOnly,
3852
- autoComplete: "off",
3853
- // Multi mode: give the input some min-width so it stays
3854
- // clickable even with many chips, and let it shrink/grow with
3855
- // the available row space.
3856
- className: cn(v.input(), isMulti && 'min-w-[6rem] flex-1 basis-24', themeSlotProps == null ? void 0 : (_themeSlotProps_input = themeSlotProps.input) == null ? void 0 : _themeSlotProps_input.className, slotProps == null ? void 0 : (_slotProps_input = slotProps.input) == null ? void 0 : _slotProps_input.className)
3857
- }),
3858
- hasAnySelection && !effectiveDisabled && !effectiveReadOnly && jsx("button", {
3859
- type: "button",
3860
- onMouseDown: preventBlur,
3861
- onClick: handleClearClick,
3862
- "aria-label": "Clear selection",
3863
- tabIndex: -1,
3864
- className: cn(v.clearButton(), themeSlotProps == null ? void 0 : (_themeSlotProps_clearButton = themeSlotProps.clearButton) == null ? void 0 : _themeSlotProps_clearButton.className, slotProps == null ? void 0 : (_slotProps_clearButton = slotProps.clearButton) == null ? void 0 : _slotProps_clearButton.className),
3865
- children: jsx(CloseIcon, {})
3866
- }),
3867
- jsx("button", {
3868
- type: "button",
3869
- onMouseDown: preventBlur,
3870
- onClick: handleTriggerClick,
3871
- "aria-label": "Open",
3872
- "aria-haspopup": "listbox",
3873
- "aria-expanded": isOpen,
3874
- tabIndex: -1,
3875
- disabled: effectiveDisabled,
3876
- className: cn(v.trigger(), themeSlotProps == null ? void 0 : (_themeSlotProps_trigger = themeSlotProps.trigger) == null ? void 0 : _themeSlotProps_trigger.className, slotProps == null ? void 0 : (_slotProps_trigger = slotProps.trigger) == null ? void 0 : _slotProps_trigger.className),
3877
- children: jsx(ChevronDownIcon$1, {})
3878
- }),
3879
- isOpen && jsx("ul", {
3880
- ref: listboxRef,
3881
- id: listboxId,
3882
- role: "listbox",
3883
- "aria-labelledby": label ? labelId : undefined,
3884
- className: cn(v.popover(), 'absolute left-0 right-0 top-full', v.listBox(), themeSlotProps == null ? void 0 : (_themeSlotProps_popover = themeSlotProps.popover) == null ? void 0 : _themeSlotProps_popover.className, slotProps == null ? void 0 : (_slotProps_popover = slotProps.popover) == null ? void 0 : _slotProps_popover.className, themeSlotProps == null ? void 0 : (_themeSlotProps_listBox = themeSlotProps.listBox) == null ? void 0 : _themeSlotProps_listBox.className, slotProps == null ? void 0 : (_slotProps_listBox = slotProps.listBox) == null ? void 0 : _slotProps_listBox.className),
3885
- children: isLoading ? jsx("li", {
3886
- className: cn(v.emptyState(), themeSlotProps == null ? void 0 : (_themeSlotProps_emptyState = themeSlotProps.emptyState) == null ? void 0 : _themeSlotProps_emptyState.className, slotProps == null ? void 0 : (_slotProps_emptyState = slotProps.emptyState) == null ? void 0 : _slotProps_emptyState.className),
3887
- "aria-live": "polite",
3888
- "aria-busy": "true",
3889
- children: loadingMessage
3890
- }) : filteredOptions.length === 0 ? jsx("li", {
3891
- className: cn(v.emptyState(), themeSlotProps == null ? void 0 : (_themeSlotProps_emptyState1 = themeSlotProps.emptyState) == null ? void 0 : _themeSlotProps_emptyState1.className, slotProps == null ? void 0 : (_slotProps_emptyState1 = slotProps.emptyState) == null ? void 0 : _slotProps_emptyState1.className),
3892
- children: emptyMessage
3893
- }) : filteredOptions.map((opt, idx)=>{
3894
- var _themeSlotProps_listItem, _slotProps_listItem;
3895
- const optValue = getOptionValue(opt);
3896
- const optDisabled = getOptionDisabled(opt);
3897
- const isHighlighted = idx === highlightedIndex;
3898
- const isSelected = selectedKeys.has(optValue);
3899
- return jsx("li", {
3900
- id: `${optionIdPrefix}${optValue}`,
3901
- role: "option",
3902
- "aria-selected": isSelected,
3903
- "aria-disabled": optDisabled || undefined,
3904
- "data-focused": isHighlighted || undefined,
3905
- "data-selected": isSelected || undefined,
3906
- "data-disabled": optDisabled || undefined,
3907
- onMouseDown: preventBlur,
3908
- onClick: ()=>handleOptionClick(opt),
3909
- onMouseEnter: ()=>setHighlightedIndex(idx),
3910
- className: cn(v.listItem(), themeSlotProps == null ? void 0 : (_themeSlotProps_listItem = themeSlotProps.listItem) == null ? void 0 : _themeSlotProps_listItem.className, slotProps == null ? void 0 : (_slotProps_listItem = slotProps.listItem) == null ? void 0 : _slotProps_listItem.className),
3911
- children: getOptionLabel(opt)
3912
- }, resolveOptionKey(opt));
4043
+ isOpen && jsx(RadixPopover.Portal, {
4044
+ children: jsx(RadixPopover.Content, {
4045
+ asChild: true,
4046
+ side: "bottom",
4047
+ align: "start",
4048
+ sideOffset: 4,
4049
+ collisionPadding: 8,
4050
+ // Anchor width → listbox width (Radix exposes this CSS var).
4051
+ style: {
4052
+ width: 'var(--radix-popover-trigger-width)'
4053
+ },
4054
+ // Focus stays on the combobox input; Radix must not steal it.
4055
+ onOpenAutoFocus: (e)=>e.preventDefault(),
4056
+ onCloseAutoFocus: (e)=>e.preventDefault(),
4057
+ /*
4058
+ THE COMBOBOX INPUT IS NOT "OUTSIDE".
4059
+
4060
+ In a combobox the focused element is the `<input>`, and the
4061
+ input is the ANCHOR — it lives outside `Popover.Content`.
4062
+ Radix's `DismissableLayer` does not know that: it sees a
4063
+ `focusin` on an element outside the layer and dismisses.
4064
+
4065
+ The symptom is that the listbox opens on focus and closes
4066
+ about 10ms later, so the FIRST keystroke after clicking the
4067
+ field never shows suggestions and the field looks broken.
4068
+ Later keystrokes work, because they raise no new focus
4069
+ event — which makes it look intermittent rather than
4070
+ systematic.
4071
+
4072
+ Both handlers guard on the component root, which contains
4073
+ the input, the chevron and the clear button. Anything
4074
+ genuinely outside still dismisses, so click-away is
4075
+ unaffected.
4076
+ */ onFocusOutside: (event)=>{
4077
+ if (isWithinCombobox(event.target, rootRef.current, listboxRef.current)) {
4078
+ event.preventDefault();
4079
+ }
4080
+ },
4081
+ onInteractOutside: (event)=>{
4082
+ if (isWithinCombobox(event.target, rootRef.current, listboxRef.current)) {
4083
+ event.preventDefault();
4084
+ }
4085
+ },
4086
+ children: jsx("ul", {
4087
+ ref: listboxRef,
4088
+ id: listboxId,
4089
+ role: "listbox",
4090
+ "aria-labelledby": label ? labelId : undefined,
4091
+ className: cn(v.popover(), v.listBox(), themeSlotProps == null ? void 0 : (_themeSlotProps_popover = themeSlotProps.popover) == null ? void 0 : _themeSlotProps_popover.className, slotProps == null ? void 0 : (_slotProps_popover = slotProps.popover) == null ? void 0 : _slotProps_popover.className, themeSlotProps == null ? void 0 : (_themeSlotProps_listBox = themeSlotProps.listBox) == null ? void 0 : _themeSlotProps_listBox.className, slotProps == null ? void 0 : (_slotProps_listBox = slotProps.listBox) == null ? void 0 : _slotProps_listBox.className),
4092
+ children: isLoading ? jsx("li", {
4093
+ className: cn(v.emptyState(), themeSlotProps == null ? void 0 : (_themeSlotProps_emptyState = themeSlotProps.emptyState) == null ? void 0 : _themeSlotProps_emptyState.className, slotProps == null ? void 0 : (_slotProps_emptyState = slotProps.emptyState) == null ? void 0 : _slotProps_emptyState.className),
4094
+ "aria-live": "polite",
4095
+ "aria-busy": "true",
4096
+ children: loadingMessage
4097
+ }) : filteredOptions.length === 0 ? jsx("li", {
4098
+ className: cn(v.emptyState(), themeSlotProps == null ? void 0 : (_themeSlotProps_emptyState1 = themeSlotProps.emptyState) == null ? void 0 : _themeSlotProps_emptyState1.className, slotProps == null ? void 0 : (_slotProps_emptyState1 = slotProps.emptyState) == null ? void 0 : _slotProps_emptyState1.className),
4099
+ children: emptyMessage
4100
+ }) : filteredOptions.map((opt, idx)=>{
4101
+ var _themeSlotProps_listItem, _slotProps_listItem;
4102
+ const optValue = getOptionValue(opt);
4103
+ const optDisabled = getOptionDisabled(opt);
4104
+ const isHighlighted = idx === highlightedIndex;
4105
+ const isSelected = selectedKeys.has(optValue);
4106
+ return jsx("li", {
4107
+ id: `${optionIdPrefix}${optValue}`,
4108
+ role: "option",
4109
+ "aria-selected": isSelected,
4110
+ "aria-disabled": optDisabled || undefined,
4111
+ "data-focused": isHighlighted || undefined,
4112
+ "data-selected": isSelected || undefined,
4113
+ "data-disabled": optDisabled || undefined,
4114
+ onMouseDown: preventBlur,
4115
+ onClick: ()=>handleOptionClick(opt),
4116
+ onMouseEnter: ()=>setHighlightedIndex(idx),
4117
+ className: cn(v.listItem(), themeSlotProps == null ? void 0 : (_themeSlotProps_listItem = themeSlotProps.listItem) == null ? void 0 : _themeSlotProps_listItem.className, slotProps == null ? void 0 : (_slotProps_listItem = slotProps.listItem) == null ? void 0 : _slotProps_listItem.className),
4118
+ children: getOptionLabel(opt)
4119
+ }, resolveOptionKey(opt));
4120
+ })
4121
+ })
3913
4122
  })
3914
4123
  })
3915
4124
  ]
@@ -4415,6 +4624,15 @@ function CalendarIcon$2() {
4415
4624
  });
4416
4625
  };
4417
4626
  }, []);
4627
+ // Dev-mode warning: if under <DashFormProvider> AND the consumer
4628
+ // passed controlled-mode props (silently ignored in form mode),
4629
+ // fire once per (component, name, prop). Zero cost in prod. See
4630
+ // BUG 2 in libs/dashforge/README-BUG.md.
4631
+ useWarnIfControlledInFormMode('DatePicker', name, {
4632
+ value: explicitValue,
4633
+ defaultValue,
4634
+ onChange
4635
+ });
4418
4636
  // ───── Derived ─────
4419
4637
  const effectiveDisabled = Boolean(disabled) || accessState.disabled;
4420
4638
  const effectiveReadOnly = accessState.readonly;
@@ -10078,7 +10296,7 @@ Slider.displayName = 'Slider';
10078
10296
  'data-[disabled=true]:opacity-50 data-[disabled=true]:cursor-not-allowed'
10079
10297
  ],
10080
10298
  listItemIndicator: [
10081
- 'shrink-0 w-4 text-primary-700',
10299
+ 'shrink-0 w-4 h-4 text-primary-700',
10082
10300
  'opacity-0 data-[selected=true]:opacity-100'
10083
10301
  ],
10084
10302
  emptyState: 'px-3 py-2 text-sm text-neutral-500',
@@ -10249,6 +10467,17 @@ Slider.displayName = 'Slider';
10249
10467
  const helperId = `${controlId}-help`;
10250
10468
  const isFormMode = Boolean(bridge == null ? void 0 : bridge.register);
10251
10469
  useStandaloneFieldWarning('Select', name, isFormMode, userValue, onChange);
10470
+ // Mirror of useStandaloneFieldWarning: warn when running under a
10471
+ // <DashFormProvider> AND the consumer passed controlled-mode props
10472
+ // that are silently ignored in form mode. See BUG 2 in
10473
+ // libs/dashforge/README-BUG.md — closes the case the type-side
10474
+ // discriminant cannot see (React context is invisible at compile
10475
+ // time). Zero cost in production.
10476
+ useWarnIfControlledInFormMode('Select', name, {
10477
+ value: userValue,
10478
+ defaultValue,
10479
+ onChange
10480
+ });
10252
10481
  // StrictMode-safe unregister
10253
10482
  const unregisterRef = useRef({
10254
10483
  bridge,
@@ -15208,10 +15437,10 @@ VisuallyHidden.displayName = 'VisuallyHidden';
15208
15437
  * `useConfirm()` from `ConfirmDialog`). Use `<Dialog>` when you want
15209
15438
  * the control flow living in your component tree.
15210
15439
  */ function Dialog(props) {
15211
- var _themeSlotProps_overlay, _slotProps_overlay, _themeSlotProps_content, _slotProps_content, _themeSlotProps_title, _slotProps_title, _themeSlotProps_description, _slotProps_description, _themeSlotProps_body, _slotProps_body, _themeSlotProps_closeButton, _slotProps_closeButton;
15440
+ var _themeSlotProps_overlay, _slotProps_overlay, _themeSlotProps_content, _slotProps_content, _themeSlotProps_title, _slotProps_title, _themeSlotProps_description, _slotProps_description, _themeSlotProps_body, _slotProps_body, _themeSlotProps_actions, _slotProps_actions, _themeSlotProps_closeButton, _slotProps_closeButton;
15212
15441
  const themeDefaults = useComponentDefaults('Dialog');
15213
15442
  const merged = _extends({}, themeDefaults == null ? void 0 : themeDefaults.defaults, props);
15214
- const { open, onOpenChange, children, title, description, showCloseButton = true, disableBackdropClose = false, disableEscapeClose = false, size = 'md', sx, slotProps } = merged;
15443
+ const { open, onOpenChange, children, title, description, actions, showCloseButton = true, disableBackdropClose = false, disableEscapeClose = false, size = 'md', sx, slotProps } = merged;
15215
15444
  // Theme-level slotProps (Option C Track B). Theme classes go first,
15216
15445
  // instance classes second, so `tailwind-merge` picks the instance
15217
15446
  // where they collide.
@@ -15251,6 +15480,10 @@ VisuallyHidden.displayName = 'VisuallyHidden';
15251
15480
  className: cn(v.body(), themeSlotProps == null ? void 0 : (_themeSlotProps_body = themeSlotProps.body) == null ? void 0 : _themeSlotProps_body.className, slotProps == null ? void 0 : (_slotProps_body = slotProps.body) == null ? void 0 : _slotProps_body.className),
15252
15481
  children: children
15253
15482
  }),
15483
+ actions != null && jsx("div", {
15484
+ className: cn(v.actions(), themeSlotProps == null ? void 0 : (_themeSlotProps_actions = themeSlotProps.actions) == null ? void 0 : _themeSlotProps_actions.className, slotProps == null ? void 0 : (_slotProps_actions = slotProps.actions) == null ? void 0 : _slotProps_actions.className),
15485
+ children: actions
15486
+ }),
15254
15487
  showCloseButton && jsx(RadixDialog.Close, {
15255
15488
  "aria-label": "Close",
15256
15489
  className: cn(v.closeButton(), themeSlotProps == null ? void 0 : (_themeSlotProps_closeButton = themeSlotProps.closeButton) == null ? void 0 : _themeSlotProps_closeButton.className, slotProps == null ? void 0 : (_slotProps_closeButton = slotProps.closeButton) == null ? void 0 : _slotProps_closeButton.className),
@@ -15283,6 +15516,11 @@ const tabsVariants = tv({
15283
15516
  trigger: [
15284
15517
  'inline-flex items-center justify-center whitespace-nowrap',
15285
15518
  'text-sm font-medium transition-colors',
15519
+ // Radix Tabs.Trigger renders a `<button>`, whose UA cursor is
15520
+ // `default`. `disabled:pointer-events-none` neutralises it on
15521
+ // the disabled state (no pointer events → no cursor swap). See
15522
+ // README-BUG § BUG 13.
15523
+ 'cursor-pointer',
15286
15524
  'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-500',
15287
15525
  'disabled:opacity-50 disabled:pointer-events-none',
15288
15526
  'motion-reduce:transition-none'
@@ -19406,6 +19644,6 @@ function SearchIcon(props) {
19406
19644
  */ // ───── Components ─────
19407
19645
  /**
19408
19646
  * Package version (synced with `package.json` at publish time).
19409
- */ const VERSION = '1.5.1';
19647
+ */ const VERSION = '1.5.2';
19410
19648
 
19411
19649
  export { AVATAR_SOFT_FALLBACK, AVATAR_TONE_FALLBACK, Accordion, Alert, AlertTitle, AppShell, AspectRatio, Autocomplete, Avatar, AvatarGroup, Badge, Box, Breadcrumbs, Button, Calendar, Card, CardActionArea, CardContent, Checkbox, Chip, ConfirmDialogProvider, Container, DRAWER_SIZE_PRESETS, DataGrid, DatePicker, DateRangePicker, DateTimePicker, Dialog, Divider, Drawer, Grid, ICON_BUTTON_BASE, ICON_BUTTON_SIZE_OVERRIDES, IconButton, Image, LeftNav, Link, Menu, MenuContent, MenuItem, MenuLabel, MenuSeparator, MenuSkeleton, MenuTrigger, NumberField, OTPField, Pagination, Popover, Progress, RadioGroup, RenderButton, RenderChip, RenderText, RenderTwoLine, RowActionsMenu, SPINNER_COLORS, SPINNER_STROKE_WIDTH, SPINNER_TRACK_OPACITY, Select, Skeleton, Slider, SnackbarProvider, Spinner, Stack, Step, Stepper, Switch, Table, Tabs, TextField, Textarea, TimePicker, Tooltip, TopBar, Typography, VERSION, Video, VisuallyHidden, accordionVariants, alertVariants, appShellVariants, autocompleteVariants, avatarVariants, badgeVariants, boxVariants, breadcrumbsVariants, buttonVariants, calendarDayVariants, calendarVariants, checkboxVariants, chipVariants, cn, confirmDialogVariants, containerVariants, dataGridVariants, datePickerVariants, dateRangeDayVariants, dateRangePickerVariants, dateTimePickerVariants, dialogVariants, dividerLineVariants, dividerVariants, drawerVariants, getNestedValue, gridVariants, imageVariants, leftNavVariants, linkVariants, menuVariants, numberFieldVariants, otpFieldVariants, paginationVariants, popoverVariants, progressVariants, radioGroupVariants, selectVariants, skeletonVariants, sliderVariants, snackbarVariants, spinnerVariants, stackVariants, stepperVariants, switchVariants, tableVariants, tabsVariants, textFieldVariants, textareaVariants, timePickerVariants, tooltipVariants, topBarVariants, typographyVariants, useAccessState, useConfirm, useSnackbar, useStep, videoVariants };