@weasel-js/ui 1.0.0 → 1.0.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 (110) hide show
  1. package/dist/chunks/ActionsBar-CAjrj_Pt.js +48 -0
  2. package/dist/chunks/{ActionsBar-CzU6Of3B.js.map → ActionsBar-CAjrj_Pt.js.map} +1 -1
  3. package/dist/chunks/{Callout-CxxrEcSb.js → Callout-DlirfLJl.js} +1 -1
  4. package/dist/chunks/{Callout-CxxrEcSb.js.map → Callout-DlirfLJl.js.map} +1 -1
  5. package/dist/chunks/{Checkbox-Cf6YHVWV.js → Checkbox-B3Z_u7k0.js} +1 -1
  6. package/dist/chunks/{Checkbox-Cf6YHVWV.js.map → Checkbox-B3Z_u7k0.js.map} +1 -1
  7. package/dist/chunks/{ColorField-sGLnThpB.js → ColorField-B4Hd2qqS.js} +1 -1
  8. package/dist/chunks/{ColorField-sGLnThpB.js.map → ColorField-B4Hd2qqS.js.map} +1 -1
  9. package/dist/chunks/{ComboBox-EnV1IytN.js → ComboBox-tbmgND-F.js} +2 -2
  10. package/dist/chunks/{ComboBox-EnV1IytN.js.map → ComboBox-tbmgND-F.js.map} +1 -1
  11. package/dist/chunks/{CurveEditor-DAb2EMyR.js → CurveEditor-CSKqAXMp.js} +1 -1
  12. package/dist/chunks/{CurveEditor-DAb2EMyR.js.map → CurveEditor-CSKqAXMp.js.map} +1 -1
  13. package/dist/chunks/{Dialog-CQymDCAl.js → Dialog-BFuakycR.js} +1 -1
  14. package/dist/chunks/{Dialog-CQymDCAl.js.map → Dialog-BFuakycR.js.map} +1 -1
  15. package/dist/chunks/{Field-BHSu2F3E.js → Field-DPxmJzZz.js} +1 -1
  16. package/dist/chunks/{Field-BHSu2F3E.js.map → Field-DPxmJzZz.js.map} +1 -1
  17. package/dist/chunks/{GradientEditor-Co9aGyRe.js → GradientEditor-3pYXGAPg.js} +3 -3
  18. package/dist/chunks/{GradientEditor-Co9aGyRe.js.map → GradientEditor-3pYXGAPg.js.map} +1 -1
  19. package/dist/chunks/{Input-qk44ESKC.js → Input-Dg_CYXg4.js} +2 -2
  20. package/dist/chunks/{Input-qk44ESKC.js.map → Input-Dg_CYXg4.js.map} +1 -1
  21. package/dist/chunks/{NumberField-CYhQeWoM.js → NumberField-BhxUgi43.js} +2 -2
  22. package/dist/chunks/{NumberField-CYhQeWoM.js.map → NumberField-BhxUgi43.js.map} +1 -1
  23. package/dist/chunks/OptionsBar-hQN-wfd-.js +52 -0
  24. package/dist/chunks/OptionsBar-hQN-wfd-.js.map +1 -0
  25. package/dist/chunks/{PointPlotter-EkbCBK9j.js → PointPlotter-DCSjvpN0.js} +2 -2
  26. package/dist/chunks/{PointPlotter-EkbCBK9j.js.map → PointPlotter-DCSjvpN0.js.map} +1 -1
  27. package/dist/chunks/{Powerline-Bg9M5oBK.js → Powerline-DkOTPnUV.js} +1 -1
  28. package/dist/chunks/{Powerline-Bg9M5oBK.js.map → Powerline-DkOTPnUV.js.map} +1 -1
  29. package/dist/chunks/{Prefs-DZjXp2Ln.js → Prefs-C4HfuTvm.js} +10 -10
  30. package/dist/chunks/{Prefs-DZjXp2Ln.js.map → Prefs-C4HfuTvm.js.map} +1 -1
  31. package/dist/chunks/{RadioGroup-rL2i3afr.js → RadioGroup-Bg3Rqxe2.js} +2 -2
  32. package/dist/chunks/{RadioGroup-rL2i3afr.js.map → RadioGroup-Bg3Rqxe2.js.map} +1 -1
  33. package/dist/chunks/{RangeSlider-DPldYd4O.js → RangeSlider-BvM_DGSr.js} +1 -1
  34. package/dist/chunks/{RangeSlider-DPldYd4O.js.map → RangeSlider-BvM_DGSr.js.map} +1 -1
  35. package/dist/chunks/{ResizeHandle-DR8X229y.js → ResizeHandle-BUkW2kZC.js} +1 -1
  36. package/dist/chunks/{ResizeHandle-DR8X229y.js.map → ResizeHandle-BUkW2kZC.js.map} +1 -1
  37. package/dist/chunks/{Select-vSeAbspK.js → Select-DC0AjrEe.js} +2 -2
  38. package/dist/chunks/{Select-vSeAbspK.js.map → Select-DC0AjrEe.js.map} +1 -1
  39. package/dist/chunks/{SelectionPanel-1mmALQba.js → SelectionPanel-DoTdisRY.js} +6 -6
  40. package/dist/chunks/{SelectionPanel-1mmALQba.js.map → SelectionPanel-DoTdisRY.js.map} +1 -1
  41. package/dist/chunks/{Sidebar-CigrFvpL.js → Sidebar-B8qig3BQ.js} +1 -1
  42. package/dist/chunks/{Sidebar-CigrFvpL.js.map → Sidebar-B8qig3BQ.js.map} +1 -1
  43. package/dist/chunks/{SidebarPanel-C0w16BrF.js → SidebarPanel-LOt2c-wb.js} +1 -1
  44. package/dist/chunks/{SidebarPanel-C0w16BrF.js.map → SidebarPanel-LOt2c-wb.js.map} +1 -1
  45. package/dist/chunks/{StatusBar-lt_Ok6WK.js → StatusBar-Cg2LzdAm.js} +1 -1
  46. package/dist/chunks/{StatusBar-lt_Ok6WK.js.map → StatusBar-Cg2LzdAm.js.map} +1 -1
  47. package/dist/chunks/{Switch-BYj762hm.js → Switch-I4putUAY.js} +1 -1
  48. package/dist/chunks/{Switch-BYj762hm.js.map → Switch-I4putUAY.js.map} +1 -1
  49. package/dist/chunks/{Tabs-DOW5jtnq.js → Tabs-irZuG_PN.js} +1 -1
  50. package/dist/chunks/{Tabs-DOW5jtnq.js.map → Tabs-irZuG_PN.js.map} +1 -1
  51. package/dist/chunks/{Toast-DLM2AsTz.js → Toast-BGYP8Pw0.js} +1 -1
  52. package/dist/chunks/{Toast-DLM2AsTz.js.map → Toast-BGYP8Pw0.js.map} +1 -1
  53. package/dist/chunks/ToggleBar-BP1zFcvg.js +74 -0
  54. package/dist/chunks/ToggleBar-BP1zFcvg.js.map +1 -0
  55. package/dist/chunks/{ToolButton-5L1sAlJC.js → ToolButton-DUeg8fPN.js} +1 -1
  56. package/dist/chunks/{ToolButton-5L1sAlJC.js.map → ToolButton-DUeg8fPN.js.map} +1 -1
  57. package/dist/chunks/{ToolGroup-BAthcF5H.js → ToolGroup-D0CvyQhQ.js} +1 -1
  58. package/dist/chunks/{ToolGroup-BAthcF5H.js.map → ToolGroup-D0CvyQhQ.js.map} +1 -1
  59. package/dist/chunks/{ToolOptionsBar-D4xmXa_a.js → ToolOptionsBar-N_MQcSo4.js} +1 -1
  60. package/dist/chunks/{ToolOptionsBar-D4xmXa_a.js.map → ToolOptionsBar-N_MQcSo4.js.map} +1 -1
  61. package/dist/chunks/{ToolPalette-BDkvV3pJ.js → ToolPalette-BipoMdZz.js} +3 -3
  62. package/dist/chunks/{ToolPalette-BDkvV3pJ.js.map → ToolPalette-BipoMdZz.js.map} +1 -1
  63. package/dist/chunks/useRovingTabIndex-DBZtq4IH.js +65 -0
  64. package/dist/chunks/useRovingTabIndex-DBZtq4IH.js.map +1 -0
  65. package/dist/components/ActionsBar/ActionsBar.d.ts.map +1 -1
  66. package/dist/components/ActionsBar/index.js +1 -1
  67. package/dist/components/Callout/index.js +1 -1
  68. package/dist/components/Checkbox/index.js +1 -1
  69. package/dist/components/ColorField/index.js +1 -1
  70. package/dist/components/ComboBox/index.js +1 -1
  71. package/dist/components/CurveEditor/index.js +1 -1
  72. package/dist/components/Dialog/index.js +1 -1
  73. package/dist/components/Field/index.js +1 -1
  74. package/dist/components/GradientEditor/index.js +1 -1
  75. package/dist/components/Input/index.js +1 -1
  76. package/dist/components/NumberField/index.js +1 -1
  77. package/dist/components/OptionsBar/OptionsBar.d.ts.map +1 -1
  78. package/dist/components/OptionsBar/index.js +1 -1
  79. package/dist/components/PointPlotter/index.js +1 -1
  80. package/dist/components/Powerline/index.js +1 -1
  81. package/dist/components/Prefs/index.js +1 -1
  82. package/dist/components/RadioGroup/index.js +1 -1
  83. package/dist/components/RangeSlider/index.js +1 -1
  84. package/dist/components/ResizeHandle/index.js +1 -1
  85. package/dist/components/Select/index.js +1 -1
  86. package/dist/components/SelectionPanel/index.js +1 -1
  87. package/dist/components/Sidebar/index.js +1 -1
  88. package/dist/components/SidebarPanel/index.js +1 -1
  89. package/dist/components/StatusBar/index.js +1 -1
  90. package/dist/components/Switch/index.js +1 -1
  91. package/dist/components/Tabs/index.js +1 -1
  92. package/dist/components/Toast/index.js +1 -1
  93. package/dist/components/ToggleBar/ToggleBar.d.ts.map +1 -1
  94. package/dist/components/ToggleBar/index.js +1 -1
  95. package/dist/components/ToolButton/index.js +1 -1
  96. package/dist/components/ToolGroup/index.js +1 -1
  97. package/dist/components/ToolOptionsBar/index.js +1 -1
  98. package/dist/components/ToolPalette/index.js +1 -1
  99. package/dist/index.d.ts +2 -0
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/index.js +38 -37
  102. package/dist/index.js.map +1 -1
  103. package/dist/useRovingTabIndex.d.ts +52 -0
  104. package/dist/useRovingTabIndex.d.ts.map +1 -0
  105. package/package.json +2 -2
  106. package/dist/chunks/ActionsBar-CzU6Of3B.js +0 -94
  107. package/dist/chunks/OptionsBar-CHOP_CiW.js +0 -98
  108. package/dist/chunks/OptionsBar-CHOP_CiW.js.map +0 -1
  109. package/dist/chunks/ToggleBar-Defj6Asn.js +0 -129
  110. package/dist/chunks/ToggleBar-Defj6Asn.js.map +0 -1
