@dashforge/tw 1.6.0 → 1.7.1

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.
Files changed (27) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/dist/index.esm.js +198 -23
  3. package/dist/src/components/Autocomplete/Autocomplete.d.ts.map +1 -1
  4. package/dist/src/components/Checkbox/Checkbox.d.ts.map +1 -1
  5. package/dist/src/components/Checkbox/checkbox.types.d.ts +16 -0
  6. package/dist/src/components/Checkbox/checkbox.types.d.ts.map +1 -1
  7. package/dist/src/components/Checkbox/checkbox.variants.d.ts +3 -0
  8. package/dist/src/components/Checkbox/checkbox.variants.d.ts.map +1 -1
  9. package/dist/src/components/DatePicker/DatePicker.d.ts.map +1 -1
  10. package/dist/src/components/DateRangePicker/DateRangePicker.d.ts.map +1 -1
  11. package/dist/src/components/DateTimePicker/DateTimePicker.d.ts.map +1 -1
  12. package/dist/src/components/NumberField/NumberField.d.ts.map +1 -1
  13. package/dist/src/components/OTPField/OTPField.d.ts.map +1 -1
  14. package/dist/src/components/RadioGroup/RadioGroup.d.ts.map +1 -1
  15. package/dist/src/components/Select/Select.d.ts.map +1 -1
  16. package/dist/src/components/Slider/Slider.d.ts.map +1 -1
  17. package/dist/src/components/Switch/Switch.d.ts.map +1 -1
  18. package/dist/src/components/Switch/switch.types.d.ts +15 -0
  19. package/dist/src/components/Switch/switch.types.d.ts.map +1 -1
  20. package/dist/src/components/Switch/switch.variants.d.ts +3 -0
  21. package/dist/src/components/Switch/switch.variants.d.ts.map +1 -1
  22. package/dist/src/components/TextField/TextField.d.ts.map +1 -1
  23. package/dist/src/components/Textarea/Textarea.d.ts.map +1 -1
  24. package/dist/src/components/TimePicker/TimePicker.d.ts.map +1 -1
  25. package/dist/src/components/_shared/resolveValidationState.d.ts +21 -11
  26. package/dist/src/components/_shared/resolveValidationState.d.ts.map +1 -1
  27. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -12,6 +12,84 @@ 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.7.1] — 2026-09-25
16
+
17
+ Patch: closes the half of BUG 17 that never reached this package.
18
+
19
+ ### Fixed
20
+
21
+ - **An explicit `helperText` no longer swallows the field's validation
22
+ message** (BUG 32). This package carries its own copy of the
23
+ validation resolver at
24
+ `src/components/_shared/resolveValidationState.ts`, and it kept the
25
+ inverted precedence that BUG 17 corrected on the MUI side back on
26
+ 2026-09-15. The effect: any bridge-managed field given a constant
27
+ hint painted the danger state and set `aria-invalid="true"` while
28
+ still rendering the hint text, so the user saw a red field with no
29
+ stated reason. **Fourteen components route through that resolver**
30
+ (Autocomplete, Checkbox, DatePicker, DateRangePicker, DateTimePicker,
31
+ NumberField, OTPField, RadioGroup, Select, Slider, Switch, TextField,
32
+ Textarea, TimePicker), so a single line fixes all of them.
33
+ `helperText` now reads `autoMessage ?? explicitHelperText`: the
34
+ validation message wins while it is showing, the hint is the fallback
35
+ for the no-error state. The `error` boolean is unchanged — an
36
+ explicit prop still forces the visual.
37
+
38
+ The resolver's docstring previously advertised itself as matching the
39
+ MUI side "byte-for-byte", which is what let the divergence survive
40
+ ten days. It now carries an explicit warning that the two files are
41
+ hand-kept copies. New regression suite at
42
+ `src/components/_shared/resolveValidationState.test.ts` (7 assertions)
43
+ mirrors the MUI-side one, and each docstring points at the other.
44
+ See `README-BUG.md` § BUG 32.
45
+
46
+ ## [1.7.0] — 2026-09-22
47
+
48
+ ### Added
49
+
50
+ - **`<Checkbox required>` and `<Switch required>`** — the last two
51
+ bridge-integrated field components in the package that did not
52
+ accept `required` (the other twelve — Autocomplete, DatePicker,
53
+ DateRangePicker, DateTimePicker, NumberField, OTPField, RadioGroup,
54
+ Select, Slider, TextField, Textarea, TimePicker — already did).
55
+ Fixes BUG 21 in `libs/dashforge/README-BUG.md`. Both components now
56
+ render a `*` marker at the end of the label (styled via a new
57
+ `requiredMark` slot in the variants recipe, colour tokens matching
58
+ `textField.variants.ts` `requiredMark`) and set `aria-required="true"`
59
+ on the underlying Radix Root button via a **ref + `useEffect`
60
+ post-mount DOM setter** (Radix v1.3.3's own internal
61
+ context-then-re-emit path for `aria-required` was verified to strip
62
+ the attribute in production browser builds, though jsdom did not
63
+ catch that; the ref-based fallback is Radix-version-agnostic). HTML5
64
+ `required` is still passed through to Radix so
65
+ `Radix.CheckboxBubbleInput` picks it up for native form validation.
66
+ The `requiredMark` slot accepts a `className` via `slotProps` for
67
+ per-instance overrides, and via `theme.components.<Name>.slotProps`
68
+ for design-system-wide overrides. Presentational only, per the
69
+ library-wide convention: form-submit enforcement still requires
70
+ `rules={{ required: … }}` or a resolver rule. Seven regression tests
71
+ in `src/components/_shared/checkboxSwitchRequired.test.tsx` pin the
72
+ marker, the aria-required attribute, the no-render-when-omitted
73
+ invariant, and the slot override plumbing.
74
+
75
+ ### Fixed
76
+
77
+ - **14 field components now honour `bridge.shouldUnregister`** (BUG 22
78
+ cross-package fix). Autocomplete, Checkbox, DatePicker,
79
+ DateRangePicker, DateTimePicker, NumberField, OTPField, RadioGroup,
80
+ Select, Slider, Switch, TextField, Textarea, TimePicker — the
81
+ unmount cleanup that previously ran unconditionally
82
+ (`queueMicrotask` schedule of `bridge.unregister(name)`) now bails
83
+ out first with `if (!cap?.shouldUnregister) return;`. When
84
+ `bridge.shouldUnregister` is `false` (the new Dashforge default,
85
+ set in `DashFormProvider`) the field's row in `formState.values`
86
+ survives the unmount, which is what `<Stepper>` and tab-swap
87
+ patterns need. Requires `@dashforge/ui-core@≥1.2.0` (new bridge
88
+ field) and `@dashforge/forms@≥1.2.0` (bridge population). The
89
+ StrictMode-safe `queueMicrotask` + `isMountedRef` pattern is
90
+ preserved verbatim; the change only decides *whether* to run the
91
+ scheduled cleanup.
92
+
15
93
  ## [1.6.0] — 2026-09-15
