@weasel-js/ui 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/ActionBar-CiKvEvXi.js +63 -0
- package/dist/chunks/ActionBar-CiKvEvXi.js.map +1 -0
- package/dist/chunks/ActionsBar-CzU6Of3B.js +94 -0
- package/dist/chunks/ActionsBar-CzU6Of3B.js.map +1 -0
- package/dist/chunks/Badge-DU8ihE7Z.js +2942 -0
- package/dist/chunks/Badge-DU8ihE7Z.js.map +1 -0
- package/dist/chunks/Button-9QNIYugK.js +87 -0
- package/dist/chunks/Button-9QNIYugK.js.map +1 -0
- package/dist/chunks/Callout-CvTKW1sd.js +114 -0
- package/dist/chunks/Callout-CvTKW1sd.js.map +1 -0
- package/dist/chunks/Checkbox-BeWFZr1M.js +47 -0
- package/dist/chunks/Checkbox-BeWFZr1M.js.map +1 -0
- package/dist/chunks/ColorField-B7vHaU5G.js +60 -0
- package/dist/chunks/ColorField-B7vHaU5G.js.map +1 -0
- package/dist/chunks/ComboBox-yfrxG0_I.js +88 -0
- package/dist/chunks/ComboBox-yfrxG0_I.js.map +1 -0
- package/dist/chunks/CurveEditor-BEQtef4P.js +786 -0
- package/dist/chunks/CurveEditor-BEQtef4P.js.map +1 -0
- package/dist/chunks/DataGrid-mUq38k0Q.js +186 -0
- package/dist/chunks/DataGrid-mUq38k0Q.js.map +1 -0
- package/dist/chunks/Dialog-tAi14bY3.js +58 -0
- package/dist/chunks/Dialog-tAi14bY3.js.map +1 -0
- package/dist/chunks/Field-4cagmYlT.js +31 -0
- package/dist/chunks/Field-4cagmYlT.js.map +1 -0
- package/dist/chunks/Input-DRei6KJr.js +55 -0
- package/dist/chunks/Input-DRei6KJr.js.map +1 -0
- package/dist/chunks/Keycaps-B9dJMYx_.js +397 -0
- package/dist/chunks/Keycaps-B9dJMYx_.js.map +1 -0
- package/dist/chunks/NumberField-BAmJwxw0.js +59 -0
- package/dist/chunks/NumberField-BAmJwxw0.js.map +1 -0
- package/dist/chunks/OptionsBar-CHOP_CiW.js +98 -0
- package/dist/chunks/OptionsBar-CHOP_CiW.js.map +1 -0
- package/dist/chunks/Plot2D-CEnhzodm.js +168 -0
- package/dist/chunks/Plot2D-CEnhzodm.js.map +1 -0
- package/dist/chunks/PointPlotter-Dvh5cyOC.js +16 -0
- package/dist/chunks/PointPlotter-Dvh5cyOC.js.map +1 -0
- package/dist/chunks/Powerline-W_yqAVMc.js +36 -0
- package/dist/chunks/Powerline-W_yqAVMc.js.map +1 -0
- package/dist/chunks/Prefs-NOoGuUHy.js +238 -0
- package/dist/chunks/Prefs-NOoGuUHy.js.map +1 -0
- package/dist/chunks/RadioGroup-DUlTy95a.js +49 -0
- package/dist/chunks/RadioGroup-DUlTy95a.js.map +1 -0
- package/dist/chunks/RangeSlider-Bks9GQuO.js +52 -0
- package/dist/chunks/RangeSlider-Bks9GQuO.js.map +1 -0
- package/dist/chunks/Select-BV70VU5O.js +97 -0
- package/dist/chunks/Select-BV70VU5O.js.map +1 -0
- package/dist/chunks/SelectionPanel-D_U7GKup.js +283 -0
- package/dist/chunks/SelectionPanel-D_U7GKup.js.map +1 -0
- package/dist/chunks/Sidebar-Bk9_TPhX.js +26 -0
- package/dist/chunks/Sidebar-Bk9_TPhX.js.map +1 -0
- package/dist/chunks/SidebarPanel-Nd9Od5WD.js +59 -0
- package/dist/chunks/SidebarPanel-Nd9Od5WD.js.map +1 -0
- package/dist/chunks/Slider-sUJGgmKR.js +221 -0
- package/dist/chunks/Slider-sUJGgmKR.js.map +1 -0
- package/dist/chunks/Switch-iUmlnP_b.js +27 -0
- package/dist/chunks/Switch-iUmlnP_b.js.map +1 -0
- package/dist/chunks/Tabs-DCs-Ww2f.js +41 -0
- package/dist/chunks/Tabs-DCs-Ww2f.js.map +1 -0
- package/dist/chunks/Toast-NdSJo2vj.js +128 -0
- package/dist/chunks/Toast-NdSJo2vj.js.map +1 -0
- package/dist/chunks/ToggleBar-BfcvLaOr.js +120 -0
- package/dist/chunks/ToggleBar-BfcvLaOr.js.map +1 -0
- package/dist/chunks/ToolButton-GAzBOvcR.js +53 -0
- package/dist/chunks/ToolButton-GAzBOvcR.js.map +1 -0
- package/dist/chunks/ToolGroup-Btg47vJF.js +25 -0
- package/dist/chunks/ToolGroup-Btg47vJF.js.map +1 -0
- package/dist/chunks/ToolPalette-C8V-I-uX.js +117 -0
- package/dist/chunks/ToolPalette-C8V-I-uX.js.map +1 -0
- package/dist/chunks/Tooltip-Clgn4trm.js +39 -0
- package/dist/chunks/Tooltip-Clgn4trm.js.map +1 -0
- package/dist/chunks/keyGlyph-BDH5fqkO.js +22 -0
- package/dist/chunks/keyGlyph-BDH5fqkO.js.map +1 -0
- package/dist/components/ActionBar/index.js +2 -0
- package/dist/components/ActionsBar/index.js +2 -0
- package/dist/components/Badge/index.js +2 -0
- package/dist/components/Button/index.js +2 -0
- package/dist/components/Callout/index.js +2 -0
- package/dist/components/Checkbox/index.js +2 -0
- package/dist/components/ColorField/index.js +2 -0
- package/dist/components/ComboBox/index.js +2 -0
- package/dist/components/CurveEditor/index.js +2 -0
- package/dist/components/DataGrid/index.js +2 -0
- package/dist/components/Dialog/index.js +2 -0
- package/dist/components/Field/index.js +2 -0
- package/dist/components/Input/index.js +2 -0
- package/dist/components/Keycaps/index.js +3 -0
- package/dist/components/NumberField/index.js +2 -0
- package/dist/components/OptionsBar/index.js +2 -0
- package/dist/components/Plot2D/index.js +2 -0
- package/dist/components/PointPlotter/index.js +2 -0
- package/dist/components/Powerline/index.js +3 -0
- package/dist/components/Prefs/index.js +2 -0
- package/dist/components/RadioGroup/index.js +2 -0
- package/dist/components/RangeSlider/index.js +2 -0
- package/dist/components/Select/index.js +2 -0
- package/dist/components/SelectionPanel/index.js +2 -0
- package/dist/components/Sidebar/index.js +2 -0
- package/dist/components/SidebarPanel/index.js +2 -0
- package/dist/components/Slider/index.js +2 -0
- package/dist/components/Switch/index.js +2 -0
- package/dist/components/Tabs/index.js +2 -0
- package/dist/components/Toast/index.js +2 -0
- package/dist/components/ToggleBar/index.js +2 -0
- package/dist/components/ToolButton/index.js +2 -0
- package/dist/components/ToolGroup/index.js +2 -0
- package/dist/components/ToolPalette/index.js +2 -0
- package/dist/components/Tooltip/index.js +2 -0
- package/dist/index.js +49 -6749
- package/dist/index.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +8 -4
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { n as e, t } from "./Tooltip-Clgn4trm.js";
|
|
2
|
+
import { useSyncExternalStore as n } from "react";
|
|
3
|
+
import { Focusable as r } from "react-aria-components";
|
|
4
|
+
import { evaluateEnabled as i, useActionsRegistry as a, useOptionalDepRegistry as o } from "@weasel-js/core";
|
|
5
|
+
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
6
|
+
var l = {
|
|
7
|
+
bar: "_bar_11z5i_7",
|
|
8
|
+
vertical: "_vertical_11z5i_18",
|
|
9
|
+
button: "_button_11z5i_22"
|
|
10
|
+
}, u = Object.freeze([]), d = () => () => {};
|
|
11
|
+
function f(e, t) {
|
|
12
|
+
if (t !== void 0) return t;
|
|
13
|
+
let n = e.icon;
|
|
14
|
+
return typeof n == "function" ? n() : n;
|
|
15
|
+
}
|
|
16
|
+
function p(e, t) {
|
|
17
|
+
return t ? `${e} (${t})` : e;
|
|
18
|
+
}
|
|
19
|
+
function m(m) {
|
|
20
|
+
let { group: h, orientation: g = "horizontal", icons: _, labels: v, className: y } = m, b = a(), x = o(), S = n(b ? b.subscribe : d, b ? b.list : () => u, b ? b.list : () => u).filter((e) => e.group === h), C = x ? {
|
|
21
|
+
selection: x.get("selection"),
|
|
22
|
+
scene: x.get("scene"),
|
|
23
|
+
history: x.get("history"),
|
|
24
|
+
view: x.get("view"),
|
|
25
|
+
pointer: x.get("pointer"),
|
|
26
|
+
activeTool: x.get("activeTool"),
|
|
27
|
+
booleansAdapter: x.get("booleansAdapter")
|
|
28
|
+
} : void 0;
|
|
29
|
+
return /* @__PURE__ */ s("div", {
|
|
30
|
+
className: [
|
|
31
|
+
l.bar,
|
|
32
|
+
g === "vertical" && l.vertical,
|
|
33
|
+
y
|
|
34
|
+
].filter(Boolean).join(" "),
|
|
35
|
+
role: "toolbar",
|
|
36
|
+
"aria-label": `${h} actions`,
|
|
37
|
+
children: S.map((n) => {
|
|
38
|
+
let a = v?.[n.id] ?? n.label, o = f(n, _?.[n.id]), { enabled: u } = i(n, C), d = !u, m = p(a, n.shortcut);
|
|
39
|
+
return /* @__PURE__ */ c(e, {
|
|
40
|
+
isDisabled: d,
|
|
41
|
+
children: [/* @__PURE__ */ s(r, {
|
|
42
|
+
isDisabled: d,
|
|
43
|
+
children: /* @__PURE__ */ s("button", {
|
|
44
|
+
type: "button",
|
|
45
|
+
"data-testid": `action-bar-item-${n.id}`,
|
|
46
|
+
"aria-label": a,
|
|
47
|
+
"aria-disabled": d || void 0,
|
|
48
|
+
disabled: d,
|
|
49
|
+
className: l.button,
|
|
50
|
+
onClick: () => {
|
|
51
|
+
d || b?.trigger(n.id);
|
|
52
|
+
},
|
|
53
|
+
children: o
|
|
54
|
+
})
|
|
55
|
+
}), /* @__PURE__ */ s(t, { children: m })]
|
|
56
|
+
}, n.id);
|
|
57
|
+
})
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { m as t };
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=ActionBar-CiKvEvXi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ActionBar-CiKvEvXi.js","names":[],"sources":["../../src/components/ActionBar/ActionBar.module.css","../../src/components/ActionBar/ActionBar.tsx"],"sourcesContent":["/* `<ActionBar>` shares the segmented widget look of the WeaselDraw\n * pathfinder panel — small chrome on the panel surface so a bar of\n * Action buttons reads as a single control. Tokens are theme-driven\n * via `--wzl-*`. Visual parity with `PathfinderPanel.module.css` is\n * intentional; this is the generic version. */\n\n.bar {\n display: flex;\n flex-direction: row;\n gap: 1px;\n background: var(--wzl-panel-bg);\n border: 1px solid var(--wzl-panel-border);\n border-radius: 4px;\n padding: 2px;\n user-select: none;\n}\n\n.bar.vertical {\n flex-direction: column;\n}\n\n.button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n background: transparent;\n border: 0;\n border-radius: 2px;\n color: var(--wzl-text);\n cursor: default;\n}\n\n.button:hover:not([disabled]) {\n background: var(--wzl-panel-border);\n}\n\n.button:active:not([disabled]) {\n background: color-mix(in srgb, var(--wzl-panel-border) 70%, transparent);\n}\n\n.button[disabled] {\n opacity: 0.4;\n cursor: default;\n}\n\n.button > svg {\n display: block;\n}\n","import { useSyncExternalStore, type ReactNode } from 'react';\nimport { Focusable } from 'react-aria-components';\nimport {\n useActionsRegistry,\n useOptionalDepRegistry,\n evaluateEnabled,\n type Action,\n} from '@weasel-js/core';\nimport { Tooltip, TooltipTrigger } from '../Tooltip';\nimport s from './ActionBar.module.css';\n\nconst EMPTY_LIST: readonly Action[] = Object.freeze([]);\nconst noopSubscribe = (): (() => void) => () => {};\n\nexport interface ActionBarProps {\n /** Group key — only actions with `action.group === group` are rendered. */\n group: string;\n /** Layout direction. Defaults to `'horizontal'`. */\n orientation?: 'horizontal' | 'vertical';\n /**\n * Per-id icon overrides — keyed by `action.id`. When an entry is provided\n * it replaces the action's own `icon` for this bar only. Mirrors\n * `PathfinderPanelProps.icons` so call sites that ship custom glyph sets\n * can swap them in without re-registering actions.\n */\n icons?: Record<string, ReactNode>;\n /**\n * Per-id label overrides — keyed by `action.id`. Drives both `aria-label`\n * and `title`. When omitted, the action's own `label` is used.\n */\n labels?: Record<string, string>;\n /** Additional class for the toolbar root. */\n className?: string;\n}\n\nfunction resolveIcon(action: Action, override: ReactNode | undefined): ReactNode {\n if (override !== undefined) return override;\n const i = action.icon;\n if (typeof i === 'function') return i();\n return i;\n}\n\nfunction resolveTitle(label: string, shortcut: string | undefined): string {\n return shortcut ? `${label} (${shortcut})` : label;\n}\n\n/**\n * Generic group-keyed action toolbar. Reads the parent `ActionsRegistry`,\n * filters to actions whose `group` matches `props.group`, and renders one\n * icon button per match. Disabled state is derived from each action's\n * `enabled` predicate via `evaluateEnabled` (so the button greys out and\n * swallows clicks while the keybinding — if any — still fires through the\n * registry's keydown listener; that's the registry's contract, not ours).\n *\n * Visual parity with the WeaselDraw `<PathfinderPanel>` is intentional;\n * this is the generic, registry-driven version. No keyboard navigation\n * (roving tabindex) yet — bar consumers today are short flat strips. Add\n * if/when a long bar lands.\n */\nexport function ActionBar(props: ActionBarProps) {\n const { group, orientation = 'horizontal', icons, labels, className } = props;\n const registry = useActionsRegistry();\n const depReg = useOptionalDepRegistry();\n const all = useSyncExternalStore(\n registry ? registry.subscribe : noopSubscribe,\n registry ? registry.list : () => EMPTY_LIST,\n registry ? registry.list : () => EMPTY_LIST,\n );\n const actions = all.filter((a) => a.group === group);\n\n // Build the deps bag fresh each render — predicates read selection / etc.\n // from these. ActionBar relies on its parent re-rendering when the\n // underlying state changes (e.g. the consumer reads `selection.current`\n // somewhere above us) for `enabled` to reflect the latest values.\n const deps = depReg\n ? {\n selection: depReg.get('selection'),\n scene: depReg.get('scene'),\n history: depReg.get('history'),\n view: depReg.get('view'),\n pointer: depReg.get('pointer'),\n activeTool: depReg.get('activeTool'),\n booleansAdapter: depReg.get('booleansAdapter'),\n }\n : undefined;\n\n const cls = [s.bar, orientation === 'vertical' && s.vertical, className]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div className={cls} role=\"toolbar\" aria-label={`${group} actions`}>\n {actions.map((action) => {\n const label = labels?.[action.id] ?? action.label;\n const icon = resolveIcon(action, icons?.[action.id]);\n const { enabled } = evaluateEnabled(action, deps);\n const disabled = !enabled;\n const title = resolveTitle(label, action.shortcut);\n return (\n <TooltipTrigger key={action.id} isDisabled={disabled}>\n <Focusable isDisabled={disabled}>\n <button\n type=\"button\"\n data-testid={`action-bar-item-${action.id}`}\n aria-label={label}\n aria-disabled={disabled || undefined}\n disabled={disabled}\n className={s.button}\n onClick={() => {\n if (disabled) return;\n // Dispatch through the registry so the enabled() guard runs.\n // If no registry is in scope the click is a no-op — ActionBar\n // is expected to render under an `ActionsProvider`.\n registry?.trigger(action.id);\n }}\n >\n {icon}\n </button>\n </Focusable>\n <Tooltip>{title}</Tooltip>\n </TooltipTrigger>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;GCWM,IAAgC,OAAO,OAAO,EAAE,CAAC,EACjD,gBAA0C;AAuBhD,SAAS,EAAY,GAAgB,GAA4C;CAC/E,IAAI,MAAa,KAAA,GAAW,OAAO;CACnC,IAAM,IAAI,EAAO;CAEjB,OADI,OAAO,KAAM,aAAmB,GAAG,GAChC;;AAGT,SAAS,EAAa,GAAe,GAAsC;CACzE,OAAO,IAAW,GAAG,EAAM,IAAI,EAAS,KAAK;;AAgB/C,SAAgB,EAAU,GAAuB;CAC/C,IAAM,EAAE,UAAO,iBAAc,cAAc,UAAO,WAAQ,iBAAc,GAClE,IAAW,GAAoB,EAC/B,IAAS,GAAwB,EAMjC,IALM,EACV,IAAW,EAAS,YAAY,GAChC,IAAW,EAAS,aAAa,GACjC,IAAW,EAAS,aAAa,EAEnB,CAAI,QAAQ,MAAM,EAAE,UAAU,EAAM,EAM9C,IAAO,IACT;EACE,WAAW,EAAO,IAAI,YAAY;EAClC,OAAO,EAAO,IAAI,QAAQ;EAC1B,SAAS,EAAO,IAAI,UAAU;EAC9B,MAAM,EAAO,IAAI,OAAO;EACxB,SAAS,EAAO,IAAI,UAAU;EAC9B,YAAY,EAAO,IAAI,aAAa;EACpC,iBAAiB,EAAO,IAAI,kBAAkB;EAC/C,GACD,KAAA;CAMJ,OACE,kBAAC,OAAD;EAAK,WALK;GAAC,EAAE;GAAK,MAAgB,cAAc,EAAE;GAAU;GAAU,CACrE,OAAO,QAAQ,CACf,KAAK,IAGU;EAAK,MAAK;EAAU,cAAY,GAAG,EAAM;YACtD,EAAQ,KAAK,MAAW;GACvB,IAAM,IAAQ,IAAS,EAAO,OAAO,EAAO,OACtC,IAAO,EAAY,GAAQ,IAAQ,EAAO,IAAI,EAC9C,EAAE,eAAY,EAAgB,GAAQ,EAAK,EAC3C,IAAW,CAAC,GACZ,IAAQ,EAAa,GAAO,EAAO,SAAS;GAClD,OACE,kBAAC,GAAD;IAAgC,YAAY;cAA5C,CACE,kBAAC,GAAD;KAAW,YAAY;eACrB,kBAAC,UAAD;MACE,MAAK;MACL,eAAa,mBAAmB,EAAO;MACvC,cAAY;MACZ,iBAAe,KAAY,KAAA;MACjB;MACV,WAAW,EAAE;MACb,eAAe;OACT,KAIJ,GAAU,QAAQ,EAAO,GAAG;;gBAG7B;MACM,CAAA;KACC,CAAA,EACZ,kBAAC,GAAD,EAAA,UAAU,GAAgB,CAAA,CACX;MArBI,EAAO,GAqBX;IAEnB;EACE,CAAA"}
|
|
@@ -0,0 +1,94 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ActionsBar-CzU6Of3B.js","names":[],"sources":["../../src/components/ActionsBar/ActionsBar.module.css","../../src/components/ActionsBar/ActionsBar.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 './ActionsBar.module.css';\n\nexport type ActionsBarItem<V extends string | number = string> = {\n value: V;\n label?: ReactNode;\n ariaLabel?: string;\n disabled?: boolean;\n onAction: () => void;\n};\n\nexport type ActionsBarSize = 'sm' | 'md';\nexport type ActionsBarVariant = 'default' | 'minimal';\n\nexport type ActionsBarProps<V extends string | number = string> = {\n items: readonly ActionsBarItem<V>[];\n ariaLabel?: string;\n className?: string;\n height?: number;\n size?: ActionsBarSize;\n variant?: ActionsBarVariant;\n};\n\nfunction firstEnabledIndex(items: readonly ActionsBarItem<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 ActionsBarItem<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 ActionsBarItem<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 ActionsBarItem<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 ActionsBar<V extends string | number = string>(props: ActionsBarProps<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 fire = (index: number) => {\n const item = items[index];\n if (item.disabled) return;\n item.onAction();\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 fire(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=\"toolbar\"\n aria-label={ariaLabel}\n style={style}\n >\n {items.map((item, i) => (\n <button\n key={item.value}\n type=\"button\"\n aria-label={item.ariaLabel}\n disabled={item.disabled}\n tabIndex={i === tabStopIndex ? 0 : -1}\n className={s.segment}\n onClick={() => fire(i)}\n onKeyDown={handleKeyDown(i)}\n >\n {item.label}\n </button>\n ))}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;ACuBA,SAAS,EAAkB,GAA2D;CACpF,KAAK,IAAI,IAAI,GAAG,IAAI,EAAM,QAAQ,KAAK,IAAI,CAAC,EAAM,GAAG,UAAU,OAAO;CACtE,OAAO;;AAGT,SAAS,EAAiB,GAA2D;CACnF,KAAK,IAAI,IAAI,EAAM,SAAS,GAAG,KAAK,GAAG,KAAK,IAAI,CAAC,EAAM,GAAG,UAAU,OAAO;CAC3E,OAAO;;AAGT,SAAS,EAAiB,GAAmD,GAAsB;CACjG,IAAM,IAAI,EAAM;CAChB,KAAK,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;EAC3B,IAAM,KAAK,IAAO,IAAI,KAAK;EAC3B,IAAI,CAAC,EAAM,GAAG,UAAU,OAAO;;CAEjC,OAAO;;AAGT,SAAS,EAAiB,GAAmD,GAAsB;CACjG,IAAM,IAAI,EAAM;CAChB,KAAK,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;EAC3B,IAAM,KAAK,IAAO,IAAI,KAAK;EAC3B,IAAI,CAAC,EAAM,GAAG,UAAU,OAAO;;CAEjC,OAAO;;AAGT,SAAgB,EAA+C,GAAyC;CACtG,IAAM,EAAE,UAAO,cAAW,cAAW,WAAQ,SAAM,eAAY,GACzD,IAAU,EAA8B,KAAK,EAE7C,IAAe,EAAkB,EAAM,EAEvC,KAAQ,MAAkB;EAC9B,IAAM,IAAO,EAAM;EACf,EAAK,YACT,EAAK,UAAU;IAGX,KAAgB,MAAkB;EACtC,IAAM,IAAO,EAAQ;EAChB,KAEL,EADqB,iBAAoC,IAAI,EAAE,UAC/D,CAAQ,IAAQ,OAAO;IAGnB,KAAiB,OAAmB,MAA6C;EACrF,IAAI,IAAY;EAChB,QAAQ,EAAE,KAAV;GACE,KAAK;GACL,KAAK;IACH,IAAY,EAAiB,GAAO,EAAM;IAC1C;GACF,KAAK;GACL,KAAK;IACH,IAAY,EAAiB,GAAO,EAAM;IAC1C;GACF,KAAK;IACH,IAAY,EAAkB,EAAM;IACpC;GACF,KAAK;IACH,IAAY,EAAiB,EAAM;IACnC;GACF,KAAK;GACL,KAAK;IAEH,AADA,EAAE,gBAAgB,EAClB,EAAK,EAAM;IACX;GACF,SACE;;EAEA,IAAY,KAAK,MAAc,MACnC,EAAE,gBAAgB,EAClB,EAAa,EAAU;IAGnB,IAAmC,MAAW,KAAA,IAEhD,KAAA,IADC,EAAG,mBAA8B,GAAG,EAAO,KAAK;CAUrD,OACE,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,MAChB,kBAAC,UAAD;GAEE,MAAK;GACL,cAAY,EAAK;GACjB,UAAU,EAAK;GACf,UAAU,MAAM,IAAe,IAAI;GACnC,WAAW,EAAE;GACb,eAAe,EAAK,EAAE;GACtB,WAAW,EAAc,EAAE;aAE1B,EAAK;GACC,EAVF,EAAK,MAUH,CACT;EACE,CAAA"}
|