cursedbelt 5.38.0 → 5.40.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.
Files changed (145) hide show
  1. package/dist/react/components/ActionGroup.d.ts +3 -0
  2. package/dist/react/components/ActionGroup.d.ts.map +1 -1
  3. package/dist/react/components/ActionGroup.js +1 -0
  4. package/dist/react/components/ActionGroup.js.map +1 -1
  5. package/dist/react/components/Button.d.ts.map +1 -1
  6. package/dist/react/components/Button.js +1 -1
  7. package/dist/react/components/Button.js.map +1 -1
  8. package/dist/react/components/ControlPanel.d.ts +46 -0
  9. package/dist/react/components/ControlPanel.d.ts.map +1 -0
  10. package/dist/react/components/ControlPanel.js +38 -0
  11. package/dist/react/components/ControlPanel.js.map +1 -0
  12. package/dist/react/components/Field.d.ts +16 -6
  13. package/dist/react/components/Field.d.ts.map +1 -1
  14. package/dist/react/components/Field.js +17 -11
  15. package/dist/react/components/Field.js.map +1 -1
  16. package/dist/react/components/FieldGrid.d.ts +23 -0
  17. package/dist/react/components/FieldGrid.d.ts.map +1 -0
  18. package/dist/react/components/FieldGrid.js +21 -0
  19. package/dist/react/components/FieldGrid.js.map +1 -0
  20. package/dist/react/components/InfoHint.d.ts +15 -20
  21. package/dist/react/components/InfoHint.d.ts.map +1 -1
  22. package/dist/react/components/InfoHint.js +61 -58
  23. package/dist/react/components/InfoHint.js.map +1 -1
  24. package/dist/react/components/InfoHintImpl.d.ts +16 -0
  25. package/dist/react/components/InfoHintImpl.d.ts.map +1 -0
  26. package/dist/react/components/InfoHintImpl.js +70 -0
  27. package/dist/react/components/InfoHintImpl.js.map +1 -0
  28. package/dist/react/components/NativeSelect.d.ts.map +1 -1
  29. package/dist/react/components/NativeSelect.js +3 -2
  30. package/dist/react/components/NativeSelect.js.map +1 -1
  31. package/dist/react/components/SegmentedControl.d.ts +13 -1
  32. package/dist/react/components/SegmentedControl.d.ts.map +1 -1
  33. package/dist/react/components/SegmentedControl.js +17 -4
  34. package/dist/react/components/SegmentedControl.js.map +1 -1
  35. package/dist/react/components/SelectField.d.ts.map +1 -1
  36. package/dist/react/components/SelectField.js +3 -2
  37. package/dist/react/components/SelectField.js.map +1 -1
  38. package/dist/react/components/Slider.d.ts +3 -1
  39. package/dist/react/components/Slider.d.ts.map +1 -1
  40. package/dist/react/components/Slider.js +2 -2
  41. package/dist/react/components/Slider.js.map +1 -1
  42. package/dist/react/components/SliderField.d.ts +34 -13
  43. package/dist/react/components/SliderField.d.ts.map +1 -1
  44. package/dist/react/components/SliderField.js +79 -12
  45. package/dist/react/components/SliderField.js.map +1 -1
  46. package/dist/react/components/TooltipImpl.d.ts.map +1 -1
  47. package/dist/react/components/TooltipImpl.js +1 -1
  48. package/dist/react/components/TooltipImpl.js.map +1 -1
  49. package/dist/react/index.d.ts +5 -3
  50. package/dist/react/index.d.ts.map +1 -1
  51. package/dist/react/index.js +5 -3
  52. package/dist/react/index.js.map +1 -1
  53. package/dist/react/lib/field.d.ts +14 -0
  54. package/dist/react/lib/field.d.ts.map +1 -1
  55. package/dist/react/lib/field.js +24 -0
  56. package/dist/react/lib/field.js.map +1 -1
  57. package/dist/react/lib/infoHint.d.ts +25 -0
  58. package/dist/react/lib/infoHint.d.ts.map +1 -0
  59. package/dist/react/lib/infoHint.js +6 -0
  60. package/dist/react/lib/infoHint.js.map +1 -0
  61. package/dist/react/media/FocusViewer.d.ts +22 -2
  62. package/dist/react/media/FocusViewer.d.ts.map +1 -1
  63. package/dist/react/media/FocusViewer.js +24 -8
  64. package/dist/react/media/FocusViewer.js.map +1 -1
  65. package/dist/react/media/MediaResize.d.ts +7 -1
  66. package/dist/react/media/MediaResize.d.ts.map +1 -1
  67. package/dist/react/media/MediaResize.js +4 -2
  68. package/dist/react/media/MediaResize.js.map +1 -1
  69. package/dist/react/media/VideoPlayer.d.ts.map +1 -1
  70. package/dist/react/media/VideoPlayer.js +15 -13
  71. package/dist/react/media/VideoPlayer.js.map +1 -1
  72. package/dist/react/media/controlBar.d.ts +28 -0
  73. package/dist/react/media/controlBar.d.ts.map +1 -0
  74. package/dist/react/media/controlBar.js +78 -0
  75. package/dist/react/media/controlBar.js.map +1 -0
  76. package/dist/react/media/playheadHandoff.d.ts +29 -0
  77. package/dist/react/media/playheadHandoff.d.ts.map +1 -0
  78. package/dist/react/media/playheadHandoff.js +44 -0
  79. package/dist/react/media/playheadHandoff.js.map +1 -0
  80. package/dist/react/media/videoChapters.d.ts +16 -0
  81. package/dist/react/media/videoChapters.d.ts.map +1 -1
  82. package/dist/react/media/videoChapters.js +39 -0
  83. package/dist/react/media/videoChapters.js.map +1 -1
  84. package/dist/react/media/videoPlayer.css +6 -4
  85. package/dist/react/media/videoRegion.d.ts +24 -0
  86. package/dist/react/media/videoRegion.d.ts.map +1 -1
  87. package/dist/react/media/videoRegion.js +33 -0
  88. package/dist/react/media/videoRegion.js.map +1 -1
  89. package/dist/scripts/guardrailsEnforce.d.ts.map +1 -1
  90. package/dist/styles-areas/analytics.css +10 -10
  91. package/dist/styles-areas/core.css +25 -23
  92. package/dist/styles-areas/data-table.css +10 -10
  93. package/dist/styles-areas/fields.css +5 -4
  94. package/dist/styles-areas/nav.css +8 -9
  95. package/dist/styles-areas/notifications.css +4 -5
  96. package/dist/styles-static.css +99 -0
  97. package/dist/styles-utilities.css +16 -0
  98. package/dist/styles.css +99 -0
  99. package/package.json +3 -3
  100. package/scripts/guardrailsEnforce.spec.ts +54 -2
  101. package/scripts/guardrailsEnforce.ts +216 -9
  102. package/scripts/styleAreas.ts +4 -0
  103. package/src/iframesMakeNoRealRequest.spec.ts +1 -0
  104. package/src/react/components/ActionGroup.tsx +4 -0
  105. package/src/react/components/Button.tsx +8 -1
  106. package/src/react/components/ControlPanel.tsx +115 -0
  107. package/src/react/components/Field.spec.tsx +72 -1
  108. package/src/react/components/Field.tsx +59 -30
  109. package/src/react/components/Field.width.spec.tsx +16 -8
  110. package/src/react/components/FieldGrid.tsx +43 -0
  111. package/src/react/components/InfoHint.spec.tsx +32 -0
  112. package/src/react/components/InfoHint.tsx +71 -109
  113. package/src/react/components/InfoHintImpl.tsx +116 -0
  114. package/src/react/components/NativeSelect.tsx +3 -2
  115. package/src/react/components/SegmentedControl.spec.tsx +22 -1
  116. package/src/react/components/SegmentedControl.tsx +25 -1
  117. package/src/react/components/SelectField.tsx +3 -2
  118. package/src/react/components/Slider.tsx +4 -1
  119. package/src/react/components/SliderField.spec.ts +23 -1
  120. package/src/react/components/SliderField.tsx +141 -55
  121. package/src/react/components/TooltipImpl.tsx +5 -3
  122. package/src/react/index.ts +17 -1
  123. package/src/react/lib/field.ts +26 -0
  124. package/src/react/lib/infoHint.ts +30 -0
  125. package/src/react/media/FocusViewer.tsx +47 -7
  126. package/src/react/media/MediaResize.tsx +12 -1
  127. package/src/react/media/VideoPlayer.spec.tsx +11 -0
  128. package/src/react/media/VideoPlayer.tsx +18 -13
  129. package/src/react/media/controlBar.tsx +136 -0
  130. package/src/react/media/playheadHandoff.spec.ts +30 -0
  131. package/src/react/media/playheadHandoff.ts +45 -0
  132. package/src/react/media/videoChapters.spec.ts +28 -0
  133. package/src/react/media/videoChapters.ts +40 -0
  134. package/src/react/media/videoPlayer.css +6 -4
  135. package/src/react/media/videoRegion.spec.ts +52 -0
  136. package/src/react/media/videoRegion.ts +34 -0
  137. package/src/styles-areas/analytics.css +10 -10
  138. package/src/styles-areas/core.css +25 -23
  139. package/src/styles-areas/data-table.css +10 -10
  140. package/src/styles-areas/fields.css +5 -4
  141. package/src/styles-areas/nav.css +8 -9
  142. package/src/styles-areas/notifications.css +4 -5
  143. package/src/styles-static.css +99 -0
  144. package/src/styles-utilities.css +16 -0
  145. package/src/styles.css +99 -0