16
94
 
17
95
  Minor release: three bug fixes (BUG 6 Dialog `actions` slot,
package/dist/index.esm.js CHANGED
@@ -870,23 +870,33 @@ const tooltipVariants = tv({
870
870
  /**
871
871
  * Compute `error` + `helperText` for a bridge-managed field.
872
872
  *
873
- * **Renderer-agnostic** — copy of the MUI-side
874
- * `textField.validation.ts`. Promoted to a `_shared/` directory inside
875
- * `@dashforge/tw` so all form components (TextField + Checkbox +
876
- * Switch) reuse the same precedence logic without depending on a
873
+ * **Renderer-agnostic.** Mirrors the MUI-side
874
+ * `ui/src/components/TextField/textField.validation.ts`. Promoted to a
875
+ * `_shared/` directory inside `@dashforge/tw` so all 14 bridge-managed
876
+ * form components reuse the same precedence without depending on a
877
877
  * specific component folder.
878
878
  *
879
- * Precedence rules (matches MUI side byte-for-byte):
880
- *
881
- * 1. **Explicit props win.** If the user passed `error` / `helperText`
882
- * explicitly, those values are used as-is.
883
- * 2. **Auto values are gated by interaction.** The bridge's error is
879
+ * ⚠️ This file is a COPY, not an import. The two sides have to be kept
880
+ * in step by hand, and once already were not: BUG 17 (2026-09-15)
881
+ * inverted the `helperText` precedence on the MUI side only, and this
882
+ * copy kept the broken order for ten days until BUG 32 caught it. The
883
+ * verification that missed it was a grep for imports of the MUI file,
884
+ * which by construction cannot reach a copy. **When you change the
885
+ * precedence here, change it there too — and vice versa.**
886
+ *
887
+ * Precedence rules:
888
+ *
889
+ * 1. **`error`: the explicit prop wins.** An author who passes `error`
890
+ * is forcing the visual state, so it overrides the auto-gate.
891
+ * 2. **`helperText`: the validation message wins while it is showing;
892
+ * the explicit prop is the fallback for the no-error state.** A
893
+ * constant hint ("Unique, uppercase") must not swallow the reason a
894
+ * required field was rejected — that leaves the user looking at a
895
+ * red field with no explanation. See README-BUG.md § BUG 17 / § BUG 32.
896
+ * 3. **Auto values are gated by interaction.** The bridge's error is
884
897
  * surfaced only when the field is `touched` OR the form has been
885
898
  * submitted at least once (`submitCount > 0`). This prevents the
886
899
  * "error spam while typing" anti-pattern.
887
- * 3. **`error === false` explicitly clears the bridge's error message
888
- * text.** Useful for forcing a "valid" visual state regardless of
889
- * bridge state.
890
900
  *
891
901
  * @param name field name registered with the bridge
892
902
  * @param bridge active `DashFormBridge` (guaranteed non-null at
@@ -899,8 +909,16 @@ const tooltipVariants = tv({
899
909
  const autoTouched = (_bridge_isTouched = bridge.isTouched(name)) != null ? _bridge_isTouched : false;
900
910
  const submitCount = (_bridge_submitCount = bridge.submitCount) != null ? _bridge_submitCount : 0;
901
911
  const allowAutoError = autoTouched || submitCount > 0;
912
+ // `error` still lets an explicit prop force the visual state.
902
913
  const error = explicitError != null ? explicitError : Boolean(autoErr) && allowAutoError;
903
- const helperText = explicitHelperText != null ? explicitHelperText : allowAutoError ? autoErr == null ? void 0 : autoErr.message : undefined;
914
+ // BUG 32: the validation message wins over the explicit hint while it
915
+ // is showing. The previous order (`explicitHelperText ?? autoMessage`)
916
+ // short-circuited on the hint, so any field carrying one painted the
917
+ // danger state and `aria-invalid="true"` while still rendering the
918
+ // hint text — a red field with no stated reason. Identical inversion
919
+ // to the one BUG 17 landed on the MUI side.
920
+ const autoMessage = allowAutoError ? autoErr == null ? void 0 : autoErr.message : undefined;
921
+ const helperText = autoMessage != null ? autoMessage : explicitHelperText;
904
922
  return {
905
923
  error,
906
924
  helperText
@@ -1095,6 +1113,11 @@ const tooltipVariants = tv({
1095
1113
  return ()=>{
1096
1114
  isMountedRef.current = false;
1097
1115
  const { bridge: cap, name: capName } = unregisterRef.current;
1116
+ // BUG 22: only release bridge state on unmount if the form
1117
+ // is configured to forget unmounted fields. Default `false`
1118
+ // keeps values in RHF so <Stepper> / tab-swap patterns can
1119
+ // read earlier answers back on later steps. See README-BUG.md § BUG 22.
1120
+ if (!(cap == null ? void 0 : cap.shouldUnregister)) return;
1098
1121
  queueMicrotask(()=>{
1099
1122
  var _cap_unregister;
1100
1123
  if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
@@ -1257,6 +1280,10 @@ const tooltipVariants = tv({
1257
1280
  ],
1258
1281
  indicator: 'flex items-center justify-center text-white',
1259
1282
  label: 'select-none cursor-pointer text-neutral-900',
1283
+ // BUG 21: `*` marker after the label, matching the `textField.variants.ts`
1284
+ // `requiredMark` slot so a consent box aligns visually with sibling
1285
+ // required fields in a form.
1286
+ requiredMark: 'text-danger-500 ml-0.5',
1260
1287
  helperText: 'text-sm text-neutral-600 mt-1',
1261
1288
  errorText: 'text-sm text-danger-600 mt-1'
1262
1289
  },
@@ -1365,13 +1392,13 @@ const tooltipVariants = tv({
1365
1392
  * rather than MUI slot components.
1366
1393
  */ function Checkbox(props) {
1367
1394
  var _ref;
1368
- var _themeDefaults_defaults, _themeSlotProps_root, _slotProps_root, _themeSlotProps_control, _slotProps_control, _themeSlotProps_indicator, _slotProps_indicator, _themeSlotProps_label, _slotProps_label, _themeSlotProps_errorText, _slotProps_errorText, _themeSlotProps_helperText, _slotProps_helperText;
1395
+ var _themeDefaults_defaults, _themeSlotProps_root, _slotProps_root, _themeSlotProps_control, _slotProps_control, _themeSlotProps_indicator, _slotProps_indicator, _themeSlotProps_label, _slotProps_label, _themeSlotProps_requiredMark, _slotProps_requiredMark, _themeSlotProps_errorText, _slotProps_errorText, _themeSlotProps_helperText, _slotProps_helperText;
1369
1396
  const themeDefaults = useComponentDefaults('Checkbox');
1370
1397
  const merged = _extends({}, themeDefaults == null ? void 0 : themeDefaults.defaults, props);
1371
1398
  const themeSlotProps = themeDefaults == null ? void 0 : themeDefaults.slotProps;
1372
1399
  // Option C deep-merge: instance `tooltip` over `theme…defaults.tooltip`.
1373
1400
  const tooltipConfig = resolveFieldTooltip(props.tooltip, themeDefaults == null ? void 0 : (_themeDefaults_defaults = themeDefaults.defaults) == null ? void 0 : _themeDefaults_defaults.tooltip);
1374
- const { name, rules, visibleWhen, label, helperText, error, access, size, disabled, checked, defaultChecked, onCheckedChange, sx, slotProps } = merged;
1401
+ const { name, rules, visibleWhen, label, helperText, error, access, size, disabled, required, checked, defaultChecked, onCheckedChange, sx, slotProps } = merged;
1375
1402
  // ───── Hooks (always called, unconditional) ─────
1376
1403
  const bridge = useContext(DashFormContext);
1377
1404
  const isVisible = useEngineVisibility(bridge == null ? void 0 : bridge.engine, visibleWhen);
@@ -1381,6 +1408,32 @@ const tooltipVariants = tv({
1381
1408
  const fieldMeta = useDashFieldMeta(name);
1382
1409
  const accessState = useAccessState(access);
1383
1410
  const controlId = useId();
1411
+ // BUG 21 v2: local ref for the Radix Root DOM button. We use this to
1412
+ // set `aria-required` post-mount because setting the attribute via a
1413
+ // JSX prop on `RadixCheckbox.Root` does not reach the browser DOM in
1414
+ // production builds (verified empirically in urbango on Radix v1.3.3;
1415
+ // jsdom does not surface the same gap).
1416
+ const buttonRef = useRef(null);
1417
+ const setControlRef = (node)=>{
1418
+ buttonRef.current = node;
1419
+ const regRef = registration == null ? void 0 : registration.ref;
1420
+ if (typeof regRef === 'function') {
1421
+ regRef(node);
1422
+ } else if (regRef && typeof regRef === 'object') {
1423
+ regRef.current = node;
1424
+ }
1425
+ };
1426
+ useEffect(()=>{
1427
+ const node = buttonRef.current;
1428
+ if (!node) return;
1429
+ if (required) {
1430
+ node.setAttribute('aria-required', 'true');
1431
+ } else {
1432
+ node.removeAttribute('aria-required');
1433
+ }
1434
+ }, [
1435
+ required
1436
+ ]);
1384
1437
  // StrictMode-safe unregister-on-unmount — mirrors MUI Checkbox.tsx
1385
1438
  // (the bridge identity changes on every keystroke, so we MUST NOT
1386
1439
  // re-run cleanup on deps changes — empty deps + ref pattern).
@@ -1398,6 +1451,11 @@ const tooltipVariants = tv({
1398
1451
  return ()=>{
1399
1452
  isMountedRef.current = false;
1400
1453
  const { bridge: cap, name: capName } = unregisterRef.current;
1454
+ // BUG 22: only release bridge state on unmount if the form
1455
+ // is configured to forget unmounted fields. Default `false`
1456
+ // keeps values in RHF so <Stepper> / tab-swap patterns can
1457
+ // read earlier answers back on later steps. See README-BUG.md § BUG 22.
1458
+ if (!(cap == null ? void 0 : cap.shouldUnregister)) return;
1401
1459
  queueMicrotask(()=>{
1402
1460
  var _cap_unregister;
1403
1461
  if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
@@ -1486,9 +1544,19 @@ const tooltipVariants = tv({
1486
1544
  name: name
1487
1545
  }, radixStateProps, {
1488
1546
  disabled: effectiveDisabled,
1547
+ required: required,
1489
1548
  onCheckedChange: handleCheckedChange,
1490
1549
  onBlur: handleBlur,
1491
- ref: registration == null ? void 0 : registration.ref,
1550
+ // BUG 21 v2: compose our own ref with `registration.ref` so we can
1551
+ // ALSO set `aria-required` post-mount via a `useEffect` below. The
1552
+ // JSX-level `aria-required` prop was verified empirically not to
1553
+ // reach the DOM in a real browser (Radix v1.3.3 reads its own
1554
+ // `required` prop into context and re-emits `aria-required` from
1555
+ // the internal trigger, but the attribute is stripped somewhere
1556
+ // in the production path — jsdom does not catch it). Post-mount
1557
+ // ref-based setter is Radix-version-agnostic and lands on the
1558
+ // element the browser actually shows.
1559
+ ref: setControlRef,
1492
1560
  className: cn(v.control(), themeSlotProps == null ? void 0 : (_themeSlotProps_control = themeSlotProps.control) == null ? void 0 : _themeSlotProps_control.className, slotProps == null ? void 0 : (_slotProps_control = slotProps.control) == null ? void 0 : _slotProps_control.className),
1493
1561
  children: jsxs(RadixCheckbox.Indicator, {
1494
1562
  className: cn(v.indicator(), 'group', themeSlotProps == null ? void 0 : (_themeSlotProps_indicator = themeSlotProps.indicator) == null ? void 0 : _themeSlotProps_indicator.className, slotProps == null ? void 0 : (_slotProps_indicator = slotProps.indicator) == null ? void 0 : _slotProps_indicator.className),
@@ -1505,10 +1573,17 @@ const tooltipVariants = tv({
1505
1573
  jsxs("div", {
1506
1574
  className: "flex flex-col",
1507
1575
  children: [
1508
- label && jsx("label", {
1576
+ label && jsxs("label", {
1509
1577
  htmlFor: controlId,
1510
1578
  className: cn(v.label(), themeSlotProps == null ? void 0 : (_themeSlotProps_label = themeSlotProps.label) == null ? void 0 : _themeSlotProps_label.className, slotProps == null ? void 0 : (_slotProps_label = slotProps.label) == null ? void 0 : _slotProps_label.className),
1511
- children: renderLabelWithTooltip(label, tooltipConfig)
1579
+ children: [
1580
+ renderLabelWithTooltip(label, tooltipConfig),
1581
+ required && jsx("span", {
1582
+ "aria-hidden": "true",
1583
+ className: cn(v.requiredMark(), themeSlotProps == null ? void 0 : (_themeSlotProps_requiredMark = themeSlotProps.requiredMark) == null ? void 0 : _themeSlotProps_requiredMark.className, slotProps == null ? void 0 : (_slotProps_requiredMark = slotProps.requiredMark) == null ? void 0 : _slotProps_requiredMark.className),
1584
+ children: "*"
1585
+ })
1586
+ ]
1512
1587
  }),
1513
1588
  resolvedHelperText && jsx("p", {
1514
1589
  className: cn(resolvedError ? v.errorText() : v.helperText(), resolvedError ? [
@@ -1559,6 +1634,9 @@ const tooltipVariants = tv({
1559
1634
  'data-[state=unchecked]:translate-x-0'
1560
1635
  ],
1561
1636
  label: 'select-none cursor-pointer text-neutral-900',
1637
+ // BUG 21: `*` marker after the label, same tokens as
1638
+ // `checkboxVariants.requiredMark` for visual parity.
1639
+ requiredMark: 'text-danger-500 ml-0.5',
1562
1640
  helperText: 'text-sm text-neutral-600 mt-1',
1563
1641
  errorText: 'text-sm text-danger-600 mt-1'
1564
1642
  },
@@ -1605,19 +1683,45 @@ const tooltipVariants = tv({
1605
1683
  * translate-x distance so the knob lands flush at each end.
1606
1684
  */ function Switch(props) {
1607
1685
  var _ref;
1608
- var _themeDefaults_defaults, _themeSlotProps_root, _slotProps_root, _themeSlotProps_control, _slotProps_control, _themeSlotProps_thumb, _slotProps_thumb, _themeSlotProps_label, _slotProps_label, _themeSlotProps_errorText, _slotProps_errorText, _themeSlotProps_helperText, _slotProps_helperText;
1686
+ var _themeDefaults_defaults, _themeSlotProps_root, _slotProps_root, _themeSlotProps_control, _slotProps_control, _themeSlotProps_thumb, _slotProps_thumb, _themeSlotProps_label, _slotProps_label, _themeSlotProps_requiredMark, _slotProps_requiredMark, _themeSlotProps_errorText, _slotProps_errorText, _themeSlotProps_helperText, _slotProps_helperText;
1609
1687
  const themeDefaults = useComponentDefaults('Switch');
1610
1688
  const merged = _extends({}, themeDefaults == null ? void 0 : themeDefaults.defaults, props);
1611
1689
  const themeSlotProps = themeDefaults == null ? void 0 : themeDefaults.slotProps;
1612
1690
  // Option C deep-merge: instance `tooltip` over `theme…defaults.tooltip`.
1613
1691
  const tooltipConfig = resolveFieldTooltip(props.tooltip, themeDefaults == null ? void 0 : (_themeDefaults_defaults = themeDefaults.defaults) == null ? void 0 : _themeDefaults_defaults.tooltip);
1614
- const { name, rules, visibleWhen, label, helperText, error, access, size, disabled, checked, defaultChecked, onCheckedChange, sx, slotProps } = merged;
1692
+ const { name, rules, visibleWhen, label, helperText, error, access, size, disabled, required, checked, defaultChecked, onCheckedChange, sx, slotProps } = merged;
1615
1693
  const bridge = useContext(DashFormContext);
1616
1694
  const isVisible = useEngineVisibility(bridge == null ? void 0 : bridge.engine, visibleWhen);
1617
1695
  // Reactive snapshot — see Checkbox.tsx for the same rationale.
1618
1696
  const fieldMeta = useDashFieldMeta(name);
1619
1697
  const accessState = useAccessState(access);
1620
1698
  const controlId = useId();
1699
+ // BUG 21 v2: local ref + post-mount `aria-required` setter — same
1700
+ // pattern as Checkbox.tsx. Radix.Switch.Root reads `required` prop
1701
+ // into context but the JSX `aria-required` attribute does not reach
1702
+ // the browser DOM in production builds. Setting via ref is
1703
+ // Radix-version-agnostic. See README-BUG.md § BUG 21.
1704
+ const buttonRef = useRef(null);
1705
+ const setControlRef = (node)=>{
1706
+ buttonRef.current = node;
1707
+ const regRef = registration == null ? void 0 : registration.ref;
1708
+ if (typeof regRef === 'function') {
1709
+ regRef(node);
1710
+ } else if (regRef && typeof regRef === 'object') {
1711
+ regRef.current = node;
1712
+ }
1713
+ };
1714
+ useEffect(()=>{
1715
+ const node = buttonRef.current;
1716
+ if (!node) return;
1717
+ if (required) {
1718
+ node.setAttribute('aria-required', 'true');
1719
+ } else {
1720
+ node.removeAttribute('aria-required');
1721
+ }
1722
+ }, [
1723
+ required
1724
+ ]);
1621
1725
  // StrictMode-safe unregister-on-unmount
1622
1726
  const unregisterRef = useRef({
1623
1727
  bridge,
@@ -1633,6 +1737,11 @@ const tooltipVariants = tv({
1633
1737
  return ()=>{
1634
1738
  isMountedRef.current = false;
1635
1739
  const { bridge: cap, name: capName } = unregisterRef.current;
1740
+ // BUG 22: only release bridge state on unmount if the form
1741
+ // is configured to forget unmounted fields. Default `false`
1742
+ // keeps values in RHF so <Stepper> / tab-swap patterns can
1743
+ // read earlier answers back on later steps. See README-BUG.md § BUG 22.
1744
+ if (!(cap == null ? void 0 : cap.shouldUnregister)) return;
1636
1745
  queueMicrotask(()=>{
1637
1746
  var _cap_unregister;
1638
1747
  if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
@@ -1708,9 +1817,13 @@ const tooltipVariants = tv({
1708
1817
  name: name
1709
1818
  }, radixStateProps, {
1710
1819
  disabled: effectiveDisabled,
1820
+ required: required,
1711
1821
  onCheckedChange: handleCheckedChange,
1712
1822
  onBlur: handleBlur,
1713
- ref: registration == null ? void 0 : registration.ref,
1823
+ // BUG 21 v2: `aria-required` set via `setControlRef` + `useEffect`
1824
+ // above, not via JSX prop. See Checkbox.tsx for the same pattern
1825
+ // and the reasoning.
1826
+ ref: setControlRef,
1714
1827
  className: cn(v.control(), themeSlotProps == null ? void 0 : (_themeSlotProps_control = themeSlotProps.control) == null ? void 0 : _themeSlotProps_control.className, slotProps == null ? void 0 : (_slotProps_control = slotProps.control) == null ? void 0 : _slotProps_control.className),
1715
1828
  children: jsx(RadixSwitch.Thumb, {
1716
1829
  className: cn(v.thumb(), themeSlotProps == null ? void 0 : (_themeSlotProps_thumb = themeSlotProps.thumb) == null ? void 0 : _themeSlotProps_thumb.className, slotProps == null ? void 0 : (_slotProps_thumb = slotProps.thumb) == null ? void 0 : _slotProps_thumb.className)
@@ -1719,10 +1832,17 @@ const tooltipVariants = tv({
1719
1832
  jsxs("div", {
1720
1833
  className: "flex flex-col",
1721
1834
  children: [
1722
- label && jsx("label", {
1835
+ label && jsxs("label", {
1723
1836
  htmlFor: controlId,
1724
1837
  className: cn(v.label(), themeSlotProps == null ? void 0 : (_themeSlotProps_label = themeSlotProps.label) == null ? void 0 : _themeSlotProps_label.className, slotProps == null ? void 0 : (_slotProps_label = slotProps.label) == null ? void 0 : _slotProps_label.className),
1725
- children: renderLabelWithTooltip(label, tooltipConfig)
1838
+ children: [
1839
+ renderLabelWithTooltip(label, tooltipConfig),
1840
+ required && jsx("span", {
1841
+ "aria-hidden": "true",
1842
+ className: cn(v.requiredMark(), themeSlotProps == null ? void 0 : (_themeSlotProps_requiredMark = themeSlotProps.requiredMark) == null ? void 0 : _themeSlotProps_requiredMark.className, slotProps == null ? void 0 : (_slotProps_requiredMark = slotProps.requiredMark) == null ? void 0 : _slotProps_requiredMark.className),
1843
+ children: "*"
1844
+ })
1845
+ ]
1726
1846
  }),
1727
1847
  resolvedHelperText && jsx("p", {
1728
1848
  className: cn(resolvedError ? v.errorText() : v.helperText(), resolvedError ? [
@@ -1903,6 +2023,11 @@ const tooltipVariants = tv({
1903
2023
  return ()=>{
1904
2024
  isMountedRef.current = false;
1905
2025
  const { bridge: cap, name: capName } = unregisterRef.current;
2026
+ // BUG 22: only release bridge state on unmount if the form
2027
+ // is configured to forget unmounted fields. Default `false`
2028
+ // keeps values in RHF so <Stepper> / tab-swap patterns can
2029
+ // read earlier answers back on later steps. See README-BUG.md § BUG 22.
2030
+ if (!(cap == null ? void 0 : cap.shouldUnregister)) return;
1906
2031
  queueMicrotask(()=>{
1907
2032
  var _cap_unregister;
1908
2033
  if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
@@ -2219,6 +2344,11 @@ const tooltipVariants = tv({
2219
2344
  return ()=>{
2220
2345
  isMountedRef.current = false;
2221
2346
  const { bridge: cap, name: capName } = unregisterRef.current;
2347
+ // BUG 22: only release bridge state on unmount if the form
2348
+ // is configured to forget unmounted fields. Default `false`
2349
+ // keeps values in RHF so <Stepper> / tab-swap patterns can
2350
+ // read earlier answers back on later steps. See README-BUG.md § BUG 22.
2351
+ if (!(cap == null ? void 0 : cap.shouldUnregister)) return;
2222
2352
  queueMicrotask(()=>{
2223
2353
  var _cap_unregister;
2224
2354
  if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
@@ -2541,6 +2671,11 @@ const tooltipVariants = tv({
2541
2671
  return ()=>{
2542
2672
  isMountedRef.current = false;
2543
2673
  const { bridge: cap, name: capName } = unregisterRef.current;
2674
+ // BUG 22: only release bridge state on unmount if the form
2675
+ // is configured to forget unmounted fields. Default `false`
2676
+ // keeps values in RHF so <Stepper> / tab-swap patterns can
2677
+ // read earlier answers back on later steps. See README-BUG.md § BUG 22.
2678
+ if (!(cap == null ? void 0 : cap.shouldUnregister)) return;
2544
2679
  queueMicrotask(()=>{
2545
2680
  var _cap_unregister;
2546
2681
  if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
@@ -2835,6 +2970,11 @@ const tooltipVariants = tv({
2835
2970
  return ()=>{
2836
2971
  isMountedRef.current = false;
2837
2972
  const { bridge: cap, name: capName } = unregisterRef.current;
2973
+ // BUG 22: only release bridge state on unmount if the form
2974
+ // is configured to forget unmounted fields. Default `false`
2975
+ // keeps values in RHF so <Stepper> / tab-swap patterns can
2976
+ // read earlier answers back on later steps. See README-BUG.md § BUG 22.
2977
+ if (!(cap == null ? void 0 : cap.shouldUnregister)) return;
2838
2978
  queueMicrotask(()=>{
2839
2979
  var _cap_unregister;
2840
2980
  if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
@@ -3311,6 +3451,11 @@ function Autocomplete(props) {
3311
3451
  return ()=>{
3312
3452
  isMountedRef.current = false;
3313
3453
  const { bridge: cap, name: capName } = unregisterRef.current;
3454
+ // BUG 22: only release bridge state on unmount if the form
3455
+ // is configured to forget unmounted fields. Default `false`
3456
+ // keeps values in RHF so <Stepper> / tab-swap patterns can
3457
+ // read earlier answers back on later steps. See README-BUG.md § BUG 22.
3458
+ if (!(cap == null ? void 0 : cap.shouldUnregister)) return;
3314
3459
  queueMicrotask(()=>{
3315
3460
  var _cap_unregister;
3316
3461
  if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
@@ -4618,6 +4763,11 @@ function CalendarIcon$2() {
4618
4763
  return ()=>{
4619
4764
  isMountedRef.current = false;
4620
4765
  const { bridge: cap, name: capName } = unregisterRef.current;
4766
+ // BUG 22: only release bridge state on unmount if the form
4767
+ // is configured to forget unmounted fields. Default `false`
4768
+ // keeps values in RHF so <Stepper> / tab-swap patterns can
4769
+ // read earlier answers back on later steps. See README-BUG.md § BUG 22.
4770
+ if (!(cap == null ? void 0 : cap.shouldUnregister)) return;
4621
4771
  queueMicrotask(()=>{
4622
4772
  var _cap_unregister;
4623
4773
  if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
@@ -4901,6 +5051,11 @@ function ClockIcon() {
4901
5051
  return ()=>{
4902
5052
  isMountedRef.current = false;
4903
5053
  const { bridge: cap, name: capName } = unregisterRef.current;
5054
+ // BUG 22: only release bridge state on unmount if the form
5055
+ // is configured to forget unmounted fields. Default `false`
5056
+ // keeps values in RHF so <Stepper> / tab-swap patterns can
5057
+ // read earlier answers back on later steps. See README-BUG.md § BUG 22.
5058
+ if (!(cap == null ? void 0 : cap.shouldUnregister)) return;
4904
5059
  queueMicrotask(()=>{
4905
5060
  var _cap_unregister;
4906
5061
  if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
@@ -5238,6 +5393,11 @@ const DATETIME_PATTERN = /^(\d{4}-\d{2}-\d{2})T(\d{2}):(\d{2})/;
5238
5393
  return ()=>{
5239
5394
  isMountedRef.current = false;
5240
5395
  const { bridge: cap, name: capName } = unregisterRef.current;
5396
+ // BUG 22: only release bridge state on unmount if the form
5397
+ // is configured to forget unmounted fields. Default `false`
5398
+ // keeps values in RHF so <Stepper> / tab-swap patterns can
5399
+ // read earlier answers back on later steps. See README-BUG.md § BUG 22.
5400
+ if (!(cap == null ? void 0 : cap.shouldUnregister)) return;
5241
5401
  queueMicrotask(()=>{
5242
5402
  var _cap_unregister;
5243
5403
  if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
@@ -5802,6 +5962,11 @@ function formatRange(range, locale) {
5802
5962
  return ()=>{
5803
5963
  isMountedRef.current = false;
5804
5964
  const { bridge: cap, name: capName } = unregisterRef.current;
5965
+ // BUG 22: only release bridge state on unmount if the form
5966
+ // is configured to forget unmounted fields. Default `false`
5967
+ // keeps values in RHF so <Stepper> / tab-swap patterns can
5968
+ // read earlier answers back on later steps. See README-BUG.md § BUG 22.
5969
+ if (!(cap == null ? void 0 : cap.shouldUnregister)) return;
5805
5970
  queueMicrotask(()=>{
5806
5971
  var _cap_unregister;
5807
5972
  if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
@@ -9946,6 +10111,11 @@ const DEFAULT_STEP = 1;
9946
10111
  return ()=>{
9947
10112
  isMountedRef.current = false;
9948
10113
  const { bridge: cap, name: capName } = unregisterRef.current;
10114
+ // BUG 22: only release bridge state on unmount if the form
10115
+ // is configured to forget unmounted fields. Default `false`
10116
+ // keeps values in RHF so <Stepper> / tab-swap patterns can
10117
+ // read earlier answers back on later steps. See README-BUG.md § BUG 22.
10118
+ if (!(cap == null ? void 0 : cap.shouldUnregister)) return;
9949
10119
  queueMicrotask(()=>{
9950
10120
  var _cap_unregister;
9951
10121
  if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
@@ -10493,6 +10663,11 @@ Slider.displayName = 'Slider';
10493
10663
  return ()=>{
10494
10664
  isMountedRef.current = false;
10495
10665
  const { bridge: cap, name: capName } = unregisterRef.current;
10666
+ // BUG 22: only release bridge state on unmount if the form
10667
+ // is configured to forget unmounted fields. Default `false`
10668
+ // keeps values in RHF so <Stepper> / tab-swap patterns can
10669
+ // read earlier answers back on later steps. See README-BUG.md § BUG 22.
10670
+ if (!(cap == null ? void 0 : cap.shouldUnregister)) return;
10496
10671
  queueMicrotask(()=>{
10497
10672
  var _cap_unregister;
10498
10673
  if (!isMountedRef.current) cap == null ? void 0 : (_cap_unregister = cap.unregister) == null ? void 0 : _cap_unregister.call(cap, capName);
@@ -1 +1 @@
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"}
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,kDAkmClC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Checkbox.d.ts","sourceRoot":"","sources":["../../../../src/components/Checkbox/Checkbox.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA0DzD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,kDA8M5C"}
1
+ {"version":3,"file":"Checkbox.d.ts","sourceRoot":"","sources":["../../../../src/components/Checkbox/Checkbox.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA0DzD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,kDAuQ5C"}
@@ -42,6 +42,14 @@ export interface CheckboxSlotProps {
42
42
  errorText?: {
43
43
  className?: string;
44
44
  };
45
+ /**
46
+ * The `*` asterisk rendered next to the label when `required` is true.
47
+ * Themed by `checkboxVariants().requiredMark()`; override here to
48
+ * change colour / spacing. See README-BUG.md § BUG 21.
49
+ */
50
+ requiredMark?: {
51
+ className?: string;
52
+ };
45
53
  }
46
54
  /**
47
55
  * Props for the Dashforge TW `<Checkbox>` component.
@@ -85,6 +93,14 @@ export interface CheckboxProps {
85
93
  defaultChecked?: boolean;
86
94
  /** Disabled — combined with RBAC disabled via OR. */
87
95
  disabled?: boolean;
96
+ /**
97
+ * Renders a `*` asterisk next to the label and sets `aria-required="true"`
98
+ * on the underlying Radix control button. This is the visual + a11y marker
99
+ * for a mandatory consent box (privacy policy, terms of service).
100
+ * Presentational only: submit-time enforcement still requires
101
+ * `rules={{ required: … }}` or a resolver rule. See README-BUG.md § BUG 21.
102
+ */
103
+ required?: boolean;
88
104
  /**
89
105
  * Forces helper text below the control. When the bridge surfaces an
90
106
  * error and `helperText` is undefined, the bridge's error message
@@ -1 +1 @@
1
- {"version":3,"file":"checkbox.types.d.ts","sourceRoot":"","sources":["../../../../src/components/Checkbox/checkbox.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;AAElE,OAAO,QAAQ,sBAAsB,CAAC;IACpC,UAAU,mBAAmB;QAC3B,QAAQ,CAAC,EAAE;YACT,QAAQ,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG;gBAAE,OAAO,CAAC,EAAE,gBAAgB,CAAA;aAAE,CAAC;YAC1E,SAAS,CAAC,EAAE,iBAAiB,CAAC;SAC/B,CAAC;KACH;CACF;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjC,SAAS,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,KAAK,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/B,UAAU,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,SAAS,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACpC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,IAAI,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAEhC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IAEb,8EAA8E;IAC9E,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;;;OAIG;IACH,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAE3B,uEAAuE;IACvE,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAE1C,0CAA0C;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;IAEvB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,wBAAwB;IACxB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAE3B,0EAA0E;IAC1E,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ,oDAAoD;IACpD,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAE9B;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC9C"}
1
+ {"version":3,"file":"checkbox.types.d.ts","sourceRoot":"","sources":["../../../../src/components/Checkbox/checkbox.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;AAElE,OAAO,QAAQ,sBAAsB,CAAC;IACpC,UAAU,mBAAmB;QAC3B,QAAQ,CAAC,EAAE;YACT,QAAQ,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG;gBAAE,OAAO,CAAC,EAAE,gBAAgB,CAAA;aAAE,CAAC;YAC1E,SAAS,CAAC,EAAE,iBAAiB,CAAC;SAC/B,CAAC;KACH;CACF;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjC,SAAS,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,KAAK,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/B,UAAU,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,SAAS,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC;;;;OAIG;IACH,YAAY,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,IAAI,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAEhC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IAEb,8EAA8E;IAC9E,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;;;OAIG;IACH,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAE3B,uEAAuE;IACvE,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAE1C,0CAA0C;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;IAEvB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,wBAAwB;IACxB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAE3B,0EAA0E;IAC1E,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ,oDAAoD;IACpD,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAE9B;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC9C"}
@@ -42,6 +42,7 @@ export declare const checkboxVariants: import("tailwind-variants").TVReturnType<
42
42
  control: string[];
43
43
  indicator: string;
44
44
  label: string;
45
+ requiredMark: string;
45
46
  helperText: string;
46
47
  errorText: string;
47
48
  }, undefined, {
@@ -72,6 +73,7 @@ export declare const checkboxVariants: import("tailwind-variants").TVReturnType<
72
73
  control: string[];
73
74
  indicator: string;
74
75
  label: string;
76
+ requiredMark: string;
75
77
  helperText: string;
76
78
  errorText: string;
77
79
  }, import("tailwind-variants").TVReturnType<{
@@ -102,6 +104,7 @@ export declare const checkboxVariants: import("tailwind-variants").TVReturnType<
102
104
  control: string[];
103
105
  indicator: string;
104
106
  label: string;
107
+ requiredMark: string;
105
108
  helperText: string;
106
109
  errorText: string;
107
110
  }, undefined, unknown, unknown, undefined>>;
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CAqD3B,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CAyD3B,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":"AAkBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAqD7D;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,kDAsPjD"}
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,kDA2PjD"}
@@ -1 +1 @@
1
- {"version":3,"file":"DateRangePicker.d.ts","sourceRoot":"","sources":["../../../../src/components/DateRangePicker/DateRangePicker.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAoQvE;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,oBAAoB,kDA4N3D"}
1
+ {"version":3,"file":"DateRangePicker.d.ts","sourceRoot":"","sources":["../../../../src/components/DateRangePicker/DateRangePicker.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAoQvE;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,oBAAoB,kDAiO3D"}
@@ -1 +1 @@
1
- {"version":3,"file":"DateTimePicker.d.ts","sourceRoot":"","sources":["../../../../src/components/DateTimePicker/DateTimePicker.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AA8ErE;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,mBAAmB,kDAyPzD"}
1
+ {"version":3,"file":"DateTimePicker.d.ts","sourceRoot":"","sources":["../../../../src/components/DateTimePicker/DateTimePicker.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AA8ErE;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,mBAAmB,kDA8PzD"}
@@ -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,kDAgRlD"}
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,kDAqRlD"}
@@ -1 +1 @@
1
- {"version":3,"file":"OTPField.d.ts","sourceRoot":"","sources":["../../../../src/components/OTPField/OTPField.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAgBvE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,kDAmN5C"}
1
+ {"version":3,"file":"OTPField.d.ts","sourceRoot":"","sources":["../../../../src/components/OTPField/OTPField.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAgBvE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,kDAwN5C"}
@@ -1 +1 @@
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
+ {"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,kDAiRhD"}
@@ -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;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
+ {"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;AA2mB3B;;;;;;;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":"Slider.d.ts","sourceRoot":"","sources":["../../../../src/components/Slider/Slider.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAEV,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAgE3B;;;;;;;;;;GAUG;AACH,eAAO,MAAM,MAAM,yGAyXjB,CAAC;AAOH,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"Slider.d.ts","sourceRoot":"","sources":["../../../../src/components/Slider/Slider.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAEV,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAgE3B;;;;;;;;;;GAUG;AACH,eAAO,MAAM,MAAM,yGA8XjB,CAAC;AAOH,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Switch.d.ts","sourceRoot":"","sources":["../../../../src/components/Switch/Switch.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;;;;;GAWG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,kDAsJxC"}
1
+ {"version":3,"file":"Switch.d.ts","sourceRoot":"","sources":["../../../../src/components/Switch/Switch.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;;;;;;;;GAWG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,kDAyMxC"}
@@ -37,6 +37,14 @@ export interface SwitchSlotProps {
37
37
  errorText?: {
38
38
  className?: string;
39
39
  };
40
+ /**
41
+ * The `*` asterisk rendered next to the label when `required` is true.
42
+ * Themed by `switchVariants().requiredMark()`; override here to change
43
+ * colour / spacing. See README-BUG.md § BUG 21.
44
+ */
45
+ requiredMark?: {
46
+ className?: string;
47
+ };
40
48
  }
41
49
  /**
42
50
  * Props for the Dashforge TW `<Switch>` component.
@@ -80,6 +88,13 @@ export interface SwitchProps {
80
88
  * @default false
81
89
  */
82
90
  disabled?: boolean;
91
+ /**
92
+ * Renders a `*` asterisk next to the label and sets `aria-required="true"`
93
+ * on the underlying Radix control button. Presentational only: submit-time
94
+ * enforcement still requires `rules={{ required: … }}` or a resolver rule.
95
+ * See README-BUG.md § BUG 21.
96
+ */
97
+ required?: boolean;
83
98
  /** Helper line below the control. Auto-replaced by bridge error when invalid. */
84
99
  helperText?: ReactNode;
85
100
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"switch.types.d.ts","sourceRoot":"","sources":["../../../../src/components/Switch/switch.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;AAE9D,OAAO,QAAQ,sBAAsB,CAAC;IACpC,UAAU,mBAAmB;QAC3B,MAAM,CAAC,EAAE;YACP,QAAQ,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG;gBAAE,OAAO,CAAC,EAAE,gBAAgB,CAAA;aAAE,CAAC;YACxE,SAAS,CAAC,EAAE,eAAe,CAAC;SAC7B,CAAC;KACH;CACF;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,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,KAAK,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/B,UAAU,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,SAAS,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACpC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAE9B,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IAEb,sFAAsF;IACtF,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;;;OAIG;IACH,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAE3B,gFAAgF;IAChF,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAE1C,gCAAgC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,iFAAiF;IACjF,UAAU,CAAC,EAAE,SAAS,CAAC;IAEvB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,uFAAuF;IACvF,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAE3B,iFAAiF;IACjF,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ,kDAAkD;IAClD,SAAS,CAAC,EAAE,eAAe,CAAC;IAE5B,gFAAgF;IAChF,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC9C"}
1
+ {"version":3,"file":"switch.types.d.ts","sourceRoot":"","sources":["../../../../src/components/Switch/switch.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;AAE9D,OAAO,QAAQ,sBAAsB,CAAC;IACpC,UAAU,mBAAmB;QAC3B,MAAM,CAAC,EAAE;YACP,QAAQ,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GAAG;gBAAE,OAAO,CAAC,EAAE,gBAAgB,CAAA;aAAE,CAAC;YACxE,SAAS,CAAC,EAAE,eAAe,CAAC;SAC7B,CAAC;KACH;CACF;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,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,KAAK,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/B,UAAU,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,SAAS,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC;;;;OAIG;IACH,YAAY,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAE9B,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IAEb,sFAAsF;IACtF,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;;;OAIG;IACH,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAE3B,gFAAgF;IAChF,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAE1C,gCAAgC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,iFAAiF;IACjF,UAAU,CAAC,EAAE,SAAS,CAAC;IAEvB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,uFAAuF;IACvF,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAE3B,iFAAiF;IACjF,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ,kDAAkD;IAClD,SAAS,CAAC,EAAE,eAAe,CAAC;IAE5B,gFAAgF;IAChF,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC9C"}
@@ -38,6 +38,7 @@ export declare const switchVariants: import("tailwind-variants").TVReturnType<{
38
38
  control: string[];
39
39
  thumb: string[];
40
40
  label: string;
41
+ requiredMark: string;
41
42
  helperText: string;
42
43
  errorText: string;
43
44
  }, undefined, {
@@ -68,6 +69,7 @@ export declare const switchVariants: import("tailwind-variants").TVReturnType<{
68
69
  control: string[];
69
70
  thumb: string[];
70
71
  label: string;
72
+ requiredMark: string;
71
73
  helperText: string;
72
74
  errorText: string;
73
75
  }, import("tailwind-variants").TVReturnType<{
@@ -98,6 +100,7 @@ export declare const switchVariants: import("tailwind-variants").TVReturnType<{
98
100
  control: string[];
99
101
  thumb: string[];
100
102
  label: string;
103
+ requiredMark: string;
101
104
  helperText: string;
102
105
  errorText: string;
103
106
  }, undefined, unknown, unknown, undefined>>;
@@ -1 +1 @@
1
- {"version":3,"file":"switch.variants.d.ts","sourceRoot":"","sources":["../../../../src/components/Switch/switch.variants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CAsDzB,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,YAAY,CAAC,OAAO,cAAc,CAAC,CAAC"}
1
+ {"version":3,"file":"switch.variants.d.ts","sourceRoot":"","sources":["../../../../src/components/Switch/switch.variants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CAyDzB,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,YAAY,CAAC,OAAO,cAAc,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,kDAqO9C"}
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,kDA0O9C"}
@@ -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,kDAoL5C"}
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,kDAyL5C"}
@@ -1 +1 @@
1
- {"version":3,"file":"TimePicker.d.ts","sourceRoot":"","sources":["../../../../src/components/TimePicker/TimePicker.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAkB7D;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,kDAgPjD"}
1
+ {"version":3,"file":"TimePicker.d.ts","sourceRoot":"","sources":["../../../../src/components/TimePicker/TimePicker.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAkB7D;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,kDAqPjD"}
@@ -14,23 +14,33 @@ export interface ValidationState {
14
14
  /**
15
15
  * Compute `error` + `helperText` for a bridge-managed field.
16
16
  *
17
- * **Renderer-agnostic** — copy of the MUI-side
18
- * `textField.validation.ts`. Promoted to a `_shared/` directory inside
19
- * `@dashforge/tw` so all form components (TextField + Checkbox +
20
- * Switch) reuse the same precedence logic without depending on a
17
+ * **Renderer-agnostic.** Mirrors the MUI-side
18
+ * `ui/src/components/TextField/textField.validation.ts`. Promoted to a
19
+ * `_shared/` directory inside `@dashforge/tw` so all 14 bridge-managed
20
+ * form components reuse the same precedence without depending on a
21
21
  * specific component folder.
22
22
  *
23
- * Precedence rules (matches MUI side byte-for-byte):
23
+ * ⚠️ This file is a COPY, not an import. The two sides have to be kept
24
+ * in step by hand, and once already were not: BUG 17 (2026-09-15)
25
+ * inverted the `helperText` precedence on the MUI side only, and this
26
+ * copy kept the broken order for ten days until BUG 32 caught it. The
27
+ * verification that missed it was a grep for imports of the MUI file,
28
+ * which by construction cannot reach a copy. **When you change the
29
+ * precedence here, change it there too — and vice versa.**
24
30
  *
25
- * 1. **Explicit props win.** If the user passed `error` / `helperText`
26
- * explicitly, those values are used as-is.
27
- * 2. **Auto values are gated by interaction.** The bridge's error is
31
+ * Precedence rules:
32
+ *
33
+ * 1. **`error`: the explicit prop wins.** An author who passes `error`
34
+ * is forcing the visual state, so it overrides the auto-gate.
35
+ * 2. **`helperText`: the validation message wins while it is showing;
36
+ * the explicit prop is the fallback for the no-error state.** A
37
+ * constant hint ("Unique, uppercase") must not swallow the reason a
38
+ * required field was rejected — that leaves the user looking at a
39
+ * red field with no explanation. See README-BUG.md § BUG 17 / § BUG 32.
40
+ * 3. **Auto values are gated by interaction.** The bridge's error is
28
41
  * surfaced only when the field is `touched` OR the form has been
29
42
  * submitted at least once (`submitCount > 0`). This prevents the
30
43
  * "error spam while typing" anti-pattern.
31
- * 3. **`error === false` explicitly clears the bridge's error message
32
- * text.** Useful for forcing a "valid" visual state regardless of
33
- * bridge state.
34
44
  *
35
45
  * @param name field name registered with the bridge
36
46
  * @param bridge active `DashFormBridge` (guaranteed non-null at
@@ -1 +1 @@
1
- {"version":3,"file":"resolveValidationState.d.ts","sourceRoot":"","sources":["../../../../src/components/_shared/resolveValidationState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,SAAS,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,cAAc,EACtB,aAAa,EAAE,OAAO,GAAG,SAAS,EAClC,kBAAkB,EAAE,SAAS,GAAG,SAAS,GACxC,eAAe,CAYjB"}
1
+ {"version":3,"file":"resolveValidationState.d.ts","sourceRoot":"","sources":["../../../../src/components/_shared/resolveValidationState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,SAAS,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,cAAc,EACtB,aAAa,EAAE,OAAO,GAAG,SAAS,EAClC,kBAAkB,EAAE,SAAS,GAAG,SAAS,GACxC,eAAe,CAoBjB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dashforge/tw",
3
- "version": "1.6.0",
3
+ "version": "1.7.1",
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.1.0",
39
- "@dashforge/forms": "1.1.0",
38
+ "@dashforge/forms": "1.2.0",
39
+ "@dashforge/ui-core": "1.2.0",
40
40
  "@dashforge/rbac": "1.0.0"
41
41
  },
42
42
  "peerDependencies": {