@dashforge/tw 1.5.2 → 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/CHANGELOG.md CHANGED
@@ -12,6 +12,161 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
12
12
  > duplicated intentionally — no shared "lowest common denominator" headless
13
13
  > layer.
14
14
 
15
+ ## [1.6.0] — 2026-09-15
16
+
17
+ Minor release: three bug fixes (BUG 6 Dialog `actions` slot,
18
+ BUG 9 tooltip DOM leak, BUG 13 pointer cursor across every
19
+ interactive `<button>`), one runtime-rete for the DashForm mode
20
+ misuse (BUG 2 wiring on Autocomplete / Select / RadioGroup /
21
+ DatePicker via the new `useWarnIfControlledInFormMode` hook from
22
+ `@dashforge/ui-core@1.1.0`), and one type-only refactor of
23
+ `AutocompleteProps` into a discriminated union so form-mode and
24
+ standalone-mode props stop compiling together.
25
+
26
+ Requires `@dashforge/ui-core@^1.1.0` at runtime for the new hook.
27
+
28
+ ### Fixed
29
+
30
+ - **Every interactive `<button>` in the package now shows the pointer
31
+ cursor on hover** (BUG 13). `buttonVariants.base` lacked
32
+ `cursor-pointer`, and the browser UA stylesheet leaves `<button>`
33
+ at `cursor: default` — so every `<Button>`, `<IconButton>`, and
34
+ `Button` in `variant="link"` mode read as "unclickable" to the
35
+ person hovering. Same shape found in the same-pass audit on
36
+ `tabs.variants.ts` (Radix.Tabs.Trigger),
37
+ `checkbox.variants.ts` (Radix.Checkbox.Root), and
38
+ `radioGroup.variants.ts` (Radix.RadioGroup.Item) — all four are
39
+ Radix primitives that surface as `<button>` under the hood. Fixed
40
+ by adding `cursor-pointer` on each interactive base/slot; the
41
+ existing `disabled:pointer-events-none` /
42
+ `data-[disabled]:cursor-not-allowed` state resets already handle
43
+ disabled instances, and `loading` on `<Button>` still overrides
44
+ to `cursor-wait` (tailwind-variants precedence). New test file
45
+ `_shared/cursorPointerAffordance.test.tsx` (7 assertions) pins
46
+ both the recipe-level class string and the rendered-DOM
47
+ `className` for `<Button>` and `<IconButton>`, so a future edit
48
+ that strips the class fails loudly. See `README-BUG.md § BUG 13`.
49
+
50
+ ### Added
51
+
52
+ - **`<Dialog>` gained an `actions` prop** (`ReactNode`) that renders
53
+ a right-aligned footer row below the body and above the close
54
+ button. The variant + `slotProps.actions` entry already existed
55
+ in the package but had never been rendered — declared API that
56
+ did nothing (README-BUG § BUG 6). The alignment (`flex justify-end
57
+ gap-2 pt-2`) is the design-system decision encoded in
58
+ `dialog.variants.ts:52` and had been surfaced consistently in
59
+ hand-rolled action rows across consumer forms; the prop lets
60
+ consumers drop that boilerplate. Additive — existing dialogs
61
+ without `actions` render identically to before.
62
+
63
+ - **Dev-mode warning when controlled / uncontrolled props are passed
64
+ to a bridge-integrated field inside a `<DashFormProvider>`** — the
65
+ runtime rete for README-BUG § BUG 2. Applied to `<Autocomplete>`,
66
+ `<Select>`, `<RadioGroup>` and `<DatePicker>` (the four
67
+ highest-usage field components; 10 more follow in a consistency
68
+ pass). Each component calls the new `useWarnIfControlledInFormMode`
69
+ hook from `@dashforge/ui-core` with its name and the destructured
70
+ controlled props; the hook warns once per
71
+ `(componentName, name, propKey)` triple with a message naming the
72
+ offending prop and the correct API (`<DashForm defaultValues={{
73
+ [name]: … }} />`). Zero cost in production — the effect body is
74
+ guarded by `process.env.NODE_ENV !== 'production'`.
75
+
76
+ Works alongside the existing type-surface split on `Autocomplete`
77
+ (which catches `rules + defaultValue` at compile time). The two
78
+ reties are complementary: types cover the `rules`-carrying case
79
+ before compile, the runtime warning covers the common case
80
+ (`rules`-less) on first render.
81
+
82
+ ### Changed
83
+
84
+ - **`<Autocomplete>` — `AutocompleteProps` split into a discriminated
85
+ union of two mode variants** (form / standalone) to close the
86
+ type-surface bug where controlled/uncontrolled value props
87
+ (`value`, `defaultValue`, `onValueChange`) were accepted alongside
88
+ `rules` and silently ignored at runtime in form mode. The runtime
89
+ behaviour is unchanged (form-mode initial values still come from
90
+ `<DashForm defaultValues={...}>` via the bridge); the fix is
91
+ purely at the TypeScript layer:
92
+
93
+ - `AutocompleteFormMixin` marks form mode via optional `rules`;
94
+ the controlled/uncontrolled props are typed `never`.
95
+ - `AutocompleteStandaloneMixin` marks standalone mode via optional
96
+ `value` / `defaultValue` / `onValueChange`; `rules` is typed
97
+ `never`.
98
+ - Consumer surface `AutocompleteProps<TOption>` still exports as a
99
+ single name — the discrimination is transparent at import sites.
100
+
101
+ Consumer misuse audit (dash, docs-lab, kits) surfaced zero existing
102
+ callers with the mixed-mode pattern, so no downstream code
103
+ changes are required. Type-regression pinned by
104
+ `autocomplete.props.type-test.ts` (compile-only, three
105
+ `@ts-expect-error` markers). See `libs/dashforge/README-BUG.md`
106
+ § BUG 2 for the full context.
107
+
108
+ ### Fixed
109
+
110
+ - **`<TextField>`, `<NumberField>` and `<Textarea>` no longer leak
111
+ the `tooltip` prop onto the rendered `<input>` / `<textarea>` as
112
+ an unknown HTML attribute.** These three components spread
113
+ `{...rest}` onto their DOM element after destructuring `merged`,
114
+ and `tooltip` was not in the destructured keys, so its value
115
+ landed on the DOM as `tooltip="…"` (the object form of the prop
116
+ stringified to `"[object Object]"`). React 19 forwards lowercase
117
+ unknown attrs silently, so nothing signalled it in dev — it took
118
+ a Playwright strict-mode failure to notice. Fix: three one-line
119
+ destructure edits consuming `tooltip` before the `...rest` catch.
120
+ Regression guard in
121
+ `libs/dashforge/tw/src/components/_shared/tooltipDomLeak.test.tsx`.
122
+ See README-BUG § BUG 9 — the report's original "all nine field
123
+ components" scope was corrected to these three after verification
124
+ (the other six do not spread `{...rest}` onto any DOM element and
125
+ therefore cannot leak structurally; Autocomplete was empirically
126
+ probed as an anchor).
127
+
128
+ - **`<Autocomplete multiple>` — the control no longer overflows its
129
+ own width by ~6px** (a regression introduced by the BUG 3 chevron
130
+ wrap fix earlier in this Unreleased block). The controls group
131
+ and the input inside it both went from `min-w-[6rem]` to
132
+ `min-w-0`, so the input can shrink under pressure and the
133
+ `shrink-0` clear + chevron buttons always fit inside the group.
134
+ The previous floor combined with the shrink-0 buttons produced an
135
+ intrinsic min-content-size of ~156px and pushed the chevron 6px
136
+ past the group's right edge when chips had consumed most of the
137
+ outer wrapper — which turned into a horizontal scrollbar inside
138
+ a `<Dialog>` (whose body is `overflow-y-auto` and so computes
139
+ `overflow-x: auto`). The BUG 3 invariant is preserved: the
140
+ chevron stays on the same row as the input, never orphaned.
141
+ Fixes README-BUG § BUG 5.
142
+
143
+ - **`<Autocomplete multiple>` — the chevron no longer wraps onto its
144
+ own line on narrow fields.** Multi mode's outer `flex-wrap`
145
+ context (needed so chip rows can grow vertically) used to let the
146
+ chevron drop onto an orphan row whenever the row width fell below
147
+ ~400px with two or more chips, producing a 90px-tall control with
148
+ an empty band. The fix keeps the `flex-wrap` on the outer wrapper
149
+ (so chips still wrap freely) but nests the input, clear `×` and
150
+ chevron in a `flex-nowrap` inner row of their own — that inner
151
+ row is structurally indivisible, so the chevron can never orphan.
152
+ Single-mode DOM is unchanged. See `libs/dashforge/README-BUG.md`
153
+ § BUG 3 for the full context and the DOM verification.
154
+ - **`<Autocomplete>` — the listbox is now portaled** to `document.body`
155
+ via `RadixPopover.Portal`, so ancestor `overflow: hidden` /
156
+ `overflow: auto` containers can no longer clip it. Fixes the
157
+ fault-line that made "multi-select in a modal form" unusable
158
+ (`<Dialog><DashForm><Autocomplete multiple/></DashForm></Dialog>`
159
+ clipped the dropdown at the dialog body's scroll boundary, and the
160
+ same happened inside any `overflow-hidden` card such as the
161
+ `inventory-kit` `SectionCard`). See `libs/dashforge/README-BUG.md`
162
+ § BUG 1 for the full context. Width is still tied to the anchor
163
+ (via Radix's `--radix-popover-trigger-width` CSS var), keyboard
164
+ model / `aria-controls` / `aria-activedescendant` / `preventBlur`
165
+ on options are unchanged, and Radix's focus management is
166
+ intentionally disabled so focus stays on the input as before.
167
+ Downstream `overflowVisible`-prop workarounds can be removed
168
+ when this ships.
169
+
15
170
  ## [1.5.2] — 2026-08-30
16
171
 
17
172
  ### Fixed
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dashforge
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
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;
@@ -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'
@@ -28,5 +28,27 @@ import type { AutocompleteOption, AutocompleteProps } from './autocomplete.types
28
28
  * shapes, and async runtime options (`optionsFromFieldData`) are
29
29
  * deferred to F5-A-bis.
30
30
  */
31
+ /**
32
+ * Is this event ours?
33
+ *
34
+ * "Ours" is the root PLUS the listbox, and the second half is the whole
35
+ * point. Since the listbox was portaled to `document.body` it is no
36
+ * longer inside the component's DOM subtree, so `root.contains(target)`
37
+ * answers FALSE for the options themselves — and two separate pieces of
38
+ * code used that question to mean "is this mine?":
39
+ *
40
+ * the click-outside handler, which closed the popover and reset the
41
+ * input on a mousedown over an option, before the option's own
42
+ * `onClick` could run (mouse selection broken, keyboard fine);
43
+ *
44
+ * Radix's `DismissableLayer`, which dismissed on the focus that the
45
+ * combobox input itself receives.
46
+ *
47
+ * Both are BUG 7 and BUG 8 in `libs/dashforge/README-BUG.md`. The
48
+ * predicate exists so the rule has ONE definition and a test can pin
49
+ * it — `rootRef` does not span the whole widget any more, and anything
50
+ * here that reasons about containment has to say so out loud.
51
+ */
52
+ export declare function isWithinCombobox(target: Node | null, root: HTMLElement | null, listbox: HTMLElement | null): boolean;
31
53
  export declare function Autocomplete<TOption = AutocompleteOption>(props: AutocompleteProps<TOption>): import("react/jsx-runtime").JSX.Element | null;
32
54
  //# sourceMappingURL=Autocomplete.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Autocomplete.d.ts","sourceRoot":"","sources":["../../../../src/components/Autocomplete/Autocomplete.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EAElB,MAAM,yBAAyB,CAAC;AA8FjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAG,kBAAkB,EACvD,KAAK,EAAE,iBAAiB,CAAC,OAAO,CAAC,kDAo6BlC"}
1
+ {"version":3,"file":"Autocomplete.d.ts","sourceRoot":"","sources":["../../../../src/components/Autocomplete/Autocomplete.tsx"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EAElB,MAAM,yBAAyB,CAAC;AA8FjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,IAAI,GAAG,IAAI,EACnB,IAAI,EAAE,WAAW,GAAG,IAAI,EACxB,OAAO,EAAE,WAAW,GAAG,IAAI,GAC1B,OAAO,CAGT;AAED,wBAAgB,YAAY,CAAC,OAAO,GAAG,kBAAkB,EACvD,KAAK,EAAE,iBAAiB,CAAC,OAAO,CAAC,kDA6lClC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=autocomplete.props.type-test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autocomplete.props.type-test.d.ts","sourceRoot":"","sources":["../../../../src/components/Autocomplete/autocomplete.props.type-test.ts"],"names":[],"mappings":""}
@@ -110,21 +110,14 @@ export interface AutocompleteSlotProps {
110
110
  */
111
111
  export type AutocompleteValue = string | string[] | null;
112
112
  /**
113
- * Props for `<Autocomplete>`.
114
- *
115
- * Bridge-integrated single-select combobox with full ARIA combobox
116
- * a11y, keyboard navigation, and Form Closure v1 error gating.
117
- *
118
- * Mirrors the MUI-side `@dashforge/ui/Autocomplete` at the bridge
119
- * level — same `name` / `rules` / `visibleWhen` / `access` semantics,
120
- * same StrictMode-safe unregister-on-unmount.
113
+ * Common `<Autocomplete>` props shared by both mode variants (bridge /
114
+ * standalone). Not a public export — consumers use `AutocompleteProps`,
115
+ * which merges these with a mode-specific mixin (`AutocompleteFormMixin`
116
+ * or `AutocompleteStandaloneMixin`).
121
117
  *
122
- * @typeParam TOption Shape of an option. Defaults to
123
- * `AutocompleteOption` (`{ value, label, disabled? }`).
124
- * Pass `<TOption>` + `getOptionValue` / `getOptionLabel`
125
- * for arbitrary domain types.
118
+ * @internal
126
119
  */
127
- export interface AutocompleteProps<TOption = AutocompleteOption> {
120
+ interface AutocompleteBaseProps<TOption = AutocompleteOption> {
128
121
  /**
129
122
  * Density tier — drives wrapper padding + input font-size.
130
123
  * @default 'md'
@@ -141,10 +134,12 @@ export interface AutocompleteProps<TOption = AutocompleteOption> {
141
134
  * @default false
142
135
  */
143
136
  fullWidth?: AutocompleteVariants['fullWidth'];
144
- /** Bridge field name (required when used inside `DashFormProvider`). */
137
+ /**
138
+ * Field name — used for the HTML `<input name>` attribute and, when a
139
+ * `DashFormProvider` is present in the tree, as the bridge registration
140
+ * key. Required in both modes.
141
+ */
145
142
  name: string;
146
- /** RHF validation rules — opaque, forwarded to the bridge. */
147
- rules?: unknown;
148
143
  /** Selectable options — an array of `TOption` (defaults to `AutocompleteOption`). */
149
144
  options: TOption[];
150
145
  /** Visible label above (or left of, per `layout`) the combobox. */
@@ -182,12 +177,6 @@ export interface AutocompleteProps<TOption = AutocompleteOption> {
182
177
  sx?: string;
183
178
  /** Per-slot className overrides. */
184
179
  slotProps?: AutocompleteSlotProps;
185
- /** Controlled value (form mode reads from the bridge if omitted). */
186
- value?: AutocompleteValue;
187
- /** Default value for uncontrolled mode (no-op in form mode). */
188
- defaultValue?: AutocompleteValue;
189
- /** Fires when the user picks an option (after bridge update in form mode). */
190
- onValueChange?: (value: AutocompleteValue) => void;
191
180
  /** Fallback text when no option matches the typed filter. */
192
181
  emptyMessage?: string;
193
182
  /**
@@ -266,4 +255,96 @@ export interface AutocompleteProps<TOption = AutocompleteOption> {
266
255
  */
267
256
  getOptionKey?: (option: TOption) => string;
268
257
  }
258
+ /**
259
+ * Mode mixin for bridge-integrated (form) use — the component is
260
+ * mounted under a `<DashFormProvider>` and reads / writes values
261
+ * through the bridge.
262
+ *
263
+ * The controlled / uncontrolled value props (`value`, `defaultValue`,
264
+ * `onValueChange`) are **forbidden by construction** in this mode.
265
+ * Initial values live on `<DashForm defaultValues={...}>`, current
266
+ * value comes from the bridge, and consumer notifications go through
267
+ * `<DashForm onSubmit={...}>` / reactions. Passing any of the
268
+ * controlled props in this mode was previously a silent runtime no-op
269
+ * (README-BUG § BUG 2) — the type surface now catches it at
270
+ * compile time.
271
+ *
272
+ * The presence of `rules` marks a component as form-mode-only.
273
+ *
274
+ * @internal
275
+ */
276
+ interface AutocompleteFormMixin {
277
+ /** RHF validation rules — opaque, forwarded to the bridge. */
278
+ rules?: unknown;
279
+ /**
280
+ * Not available in form mode. Values in form mode come from
281
+ * `<DashForm defaultValues={...}>` via the bridge.
282
+ */
283
+ value?: never;
284
+ /**
285
+ * Not available in form mode. Set initial values on
286
+ * `<DashForm defaultValues={...}>` instead.
287
+ */
288
+ defaultValue?: never;
289
+ /**
290
+ * Not available in form mode. Use `<DashForm onSubmit={...}>` or
291
+ * a reaction watching this field name.
292
+ */
293
+ onValueChange?: never;
294
+ }
295
+ /**
296
+ * Mode mixin for standalone (controlled / uncontrolled) use — the
297
+ * component is mounted outside a `<DashFormProvider>`, or the consumer
298
+ * deliberately wants to bypass the bridge and manage state locally.
299
+ *
300
+ * The `rules` prop is **forbidden by construction** in this mode
301
+ * (no bridge → nowhere to forward rules to).
302
+ *
303
+ * @internal
304
+ */
305
+ interface AutocompleteStandaloneMixin {
306
+ /**
307
+ * Not available in standalone mode. There is no bridge to forward
308
+ * rules to — validate at the consumer level.
309
+ */
310
+ rules?: never;
311
+ /** Controlled value. */
312
+ value?: AutocompleteValue;
313
+ /** Default value (uncontrolled). */
314
+ defaultValue?: AutocompleteValue;
315
+ /** Fires when the user picks an option. */
316
+ onValueChange?: (value: AutocompleteValue) => void;
317
+ }
318
+ /**
319
+ * Props for `<Autocomplete>`.
320
+ *
321
+ * Bridge-integrated single-select combobox with full ARIA combobox
322
+ * a11y, keyboard navigation, and Form Closure v1 error gating.
323
+ *
324
+ * Mirrors the MUI-side `@dashforge/ui/Autocomplete` at the bridge
325
+ * level — same `name` / `rules` / `visibleWhen` / `access` semantics,
326
+ * same StrictMode-safe unregister-on-unmount.
327
+ *
328
+ * ## Two modes, mutually exclusive at the type level
329
+ *
330
+ * `AutocompleteProps` is a **discriminated union** of two modes:
331
+ *
332
+ * - **Form mode** (`AutocompleteFormMixin`) — component runs inside
333
+ * `<DashFormProvider>`. Passing `rules` marks this variant. The
334
+ * controlled/uncontrolled value props (`value`, `defaultValue`,
335
+ * `onValueChange`) are typed as `never` and rejected at compile
336
+ * time. Initial values come from `<DashForm defaultValues={...}>`,
337
+ * current value from the bridge.
338
+ * - **Standalone mode** (`AutocompleteStandaloneMixin`) — component
339
+ * is uncontrolled or consumer-controlled via `value` /
340
+ * `defaultValue` / `onValueChange`. The `rules` prop is typed as
341
+ * `never` in this branch (no bridge to forward to).
342
+ *
343
+ * @typeParam TOption Shape of an option. Defaults to
344
+ * `AutocompleteOption` (`{ value, label, disabled? }`).
345
+ * Pass `<TOption>` + `getOptionValue` / `getOptionLabel`
346
+ * for arbitrary domain types.
347
+ */
348
+ export type AutocompleteProps<TOption = AutocompleteOption> = AutocompleteBaseProps<TOption> & (AutocompleteFormMixin | AutocompleteStandaloneMixin);
349
+ export {};
269
350
  //# sourceMappingURL=autocomplete.types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"autocomplete.types.d.ts","sourceRoot":"","sources":["../../../../src/components/Autocomplete/autocomplete.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"autocomplete.types.d.ts","sourceRoot":"","sources":["../../../../src/components/Autocomplete/autocomplete.types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"button.variants.d.ts","sourceRoot":"","sources":["../../../../src/components/Button/button.variants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qDAiIzB,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,YAAY,CAAC,OAAO,cAAc,CAAC,CAAC"}
1
+ {"version":3,"file":"button.variants.d.ts","sourceRoot":"","sources":["../../../../src/components/Button/button.variants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qDAuIzB,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,YAAY,CAAC,OAAO,cAAc,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"checkbox.variants.d.ts","sourceRoot":"","sources":["../../../../src/components/Checkbox/checkbox.variants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CAgD3B,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,YAAY,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
1
+ {"version":3,"file":"checkbox.variants.d.ts","sourceRoot":"","sources":["../../../../src/components/Checkbox/checkbox.variants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CAqD3B,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,YAAY,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"DatePicker.d.ts","sourceRoot":"","sources":["../../../../src/components/DatePicker/DatePicker.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAqD7D;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,kDA4OjD"}
1
+ {"version":3,"file":"DatePicker.d.ts","sourceRoot":"","sources":["../../../../src/components/DatePicker/DatePicker.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAqD7D;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,kDAsPjD"}
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../../../../src/components/Dialog/Dialog.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,2CAmHxC"}
1
+ {"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../../../../src/components/Dialog/Dialog.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,2CA+HxC"}
@@ -76,6 +76,34 @@ export interface DialogProps {
76
76
  title?: ReactNode;
77
77
  /** Dialog description (announced via `aria-describedby`). */
78
78
  description?: ReactNode;
79
+ /**
80
+ * Footer action bar — usually one or more `<Button>`s. Rendered
81
+ * below the body in a right-aligned flex row (`flex justify-end
82
+ * gap-2 pt-2` — see `dialog.variants.ts` `actions` slot). Omit
83
+ * to render no action row.
84
+ *
85
+ * The alignment is a design-system decision (primary action at
86
+ * the bottom-right corner) and is intentionally encoded here so
87
+ * every consumer does not re-decide it in the body.
88
+ *
89
+ * @example
90
+ * ```tsx
91
+ * <Dialog
92
+ * open={open}
93
+ * onOpenChange={setOpen}
94
+ * title="Delete article"
95
+ * actions={
96
+ * <>
97
+ * <Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
98
+ * <Button variant="solid" color="danger" onClick={confirm}>Delete</Button>
99
+ * </>
100
+ * }
101
+ * >
102
+ * Are you sure? This cannot be undone.
103
+ * </Dialog>
104
+ * ```
105
+ */
106
+ actions?: ReactNode;
79
107
  /**
80
108
  * Show the `×` close button in the top-right corner.
81
109
  * @default true
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.types.d.ts","sourceRoot":"","sources":["../../../../src/components/Dialog/dialog.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAC9B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,OAAO,QAAQ,sBAAsB,CAAC;IACpC,UAAU,mBAAmB;QAC3B,MAAM,CAAC,EAAE;YACP,QAAQ,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;YACvC,SAAS,CAAC,EAAE,eAAe,CAAC;SAC7B,CAAC;KACH;CACF;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjC,KAAK,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/B,WAAW,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,WAAW,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAClC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAE9B,6BAA6B;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,4DAA4D;IAC5D,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,yDAAyD;IACzD,QAAQ,EAAE,SAAS,CAAC;IACpB,oEAAoE;IACpE,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,sDAAsD;IACtD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,0BAA0B;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B"}
1
+ {"version":3,"file":"dialog.types.d.ts","sourceRoot":"","sources":["../../../../src/components/Dialog/dialog.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAC9B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,OAAO,QAAQ,sBAAsB,CAAC;IACpC,UAAU,mBAAmB;QAC3B,MAAM,CAAC,EAAE;YACP,QAAQ,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;YACvC,SAAS,CAAC,EAAE,eAAe,CAAC;SAC7B,CAAC;KACH;CACF;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjC,KAAK,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/B,WAAW,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,WAAW,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAClC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAE9B,6BAA6B;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,4DAA4D;IAC5D,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,yDAAyD;IACzD,QAAQ,EAAE,SAAS,CAAC;IACpB,oEAAoE;IACpE,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,sDAAsD;IACtD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,0BAA0B;IAC1B,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B"}
@@ -1 +1 @@
1
- {"version":3,"file":"NumberField.d.ts","sourceRoot":"","sources":["../../../../src/components/NumberField/NumberField.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAuC/D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,kDA2QlD"}
1
+ {"version":3,"file":"NumberField.d.ts","sourceRoot":"","sources":["../../../../src/components/NumberField/NumberField.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAuC/D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,kDAgRlD"}
@@ -1 +1 @@
1
- {"version":3,"file":"RadioGroup.d.ts","sourceRoot":"","sources":["../../../../src/components/RadioGroup/RadioGroup.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,kDAkQhD"}
1
+ {"version":3,"file":"RadioGroup.d.ts","sourceRoot":"","sources":["../../../../src/components/RadioGroup/RadioGroup.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,kDA4QhD"}
@@ -1 +1 @@
1
- {"version":3,"file":"radioGroup.variants.d.ts","sourceRoot":"","sources":["../../../../src/components/RadioGroup/radioGroup.variants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CA6D7B,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
1
+ {"version":3,"file":"radioGroup.variants.d.ts","sourceRoot":"","sources":["../../../../src/components/RadioGroup/radioGroup.variants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CAkE7B,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../../src/components/Select/Select.tsx"],"names":[],"mappings":"AAAA,OAAO,EAUL,KAAK,YAAY,EAElB,MAAM,OAAO,CAAC;AAYf,OAAO,KAAK,EAIV,WAAW,EACX,WAAW,EACZ,MAAM,mBAAmB,CAAC;AA0lB3B;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,EAA8B,CAAC,CAAC,SAAS,WAAW,GAAG,MAAM,EAC9E,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;CAAE,KAC3D,YAAY,GAAG,IAAI,CAAC"}
1
+ {"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../../src/components/Select/Select.tsx"],"names":[],"mappings":"AAAA,OAAO,EAUL,KAAK,YAAY,EAElB,MAAM,OAAO,CAAC;AAgBf,OAAO,KAAK,EAIV,WAAW,EACX,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAsmB3B;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,EAA8B,CAAC,CAAC,SAAS,WAAW,GAAG,MAAM,EAC9E,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;CAAE,KAC3D,YAAY,GAAG,IAAI,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.variants.d.ts","sourceRoot":"","sources":["../../../../src/components/Tabs/tabs.variants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE1D,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CAgEvB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,YAAY,CAAC,OAAO,YAAY,CAAC,CAAC"}
1
+ {"version":3,"file":"tabs.variants.d.ts","sourceRoot":"","sources":["../../../../src/components/Tabs/tabs.variants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE1D,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CAqEvB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,YAAY,CAAC,OAAO,YAAY,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"TextField.d.ts","sourceRoot":"","sources":["../../../../src/components/TextField/TextField.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,kDA6N9C"}
1
+ {"version":3,"file":"TextField.d.ts","sourceRoot":"","sources":["../../../../src/components/TextField/TextField.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,kDAqO9C"}
@@ -1 +1 @@
1
- {"version":3,"file":"Textarea.d.ts","sourceRoot":"","sources":["../../../../src/components/Textarea/Textarea.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,kDA+K5C"}
1
+ {"version":3,"file":"Textarea.d.ts","sourceRoot":"","sources":["../../../../src/components/Textarea/Textarea.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,kDAoL5C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dashforge/tw",
3
- "version": "1.5.2",
3
+ "version": "1.6.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.esm.js",
@@ -35,8 +35,8 @@
35
35
  "tailwind-merge": "^3.0.0",
36
36
  "tailwind-variants": "^3.1.1",
37
37
  "@dashforge/calendar-core": "1.0.0",
38
- "@dashforge/ui-core": "1.0.0",
39
- "@dashforge/forms": "1.0.0",
38
+ "@dashforge/ui-core": "1.1.0",
39
+ "@dashforge/forms": "1.1.0",
40
40
  "@dashforge/rbac": "1.0.0"
41
41
  },
42
42
  "peerDependencies": {
@@ -47,6 +47,8 @@
47
47
  },
48
48
  "devDependencies": {
49
49
  "@vitejs/plugin-react": "*",
50
+ "react": "^19.2.5",
51
+ "react-dom": "^19.2.5",
50
52
  "vitest": "*"
51
53
  }
52
54
  }