@@ -1 +1 @@
1
- {"version":3,"file":"InfoHint.js","sourceRoot":"","sources":["../../../src/react/components/InfoHint.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"InfoHint.js","sourceRoot":"","sources":["../../../src/react/components/InfoHint.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAsB,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxE,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAA8C,MAAM,oBAAoB,CAAC;AAMnG,IAAI,UAAU,GAAiC,IAAI,CAAC;AACpD,IAAI,WAAW,GAA0C,IAAI,CAAC;AAE9D,0DAA0D;AAC1D,SAAS,eAAe;IACtB,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,WAAW,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;YACnD,UAAU,GAAG,CAAC,CAAC,OAAO,CAAC;YACvB,OAAO,CAAC,CAAC,OAAO,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,yFAAyF;AACzF,6FAA6F;AAC7F,IAAI,OAAO,MAAM,KAAK,WAAW;IAAE,KAAK,eAAe,EAAE,CAAC;AAE1D;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAoB;IAC3C,mFAAmF;IACnF,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAA+B,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC;IACjF,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAE9B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,IAAI;YAAE,OAAO;QACjB,IAAI,KAAK,GAAG,IAAI,CAAC;QACjB,KAAK,eAAe,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;YAChC,IAAI,KAAK;gBAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,OAAO,GAAG,EAAE;YACV,KAAK,GAAG,KAAK,CAAC;QAChB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,IAAI,IAAI;QAAE,OAAO,KAAC,IAAI,OAAK,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,OAAO,GAAI,CAAC;IAElG,MAAM,EAAE,KAAK,GAAG,WAAW,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IACjD,OAAO,CACL;QACE,mFAAmF;QACnF,+EAA+E;QAC/E,IAAI,EAAC,QAAQ,gBACD,KAAK,EACjB,SAAS,EAAE,EAAE,CAAC,iBAAiB,EAAE,SAAS,CAAC,EAC3C,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;QACzB,CAAC,EACD,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;QACzB,CAAC,EACD,MAAM,EAAE,GAAG,EAAE;YACX,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC;QAC1B,CAAC,YAED,KAAC,IAAI,IAAC,SAAS,EAAC,QAAQ,wBAAe,GAChC,CACV,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { type InfoHintImplProps } from '../lib/infoHint.js';
2
+ /**
3
+ * "ⓘ" field-help — the bespoke anchored composite on @floating-ui/react (portaled,
4
+ * flips + shifts, never clipped by an overflow ancestor). The reference model for
5
+ * any future bespoke anchored composite (color picker on a swatch, date picker on an
6
+ * input); standard primitives (Tooltip/DropdownMenu/SelectField/Popover/HoverCard)
7
+ * use Radix instead.
8
+ *
9
+ * Opens on hover + focus on pointer devices, and on click/tap everywhere — so it is
10
+ * reachable on touch screens (which have no hover). `useHasHover` disables the hover
11
+ * interaction on touch devices so the panel isn't left stuck open after a tap.
12
+ *
13
+ * Loaded by `InfoHint.tsx` with a dynamic `import()` — see that file for why.
14
+ */
15
+ export default function InfoHintImpl({ children, title, align, className, label, initialOpen, initialFocus, }: InfoHintImplProps): import("react").JSX.Element;
16
+ //# sourceMappingURL=InfoHintImpl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InfoHintImpl.d.ts","sourceRoot":"","sources":["../../../src/react/components/InfoHintImpl.tsx"],"names":[],"mappings":"AAoBA,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE/E;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACnC,QAAQ,EACR,KAAK,EACL,KAAc,EACd,SAAS,EACT,KAAmB,EACnB,WAAmB,EACnB,YAAoB,GACrB,EAAE,iBAAiB,+BAwEnB"}
@@ -0,0 +1,70 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { autoUpdate, FloatingPortal, flip, offset, shift, useClick, useDismiss, useFloating, useFocus, useHover, useInteractions, useRole, } from '@floating-ui/react';
3
+ import { Info } from 'lucide-react';
4
+ import { useEffect, useState } from 'react';
5
+ import { useHasHover } from '../hooks/useHasHover.js';
6
+ import { cn } from '../lib/cn.js';
7
+ import { HOVER_HINT_DELAY_MS } from '../lib/hoverIntent.js';
8
+ import { INFO_HINT_TRIGGER } from '../lib/infoHint.js';
9
+ /**
10
+ * "ⓘ" field-help — the bespoke anchored composite on @floating-ui/react (portaled,
11
+ * flips + shifts, never clipped by an overflow ancestor). The reference model for
12
+ * any future bespoke anchored composite (color picker on a swatch, date picker on an
13
+ * input); standard primitives (Tooltip/DropdownMenu/SelectField/Popover/HoverCard)
14
+ * use Radix instead.
15
+ *
16
+ * Opens on hover + focus on pointer devices, and on click/tap everywhere — so it is
17
+ * reachable on touch screens (which have no hover). `useHasHover` disables the hover
18
+ * interaction on touch devices so the panel isn't left stuck open after a tap.
19
+ *
20
+ * Loaded by `InfoHint.tsx` with a dynamic `import()` — see that file for why.
21
+ */
22
+ export default function InfoHintImpl({ children, title, align = 'left', className, label = 'More info', initialOpen = false, initialFocus = false, }) {
23
+ const [open, setOpen] = useState(initialOpen);
24
+ const hasHover = useHasHover();
25
+ const { refs, floatingStyles, context } = useFloating({
26
+ open,
27
+ onOpenChange: setOpen,
28
+ placement: align === 'right' ? 'bottom-end' : 'bottom-start',
29
+ whileElementsMounted: autoUpdate,
30
+ middleware: [offset(6), flip(), shift({ padding: 8 })],
31
+ });
32
+ // Hover only where a hover pointer exists; click/tap works on every device.
33
+ //
34
+ // 🔴 The hover half waits (`lib/hoverIntent.ts`); the CLICK half does not, and that
35
+ // asymmetry is the point. An (i) is small and it sits inside dense label rows, so a
36
+ // pointer on its way somewhere else crosses it constantly — this panel is richer than
37
+ // a tooltip bubble and occludes correspondingly more when it fires by accident. A
38
+ // click on it is an unambiguous request and still opens instantly, below.
39
+ const hover = useHover(context, {
40
+ move: false,
41
+ enabled: hasHover,
42
+ delay: { open: HOVER_HINT_DELAY_MS, close: 0 },
43
+ });
44
+ const focus = useFocus(context);
45
+ const click = useClick(context);
46
+ const dismiss = useDismiss(context);
47
+ const role = useRole(context, { role: 'tooltip' });
48
+ const { getReferenceProps, getFloatingProps } = useInteractions([
49
+ hover,
50
+ focus,
51
+ click,
52
+ dismiss,
53
+ role,
54
+ ]);
55
+ // The placeholder trigger had focus when this replaced it: hand it to the real one, so a
56
+ // keyboard user's place is not dropped to <body> by the swap.
57
+ // biome-ignore lint/correctness/useExhaustiveDependencies: once, on the swap
58
+ useEffect(() => {
59
+ if (initialFocus)
60
+ refs.domReference.current?.focus();
61
+ }, []);
62
+ return (_jsxs(_Fragment, { children: [_jsx("button", {
63
+ // guardrails-ignore no-raw-action-button: presentational hover/click disclosure
64
+ // trigger for the floating help panel — no destructive/mutating intent, and the
65
+ // floating-ui ref/interaction wiring here doesn't fit the Button primitive.
66
+ type: 'button', ref: refs.setReference, "aria-label": label, className: cn(INFO_HINT_TRIGGER, className), ...getReferenceProps(), children: _jsx(Info, { className: 'size-4', "aria-hidden": true }) }), open ? (_jsx(FloatingPortal, { children: _jsxs("div", {
67
+ // guardrails-ignore no-hand-rolled-surface: the hint's floating-ui bubble — a tooltip-class overlay with its own z-index and shadow, not a card
68
+ ref: refs.setFloating, "data-cb-prose": '', style: floatingStyles, ...getFloatingProps(), className: 'z-50 max-w-xs rounded-md border border-border bg-popover px-3 py-2 text-xs text-popover-foreground shadow-[var(--shadow-overlay)]', children: [title ? _jsx("p", { className: 'mb-1 font-semibold', children: title }) : null, children] }) })) : null] }));
69
+ }
70
+ //# sourceMappingURL=InfoHintImpl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InfoHintImpl.js","sourceRoot":"","sources":["../../../src/react/components/InfoHintImpl.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"NativeSelect.d.ts","sourceRoot":"","sources":["../../../src/react/components/NativeSelect.tsx"],"names":[],"mappings":"AACA,OAAO,EAA4B,KAAK,qBAAqB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE7F,OAAO,EAAE,KAAK,WAAW,EAAwC,MAAM,iBAAiB,CAAC;AAEzF,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IACtF,iFAAiF;IACjF,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;gFAC4E;IAC5E,OAAO,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACxC;;;kBAGc;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAmCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,YAAY,CAAC,EAC3B,IAAW,EACX,OAAO,EACP,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,iBAAiB,+BA6CnB"}
1
+ {"version":3,"file":"NativeSelect.d.ts","sourceRoot":"","sources":["../../../src/react/components/NativeSelect.tsx"],"names":[],"mappings":"AACA,OAAO,EAA4B,KAAK,qBAAqB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE7F,OAAO,EAAE,KAAK,WAAW,EAA0D,MAAM,iBAAiB,CAAC;AAE3G,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IACtF,iFAAiF;IACjF,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;gFAC4E;IAC5E,OAAO,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACxC;;;kBAGc;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAmCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,YAAY,CAAC,EAC3B,IAAW,EACX,OAAO,EACP,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,iBAAiB,+BA6CnB"}
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { ChevronDown } from 'lucide-react';
3
3
  import { Children, isValidElement } from 'react';
4
4
  import { cn } from '../lib/cn.js';
5
- import { declareFieldWidth, fieldControlClass } from '../lib/field.js';
5
+ import { choiceFieldWidth, declareFieldWidth, fieldControlClass } from '../lib/field.js';
6
6
  /**
7
7
  * Does this control offer anything the reader can actually pick?
8
8
  *
@@ -84,5 +84,6 @@ export function NativeSelect({ size = 'md', options, placeholder, className, wra
84
84
  // reserves the room the drawn chevron below occupies.
85
85
  'appearance-none pr-9', className), ...props, children: [placeholder !== undefined && (_jsx("option", { value: '', disabled: true, children: placeholder })), options?.map((option) => (_jsx("option", { value: option.value, disabled: option.disabled, children: option.label }, option.value))), children, empty && (_jsx("option", { disabled: true, value: '__empty__', children: emptyLabel ?? 'Nothing to choose from yet' }))] }), _jsx(ChevronDown, { "aria-hidden": 'true', className: 'pointer-events-none absolute top-1/2 right-3 size-4 -translate-y-1/2 opacity-60' })] }));
86
86
  }
87
- declareFieldWidth(NativeSelect, 'md');
87
+ // Sized by its longest option, not stretched to the panel (FRM-3, forge task 2463).
88
+ declareFieldWidth(NativeSelect, choiceFieldWidth);
88
89
  //# sourceMappingURL=NativeSelect.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"NativeSelect.js","sourceRoot":"","sources":["../../../src/react/components/NativeSelect.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,cAAc,EAA8C,MAAM,OAAO,CAAC;AAC7F,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAoB,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAqCzF;;;;;;;GAOG;AACH,SAAS,mBAAmB,CAC1B,OAAkD,EAClD,QAAmB;IAEnB,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,MAAM,KAAK,GAAG,CAAC,IAAe,EAAQ,EAAE;QACtC,IAAI,KAAK;YAAE,OAAO;QAClB,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,IAAI,KAAK;gBAAE,OAAO;YAClB,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;gBAAE,SAAS;YACrC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAsE,CAAC;YAC3F,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC9B,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBACtB,SAAS;YACX,CAAC;YACD,IAAI,KAAK,CAAC,QAAQ;gBAAE,SAAS;YAC7B,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,EAAE;gBAAE,SAAS;YAC9D,KAAK,GAAG,IAAI,CAAC;QACf,CAAC;IACH,CAAC,CAAC;IACF,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChB,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,YAAY,CAAC,EAC3B,IAAI,GAAG,IAAI,EACX,OAAO,EACP,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACR,GAAG,KAAK,EACU;IAClB,MAAM,KAAK,GAAG,CAAC,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACtD,OAAO,CACL,gBAAM,SAAS,EAAE,EAAE,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,aACrD;gBACE,6EAA6E;gBAC7E,qEAAqE;gBACrE,SAAS,EAAE,EAAE,CACX,iBAAiB,CAAC,IAAI,CAAC;gBACvB,wEAAwE;gBACxE,uEAAuE;gBACvE,sDAAsD;gBACtD,sBAAsB,EACtB,SAAS,CACV,KACG,KAAK,aAER,WAAW,KAAK,SAAS,IAAI,CAC5B,iBAAQ,KAAK,EAAC,EAAE,EAAC,QAAQ,kBACtB,WAAW,GACL,CACV,EACA,OAAO,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CACxB,iBAA2B,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,YACtE,MAAM,CAAC,KAAK,IADF,MAAM,CAAC,KAAK,CAEhB,CACV,CAAC,EACD,QAAQ,EAIR,KAAK,IAAI,CACR,iBAAQ,QAAQ,QAAC,KAAK,EAAC,WAAW,YAC/B,UAAU,IAAI,4BAA4B,GACpC,CACV,IACM,EAGT,KAAC,WAAW,mBACE,MAAM,EAClB,SAAS,EAAC,iFAAiF,GAC3F,IACG,CACR,CAAC;AACJ,CAAC;AAED,iBAAiB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC"}
1
+ {"version":3,"file":"NativeSelect.js","sourceRoot":"","sources":["../../../src/react/components/NativeSelect.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,cAAc,EAA8C,MAAM,OAAO,CAAC;AAC7F,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAoB,gBAAgB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAqC3G;;;;;;;GAOG;AACH,SAAS,mBAAmB,CAC1B,OAAkD,EAClD,QAAmB;IAEnB,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,MAAM,KAAK,GAAG,CAAC,IAAe,EAAQ,EAAE;QACtC,IAAI,KAAK;YAAE,OAAO;QAClB,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,IAAI,KAAK;gBAAE,OAAO;YAClB,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;gBAAE,SAAS;YACrC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAsE,CAAC;YAC3F,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC9B,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBACtB,SAAS;YACX,CAAC;YACD,IAAI,KAAK,CAAC,QAAQ;gBAAE,SAAS;YAC7B,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,EAAE;gBAAE,SAAS;YAC9D,KAAK,GAAG,IAAI,CAAC;QACf,CAAC;IACH,CAAC,CAAC;IACF,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChB,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,YAAY,CAAC,EAC3B,IAAI,GAAG,IAAI,EACX,OAAO,EACP,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACR,GAAG,KAAK,EACU;IAClB,MAAM,KAAK,GAAG,CAAC,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACtD,OAAO,CACL,gBAAM,SAAS,EAAE,EAAE,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,aACrD;gBACE,6EAA6E;gBAC7E,qEAAqE;gBACrE,SAAS,EAAE,EAAE,CACX,iBAAiB,CAAC,IAAI,CAAC;gBACvB,wEAAwE;gBACxE,uEAAuE;gBACvE,sDAAsD;gBACtD,sBAAsB,EACtB,SAAS,CACV,KACG,KAAK,aAER,WAAW,KAAK,SAAS,IAAI,CAC5B,iBAAQ,KAAK,EAAC,EAAE,EAAC,QAAQ,kBACtB,WAAW,GACL,CACV,EACA,OAAO,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CACxB,iBAA2B,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,YACtE,MAAM,CAAC,KAAK,IADF,MAAM,CAAC,KAAK,CAEhB,CACV,CAAC,EACD,QAAQ,EAIR,KAAK,IAAI,CACR,iBAAQ,QAAQ,QAAC,KAAK,EAAC,WAAW,YAC/B,UAAU,IAAI,4BAA4B,GACpC,CACV,IACM,EAGT,KAAC,WAAW,mBACE,MAAM,EAClB,SAAS,EAAC,iFAAiF,GAC3F,IACG,CACR,CAAC;AACJ,CAAC;AAED,oFAAoF;AACpF,iBAAiB,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC"}
@@ -23,7 +23,19 @@ export interface SegmentedControlProps<T extends string> {
23
23
  /** Segment height on the shared control-height scale (`--control-h-*`, task
24
24
  * cbux-41). Default `md`. */
25
25
  size?: ControlSize;
26
+ /**
27
+ * Every segment the same width and height, on one baseline (FRM-7) — the strip a set of
28
+ * short peers (z² … z⁸, 1×/2×/4×) reads as one control instead of bouncing. Default: on
29
+ * when every label is a string of at most {@link EQUAL_SEGMENT_MAX_CHARS} characters.
30
+ */
31
+ equal?: boolean;
26
32
  }
33
+ /** Labels this short are peers: the strip gives them equal segments unless told otherwise. */
34
+ export declare const EQUAL_SEGMENT_MAX_CHARS = 4;
35
+ /** Whether a set of options gets equal segments by default (FRM-7). Exported for tests. */
36
+ export declare function segmentsAreShortPeers<O extends {
37
+ label: ReactNode;
38
+ }>(options: readonly O[]): boolean;
27
39
  /**
28
40
  * A pill-style segment toggle / view switcher. Backed by Radix `Tabs` purely for
29
41
  * its a11y (roving focus + arrow-key navigation + the tablist/tab ARIA pattern) —
@@ -31,5 +43,5 @@ export interface SegmentedControlProps<T extends string> {
31
43
  * without them). The active segment lifts onto a `background` pill over the `muted`
32
44
  * track. Options may be individually `disabled` (with a `tooltip` explaining why).
33
45
  */
34
- export declare function SegmentedControl<T extends string>({ options, value, onChange, capitalize, className, 'aria-label': ariaLabel, size, }: SegmentedControlProps<T>): import("react").JSX.Element;
46
+ export declare function SegmentedControl<T extends string>({ options, value, onChange, capitalize, className, 'aria-label': ariaLabel, size, equal, }: SegmentedControlProps<T>): import("react").JSX.Element;
35
47
  //# sourceMappingURL=SegmentedControl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentedControl.d.ts","sourceRoot":"","sources":["../../../src/react/components/SegmentedControl.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAwB,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAIzE,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,MAAM;IAC7C,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,SAAS,CAAC;IACjB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;sFACkF;IAClF,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,qFAAqF;IACrF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB,CAAC,CAAC,SAAS,MAAM;IACrD,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5B,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC7B,0EAA0E;IAC1E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;kCAC8B;IAC9B,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAAE,EACjD,OAAO,EACP,KAAK,EACL,QAAQ,EACR,UAAkB,EAClB,SAAS,EACT,YAAY,EAAE,SAAqB,EACnC,IAAW,GACZ,EAAE,qBAAqB,CAAC,CAAC,CAAC,+BAuD1B"}
1
+ {"version":3,"file":"SegmentedControl.d.ts","sourceRoot":"","sources":["../../../src/react/components/SegmentedControl.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAwB,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAIzE,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,MAAM;IAC7C,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,SAAS,CAAC;IACjB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;sFACkF;IAClF,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,qFAAqF;IACrF,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB,CAAC,CAAC,SAAS,MAAM;IACrD,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5B,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC7B,0EAA0E;IAC1E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;kCAC8B;IAC9B,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,8FAA8F;AAC9F,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,2FAA2F;AAC3F,wBAAgB,qBAAqB,CAAC,CAAC,SAAS;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,GAAG,OAAO,CAEpG;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAAE,EACjD,OAAO,EACP,KAAK,EACL,QAAQ,EACR,UAAkB,EAClB,SAAS,EACT,YAAY,EAAE,SAAqB,EACnC,IAAW,EACX,KAAK,GACN,EAAE,qBAAqB,CAAC,CAAC,CAAC,+BAgE1B"}
@@ -4,6 +4,12 @@ import { cn } from '../lib/cn.js';
4
4
  import { CONTROL_HEIGHT_CLASS } from '../lib/field.js';
5
5
  import { Tooltip } from './Tooltip.js';
6
6
  import { TAP_TARGET } from '../lib/tapTarget.js';
7
+ /** Labels this short are peers: the strip gives them equal segments unless told otherwise. */
8
+ export const EQUAL_SEGMENT_MAX_CHARS = 4;
9
+ /** Whether a set of options gets equal segments by default (FRM-7). Exported for tests. */
10
+ export function segmentsAreShortPeers(options) {
11
+ return options.length > 1 && options.every((o) => typeof o.label === 'string' && [...o.label].length <= EQUAL_SEGMENT_MAX_CHARS);
12
+ }
7
13
  /**
8
14
  * A pill-style segment toggle / view switcher. Backed by Radix `Tabs` purely for
9
15
  * its a11y (roving focus + arrow-key navigation + the tablist/tab ARIA pattern) —
@@ -11,12 +17,19 @@ import { TAP_TARGET } from '../lib/tapTarget.js';
11
17
  * without them). The active segment lifts onto a `background` pill over the `muted`
12
18
  * track. Options may be individually `disabled` (with a `tooltip` explaining why).
13
19
  */
14
- export function SegmentedControl({ options, value, onChange, capitalize = false, className, 'aria-label': ariaLabel = 'Segment', size = 'md', }) {
15
- return (_jsx(Tabs.Root, { className: 'min-w-0', value: value, onValueChange: (v) => onChange(v), children: _jsx(Tabs.List, { "aria-label": ariaLabel, "data-cb-scrollarea": '', className: cn(
20
+ export function SegmentedControl({ options, value, onChange, capitalize = false, className, 'aria-label': ariaLabel = 'Segment', size = 'md', equal, }) {
21
+ const uniform = equal ?? segmentsAreShortPeers(options);
22
+ return (_jsx(Tabs.Root, { className: 'min-w-0', value: value, onValueChange: (v) => onChange(v), children: _jsx(Tabs.List, { "aria-label": ariaLabel, "data-cb-scrollarea": '', "data-cb-segments-equal": uniform ? '' : undefined, className: cn(
16
23
  // guardrails-ignore no-raw-overflow: small inline horizontal scroller for the
17
24
  // segment-pill row, not a keyboard-aware page scroll region.
18
- 'inline-flex max-w-full items-center gap-0.5 overflow-x-auto rounded-md bg-muted p-1', className), children: options.map((opt) => {
19
- const trigger = (_jsx(Tabs.Trigger, { value: opt.value, disabled: opt.disabled, "data-testid": opt['data-testid'], className: cn('inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded-[calc(var(--radius-md)-0.25rem)] px-3 text-sm font-medium transition-colors', CONTROL_HEIGHT_CLASS[size], 'text-muted-foreground hover:text-foreground', 'data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-raised', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring', 'disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:text-muted-foreground', TAP_TARGET, capitalize && 'capitalize'), children: opt.label }, opt.value));
25
+ 'max-w-full items-center gap-0.5 overflow-x-auto rounded-md bg-muted p-1',
26
+ // Equal: one grid track per segment, every track 1fr of the widest — so z² and z⁸
27
+ // are the same size and the strip does not bounce (FRM-7).
28
+ uniform ? 'inline-grid auto-cols-fr grid-flow-col' : 'inline-flex', className), children: options.map((opt) => {
29
+ const trigger = (_jsx(Tabs.Trigger, { value: opt.value, disabled: opt.disabled, "data-testid": opt['data-testid'], className: cn('inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded-[calc(var(--radius-md)-0.25rem)] px-3 text-sm font-medium transition-colors', CONTROL_HEIGHT_CLASS[size], 'text-muted-foreground hover:text-foreground', 'data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-raised', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring', 'disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:text-muted-foreground', TAP_TARGET,
30
+ // One line box for every segment: a superscript (`<sup>`) must not push its
31
+ // segment's baseline down and make the row uneven.
32
+ 'leading-none [&_sup]:leading-none', uniform && 'w-full', capitalize && 'capitalize'), children: opt.label }, opt.value));
20
33
  return opt.tooltip != null ? (_jsx(Tooltip, { content: opt.tooltip, children: _jsx("span", { className: 'inline-flex', children: trigger }) }, opt.value)) : (trigger);
21
34
  }) }) }));
22
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentedControl.js","sourceRoot":"","sources":["../../../src/react/components/SegmentedControl.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,IAAI,MAAM,sBAAsB,CAAC;AAE7C,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAoB,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AA4BjD;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAmB,EACjD,OAAO,EACP,KAAK,EACL,QAAQ,EACR,UAAU,GAAG,KAAK,EAClB,SAAS,EACT,YAAY,EAAE,SAAS,GAAG,SAAS,EACnC,IAAI,GAAG,IAAI,GACc;IACzB,OAAO,CAML,KAAC,IAAI,CAAC,IAAI,IAAC,SAAS,EAAC,SAAS,EAAC,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAM,CAAC,YACjF,KAAC,IAAI,CAAC,IAAI,kBACI,SAAS,wBAIF,EAAE,EACrB,SAAS,EAAE,EAAE;YACX,8EAA8E;YAC9E,6DAA6D;YAC7D,qFAAqF,EACrF,SAAS,CACV,YAEA,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;gBACnB,MAAM,OAAO,GAAG,CACd,KAAC,IAAI,CAAC,OAAO,IAEX,KAAK,EAAE,GAAG,CAAC,KAAK,EAChB,QAAQ,EAAE,GAAG,CAAC,QAAQ,iBACT,GAAG,CAAC,aAAa,CAAC,EAC/B,SAAS,EAAE,EAAE,CACX,wJAAwJ,EACxJ,oBAAoB,CAAC,IAAI,CAAC,EAC1B,6CAA6C,EAC7C,yGAAyG,EACzG,yEAAyE,EACzE,sFAAsF,EACtF,UAAU,EACV,UAAU,IAAI,YAAY,CAC3B,YAEA,GAAG,CAAC,KAAK,IAfL,GAAG,CAAC,KAAK,CAgBD,CAChB,CAAC;gBACF,OAAO,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,CAG3B,KAAC,OAAO,IAAiB,OAAO,EAAE,GAAG,CAAC,OAAO,YAC3C,eAAM,SAAS,EAAC,aAAa,YAAE,OAAO,GAAQ,IADlC,GAAG,CAAC,KAAK,CAEb,CACX,CAAC,CAAC,CAAC,CACF,OAAO,CACR,CAAC;YACJ,CAAC,CAAC,GACQ,GACF,CACb,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"SegmentedControl.js","sourceRoot":"","sources":["../../../src/react/components/SegmentedControl.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,IAAI,MAAM,sBAAsB,CAAC;AAE7C,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,oBAAoB,EAAoB,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAkCjD,8FAA8F;AAC9F,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAEzC,2FAA2F;AAC3F,MAAM,UAAU,qBAAqB,CAAiC,OAAqB;IACzF,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI,uBAAuB,CAAC,CAAC;AACnI,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAmB,EACjD,OAAO,EACP,KAAK,EACL,QAAQ,EACR,UAAU,GAAG,KAAK,EAClB,SAAS,EACT,YAAY,EAAE,SAAS,GAAG,SAAS,EACnC,IAAI,GAAG,IAAI,EACX,KAAK,GACoB;IACzB,MAAM,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACxD,OAAO,CAML,KAAC,IAAI,CAAC,IAAI,IAAC,SAAS,EAAC,SAAS,EAAC,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAM,CAAC,YACjF,KAAC,IAAI,CAAC,IAAI,kBACI,SAAS,wBAIF,EAAE,4BACG,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,EAChD,SAAS,EAAE,EAAE;YACX,8EAA8E;YAC9E,6DAA6D;YAC7D,yEAAyE;YACzE,kFAAkF;YAClF,2DAA2D;YAC3D,OAAO,CAAC,CAAC,CAAC,wCAAwC,CAAC,CAAC,CAAC,aAAa,EAClE,SAAS,CACV,YAEA,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;gBACnB,MAAM,OAAO,GAAG,CACd,KAAC,IAAI,CAAC,OAAO,IAEX,KAAK,EAAE,GAAG,CAAC,KAAK,EAChB,QAAQ,EAAE,GAAG,CAAC,QAAQ,iBACT,GAAG,CAAC,aAAa,CAAC,EAC/B,SAAS,EAAE,EAAE,CACX,wJAAwJ,EACxJ,oBAAoB,CAAC,IAAI,CAAC,EAC1B,6CAA6C,EAC7C,yGAAyG,EACzG,yEAAyE,EACzE,sFAAsF,EACtF,UAAU;oBACV,4EAA4E;oBAC5E,mDAAmD;oBACnD,mCAAmC,EACnC,OAAO,IAAI,QAAQ,EACnB,UAAU,IAAI,YAAY,CAC3B,YAEA,GAAG,CAAC,KAAK,IAnBL,GAAG,CAAC,KAAK,CAoBD,CAChB,CAAC;gBACF,OAAO,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,CAG3B,KAAC,OAAO,IAAiB,OAAO,EAAE,GAAG,CAAC,OAAO,YAC3C,eAAM,SAAS,EAAC,aAAa,YAAE,OAAO,GAAQ,IADlC,GAAG,CAAC,KAAK,CAEb,CACX,CAAC,CAAC,CAAC,CACF,OAAO,CACR,CAAC;YACJ,CAAC,CAAC,GACQ,GACF,CACb,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"SelectField.d.ts","sourceRoot":"","sources":["../../../src/react/components/SelectField.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,EAAE,KAAK,WAAW,EAAwC,MAAM,iBAAiB,CAAC;AAQzF,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qFAAqF;IACrF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;mEAC+D;IAC/D,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,6EAA6E;IAC7E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,sEAAsE;IACtE,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;sFACkF;IAClF,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IAC5C,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,aAAa,EACb,OAAY,EACZ,MAAW,EACX,WAAuB,EACvB,QAAQ,EACR,UAAiB,EACjB,IAAW,EACX,EAAE,EACF,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,UAAU,EACV,SAAS,EACT,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,GACpC,EAAE,gBAAgB,+BA2FlB"}
1
+ {"version":3,"file":"SelectField.d.ts","sourceRoot":"","sources":["../../../src/react/components/SelectField.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,EAAE,KAAK,WAAW,EAA0D,MAAM,iBAAiB,CAAC;AAQ3G,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qFAAqF;IACrF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;mEAC+D;IAC/D,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,6EAA6E;IAC7E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,sEAAsE;IACtE,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;sFACkF;IAClF,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IAC5C,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,aAAa,EACb,OAAY,EACZ,MAAW,EACX,WAAuB,EACvB,QAAQ,EACR,UAAiB,EACjB,IAAW,EACX,EAAE,EACF,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,UAAU,EACV,SAAS,EACT,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,GACpC,EAAE,gBAAgB,+BA2FlB"}
@@ -3,7 +3,7 @@ import * as RSelect from '@radix-ui/react-select';
3
3
  import { Check, ChevronDown, ChevronUp } from 'lucide-react';
4
4
  import { cn } from '../lib/cn.js';
5
5
  import { useFloatingContainer } from '../lib/floatingContainer.js';
6
- import { declareFieldWidth, fieldControlClass } from '../lib/field.js';
6
+ import { choiceFieldWidth, declareFieldWidth, fieldControlClass } from '../lib/field.js';
7
7
  import { FLOATING_ANIMATION, FLOATING_COLLISION_PADDING, FLOATING_CONTENT_BASE, FLOATING_ITEM_BASE, } from '../lib/floatingStyles.js';
8
8
  /**
9
9
  * Portal-based select control on Radix Select. Replaces the native `<select>`
@@ -24,5 +24,6 @@ export function SelectField({ value, onValueChange, options = [], groups = [], p
24
24
  const container = useFloatingContainer();
25
25
  return (_jsxs(RSelect.Root, { value: value, onValueChange: onValueChange, disabled: disabled, name: name, required: required, children: [_jsxs(RSelect.Trigger, { id: id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedBy, className: cn(fieldStyle && fieldControlClass(size), 'flex items-center justify-between gap-2 data-[placeholder]:text-muted-foreground', className), children: [_jsx(RSelect.Value, { placeholder: placeholder }), _jsx(RSelect.Icon, { asChild: true, children: _jsx(ChevronDown, { className: 'size-4 shrink-0 opacity-50' }) })] }), _jsx(RSelect.Portal, { container: container, children: _jsxs(RSelect.Content, { position: 'popper', sideOffset: 4, collisionPadding: FLOATING_COLLISION_PADDING, className: cn(FLOATING_COLLISION_PADDING, FLOATING_CONTENT_BASE, FLOATING_ANIMATION, 'max-h-[var(--radix-select-content-available-height)] min-w-[var(--radix-select-trigger-width)] p-1'), children: [_jsx(RSelect.ScrollUpButton, { className: 'flex cursor-default items-center justify-center py-1', children: _jsx(ChevronUp, { className: 'size-4' }) }), _jsxs(RSelect.Viewport, { children: [empty && (_jsxs("div", { className: 'flex flex-col gap-0.5 px-2 py-2.5 text-left', children: [_jsx("span", { className: 'text-sm font-medium', children: emptyLabel ?? 'Nothing to choose from yet' }), emptyHint && _jsx("span", { className: 'text-xs text-muted-foreground', children: emptyHint })] })), allGroups.map((group, gi) => (_jsxs(RSelect.Group, { children: [group.label && (_jsx(RSelect.Label, { className: 'px-2 py-1.5 text-xs font-semibold text-muted-foreground', children: group.label })), group.options.map((opt) => (_jsxs(RSelect.Item, { value: opt.value, disabled: opt.disabled, className: cn(FLOATING_ITEM_BASE, 'pr-8'), children: [_jsx(RSelect.ItemIndicator, { className: 'absolute right-2 flex size-4 items-center justify-center', children: _jsx(Check, { className: 'size-3' }) }), _jsx(RSelect.ItemText, { children: opt.label }), opt.description && (_jsx("span", { className: 'text-xs text-muted-foreground', children: opt.description }))] }, opt.value))), gi < allGroups.length - 1 && _jsx(RSelect.Separator, { className: 'my-1 h-px bg-border' })] }, group.label ?? gi)))] }), _jsx(RSelect.ScrollDownButton, { className: 'flex cursor-default items-center justify-center py-1', children: _jsx(ChevronDown, { className: 'size-4' }) })] }) })] }));
26
26
  }
27
- declareFieldWidth(SelectField, 'md');
27
+ // Sized by its longest option, not stretched to the panel (FRM-3, forge task 2463).
28
+ declareFieldWidth(SelectField, choiceFieldWidth);
28
29
  //# sourceMappingURL=SelectField.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SelectField.js","sourceRoot":"","sources":["../../../src/react/components/SelectField.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SelectField.js","sourceRoot":"","sources":["../../../src/react/components/SelectField.tsx"],"names":[],"mappings":"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"}
@@ -15,6 +15,8 @@ export interface SliderProps extends SliderBaseProps {
15
15
  onChange?: (value: number) => void;
16
16
  /** Fired once when the user releases the thumb (commit semantics). */
17
17
  onCommit?: (value: number) => void;
18
+ /** The value as words for a screen reader (e.g. `"40%"`, `"Screen edges"`). */
19
+ 'aria-valuetext'?: string;
18
20
  }
19
21
  /**
20
22
  * A single-value slider form control built on Radix `Slider` — full slider ARIA
@@ -22,7 +24,7 @@ export interface SliderProps extends SliderBaseProps {
22
24
  * Accent fill over a `muted` track. For media trim ranges keep using the specialized
23
25
  * `TrimRangeSlider`; this is the general form control.
24
26
  */
25
- export declare function Slider({ value, defaultValue, onChange, onCommit, min, max, step, disabled, 'aria-label': ariaLabel, className, }: SliderProps): import("react").JSX.Element;
27
+ export declare function Slider({ value, defaultValue, onChange, onCommit, min, max, step, disabled, 'aria-label': ariaLabel, 'aria-valuetext': ariaValueText, className, }: SliderProps): import("react").JSX.Element;
26
28
  export interface RangeSliderProps extends SliderBaseProps {
27
29
  /** Controlled [low, high] pair. */
28
30
  value?: [number, number];
@@ -1 +1 @@
1
- {"version":3,"file":"Slider.d.ts","sourceRoot":"","sources":["../../../src/react/components/Slider.tsx"],"names":[],"mappings":"AAGA,UAAU,eAAe;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAY,SAAQ,eAAe;IAClD,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AASD;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,GAAO,EACP,GAAS,EACT,IAAQ,EACR,QAAQ,EACR,YAAY,EAAE,SAAS,EACvB,SAAS,GACV,EAAE,WAAW,+BAmBb;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,mCAAmC;IACnC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzB,sCAAsC;IACtC,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IAC7C,oEAAoE;IACpE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IAC7C,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,GAAO,EACP,GAAS,EACT,IAAQ,EACR,MAAU,EACV,QAAQ,EACR,WAAoC,EACpC,SAAS,GACV,EAAE,gBAAgB,+BAsBlB"}
1
+ {"version":3,"file":"Slider.d.ts","sourceRoot":"","sources":["../../../src/react/components/Slider.tsx"],"names":[],"mappings":"AAGA,UAAU,eAAe;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAY,SAAQ,eAAe;IAClD,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AASD;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,GAAO,EACP,GAAS,EACT,IAAQ,EACR,QAAQ,EACR,YAAY,EAAE,SAAS,EACvB,gBAAgB,EAAE,aAAa,EAC/B,SAAS,GACV,EAAE,WAAW,+BAmBb;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,mCAAmC;IACnC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzB,sCAAsC;IACtC,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IAC7C,oEAAoE;IACpE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IAC7C,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,GAAO,EACP,GAAS,EACT,IAAQ,EACR,MAAU,EACV,QAAQ,EACR,WAAoC,EACpC,SAAS,GACV,EAAE,gBAAgB,+BAsBlB"}
@@ -12,8 +12,8 @@ const THUMB = 'block size-4 rounded-full border border-border bg-background shad
12
12
  * Accent fill over a `muted` track. For media trim ranges keep using the specialized
13
13
  * `TrimRangeSlider`; this is the general form control.
14
14
  */
15
- export function Slider({ value, defaultValue, onChange, onCommit, min = 0, max = 100, step = 1, disabled, 'aria-label': ariaLabel, className, }) {
16
- return (_jsxs(RadixSlider.Root, { value: value == null ? undefined : [value], defaultValue: defaultValue == null ? undefined : [defaultValue], onValueChange: (v) => onChange?.(v[0] ?? min), onValueCommit: (v) => onCommit?.(v[0] ?? min), min: min, max: max, step: step, disabled: disabled, className: cn('relative flex w-full touch-none select-none items-center py-2', className), children: [_jsx(RadixSlider.Track, { className: TRACK, children: _jsx(RadixSlider.Range, { className: RANGE }) }), _jsx(RadixSlider.Thumb, { "aria-label": ariaLabel, className: THUMB })] }));
15
+ export function Slider({ value, defaultValue, onChange, onCommit, min = 0, max = 100, step = 1, disabled, 'aria-label': ariaLabel, 'aria-valuetext': ariaValueText, className, }) {
16
+ return (_jsxs(RadixSlider.Root, { value: value == null ? undefined : [value], defaultValue: defaultValue == null ? undefined : [defaultValue], onValueChange: (v) => onChange?.(v[0] ?? min), onValueCommit: (v) => onCommit?.(v[0] ?? min), min: min, max: max, step: step, disabled: disabled, className: cn('relative flex w-full touch-none select-none items-center py-2', className), children: [_jsx(RadixSlider.Track, { className: TRACK, children: _jsx(RadixSlider.Range, { className: RANGE }) }), _jsx(RadixSlider.Thumb, { "aria-label": ariaLabel, "aria-valuetext": ariaValueText, className: THUMB })] }));
17
17
  }
18
18
  /**
19
19
  * A dual-thumb range slider (min/max pair) on the same Radix base and visual
@@ -1 +1 @@
1
- {"version":3,"file":"Slider.js","sourceRoot":"","sources":["../../../src/react/components/Slider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Slider.js","sourceRoot":"","sources":["../../../src/react/components/Slider.tsx"],"names":[],"mappings":"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"}
@@ -5,39 +5,60 @@ import { type ReactNode } from 'react';
5
5
  * nearest step from `min`. Exported for unit tests.
6
6
  */
7
7
  export declare function clampSliderValue(raw: number, min: number, max: number, step: number, fallback: number): number;
8
+ /** How many decimals a step can resolve — `1` shows none, `0.05` shows two (FRM-5). */
9
+ export declare function stepDecimals(step: number): number;
10
+ /** The value as the step can resolve it: an integer step never shows `16.00`. */
11
+ export declare function formatSliderValue(value: number, step: number): string;
8
12
  export interface SliderFieldProps {
9
- /** Field label, rendered above the control. */
13
+ /** Field label — the first cell of the row (FRM-5). Inside a `FieldGrid` it takes the shared label column. */
10
14
  label: ReactNode;
11
15
  /** Controlled value. */
12
16
  value: number;
13
17
  min: number;
14
18
  max: number;
19
+ /** What the parameter can resolve. It drives the readout's precision: an integer step shows no decimals. */
15
20
  step?: number;
16
21
  disabled?: boolean;
17
- /** Fired on every drag/typed change (live value). */
22
+ /**
23
+ * The live value while dragging or typing. With `debounceMs` it fires at most once per
24
+ * pause instead of on every pixel — the thumb and the readout still follow the pointer.
25
+ */
18
26
  onChange?: (value: number) => void;
19
27
  /** Fired once when the user releases the thumb or commits the input (Enter/blur). */
20
28
  onCommit?: (value: number) => void;
21
29
  /**
22
- * Human-readable rendering of the current value, shown right-aligned in the label
23
- * row (e.g. `(v) => `${v} concurrent attempts``). Default: the bare number.
30
+ * Debounce `onChange` by this many ms (default 0: every change). For an EXPENSIVE render —
31
+ * a fractal, a re-tile — use 150 to preview while dragging, or render on `onCommit` alone
32
+ * (FRM-5). `onCommit` is never debounced, and it flushes a pending preview first.
33
+ */
34
+ debounceMs?: number;
35
+ /**
36
+ * The value as words, shown in the value cell when it is not being edited (e.g. `"Screen
37
+ * edges"` at the max, or `"40%"`), and read as the slider's `aria-valuetext`. Typing still
38
+ * edits the bare number. Default: the number at the step's precision.
24
39
  */
25
40
  formatValue?: (value: number) => ReactNode;
26
- /** Helper text under the control (kept at readable `muted-foreground` contrast). */
41
+ /**
42
+ * Help under the track: 12px, muted, at most two lines (FRM-9). A string longer than
43
+ * {@link HELP_FOLD_CHARS} (the same rule as `Field`) moves into an ⓘ beside the label instead.
44
+ */
27
45
  hint?: ReactNode;
46
+ /** `capped` (default): the track stops at `--cb-slider-max` (16rem). `full`: it fills the row. */
47
+ width?: 'capped' | 'full';
28
48
  /** Accessible name for the slider thumb + number input. Required when `label` isn't plain text. */
29
49
  'aria-label'?: string;
30
50
  className?: string;
31
51
  }
32
52
  /**
33
- * The standard "professional" numeric-range field: a {@link Slider} paired with a
34
- * numeric {@link Input} so users can drag for feel OR type an exact value, plus
35
- * always-visible min/max bound labels and a live value readout in the label row.
36
- * Pair-with-input is the commercial-dashboard norm — a bare slider forces users to
37
- * guess at exact values with the mouse.
53
+ * The one numeric-range field: `[label] [track] [value]` on ONE row (FRM-5). The value cell
54
+ * is a fixed-width, right-aligned, `tabular-nums` box you can type into; it shows the value
55
+ * at the step's precision, so an integer parameter never jumps through `16.00`. Help sits
56
+ * under the track. Inside a {@link FieldGrid} every slider and inline field shares one label
57
+ * column, so a panel of them reads as one straight-edged table.
38
58
  *
39
- * The number input is committed on Enter/blur (clamped to `[min, max]` and snapped
40
- * to `step`); the slider commits on thumb release. Both funnel through `onCommit`.
59
+ * Which callback to use for an expensive render: preview on `onChange` with
60
+ * `debounceMs={150}`, and do the full-quality pass on `onCommit` (release / Enter / blur).
61
+ * The typed value is clamped to `[min, max]` and snapped to `step`.
41
62
  */
42
- export declare function SliderField({ label, value, min, max, step, disabled, onChange, onCommit, formatValue, hint, 'aria-label': ariaLabel, className, }: SliderFieldProps): import("react").JSX.Element;
63
+ export declare function SliderField({ label, value, min, max, step, disabled, onChange, onCommit, debounceMs, formatValue, hint, width, 'aria-label': ariaLabel, className, }: SliderFieldProps): import("react").JSX.Element;
43
64
  //# sourceMappingURL=SliderField.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SliderField.d.ts","sourceRoot":"","sources":["../../../src/react/components/SliderField.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,OAAO,CAAC;AAKxD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI9G;AAED,MAAM,WAAW,gBAAgB;IAC/B,+CAA+C;IAC/C,KAAK,EAAE,SAAS,CAAC;IACjB,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,qFAAqF;IACrF,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;IAC3C,oFAAoF;IACpF,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,mGAAmG;IACnG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,KAAK,EACL,GAAG,EACH,GAAG,EACH,IAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,IAAI,EACJ,YAAY,EAAE,SAAS,EACvB,SAAS,GACV,EAAE,gBAAgB,+BA8DlB"}
1
+ {"version":3,"file":"SliderField.d.ts","sourceRoot":"","sources":["../../../src/react/components/SliderField.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,OAAO,CAAC;AAQxD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM9G;AAED,uFAAuF;AACvF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMjD;AAED,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAErE;AAKD,MAAM,WAAW,gBAAgB;IAC/B,8GAA8G;IAC9G,KAAK,EAAE,SAAS,CAAC;IACjB,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,4GAA4G;IAC5G,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,qFAAqF;IACrF,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;IAC3C;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,kGAAkG;IAClG,KAAK,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC1B,mGAAmG;IACnG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,KAAK,EACL,GAAG,EACH,GAAG,EACH,IAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,UAAc,EACd,WAAW,EACX,IAAI,EACJ,KAAgB,EAChB,YAAY,EAAE,SAAS,EACvB,SAAS,GACV,EAAE,gBAAgB,+BA2GlB"}
@@ -1,6 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useId, useState } from 'react';
3
+ import { useDebouncedCallback } from '../hooks/useDebouncedCallback.js';
3
4
  import { cn } from '../lib/cn.js';
5
+ import { HELP_FOLD_CHARS } from '../lib/field.js';
6
+ import { InfoHint } from './InfoHint.js';
4
7
  import { Input } from './Input.js';
5
8
  import { Slider } from './Slider.js';
6
9
  /**
@@ -12,32 +15,96 @@ export function clampSliderValue(raw, min, max, step, fallback) {
12
15
  if (Number.isNaN(raw))
13
16
  return fallback;
14
17
  const stepped = step > 0 ? min + Math.round((raw - min) / step) * step : raw;
15
- return Math.min(max, Math.max(min, stepped));
18
+ // Re-round to the step's own precision: 0.1 * 3 is 0.30000000000000004, not 0.3.
19
+ const tidy = step > 0 ? Number(stepped.toFixed(stepDecimals(step))) : stepped;
20
+ return Math.min(max, Math.max(min, tidy));
16
21
  }
22
+ /** How many decimals a step can resolve — `1` shows none, `0.05` shows two (FRM-5). */
23
+ export function stepDecimals(step) {
24
+ if (!Number.isFinite(step) || step <= 0 || Number.isInteger(step))
25
+ return 0;
26
+ const text = String(step);
27
+ const exp = /e-(\d+)$/.exec(text);
28
+ if (exp)
29
+ return Number(exp[1]);
30
+ return text.split('.')[1]?.length ?? 0;
31
+ }
32
+ /** The value as the step can resolve it: an integer step never shows `16.00`. */
33
+ export function formatSliderValue(value, step) {
34
+ return value.toFixed(stepDecimals(step));
35
+ }
36
+ /** A formatted readout longer than this widens the value cell instead of truncating. */
37
+ const WIDE_READOUT_CHARS = 6;
17
38
  /**
18
- * The standard "professional" numeric-range field: a {@link Slider} paired with a
19
- * numeric {@link Input} so users can drag for feel OR type an exact value, plus
20
- * always-visible min/max bound labels and a live value readout in the label row.
21
- * Pair-with-input is the commercial-dashboard norm — a bare slider forces users to
22
- * guess at exact values with the mouse.
39
+ * The one numeric-range field: `[label] [track] [value]` on ONE row (FRM-5). The value cell
40
+ * is a fixed-width, right-aligned, `tabular-nums` box you can type into; it shows the value
41
+ * at the step's precision, so an integer parameter never jumps through `16.00`. Help sits
42
+ * under the track. Inside a {@link FieldGrid} every slider and inline field shares one label
43
+ * column, so a panel of them reads as one straight-edged table.
23
44
  *
24
- * The number input is committed on Enter/blur (clamped to `[min, max]` and snapped
25
- * to `step`); the slider commits on thumb release. Both funnel through `onCommit`.
45
+ * Which callback to use for an expensive render: preview on `onChange` with
46
+ * `debounceMs={150}`, and do the full-quality pass on `onCommit` (release / Enter / blur).
47
+ * The typed value is clamped to `[min, max]` and snapped to `step`.
26
48
  */
27
- export function SliderField({ label, value, min, max, step = 1, disabled, onChange, onCommit, formatValue, hint, 'aria-label': ariaLabel, className, }) {
49
+ export function SliderField({ label, value, min, max, step = 1, disabled, onChange, onCommit, debounceMs = 0, formatValue, hint, width = 'capped', 'aria-label': ariaLabel, className, }) {
28
50
  const id = useId();
51
+ const helpId = `${id}-help`;
29
52
  // The input keeps its own draft while focused so partial entries ("1" on the way
30
53
  // to "12") aren't clamped mid-keystroke; the slider value stays authoritative.
31
54
  const [draft, setDraft] = useState(null);
55
+ // The value the thumb is at while a debounced drag has not reached the caller yet.
56
+ const [live, setLive] = useState(null);
57
+ // Once the caller has caught up, the prop is the truth again (adjusted during render, so no
58
+ // frame ever paints the stale drag value over the new prop).
59
+ const [seen, setSeen] = useState(value);
60
+ if (seen !== value) {
61
+ setSeen(value);
62
+ setLive(null);
63
+ }
64
+ const shown = live ?? value;
65
+ const preview = useDebouncedCallback((next) => onChange?.(next), debounceMs);
66
+ const change = (next) => {
67
+ if (debounceMs <= 0) {
68
+ onChange?.(next);
69
+ return;
70
+ }
71
+ setLive(next);
72
+ preview(next);
73
+ };
74
+ // A release: every change already reached the caller, unless one is still waiting on the debounce.
75
+ const commit = (next) => {
76
+ preview.cancel();
77
+ if (debounceMs > 0)
78
+ onChange?.(next);
79
+ onCommit?.(next);
80
+ };
81
+ // A typed value never went through `onChange` at all, so it is both a change and a commit.
82
+ const commitTyped = (next) => {
83
+ preview.cancel();
84
+ setLive(null);
85
+ onChange?.(next);
86
+ onCommit?.(next);
87
+ };
32
88
  const name = ariaLabel ?? (typeof label === 'string' ? label : undefined);
89
+ const readout = formatValue ? formatValue(shown) : formatSliderValue(shown, step);
90
+ const readoutText = typeof readout === 'string' || typeof readout === 'number' ? String(readout) : null;
91
+ // Size the cell from the longest readout the field can show, measured at the bounds, so it
92
+ // does not resize mid-drag and a word readout ("Screen edges") is not truncated.
93
+ const widest = Math.max(...[min, max, shown].map((v) => {
94
+ const r = formatValue ? formatValue(v) : formatSliderValue(v, step);
95
+ return typeof r === 'string' || typeof r === 'number' ? String(r).length : 0;
96
+ }));
97
+ const wide = widest > WIDE_READOUT_CHARS;
98
+ const folds = typeof hint === 'string' && hint.length > HELP_FOLD_CHARS;
33
99
  const commitDraft = () => {
34
100
  if (draft == null)
35
101
  return;
36
102
  const next = clampSliderValue(Number(draft), min, max, step, value);
37
103
  setDraft(null);
38
- onChange?.(next);
39
- onCommit?.(next);
104
+ // Focusing the box seeds the draft, so a focus and a blur with no edit must not commit.
105
+ if (next !== shown)
106
+ commitTyped(next);
40
107
  };
41
- return (_jsxs("div", { className: cn('flex flex-col gap-1.5', className), children: [_jsxs("div", { className: 'flex items-baseline justify-between gap-3', children: [_jsx("label", { htmlFor: id, className: 'text-sm font-semibold text-foreground', children: label }), _jsx("span", { className: 'text-sm text-muted-foreground tabular-nums', children: formatValue ? formatValue(value) : value })] }), _jsxs("div", { className: 'flex items-center gap-3', children: [_jsxs("div", { className: 'min-w-0 flex-1', children: [_jsx(Slider, { value: value, min: min, max: max, step: step, disabled: disabled, onChange: onChange, onCommit: onCommit, "aria-label": name }), _jsxs("div", { "aria-hidden": 'true', className: 'flex justify-between text-xs text-muted-foreground tabular-nums', children: [_jsx("span", { children: min }), _jsx("span", { children: max })] })] }), _jsx(Input, { id: id, type: 'number', inputMode: 'numeric', min: min, max: max, step: step, disabled: disabled, value: draft ?? String(value), onChange: (e) => setDraft(e.target.value), onEnter: commitDraft, onBlur: commitDraft, "aria-label": name, className: 'w-20 shrink-0 text-right' })] }), hint && _jsx("p", { className: 'm-0 text-xs leading-relaxed text-muted-foreground', children: hint })] }));
108
+ return (_jsxs("div", { className: cn('cb-slider-row', className), "data-cb-field": '', "data-cb-slider-width": width, children: [_jsxs("div", { className: 'flex min-w-0 items-center gap-1', "data-cb-field-head": '', children: [_jsx("label", { htmlFor: id, className: 'text-sm font-medium text-foreground', "data-cb-field-label": '', children: label }), folds ? _jsx(InfoHint, { title: typeof label === 'string' ? label : undefined, children: hint }) : null] }), _jsx(Slider, { value: shown, min: min, max: max, step: step, disabled: disabled, onChange: change, onCommit: commit, "aria-label": name, "aria-valuetext": readoutText ?? undefined }), _jsx(Input, { id: id, type: 'text', inputMode: step > 0 && Number.isInteger(step) && min >= 0 ? 'numeric' : 'decimal', disabled: disabled, value: draft ?? readoutText ?? formatSliderValue(shown, step), onFocus: () => setDraft(formatSliderValue(shown, step)), onChange: (e) => setDraft(e.target.value), onEnter: commitDraft, onBlur: commitDraft, "aria-label": name, "aria-describedby": hint != null && !folds ? helpId : undefined, className: cn('shrink-0 text-right tabular-nums', wide ? 'w-32' : 'w-20'), "data-cb-slider-value": '' }), hint != null && !folds ? (_jsx("p", { id: helpId, className: 'm-0 line-clamp-2 text-xs leading-snug text-muted-foreground', "data-cb-field-help": '', children: hint })) : null] }));
42
109
  }
43
110
  //# sourceMappingURL=SliderField.js.map