@@ -1,94 +0,0 @@
1
- import { useRef as e } from "react";
2
- import { jsx as t } from "react/jsx-runtime";
3
- var n = {
4
- root: "_root_13y7a_6",
5
- segment: "_segment_13y7a_28",
6
- segmentSelected: "_segmentSelected_13y7a_75",
7
- size_sm: "_size_sm_13y7a_133",
8
- variant_minimal: "_variant_minimal_13y7a_146"
9
- };
10
- //#endregion
11
- //#region src/components/ActionsBar/ActionsBar.tsx
12
- function r(e) {
13
- for (let t = 0; t < e.length; t++) if (!e[t].disabled) return t;
14
- return -1;
15
- }
16
- function i(e) {
17
- for (let t = e.length - 1; t >= 0; t--) if (!e[t].disabled) return t;
18
- return -1;
19
- }
20
- function a(e, t) {
21
- let n = e.length;
22
- for (let r = 1; r <= n; r++) {
23
- let i = (t + r + n) % n;
24
- if (!e[i].disabled) return i;
25
- }
26
- return t;
27
- }
28
- function o(e, t) {
29
- let n = e.length;
30
- for (let r = 1; r <= n; r++) {
31
- let i = (t - r + n) % n;
32
- if (!e[i].disabled) return i;
33
- }
34
- return t;
35
- }
36
- function s(s) {
37
- let { items: c, ariaLabel: l, className: u, height: d, size: f, variant: p } = s, m = e(null), h = r(c), g = (e) => {
38
- let t = c[e];
39
- t.disabled || t.onAction();
40
- }, _ = (e) => {
41
- let t = m.current;
42
- t && t.querySelectorAll(`.${n.segment}`)[e]?.focus();
43
- }, v = (e) => (t) => {
44
- let n = -1;
45
- switch (t.key) {
46
- case "ArrowLeft":
47
- case "ArrowUp":
48
- n = o(c, e);
49
- break;
50
- case "ArrowRight":
51
- case "ArrowDown":
52
- n = a(c, e);
53
- break;
54
- case "Home":
55
- n = r(c);
56
- break;
57
- case "End":
58
- n = i(c);
59
- break;
60
- case " ":
61
- case "Enter":
62
- t.preventDefault(), g(e);
63
- return;
64
- default: return;
65
- }
66
- n < 0 || n === e || (t.preventDefault(), _(n));
67
- }, y = d === void 0 ? void 0 : { "--wzl-tb-height": `${d}px` };
68
- return /* @__PURE__ */ t("div", {
69
- ref: m,
70
- className: [
71
- n.root,
72
- f && n[`size_${f}`],
73
- p && n[`variant_${p}`],
74
- u
75
- ].filter(Boolean).join(" "),
76
- role: "toolbar",
77
- "aria-label": l,
78
- style: y,
79
- children: c.map((e, r) => /* @__PURE__ */ t("button", {
80
- type: "button",
81
- "aria-label": e.ariaLabel,
82
- disabled: e.disabled,
83
- tabIndex: r === h ? 0 : -1,
84
- className: n.segment,
85
- onClick: () => g(r),
86
- onKeyDown: v(r),
87
- children: e.label
88
- }, e.value))
89
- });
90
- }
91
- //#endregion
92
- export { s as t };
93
-
94
- //# sourceMappingURL=ActionsBar-CzU6Of3B.js.map
@@ -1,98 +0,0 @@
1
- import { useRef as e } from "react";
2
- import { jsx as t } from "react/jsx-runtime";
3
- var n = {
4
- root: "_root_13y7a_6",
5
- segment: "_segment_13y7a_28",
6
- segmentSelected: "_segmentSelected_13y7a_75",
7
- size_sm: "_size_sm_13y7a_133",
8
- variant_minimal: "_variant_minimal_13y7a_146"
9
- };
10
- //#endregion
11
- //#region src/components/OptionsBar/OptionsBar.tsx
12
- function r(e) {
13
- for (let t = 0; t < e.length; t++) if (!e[t].disabled) return t;
14
- return -1;
15
- }
16
- function i(e) {
17
- for (let t = e.length - 1; t >= 0; t--) if (!e[t].disabled) return t;
18
- return -1;
19
- }
20
- function a(e, t) {
21
- let n = e.length;
22
- for (let r = 1; r <= n; r++) {
23
- let i = (t + r + n) % n;
24
- if (!e[i].disabled) return i;
25
- }
26
- return t;
27
- }
28
- function o(e, t) {
29
- let n = e.length;
30
- for (let r = 1; r <= n; r++) {
31
- let i = (t - r + n) % n;
32
- if (!e[i].disabled) return i;
33
- }
34
- return t;
35
- }
36
- function s(s) {
37
- let { items: c, ariaLabel: l, className: u, height: d, size: f, variant: p } = s, m = e(null), h = r(c), g = (e) => {
38
- let t = c[e];
39
- t.disabled || t.onChange(!t.selected);
40
- }, _ = (e) => {
41
- let t = m.current;
42
- t && t.querySelectorAll(`.${n.segment}`)[e]?.focus();
43
- }, v = (e) => (t) => {
44
- let n = -1;
45
- switch (t.key) {
46
- case "ArrowLeft":
47
- case "ArrowUp":
48
- n = o(c, e);
49
- break;
50
- case "ArrowRight":
51
- case "ArrowDown":
52
- n = a(c, e);
53
- break;
54
- case "Home":
55
- n = r(c);
56
- break;
57
- case "End":
58
- n = i(c);
59
- break;
60
- case " ":
61
- case "Enter":
62
- t.preventDefault(), g(e);
63
- return;
64
- default: return;
65
- }
66
- n < 0 || n === e || (t.preventDefault(), _(n));
67
- }, y = d === void 0 ? void 0 : { "--wzl-tb-height": `${d}px` };
68
- return /* @__PURE__ */ t("div", {
69
- ref: m,
70
- className: [
71
- n.root,
72
- f && n[`size_${f}`],
73
- p && n[`variant_${p}`],
74
- u
75
- ].filter(Boolean).join(" "),
76
- role: "group",
77
- "aria-label": l,
78
- style: y,
79
- children: c.map((e, r) => {
80
- let i = `${n.segment}${e.selected ? ` ${n.segmentSelected}` : ""}`;
81
- return /* @__PURE__ */ t("button", {
82
- type: "button",
83
- "aria-pressed": e.selected,
84
- "aria-label": e.ariaLabel,
85
- disabled: e.disabled,
86
- tabIndex: r === h ? 0 : -1,
87
- className: i,
88
- onClick: () => g(r),
89
- onKeyDown: v(r),
90
- children: e.label
91
- }, e.value);
92
- })
93
- });
94
- }
95
- //#endregion
96
- export { s as t };
97
-
98
- //# sourceMappingURL=OptionsBar-CHOP_CiW.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"OptionsBar-CHOP_CiW.js","names":[],"sources":["../../src/components/OptionsBar/OptionsBar.module.css","../../src/components/OptionsBar/OptionsBar.tsx"],"sourcesContent":["/* Aqua-glass segmented control. The track is a pill-shaped well; the\n selected segment becomes a tinted glass cylinder that reads as the same\n \"lozenge\" family as the standalone Button. Visual params come from the\n `--btn-*` custom properties (see Button.module.css) so the Button Lab\n can tune both surfaces with one set of sliders. */\n.root {\n display: inline-flex;\n height: var(--wzl-tb-height, 28px);\n padding: 2px;\n background: linear-gradient(\n 180deg,\n rgba(0, 0, 0, 0.18) 0%,\n rgba(0, 0, 0, 0.05) 100%\n );\n border-radius: 999px;\n /* Clip segments to the track outline so interior corners read crisp and\n the selected segment's glass treatment doesn't paint over the rounded\n outer pixels. */\n overflow: hidden;\n box-shadow:\n inset 0 1px 2px rgba(0, 0, 0, 0.4),\n 0 1px 0 rgba(255, 255, 255, 0.06);\n user-select: none;\n -webkit-user-select: none;\n touch-action: none;\n}\n\n.segment {\n position: relative;\n flex: 1 1 0;\n min-width: 0;\n padding: 0 12px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n margin: 0;\n font-family: var(--wzl-font-ui);\n font-weight: 300;\n font-size: var(--btn-fontsize, 14px);\n line-height: 1;\n color: var(--wzl-fg-muted);\n cursor: pointer;\n /* Only round the outer corners of the bar — middle segments stay square\n so the seams between them don't render as facing parentheses. */\n border-radius: 0;\n isolation: isolate;\n overflow: hidden;\n transition: color var(--wzl-motion-fast);\n}\n\n.segment:first-child {\n border-radius: 999px 0 0 999px;\n}\n\n.segment:last-child {\n border-radius: 0 999px 999px 0;\n}\n\n.segment:only-child {\n border-radius: 999px;\n}\n\n.segment:focus-visible {\n outline: 2px solid var(--wzl-accent);\n outline-offset: -2px;\n}\n\n.segment:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.segment:hover:not(:disabled):not(.segmentSelected) {\n color: var(--wzl-fg);\n}\n\n/* Selected segment — full Aqua glass cylinder. Mirrors Button.variant_primary. */\n.segmentSelected {\n background: linear-gradient(\n 180deg,\n color-mix(in srgb, var(--wzl-accent) var(--btn-top-alpha, 45%), transparent) 0%,\n color-mix(in srgb, var(--wzl-accent) var(--btn-upper-alpha, 70%), transparent) calc(var(--btn-equator, 52%) - var(--btn-equator-spread, 12%)),\n color-mix(in srgb, var(--wzl-accent) var(--btn-equator-tint, 95%), white) var(--btn-equator, 52%),\n var(--wzl-accent) calc(var(--btn-equator, 52%) + var(--btn-equator-spread, 12%) * 1.6),\n color-mix(in srgb, var(--wzl-accent) var(--btn-base-tint, 70%), black) 100%\n );\n backdrop-filter: blur(var(--btn-blur, 6px)) saturate(var(--btn-saturate, 1.3));\n -webkit-backdrop-filter: blur(var(--btn-blur, 6px)) saturate(var(--btn-saturate, 1.3));\n color: var(--wzl-fg-on-accent);\n text-shadow:\n 0 1px 0 rgba(0, 0, 0, var(--btn-text-shadow, 0.35)),\n var(--btn-text-inset-x, 0px) var(--btn-text-inset-y, 1px) 0 rgba(0, 0, 0, var(--btn-text-inset, 0.55)),\n 0 0 6px rgba(0, 0, 0, calc(var(--btn-text-shadow, 0.35) * 0.5));\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, var(--btn-inset-hi, 0.42)),\n inset 0 -1px 2px rgba(0, 0, 0, var(--btn-inset-lo, 0.3)),\n 0 0 0 1px rgba(0, 0, 0, var(--btn-rim, 0.22)),\n 0 1px 2px rgba(0, 0, 0, var(--btn-drop-near, 0.3)),\n 0 2px 4px rgba(0, 0, 0, calc(var(--btn-drop-far, 0.18) * 0.8));\n}\n\n/* Specular gloss on the selected segment. Top corners inherit the\n segment's radius so they hug the upper edge cleanly; bottom corners\n are flattened so the gloss ends in a straight line at the equator\n instead of two little curves that read as `)(` brackets. */\n.segmentSelected::before {\n content: '';\n position: absolute;\n inset: 1px 1px var(--btn-gloss-bottom, 50%) 1px;\n border-radius: inherit;\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, var(--btn-gloss-top, 0.42)) 0%,\n rgba(255, 255, 255, var(--btn-gloss-mid, 0.12)) 60%,\n rgba(255, 255, 255, 0) 100%\n );\n pointer-events: none;\n z-index: 1;\n}\n\n.segmentSelected > * {\n position: relative;\n z-index: 2;\n}\n\n/* Small variant — ~60% of the default height, with proportionally reduced\n padding and font. Sized for dense surfaces (lab control panels, inline\n filters, etc.). */\n.size_sm {\n height: 17px;\n padding: 1px;\n}\n\n.size_sm .segment {\n padding: 0 8px;\n font-size: 11px;\n}\n\n/* Minimal variant — strips the pill track, glass selected state, inset\n shadows, and outer padding. Used in dense diagnostic surfaces (dispatch\n trace, lab inspectors) where the bar must read as plain text controls. */\n.variant_minimal {\n height: auto;\n padding: 0;\n background: none;\n border-radius: 0;\n box-shadow: none;\n gap: 2px;\n}\n\n.variant_minimal .segment {\n padding: 0 4px;\n font-size: 11px;\n font-weight: 400;\n line-height: 1.4;\n border-radius: 2px;\n color: var(--wzl-fg-muted);\n transition: none;\n}\n\n.variant_minimal .segment:first-child,\n.variant_minimal .segment:last-child,\n.variant_minimal .segment:only-child {\n border-radius: 2px;\n}\n\n.variant_minimal .segment:hover:not(:disabled):not(.segmentSelected) {\n color: var(--wzl-fg);\n background: rgba(255, 255, 255, 0.06);\n}\n\n.variant_minimal .segmentSelected {\n background: none;\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n color: var(--wzl-accent-fg, var(--wzl-accent));\n text-shadow: none;\n box-shadow: none;\n font-weight: 500;\n}\n\n.variant_minimal .segmentSelected::before {\n content: none;\n}\n","import { useRef, type CSSProperties, type KeyboardEvent as ReactKeyboardEvent, type ReactElement, type ReactNode } from 'react';\nimport s from './OptionsBar.module.css';\n\nexport type OptionsBarItem<V extends string | number = string> = {\n value: V;\n label?: ReactNode;\n ariaLabel?: string;\n disabled?: boolean;\n selected: boolean;\n onChange: (next: boolean) => void;\n};\n\nexport type OptionsBarSize = 'sm' | 'md';\nexport type OptionsBarVariant = 'default' | 'minimal';\n\nexport type OptionsBarProps<V extends string | number = string> = {\n items: readonly OptionsBarItem<V>[];\n ariaLabel?: string;\n className?: string;\n height?: number;\n /** Size variant. `sm` is ~60% of the default height with reduced padding\n * and font size — sized for dense surfaces like lab control panels. */\n size?: OptionsBarSize;\n /** Visual variant. `minimal` strips the pill track and glass treatment;\n * selection becomes a flat accent. For dense diagnostic surfaces. */\n variant?: OptionsBarVariant;\n};\n\nfunction firstEnabledIndex(items: readonly OptionsBarItem<string | number>[]): number {\n for (let i = 0; i < items.length; i++) if (!items[i].disabled) return i;\n return -1;\n}\n\nfunction lastEnabledIndex(items: readonly OptionsBarItem<string | number>[]): number {\n for (let i = items.length - 1; i >= 0; i--) if (!items[i].disabled) return i;\n return -1;\n}\n\nfunction nextEnabledIndex(items: readonly OptionsBarItem<string | number>[], from: number): number {\n const n = items.length;\n for (let k = 1; k <= n; k++) {\n const i = (from + k + n) % n;\n if (!items[i].disabled) return i;\n }\n return from;\n}\n\nfunction prevEnabledIndex(items: readonly OptionsBarItem<string | number>[], from: number): number {\n const n = items.length;\n for (let k = 1; k <= n; k++) {\n const i = (from - k + n) % n;\n if (!items[i].disabled) return i;\n }\n return from;\n}\n\nexport function OptionsBar<V extends string | number = string>(props: OptionsBarProps<V>): ReactElement {\n const { items, ariaLabel, className, height, size, variant } = props;\n const rootRef = useRef<HTMLDivElement | null>(null);\n\n const tabStopIndex = firstEnabledIndex(items);\n\n const toggle = (index: number) => {\n const item = items[index];\n if (item.disabled) return;\n item.onChange(!item.selected);\n };\n\n const focusSegment = (index: number) => {\n const root = rootRef.current;\n if (!root) return;\n const buttons = root.querySelectorAll<HTMLButtonElement>(`.${s.segment}`);\n buttons[index]?.focus();\n };\n\n const handleKeyDown = (index: number) => (e: ReactKeyboardEvent<HTMLButtonElement>) => {\n let nextIndex = -1;\n switch (e.key) {\n case 'ArrowLeft':\n case 'ArrowUp':\n nextIndex = prevEnabledIndex(items, index);\n break;\n case 'ArrowRight':\n case 'ArrowDown':\n nextIndex = nextEnabledIndex(items, index);\n break;\n case 'Home':\n nextIndex = firstEnabledIndex(items);\n break;\n case 'End':\n nextIndex = lastEnabledIndex(items);\n break;\n case ' ':\n case 'Enter':\n e.preventDefault();\n toggle(index);\n return;\n default:\n return;\n }\n if (nextIndex < 0 || nextIndex === index) return;\n e.preventDefault();\n focusSegment(nextIndex);\n };\n\n const style: CSSProperties | undefined = height !== undefined\n ? ({ ['--wzl-tb-height' as string]: `${height}px` } as CSSProperties)\n : undefined;\n\n const rootCls = [\n s.root,\n size && s[`size_${size}`],\n variant && s[`variant_${variant}`],\n className,\n ].filter(Boolean).join(' ');\n\n return (\n <div\n ref={rootRef}\n className={rootCls}\n role=\"group\"\n aria-label={ariaLabel}\n style={style}\n >\n {items.map((item, i) => {\n const cls = `${s.segment}${item.selected ? ` ${s.segmentSelected}` : ''}`;\n return (\n <button\n key={item.value}\n type=\"button\"\n aria-pressed={item.selected}\n aria-label={item.ariaLabel}\n disabled={item.disabled}\n tabIndex={i === tabStopIndex ? 0 : -1}\n className={cls}\n onClick={() => toggle(i)}\n onKeyDown={handleKeyDown(i)}\n >\n {item.label}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;AC4BA,SAAS,EAAkB,GAA2D;AACpF,MAAK,IAAI,IAAI,GAAG,IAAI,EAAM,QAAQ,IAAK,KAAI,CAAC,EAAM,GAAG,SAAU,QAAO;AACtE,QAAO;;AAGT,SAAS,EAAiB,GAA2D;AACnF,MAAK,IAAI,IAAI,EAAM,SAAS,GAAG,KAAK,GAAG,IAAK,KAAI,CAAC,EAAM,GAAG,SAAU,QAAO;AAC3E,QAAO;;AAGT,SAAS,EAAiB,GAAmD,GAAsB;CACjG,IAAM,IAAI,EAAM;AAChB,MAAK,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;EAC3B,IAAM,KAAK,IAAO,IAAI,KAAK;AAC3B,MAAI,CAAC,EAAM,GAAG,SAAU,QAAO;;AAEjC,QAAO;;AAGT,SAAS,EAAiB,GAAmD,GAAsB;CACjG,IAAM,IAAI,EAAM;AAChB,MAAK,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;EAC3B,IAAM,KAAK,IAAO,IAAI,KAAK;AAC3B,MAAI,CAAC,EAAM,GAAG,SAAU,QAAO;;AAEjC,QAAO;;AAGT,SAAgB,EAA+C,GAAyC;CACtG,IAAM,EAAE,UAAO,cAAW,cAAW,WAAQ,SAAM,eAAY,GACzD,IAAU,EAA8B,KAAK,EAE7C,IAAe,EAAkB,EAAM,EAEvC,KAAU,MAAkB;EAChC,IAAM,IAAO,EAAM;AACf,IAAK,YACT,EAAK,SAAS,CAAC,EAAK,SAAS;IAGzB,KAAgB,MAAkB;EACtC,IAAM,IAAO,EAAQ;AAChB,OACW,EAAK,iBAAoC,IAAI,EAAE,UAC/D,CAAQ,IAAQ,OAAO;IAGnB,KAAiB,OAAmB,MAA6C;EACrF,IAAI,IAAY;AAChB,UAAQ,EAAE,KAAV;GACE,KAAK;GACL,KAAK;AACH,QAAY,EAAiB,GAAO,EAAM;AAC1C;GACF,KAAK;GACL,KAAK;AACH,QAAY,EAAiB,GAAO,EAAM;AAC1C;GACF,KAAK;AACH,QAAY,EAAkB,EAAM;AACpC;GACF,KAAK;AACH,QAAY,EAAiB,EAAM;AACnC;GACF,KAAK;GACL,KAAK;AAEH,IADA,EAAE,gBAAgB,EAClB,EAAO,EAAM;AACb;GACF,QACE;;AAEA,MAAY,KAAK,MAAc,MACnC,EAAE,gBAAgB,EAClB,EAAa,EAAU;IAGnB,IAAmC,MAAW,KAAA,IAEhD,KAAA,IADC,EAAG,mBAA8B,GAAG,EAAO,KAAK;AAUrD,QACE,kBAAC,OAAD;EACE,KAAK;EACL,WAVY;GACd,EAAE;GACF,KAAQ,EAAE,QAAQ;GAClB,KAAW,EAAE,WAAW;GACxB;GACD,CAAC,OAAO,QAAQ,CAAC,KAAK,IAKR;EACX,MAAK;EACL,cAAY;EACL;YAEN,EAAM,KAAK,GAAM,MAAM;GACtB,IAAM,IAAM,GAAG,EAAE,UAAU,EAAK,WAAW,IAAI,EAAE,oBAAoB;AACrE,UACE,kBAAC,UAAD;IAEE,MAAK;IACL,gBAAc,EAAK;IACnB,cAAY,EAAK;IACjB,UAAU,EAAK;IACf,UAAU,MAAM,IAAe,IAAI;IACnC,WAAW;IACX,eAAe,EAAO,EAAE;IACxB,WAAW,EAAc,EAAE;cAE1B,EAAK;IACC,EAXF,EAAK,MAWH;IAEX;EACE,CAAA"}
@@ -1,129 +0,0 @@
1
- import { useRef as e } from "react";
2
- import { jsx as t } from "react/jsx-runtime";
3
- var n = {
4
- root: "_root_1pyfg_6",
5
- segment: "_segment_1pyfg_28",
6
- segmentSelected: "_segmentSelected_1pyfg_75",
7
- segmentMixed: "_segmentMixed_1pyfg_134",
8
- variant_minimal: "_variant_minimal_1pyfg_144",
9
- size_sm: "_size_sm_1pyfg_153"
10
- };
11
- //#endregion
12
- //#region src/components/ToggleBar/ToggleBar.tsx
13
- function r(e) {
14
- for (let t = 0; t < e.length; t++) if (!e[t].disabled) return t;
15
- return -1;
16
- }
17
- function i(e) {
18
- for (let t = e.length - 1; t >= 0; t--) if (!e[t].disabled) return t;
19
- return -1;
20
- }
21
- function a(e, t) {
22
- let n = e.length;
23
- for (let r = 1; r <= n; r++) {
24
- let i = (t + r + n) % n;
25
- if (!e[i].disabled) return i;
26
- }
27
- return t;
28
- }
29
- function o(e, t) {
30
- let n = e.length;
31
- for (let r = 1; r <= n; r++) {
32
- let i = (t - r + n) % n;
33
- if (!e[i].disabled) return i;
34
- }
35
- return t;
36
- }
37
- function s(s) {
38
- let { items: c, ariaLabel: l, className: u, height: d, size: f, variant: p } = s, m = s.mode ?? "single", h = e(null), g = (e) => m === "multiple" ? s.value.includes(e) : s.value === e, _ = (e) => {
39
- if (m !== "multiple") return !1;
40
- let t = s.mixedValues;
41
- return t !== void 0 && t.includes(e) && !g(e);
42
- }, v = -1;
43
- if (m === "single") {
44
- let e = c.findIndex((e) => e.value === s.value);
45
- v = e >= 0 && !c[e].disabled ? e : r(c);
46
- } else v = r(c);
47
- let y = (e) => () => {
48
- let t = c[e];
49
- if (!t.disabled) if (m === "multiple") {
50
- let e = s.value, n = e.includes(t.value) ? e.filter((e) => e !== t.value) : [...e, t.value];
51
- s.onChange(n);
52
- } else {
53
- if (s.value === t.value) {
54
- s.allowDeselect && s.onChange(null);
55
- return;
56
- }
57
- s.onChange(t.value);
58
- }
59
- }, b = (e) => {
60
- let t = h.current;
61
- t && t.querySelectorAll(`.${n.segment}`)[e]?.focus();
62
- }, x = (e) => (t) => {
63
- let n = -1;
64
- switch (t.key) {
65
- case "ArrowLeft":
66
- case "ArrowUp":
67
- n = o(c, e);
68
- break;
69
- case "ArrowRight":
70
- case "ArrowDown":
71
- n = a(c, e);
72
- break;
73
- case "Home":
74
- n = r(c);
75
- break;
76
- case "End":
77
- n = i(c);
78
- break;
79
- case " ":
80
- case "Enter":
81
- m === "multiple" && (t.preventDefault(), y(e)());
82
- return;
83
- default: return;
84
- }
85
- if (!(n < 0 || n === e)) {
86
- if (t.preventDefault(), m === "single") {
87
- let e = c[n];
88
- s.onChange(e.value);
89
- }
90
- b(n);
91
- }
92
- }, S = d === void 0 ? void 0 : { "--wzl-tb-height": `${d}px` };
93
- return /* @__PURE__ */ t("div", {
94
- ref: h,
95
- className: [
96
- n.root,
97
- f && n[`size_${f}`],
98
- p && n[`variant_${p}`],
99
- u
100
- ].filter(Boolean).join(" "),
101
- role: m === "multiple" ? "group" : "radiogroup",
102
- "aria-label": l,
103
- style: S,
104
- children: c.map((e, r) => {
105
- let i = g(e.value), a = _(e.value), o = [
106
- n.segment,
107
- i && n.segmentSelected,
108
- a && n.segmentMixed
109
- ].filter(Boolean).join(" ");
110
- return /* @__PURE__ */ t("button", {
111
- type: "button",
112
- role: m === "multiple" ? void 0 : "radio",
113
- "aria-checked": m === "multiple" ? void 0 : i,
114
- "aria-pressed": m === "multiple" ? a ? "mixed" : i : void 0,
115
- "aria-label": e.ariaLabel,
116
- disabled: e.disabled,
117
- tabIndex: r === v ? 0 : -1,
118
- className: o,
119
- onClick: y(r),
120
- onKeyDown: x(r),
121
- children: e.label
122
- }, e.value);
123
- })
124
- });
125
- }
126
- //#endregion
127
- export { s as t };
128
-
129
- //# sourceMappingURL=ToggleBar-Defj6Asn.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ToggleBar-Defj6Asn.js","names":[],"sources":["../../src/components/ToggleBar/ToggleBar.module.css","../../src/components/ToggleBar/ToggleBar.tsx"],"sourcesContent":["/* Aqua-glass segmented control. The track is a pill-shaped well; the\n selected segment becomes a tinted glass cylinder that reads as the same\n \"lozenge\" family as the standalone Button. Visual params come from the\n `--btn-*` custom properties (see Button.module.css) so the Button Lab\n can tune both surfaces with one set of sliders. */\n.root {\n display: inline-flex;\n height: var(--wzl-tb-height, 28px);\n padding: 2px;\n background: linear-gradient(\n 180deg,\n rgba(0, 0, 0, 0.18) 0%,\n rgba(0, 0, 0, 0.05) 100%\n );\n border-radius: 999px;\n /* Clip segments to the track outline so interior corners read crisp and\n the selected segment's glass treatment doesn't paint over the rounded\n outer pixels. */\n overflow: hidden;\n box-shadow:\n inset 0 1px 2px rgba(0, 0, 0, 0.4),\n 0 1px 0 rgba(255, 255, 255, 0.06);\n user-select: none;\n -webkit-user-select: none;\n touch-action: none;\n}\n\n.segment {\n position: relative;\n flex: 1 1 0;\n min-width: 0;\n padding: 0 12px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n margin: 0;\n font-family: var(--wzl-font-ui);\n font-weight: 300;\n font-size: var(--btn-fontsize, 14px);\n line-height: 1;\n color: var(--wzl-fg-muted);\n cursor: pointer;\n /* Only round the outer corners of the bar — middle segments stay square\n so the seams between them don't render as facing parentheses. */\n border-radius: 0;\n isolation: isolate;\n overflow: hidden;\n transition: color var(--wzl-motion-fast);\n}\n\n.segment:first-child {\n border-radius: 999px 0 0 999px;\n}\n\n.segment:last-child {\n border-radius: 0 999px 999px 0;\n}\n\n.segment:only-child {\n border-radius: 999px;\n}\n\n.segment:focus-visible {\n outline: 2px solid var(--wzl-accent);\n outline-offset: -2px;\n}\n\n.segment:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.segment:hover:not(:disabled):not(.segmentSelected) {\n color: var(--wzl-fg);\n}\n\n/* Selected segment — full Aqua glass cylinder. Mirrors Button.variant_primary. */\n.segmentSelected {\n background: linear-gradient(\n 180deg,\n color-mix(in srgb, var(--wzl-accent) var(--btn-top-alpha, 45%), transparent) 0%,\n color-mix(in srgb, var(--wzl-accent) var(--btn-upper-alpha, 70%), transparent) calc(var(--btn-equator, 52%) - var(--btn-equator-spread, 12%)),\n color-mix(in srgb, var(--wzl-accent) var(--btn-equator-tint, 95%), white) var(--btn-equator, 52%),\n var(--wzl-accent) calc(var(--btn-equator, 52%) + var(--btn-equator-spread, 12%) * 1.6),\n color-mix(in srgb, var(--wzl-accent) var(--btn-base-tint, 70%), black) 100%\n );\n backdrop-filter: blur(var(--btn-blur, 6px)) saturate(var(--btn-saturate, 1.3));\n -webkit-backdrop-filter: blur(var(--btn-blur, 6px)) saturate(var(--btn-saturate, 1.3));\n color: var(--wzl-fg-on-accent);\n text-shadow:\n 0 1px 0 rgba(0, 0, 0, var(--btn-text-shadow, 0.35)),\n var(--btn-text-inset-x, 0px) var(--btn-text-inset-y, 1px) 0 rgba(0, 0, 0, var(--btn-text-inset, 0.55)),\n 0 0 6px rgba(0, 0, 0, calc(var(--btn-text-shadow, 0.35) * 0.5));\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, var(--btn-inset-hi, 0.42)),\n inset 0 -1px 2px rgba(0, 0, 0, var(--btn-inset-lo, 0.3)),\n 0 0 0 1px rgba(0, 0, 0, var(--btn-rim, 0.22)),\n 0 1px 2px rgba(0, 0, 0, var(--btn-drop-near, 0.3)),\n 0 2px 4px rgba(0, 0, 0, calc(var(--btn-drop-far, 0.18) * 0.8));\n}\n\n/* Specular gloss on the selected segment. Top corners inherit the\n segment's radius so they hug the upper edge cleanly; bottom corners\n are flattened so the gloss ends in a straight line at the equator\n instead of two little curves that read as `)(` brackets. */\n.segmentSelected::before {\n content: '';\n position: absolute;\n inset: 1px 1px var(--btn-gloss-bottom, 50%) 1px;\n border-radius: inherit;\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, var(--btn-gloss-top, 0.42)) 0%,\n rgba(255, 255, 255, var(--btn-gloss-mid, 0.12)) 60%,\n rgba(255, 255, 255, 0) 100%\n );\n pointer-events: none;\n z-index: 1;\n}\n\n.segmentSelected > * {\n position: relative;\n z-index: 2;\n}\n\n/* Mixed segment (`aria-pressed=\"mixed\"`) — the sources disagree. Reads as a\n deliberate third state rather than a dimmed \"on\": a flat accent wash with\n none of the selected segment's gloss/cylinder treatment, so it can't be\n mistaken for the glass lozenge at a glance. */\n.segmentMixed {\n background: color-mix(in srgb, var(--wzl-accent) 22%, transparent);\n color: var(--wzl-fg);\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--wzl-accent) 45%, transparent);\n}\n\n.segmentMixed:hover:not(:disabled) {\n background: color-mix(in srgb, var(--wzl-accent) 32%, transparent);\n}\n\n.variant_minimal .segmentMixed {\n background: color-mix(in srgb, var(--wzl-accent) 18%, transparent);\n box-shadow: none;\n color: var(--wzl-fg);\n}\n\n/* Small variant — ~60% of the default height, with proportionally reduced\n padding and font. Sized for dense surfaces (lab control panels, inline\n filters, etc.). */\n.size_sm {\n height: 17px;\n padding: 1px;\n}\n\n.size_sm .segment {\n padding: 0 8px;\n font-size: 11px;\n}\n\n/* Minimal variant — strips the pill track, glass selected state, inset\n shadows, and outer padding. Used in dense diagnostic surfaces (dispatch\n trace, lab inspectors) where the bar must read as plain text controls. */\n.variant_minimal {\n height: auto;\n padding: 0;\n background: none;\n border: 1px solid var(--wzl-border, rgba(255, 255, 255, 0.18));\n border-radius: 3px;\n box-shadow: none;\n gap: 0;\n}\n\n.variant_minimal .segment {\n padding: 0 6px;\n font-size: 11px;\n font-weight: 400;\n line-height: 1.4;\n border-radius: 0;\n color: var(--wzl-fg-muted);\n transition: none;\n}\n\n/* Dividers between segments make the mutual-exclusion grouping visible\n without a heavy track. Only the inner edges get a rule — the outer\n border on `.variant_minimal` handles the perimeter. */\n.variant_minimal .segment + .segment {\n border-left: 1px solid var(--wzl-border, rgba(255, 255, 255, 0.18));\n}\n\n.variant_minimal .segment:first-child,\n.variant_minimal .segment:last-child,\n.variant_minimal .segment:only-child {\n border-radius: 0;\n}\n\n.variant_minimal .segment:hover:not(:disabled):not(.segmentSelected) {\n color: var(--wzl-fg);\n background: rgba(255, 255, 255, 0.06);\n}\n\n.variant_minimal .segmentSelected {\n background: none;\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n color: var(--wzl-accent-fg, var(--wzl-accent));\n text-shadow: none;\n box-shadow: none;\n font-weight: 500;\n}\n\n.variant_minimal .segmentSelected::before {\n content: none;\n}\n","import { useRef, type CSSProperties, type KeyboardEvent as ReactKeyboardEvent, type ReactElement, type ReactNode } from 'react';\nimport s from './ToggleBar.module.css';\n\nexport type ToggleBarItem<V extends string | number = string> = {\n value: V;\n label?: ReactNode;\n ariaLabel?: string;\n disabled?: boolean;\n};\n\nexport type ToggleBarSize = 'sm' | 'md';\nexport type ToggleBarVariant = 'default' | 'minimal';\n\ntype CommonProps = {\n ariaLabel?: string;\n className?: string;\n height?: number;\n /** Size variant. `sm` is ~60% of the default height with reduced padding\n * and font size — sized for dense surfaces like lab control panels. */\n size?: ToggleBarSize;\n /** Visual variant. `minimal` strips the pill track and glass treatment;\n * selection becomes a flat accent. For dense diagnostic surfaces. */\n variant?: ToggleBarVariant;\n};\n\nexport type ToggleBarProps<V extends string | number = string> =\n | (CommonProps & {\n mode?: 'single';\n items: readonly ToggleBarItem<V>[];\n value: V | null;\n onChange: (next: V | null) => void;\n allowDeselect?: boolean;\n })\n | (CommonProps & {\n mode: 'multiple';\n items: readonly ToggleBarItem<V>[];\n value: readonly V[];\n /**\n * Values that are neither on nor off — the sources this bar\n * aggregates disagree (a text range that is bold in part of it, a\n * multi-selection whose nodes differ). Rendered `aria-pressed=\"mixed\"`,\n * the ARIA tri-state a toggle button actually has, rather than\n * `SelectionPanel`'s reduced-opacity-plus-`title` workaround for\n * `Switch`, which has no indeterminate state to render.\n *\n * `value` wins where the two lists overlap, so a caller that can't\n * cheaply keep them disjoint doesn't get an ambiguous segment.\n *\n * Clicking a mixed segment turns it fully **on**, matching the\n * everywhere-else convention (and `toggleFlagInRange`'s rule for a\n * partially-styled text range) that a mixed toggle resolves toward\n * the affirmative rather than clearing.\n */\n mixedValues?: readonly V[];\n onChange: (next: V[]) => void;\n });\n\nfunction firstEnabledIndex(items: readonly ToggleBarItem<string | number>[]): number {\n for (let i = 0; i < items.length; i++) if (!items[i].disabled) return i;\n return -1;\n}\n\nfunction lastEnabledIndex(items: readonly ToggleBarItem<string | number>[]): number {\n for (let i = items.length - 1; i >= 0; i--) if (!items[i].disabled) return i;\n return -1;\n}\n\nfunction nextEnabledIndex(items: readonly ToggleBarItem<string | number>[], from: number): number {\n const n = items.length;\n for (let k = 1; k <= n; k++) {\n const i = (from + k + n) % n;\n if (!items[i].disabled) return i;\n }\n return from;\n}\n\nfunction prevEnabledIndex(items: readonly ToggleBarItem<string | number>[], from: number): number {\n const n = items.length;\n for (let k = 1; k <= n; k++) {\n const i = (from - k + n) % n;\n if (!items[i].disabled) return i;\n }\n return from;\n}\n\nexport function ToggleBar<V extends string | number = string>(props: ToggleBarProps<V>): ReactElement {\n const { items, ariaLabel, className, height, size, variant } = props;\n const mode = props.mode ?? 'single';\n const rootRef = useRef<HTMLDivElement | null>(null);\n\n const isSelected = (value: V): boolean => {\n if (mode === 'multiple') return (props.value as readonly V[]).includes(value);\n return (props.value as V | null) === value;\n };\n\n /** Mixed only in multiple mode, and only where `value` doesn't already\n * claim the segment. Single mode has nothing to be mixed about — its\n * aggregate is one value or none. */\n const isMixed = (value: V): boolean => {\n if (mode !== 'multiple') return false;\n const mixed = (props as { mixedValues?: readonly V[] }).mixedValues;\n return mixed !== undefined && mixed.includes(value) && !isSelected(value);\n };\n\n let tabStopIndex = -1;\n if (mode === 'single') {\n const sel = items.findIndex(it => it.value === (props.value as V | null));\n tabStopIndex = sel >= 0 && !items[sel].disabled ? sel : firstEnabledIndex(items);\n } else {\n tabStopIndex = firstEnabledIndex(items);\n }\n\n const handleClick = (index: number) => () => {\n const item = items[index];\n if (item.disabled) return;\n if (mode === 'multiple') {\n const current = props.value as readonly V[];\n const next = current.includes(item.value)\n ? current.filter(v => v !== item.value)\n : [...current, item.value];\n (props.onChange as (n: V[]) => void)(next);\n } else {\n const current = props.value as V | null;\n if (current === item.value) {\n if ((props as { allowDeselect?: boolean }).allowDeselect) {\n (props.onChange as (n: V | null) => void)(null);\n }\n return;\n }\n (props.onChange as (n: V | null) => void)(item.value);\n }\n };\n\n const focusSegment = (index: number) => {\n const root = rootRef.current;\n if (!root) return;\n const buttons = root.querySelectorAll<HTMLButtonElement>(`.${s.segment}`);\n buttons[index]?.focus();\n };\n\n const handleKeyDown = (index: number) => (e: ReactKeyboardEvent<HTMLButtonElement>) => {\n let nextIndex = -1;\n switch (e.key) {\n case 'ArrowLeft':\n case 'ArrowUp':\n nextIndex = prevEnabledIndex(items, index);\n break;\n case 'ArrowRight':\n case 'ArrowDown':\n nextIndex = nextEnabledIndex(items, index);\n break;\n case 'Home':\n nextIndex = firstEnabledIndex(items);\n break;\n case 'End':\n nextIndex = lastEnabledIndex(items);\n break;\n case ' ':\n case 'Enter':\n if (mode === 'multiple') {\n e.preventDefault();\n handleClick(index)();\n }\n return;\n default:\n return;\n }\n if (nextIndex < 0 || nextIndex === index) return;\n e.preventDefault();\n if (mode === 'single') {\n const item = items[nextIndex];\n (props.onChange as (n: V | null) => void)(item.value);\n }\n focusSegment(nextIndex);\n };\n\n const style: CSSProperties | undefined = height !== undefined\n ? ({ ['--wzl-tb-height' as string]: `${height}px` } as CSSProperties)\n : undefined;\n\n const rootCls = [\n s.root,\n size && s[`size_${size}`],\n variant && s[`variant_${variant}`],\n className,\n ].filter(Boolean).join(' ');\n\n return (\n <div\n ref={rootRef}\n className={rootCls}\n role={mode === 'multiple' ? 'group' : 'radiogroup'}\n aria-label={ariaLabel}\n style={style}\n >\n {items.map((item, i) => {\n const selected = isSelected(item.value);\n const mixed = isMixed(item.value);\n const cls = [s.segment, selected && s.segmentSelected, mixed && s.segmentMixed]\n .filter(Boolean)\n .join(' ');\n return (\n <button\n key={item.value}\n type=\"button\"\n role={mode === 'multiple' ? undefined : 'radio'}\n aria-checked={mode === 'multiple' ? undefined : selected}\n aria-pressed={mode === 'multiple' ? (mixed ? 'mixed' : selected) : undefined}\n aria-label={item.ariaLabel}\n disabled={item.disabled}\n tabIndex={i === tabStopIndex ? 0 : -1}\n className={cls}\n onClick={handleClick(i)}\n onKeyDown={handleKeyDown(i)}\n >\n {item.label}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":"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"}