@weasel-js/labkit 1.7.1 → 1.7.2

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 (67) hide show
  1. package/dist/chrome/index.js +4 -4
  2. package/dist/{chunk-GAHELLJT.js → chunk-RODIY7HI.js} +7 -7
  3. package/dist/{chunk-GAHELLJT.js.map → chunk-RODIY7HI.js.map} +1 -1
  4. package/dist/{chunk-4KSC7NXL.js → chunk-U6UQVGFP.js} +1984 -1892
  5. package/dist/chunk-U6UQVGFP.js.map +1 -0
  6. package/dist/chunk-WFALF2X2.js +302 -0
  7. package/dist/chunk-WFALF2X2.js.map +1 -0
  8. package/dist/{chunk-JFOJESJF.js → chunk-WWJDPNZZ.js} +22 -22
  9. package/dist/chunk-WWJDPNZZ.js.map +1 -0
  10. package/dist/{chunk-CEGFXTBD.js → chunk-XRX5S5NT.js} +4 -4
  11. package/dist/{chunk-CEGFXTBD.js.map → chunk-XRX5S5NT.js.map} +1 -1
  12. package/dist/{chunk-FB4MIZOO.js → chunk-XZDCEMEL.js} +6 -6
  13. package/dist/chunk-XZDCEMEL.js.map +1 -0
  14. package/dist/controls/index.d.ts +55 -3
  15. package/dist/controls/index.js +3 -2
  16. package/dist/fonts/oswald-tabular-digits.woff2 +0 -0
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.js +135 -134
  19. package/dist/index.js.map +1 -1
  20. package/dist/layers/index.js +1 -1
  21. package/dist/passthrough/weasel-ui.js +1 -1
  22. package/dist/primitives/index.js +3 -3
  23. package/dist/styles.css +228 -11
  24. package/package.json +11 -11
  25. package/src/annotations/capture.browser.test.ts +9 -3
  26. package/src/canvas/Stage.test.tsx +34 -25
  27. package/src/chrome/labRegions.test.tsx +37 -26
  28. package/src/chrome/regions/PaletteRegion.test.tsx +2 -2
  29. package/src/controls/ControlMatrix.less +245 -0
  30. package/src/controls/ControlMatrix.stories.less +13 -0
  31. package/src/controls/ControlMatrix.stories.tsx +135 -0
  32. package/src/controls/ControlMatrix.test.tsx +206 -0
  33. package/src/controls/ControlMatrix.tsx +446 -0
  34. package/src/controls/ControlPanel.tsx +4 -2
  35. package/src/controls/index.ts +6 -0
  36. package/src/dragdrop/dragDrop.test.tsx +34 -33
  37. package/src/index.ts +6 -0
  38. package/src/lab/Lab.chrome.test.tsx +15 -10
  39. package/src/lab/Lab.nebula.test.tsx +5 -5
  40. package/src/lab/Lab.surface.test.tsx +30 -21
  41. package/src/lab/Lab.test.tsx +75 -74
  42. package/src/lab/Lab.undock.test.tsx +15 -10
  43. package/src/lab/LabHeader.test.tsx +15 -14
  44. package/src/lab/LabPalette.test.tsx +12 -7
  45. package/src/lab/LabShell.less +1 -2
  46. package/src/lab/LabZoom.test.tsx +55 -44
  47. package/src/lab/Workspace.surface.test.tsx +16 -13
  48. package/src/lab/Workspace.test.tsx +32 -27
  49. package/src/overview/OverviewMarks.test.tsx +9 -8
  50. package/src/overview/TrialOverview.test.tsx +18 -17
  51. package/src/primitives/FpsMeter.less +1 -2
  52. package/src/primitives/JobProgress.less +1 -2
  53. package/src/primitives/ScaleIndicator.less +1 -1
  54. package/src/primitives/StatusBar.less +1 -1
  55. package/src/specimen/Specimen.less +1 -0
  56. package/src/styles.less +3 -0
  57. package/src/trial/Trial.annotations.persist.test.tsx +20 -9
  58. package/src/trial/Trial.annotations.test.tsx +46 -41
  59. package/src/trial/Trial.canvas.test.tsx +21 -17
  60. package/src/trial/Trial.config.test.tsx +34 -27
  61. package/src/trial/Trial.loupe.test.tsx +27 -18
  62. package/src/trial/Trial.targets.test.tsx +9 -8
  63. package/src/trial/Trial.test.tsx +51 -46
  64. package/src/trial/Trial.trialId.test.tsx +7 -6
  65. package/dist/chunk-4KSC7NXL.js.map +0 -1
  66. package/dist/chunk-FB4MIZOO.js.map +0 -1
  67. package/dist/chunk-JFOJESJF.js.map +0 -1
@@ -0,0 +1,302 @@
1
+ import { ControlRow, summarizeValue } from './chunk-WWJDPNZZ.js';
2
+ import { valueAtPath, auto, schemaNodeAtPath } from './chunk-READTDQX.js';
3
+ import { l2, R, oe, c, ae2, l3, i2, u, h3, c4 } from './chunk-U6UQVGFP.js';
4
+ import { isBuiltinToolPref, toHex8, withAlpha01, getAlpha01 } from '@weasel-js/core';
5
+ import { useState, useRef } from 'react';
6
+ import { Popover, Dialog } from 'react-aria-components';
7
+ import { jsxs, jsx } from 'react/jsx-runtime';
8
+
9
+ var NO_AUTO = /* @__PURE__ */ new Set();
10
+ var noop = () => {
11
+ };
12
+ var nameOf = (column) => column.title ?? column.label;
13
+ function ControlMatrix({
14
+ title,
15
+ stance,
16
+ tone,
17
+ schema,
18
+ columns,
19
+ rows,
20
+ config,
21
+ auto: auto2,
22
+ setConfig,
23
+ onColumnClick,
24
+ inheritHint,
25
+ className
26
+ }) {
27
+ const fallback = columns[0];
28
+ const hintFor = inheritHint ?? ((_) => fallback ? `from ${nameOf(fallback)}` : "");
29
+ const [open, setOpen] = useState(null);
30
+ const triggerRef = useRef(null);
31
+ const { anchor, portalProps } = l2();
32
+ const leafAt = (path) => {
33
+ const node = schemaNodeAtPath(schema.group, path);
34
+ return node && c4(node) ? node : void 0;
35
+ };
36
+ const rowSpecs = rows.map((row) => {
37
+ const leaves = columns.map((column) => leafAt(`${column.key}.${row.key}`));
38
+ const named = leaves.find((leaf) => leaf !== void 0);
39
+ return { row, leaves, label: row.label ?? named?.name ?? row.key, about: named?.description };
40
+ });
41
+ const table = /* @__PURE__ */ jsxs("div", { className: className ? `lk-control-matrix ${className}` : "lk-control-matrix", children: [
42
+ anchor,
43
+ /* @__PURE__ */ jsxs("table", { className: "lk-control-matrix__table", children: [
44
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
45
+ /* @__PURE__ */ jsx("td", { className: "lk-control-matrix__corner" }),
46
+ columns.map((column, i2) => /* @__PURE__ */ jsx(
47
+ "th",
48
+ {
49
+ scope: "col",
50
+ className: i2 === 0 ? "lk-control-matrix__head is-first" : "lk-control-matrix__head",
51
+ children: /* @__PURE__ */ jsx(ColumnHeader, { column, onClick: onColumnClick })
52
+ },
53
+ column.key
54
+ ))
55
+ ] }) }),
56
+ /* @__PURE__ */ jsx("tbody", { children: rowSpecs.map(({ row, leaves, label, about }) => /* @__PURE__ */ jsxs("tr", { children: [
57
+ /* @__PURE__ */ jsxs("th", { scope: "row", className: "lk-control-matrix__label", children: [
58
+ /* @__PURE__ */ jsx("span", { className: "lk-control-matrix__label-text", children: label }),
59
+ about ? /* @__PURE__ */ jsx(R, { label, description: about }) : null
60
+ ] }),
61
+ columns.map((column, i2) => {
62
+ const path = `${column.key}.${row.key}`;
63
+ const leaf = leaves[i2];
64
+ if (!leaf) {
65
+ return /* @__PURE__ */ jsx("td", { className: "lk-control-matrix__cell is-missing", children: /* @__PURE__ */ jsx("span", { role: "img", "aria-label": `${nameOf(column)} has no ${label}`, children: "\u2014" }) }, column.key);
66
+ }
67
+ const first = i2 === 0;
68
+ const inherited = !first && auto2.has(path);
69
+ return /* @__PURE__ */ jsx(
70
+ "td",
71
+ {
72
+ className: inherited ? "lk-control-matrix__cell is-inherited" : "lk-control-matrix__cell",
73
+ children: /* @__PURE__ */ jsx(
74
+ Cell,
75
+ {
76
+ path,
77
+ leaf,
78
+ value: valueAtPath(config, path),
79
+ name: `${nameOf(column)} ${label}`,
80
+ hint: inherited ? hintFor(column) : void 0,
81
+ canUnpin: !first && !inherited,
82
+ setConfig,
83
+ onOpen: (el) => {
84
+ triggerRef.current = el;
85
+ setOpen({ path, leaf, column, first, label });
86
+ }
87
+ }
88
+ )
89
+ },
90
+ column.key
91
+ );
92
+ })
93
+ ] }, row.key)) })
94
+ ] }),
95
+ /* @__PURE__ */ jsx(
96
+ Popover,
97
+ {
98
+ triggerRef,
99
+ isOpen: open !== null,
100
+ onOpenChange: (next) => {
101
+ if (!next) setOpen(null);
102
+ },
103
+ placement: "bottom",
104
+ className: "lk-control-matrix__popover",
105
+ "data-weasel-overlay": "",
106
+ ...portalProps,
107
+ children: open ? /* @__PURE__ */ jsxs(
108
+ Dialog,
109
+ {
110
+ className: "lk-control-matrix__editor",
111
+ "aria-label": `${nameOf(open.column)} ${open.label}`,
112
+ children: [
113
+ /* @__PURE__ */ jsx(oe, { pack: "one-up", children: /* @__PURE__ */ jsx(
114
+ ControlRow,
115
+ {
116
+ path: open.path,
117
+ leaf: open.leaf,
118
+ resolved: schema,
119
+ config,
120
+ shown: config,
121
+ setConfig,
122
+ pack: "one-up",
123
+ auto: NO_AUTO,
124
+ setRowAuto: noop
125
+ }
126
+ ) }),
127
+ clearable(open.leaf) ? /* @__PURE__ */ jsx("div", { className: "lk-control-matrix__editor-actions", children: /* @__PURE__ */ jsx(
128
+ c,
129
+ {
130
+ size: "sm",
131
+ variant: "ghost",
132
+ disabled: !valueAtPath(config, open.path) || auto2.has(open.path),
133
+ onClick: () => setConfig(open.path, null),
134
+ children: "Clear"
135
+ }
136
+ ) }) : null,
137
+ open.first ? null : /* @__PURE__ */ jsx("div", { className: "lk-control-matrix__editor-actions", children: /* @__PURE__ */ jsx(
138
+ c,
139
+ {
140
+ size: "sm",
141
+ variant: "ghost",
142
+ disabled: auto2.has(open.path),
143
+ tooltip: `Inherit ${hintFor(open.column)}`,
144
+ onClick: () => setConfig(open.path, auto),
145
+ children: "Inherit"
146
+ }
147
+ ) })
148
+ ]
149
+ }
150
+ ) : null
151
+ }
152
+ )
153
+ ] });
154
+ if (title === void 0 && stance === void 0 && tone === void 0) return table;
155
+ return /* @__PURE__ */ jsx(ae2, { title, stance, tone, children: table });
156
+ }
157
+ function ColumnHeader({
158
+ column,
159
+ onClick
160
+ }) {
161
+ const name = nameOf(column);
162
+ if (!onClick) {
163
+ return column.title && column.title !== column.label ? /* @__PURE__ */ jsx("abbr", { title: column.title, className: "lk-control-matrix__head-text", children: column.label }) : /* @__PURE__ */ jsx("span", { className: "lk-control-matrix__head-text", children: column.label });
164
+ }
165
+ return /* @__PURE__ */ jsxs(l3, { children: [
166
+ /* @__PURE__ */ jsx(i2, { children: /* @__PURE__ */ jsx(
167
+ "button",
168
+ {
169
+ type: "button",
170
+ className: "lk-control-matrix__head-button",
171
+ "aria-label": name,
172
+ onClick: () => onClick(column),
173
+ children: column.label
174
+ }
175
+ ) }),
176
+ /* @__PURE__ */ jsx(u, { children: name })
177
+ ] });
178
+ }
179
+ var clearable = (leaf) => leaf.kind === "color" && leaf.default === "";
180
+ function decimalsOf(step) {
181
+ if (step === void 0 || !Number.isFinite(step) || step <= 0) return 0;
182
+ const text = String(step);
183
+ const exp = /e-(\d+)$/.exec(text);
184
+ if (exp) return Number(exp[1]);
185
+ const dot = text.indexOf(".");
186
+ return dot === -1 ? 0 : text.length - dot - 1;
187
+ }
188
+ function summaryOf(field, value) {
189
+ if (field?.kind === "number") {
190
+ return typeof field.value === "number" ? field.value.toFixed(decimalsOf(field.step)) : "\u2014";
191
+ }
192
+ if (field?.kind === "enum") {
193
+ const option = field.options.find((o) => o.value === field.value);
194
+ if (!option) return "\u2014";
195
+ return typeof option.glyph === "string" ? option.glyph : option.label;
196
+ }
197
+ if (field?.kind === "string") return field.value || "\u2014";
198
+ return summarizeValue(value);
199
+ }
200
+ function Cell({
201
+ path,
202
+ leaf,
203
+ value,
204
+ name,
205
+ hint,
206
+ canUnpin,
207
+ setConfig,
208
+ onOpen
209
+ }) {
210
+ const shown = value ?? leaf.default;
211
+ const write = (next) => setConfig(path, next);
212
+ const field = isBuiltinToolPref(leaf) ? h3(leaf, { value: shown, setValue: write }) : null;
213
+ const label = hint ? `${name}, ${hint}` : name;
214
+ const unpinned = (e) => {
215
+ if (!e.altKey) return false;
216
+ e.preventDefault();
217
+ if (canUnpin) setConfig(path, auto);
218
+ return true;
219
+ };
220
+ let control;
221
+ if (field?.kind === "boolean") {
222
+ const on = field.value === true;
223
+ control = /* @__PURE__ */ jsx(
224
+ "button",
225
+ {
226
+ type: "button",
227
+ role: "switch",
228
+ "aria-checked": on,
229
+ "aria-label": label,
230
+ className: "lk-control-matrix__switch",
231
+ onClick: (e) => {
232
+ if (!unpinned(e)) field.onChange(!on);
233
+ },
234
+ children: /* @__PURE__ */ jsx("span", { className: "lk-control-matrix__track", "aria-hidden": "true", children: /* @__PURE__ */ jsx("span", { className: "lk-control-matrix__thumb" }) })
235
+ }
236
+ );
237
+ } else if (field?.kind === "color" && !clearable(leaf)) {
238
+ const stored = typeof field.value === "string" && field.value !== "" ? toHex8(field.value) : "#000000ff";
239
+ control = /* @__PURE__ */ jsx(
240
+ "input",
241
+ {
242
+ type: "color",
243
+ "aria-label": label,
244
+ className: "lk-control-matrix__swatch",
245
+ value: stored.slice(0, 7),
246
+ onClick: (e) => {
247
+ unpinned(e);
248
+ },
249
+ onChange: (e) => {
250
+ const rgb = e.currentTarget.value;
251
+ field.onChange(field.alpha ? withAlpha01(rgb, getAlpha01(stored)) : rgb);
252
+ }
253
+ }
254
+ );
255
+ } else if (field?.kind === "color") {
256
+ const set = typeof field.value === "string" && field.value !== "";
257
+ control = /* @__PURE__ */ jsx(
258
+ "button",
259
+ {
260
+ type: "button",
261
+ "aria-label": set ? label : `${label}, unset`,
262
+ "aria-haspopup": "dialog",
263
+ className: "lk-control-matrix__value",
264
+ onClick: (e) => {
265
+ if (!unpinned(e)) onOpen(e.currentTarget);
266
+ },
267
+ children: /* @__PURE__ */ jsx(
268
+ "span",
269
+ {
270
+ className: set ? "lk-control-matrix__chip" : "lk-control-matrix__chip is-unset",
271
+ style: set ? { "--lk-chip": field.value } : void 0,
272
+ "aria-hidden": "true"
273
+ }
274
+ )
275
+ }
276
+ );
277
+ } else {
278
+ const valueClass = field?.kind === "number" ? "lk-control-matrix__value is-number" : "lk-control-matrix__value";
279
+ control = /* @__PURE__ */ jsx(
280
+ "button",
281
+ {
282
+ type: "button",
283
+ "aria-label": label,
284
+ "aria-haspopup": "dialog",
285
+ className: valueClass,
286
+ onClick: (e) => {
287
+ if (!unpinned(e)) onOpen(e.currentTarget);
288
+ },
289
+ children: summaryOf(field, shown)
290
+ }
291
+ );
292
+ }
293
+ if (!hint) return control;
294
+ return /* @__PURE__ */ jsxs(l3, { children: [
295
+ /* @__PURE__ */ jsx(i2, { children: control }),
296
+ /* @__PURE__ */ jsx(u, { children: hint })
297
+ ] });
298
+ }
299
+
300
+ export { ControlMatrix };
301
+ //# sourceMappingURL=chunk-WFALF2X2.js.map
302
+ //# sourceMappingURL=chunk-WFALF2X2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/controls/ControlMatrix.tsx"],"names":["auto","l","c","i","RACPopover","RACDialog","ae","h"],"mappings":"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","file":"chunk-WFALF2X2.js","sourcesContent":["import { getAlpha01, isBuiltinToolPref, toHex8, withAlpha01 } from '@weasel-js/core';\nimport {\n Button,\n Focusable,\n isPrefLeaf,\n type PrefLeaf,\n type PropertyControlProps,\n PropertyHelp,\n PropertyList,\n PropertyPanel,\n prefFieldProps,\n type StanceProps,\n Tooltip,\n TooltipTrigger,\n useOverlayPortal,\n} from '@weasel-js/ui';\nimport {\n type CSSProperties,\n type DOMAttributes,\n type MouseEvent,\n type ReactElement,\n type ReactNode,\n useRef,\n useState,\n} from 'react';\nimport { Dialog as RACDialog, Popover as RACPopover } from 'react-aria-components';\nimport { auto as autoValue } from '../config/auto';\nimport { schemaNodeAtPath, valueAtPath } from '../config/path';\nimport type { ResolvedConfig } from '../config/types';\nimport { ControlRow } from './ControlPanel';\nimport { summarizeValue } from './inDialog';\n\n/** One column of a {@link ControlMatrix}: a config group, every one the same shape. */\nexport interface ControlMatrixColumn {\n /** Config path prefix of this column's group, e.g. `'looks.window'`. */\n key: string;\n /** Short header shown at narrow width, e.g. `'Win'`. */\n label: string;\n /** Full name, for the header's tooltip and accessible name, e.g. `'Window'`. */\n title?: string;\n}\n\n/** One row of a {@link ControlMatrix}: a setting every column's group may hold. */\nexport interface ControlMatrixRow {\n /** Path of the setting inside each column's group, e.g. `'background'` or `'fill.colorBy'`. */\n key: string;\n /** Row label. Defaults to the leaf's own name from the schema. */\n label?: string;\n}\n\nexport interface ControlMatrixProps extends StanceProps {\n /** Heads the matrix. With `title`, `stance` or `tone` given it sits in a\n * `<PropertyPanel>`, as a `ControlPanel` does. */\n title?: ReactNode;\n /** The whole resolved schema. A cell's leaf is looked up at\n * `${column.key}.${row.key}`; a cell with none draws a dash. */\n schema: ResolvedConfig;\n /** The scopes. The first is the fallback the others inherit from: its cells\n * never inherit, and its header is emphasized. */\n columns: readonly ControlMatrixColumn[];\n rows: readonly ControlMatrixRow[];\n /** Values to show, already resolved: an inherited cell's value is the one it\n * inherits. */\n config: Record<string, unknown>;\n /** Full dotted paths whose cells inherit, drawn ghosted. */\n auto: ReadonlySet<string>;\n /** Writes a value, which pins the cell, or labkit's `auto` sentinel, which\n * unpins it. */\n setConfig: (path: string, value: unknown) => void;\n /** Clicking a column header. Without it the headers are plain text. */\n onColumnClick?: (column: ControlMatrixColumn) => void;\n /** What an inherited cell's tooltip says. Defaults to `from <first column>`. */\n inheritHint?: (column: ControlMatrixColumn) => string;\n className?: string;\n}\n\nconst NO_AUTO: ReadonlySet<string> = new Set();\nconst noop = (): void => {};\n\nconst nameOf = (column: ControlMatrixColumn): string => column.title ?? column.label;\n\n/** The open popover: which cell, and the element it hangs off. */\ninterface OpenCell {\n path: string;\n leaf: PrefLeaf;\n column: ControlMatrixColumn;\n first: boolean;\n label: string;\n}\n\n/**\n * One setting across several config groups of the same shape: settings down\n * the side, scopes across the top, a compact read-only cell at each crossing.\n * A cell inherits from the first column until it is pinned; inherited cells\n * draw ghosted. Click a cell to edit it with the control a `ControlPanel` would\n * draw (a boolean flips and a color opens its picker in place); editing pins,\n * and the popover's Inherit button — or Option/Alt-click on the cell — unpins.\n */\nexport function ControlMatrix({\n title,\n stance,\n tone,\n schema,\n columns,\n rows,\n config,\n auto,\n setConfig,\n onColumnClick,\n inheritHint,\n className,\n}: ControlMatrixProps): ReactElement {\n const fallback = columns[0];\n const hintFor =\n inheritHint ?? ((_: ControlMatrixColumn) => (fallback ? `from ${nameOf(fallback)}` : ''));\n const [open, setOpen] = useState<OpenCell | null>(null);\n const triggerRef = useRef<HTMLElement | null>(null);\n const { anchor, portalProps } = useOverlayPortal();\n\n const leafAt = (path: string): PrefLeaf | undefined => {\n const node = schemaNodeAtPath(schema.group, path);\n return node && isPrefLeaf(node) ? node : undefined;\n };\n\n const rowSpecs = rows.map((row) => {\n const leaves = columns.map((column) => leafAt(`${column.key}.${row.key}`));\n const named = leaves.find((leaf) => leaf !== undefined);\n return { row, leaves, label: row.label ?? named?.name ?? row.key, about: named?.description };\n });\n\n const table = (\n <div className={className ? `lk-control-matrix ${className}` : 'lk-control-matrix'}>\n {anchor}\n <table className=\"lk-control-matrix__table\">\n <thead>\n <tr>\n <td className=\"lk-control-matrix__corner\" />\n {columns.map((column, i) => (\n <th\n key={column.key}\n scope=\"col\"\n className={i === 0 ? 'lk-control-matrix__head is-first' : 'lk-control-matrix__head'}\n >\n <ColumnHeader column={column} onClick={onColumnClick} />\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {rowSpecs.map(({ row, leaves, label, about }) => (\n <tr key={row.key}>\n <th scope=\"row\" className=\"lk-control-matrix__label\">\n <span className=\"lk-control-matrix__label-text\">{label}</span>\n {about ? <PropertyHelp label={label} description={about} /> : null}\n </th>\n {columns.map((column, i) => {\n const path = `${column.key}.${row.key}`;\n const leaf = leaves[i];\n if (!leaf) {\n return (\n <td key={column.key} className=\"lk-control-matrix__cell is-missing\">\n <span role=\"img\" aria-label={`${nameOf(column)} has no ${label}`}>\n —\n </span>\n </td>\n );\n }\n const first = i === 0;\n const inherited = !first && auto.has(path);\n return (\n <td\n key={column.key}\n className={\n inherited ? 'lk-control-matrix__cell is-inherited' : 'lk-control-matrix__cell'\n }\n >\n <Cell\n path={path}\n leaf={leaf}\n value={valueAtPath(config, path)}\n name={`${nameOf(column)} ${label}`}\n hint={inherited ? hintFor(column) : undefined}\n canUnpin={!first && !inherited}\n setConfig={setConfig}\n onOpen={(el) => {\n triggerRef.current = el;\n setOpen({ path, leaf, column, first, label });\n }}\n />\n </td>\n );\n })}\n </tr>\n ))}\n </tbody>\n </table>\n <RACPopover\n triggerRef={triggerRef}\n isOpen={open !== null}\n onOpenChange={(next) => {\n if (!next) setOpen(null);\n }}\n placement=\"bottom\"\n className=\"lk-control-matrix__popover\"\n data-weasel-overlay=\"\"\n {...portalProps}\n >\n {open ? (\n <RACDialog\n className=\"lk-control-matrix__editor\"\n aria-label={`${nameOf(open.column)} ${open.label}`}\n >\n <PropertyList pack=\"one-up\">\n <ControlRow\n path={open.path}\n leaf={open.leaf}\n resolved={schema}\n config={config}\n shown={config}\n setConfig={setConfig}\n pack=\"one-up\"\n auto={NO_AUTO}\n setRowAuto={noop}\n />\n </PropertyList>\n {clearable(open.leaf) ? (\n <div className=\"lk-control-matrix__editor-actions\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n disabled={!valueAtPath(config, open.path) || auto.has(open.path)}\n onClick={() => setConfig(open.path, null)}\n >\n Clear\n </Button>\n </div>\n ) : null}\n {open.first ? null : (\n <div className=\"lk-control-matrix__editor-actions\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n disabled={auto.has(open.path)}\n tooltip={`Inherit ${hintFor(open.column)}`}\n onClick={() => setConfig(open.path, autoValue)}\n >\n Inherit\n </Button>\n </div>\n )}\n </RACDialog>\n ) : null}\n </RACPopover>\n </div>\n );\n\n if (title === undefined && stance === undefined && tone === undefined) return table;\n return (\n <PropertyPanel title={title} stance={stance} tone={tone}>\n {table}\n </PropertyPanel>\n );\n}\n\nfunction ColumnHeader({\n column,\n onClick,\n}: {\n column: ControlMatrixColumn;\n onClick?: (column: ControlMatrixColumn) => void;\n}) {\n const name = nameOf(column);\n if (!onClick) {\n return column.title && column.title !== column.label ? (\n <abbr title={column.title} className=\"lk-control-matrix__head-text\">\n {column.label}\n </abbr>\n ) : (\n <span className=\"lk-control-matrix__head-text\">{column.label}</span>\n );\n }\n return (\n <TooltipTrigger>\n <Focusable>\n <button\n type=\"button\"\n className=\"lk-control-matrix__head-button\"\n aria-label={name}\n onClick={() => onClick(column)}\n >\n {column.label}\n </button>\n </Focusable>\n <Tooltip>{name}</Tooltip>\n </TooltipTrigger>\n );\n}\n\n/** A color leaf whose default is empty: unset is a value of its own, not black. */\nconst clearable = (leaf: PrefLeaf): boolean => leaf.kind === 'color' && leaf.default === '';\n\n/** The number of decimals a step implies: `0.05` shows two, `1` none. */\nfunction decimalsOf(step: number | undefined): number {\n if (step === undefined || !Number.isFinite(step) || step <= 0) return 0;\n const text = String(step);\n const exp = /e-(\\d+)$/.exec(text);\n if (exp) return Number(exp[1]);\n const dot = text.indexOf('.');\n return dot === -1 ? 0 : text.length - dot - 1;\n}\n\n/** What a cell shows of a value it opens a popover to edit. */\nfunction summaryOf(field: PropertyControlProps | null, value: unknown): ReactNode {\n if (field?.kind === 'number') {\n return typeof field.value === 'number' ? field.value.toFixed(decimalsOf(field.step)) : '—';\n }\n if (field?.kind === 'enum') {\n const option = field.options.find((o) => o.value === field.value);\n if (!option) return '—';\n return typeof option.glyph === 'string' ? option.glyph : option.label;\n }\n if (field?.kind === 'string') return field.value || '—';\n return summarizeValue(value);\n}\n\nfunction Cell({\n path,\n leaf,\n value,\n name,\n hint,\n canUnpin,\n setConfig,\n onOpen,\n}: {\n path: string;\n leaf: PrefLeaf;\n value: unknown;\n /** The cell's accessible name: column and row. */\n name: string;\n /** Present while the cell inherits: where from. */\n hint?: string;\n canUnpin: boolean;\n setConfig: (path: string, value: unknown) => void;\n onOpen: (el: HTMLElement) => void;\n}) {\n const shown = value ?? leaf.default;\n const write = (next: unknown): void => setConfig(path, next);\n const field = isBuiltinToolPref(leaf)\n ? prefFieldProps(leaf, { value: shown, setValue: write })\n : null;\n const label = hint ? `${name}, ${hint}` : name;\n\n // Option/Alt-click hands a pinned cell back to the fallback, and does nothing\n // else on any cell — it must not also flip or open what it lands on.\n const unpinned = (e: MouseEvent): boolean => {\n if (!e.altKey) return false;\n e.preventDefault();\n if (canUnpin) setConfig(path, autoValue);\n return true;\n };\n\n // The shape `Focusable` asks of the element it makes a tooltip trigger.\n let control: ReactElement<DOMAttributes<HTMLElement>, string>;\n if (field?.kind === 'boolean') {\n const on = field.value === true;\n control = (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={on}\n aria-label={label}\n className=\"lk-control-matrix__switch\"\n onClick={(e) => {\n if (!unpinned(e)) field.onChange(!on);\n }}\n >\n <span className=\"lk-control-matrix__track\" aria-hidden=\"true\">\n <span className=\"lk-control-matrix__thumb\" />\n </span>\n </button>\n );\n } else if (field?.kind === 'color' && !clearable(leaf)) {\n const stored =\n typeof field.value === 'string' && field.value !== '' ? toHex8(field.value) : '#000000ff';\n control = (\n <input\n type=\"color\"\n aria-label={label}\n className=\"lk-control-matrix__swatch\"\n value={stored.slice(0, 7)}\n onClick={(e) => {\n unpinned(e);\n }}\n onChange={(e) => {\n const rgb = e.currentTarget.value;\n field.onChange(field.alpha ? withAlpha01(rgb, getAlpha01(stored)) : rgb);\n }}\n />\n );\n } else if (field?.kind === 'color') {\n // A color that may be unset opens the popover, which is the only place it can be cleared.\n const set = typeof field.value === 'string' && field.value !== '';\n control = (\n <button\n type=\"button\"\n aria-label={set ? label : `${label}, unset`}\n aria-haspopup=\"dialog\"\n className=\"lk-control-matrix__value\"\n onClick={(e) => {\n if (!unpinned(e)) onOpen(e.currentTarget);\n }}\n >\n <span\n className={set ? 'lk-control-matrix__chip' : 'lk-control-matrix__chip is-unset'}\n style={set ? ({ '--lk-chip': field.value } as CSSProperties) : undefined}\n aria-hidden=\"true\"\n />\n </button>\n );\n } else {\n const valueClass =\n field?.kind === 'number' ? 'lk-control-matrix__value is-number' : 'lk-control-matrix__value';\n control = (\n <button\n type=\"button\"\n aria-label={label}\n aria-haspopup=\"dialog\"\n className={valueClass}\n onClick={(e) => {\n if (!unpinned(e)) onOpen(e.currentTarget);\n }}\n >\n {summaryOf(field, shown)}\n </button>\n );\n }\n\n if (!hint) return control;\n return (\n <TooltipTrigger>\n <Focusable>{control}</Focusable>\n <Tooltip>{hint}</Tooltip>\n </TooltipTrigger>\n );\n}\n"]}
@@ -1,9 +1,9 @@
1
1
  import { fromConfigFields, isLeafVisible } from './chunk-WLMDTI2Q.js';
2
- import { resolveAutoConfig, schemaNodeAtPath, valueAtPath, auto } from './chunk-READTDQX.js';
3
- import { v, se, oe, b3, c3, F2, l5, R, c, B, z2, h3 } from './chunk-4KSC7NXL.js';
2
+ import { resolveAutoConfig, valueAtPath, schemaNodeAtPath, auto } from './chunk-READTDQX.js';
3
+ import { v, oe, ae2, l6, de, h3, L2, b3, c4, c, B, fe2 } from './chunk-U6UQVGFP.js';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
  import { isBuiltinToolPref, toHex8, withAlpha01, getAlpha01 } from '@weasel-js/core';
6
- import { useMemo, useState, Fragment as Fragment$1, useRef, useEffect } from 'react';
6
+ import { useMemo, useState, useRef, useEffect, Fragment as Fragment$1 } from 'react';
7
7
 
8
8
  function summarizeValue(value) {
9
9
  if (Array.isArray(value)) return value.length === 0 ? "None" : value.join(", ");
@@ -42,7 +42,7 @@ var NO_AUTO = /* @__PURE__ */ new Set();
42
42
  function leavesUnder(group, at) {
43
43
  return Object.entries(group.children).flatMap(([key, child]) => {
44
44
  const path = at === "" ? key : `${at}.${key}`;
45
- return c3(child) ? [[path, child.default]] : leavesUnder(child, path);
45
+ return c4(child) ? [[path, child.default]] : leavesUnder(child, path);
46
46
  });
47
47
  }
48
48
  function ResetGroup({
@@ -124,7 +124,7 @@ function ControlPanel({
124
124
  const found = schemaNodeAtPath(resolved.group, path);
125
125
  if (!found) return null;
126
126
  if (!isLeafVisible(resolved, path, config, showHidden)) return null;
127
- if (c3(found)) {
127
+ if (c4(found)) {
128
128
  return /* @__PURE__ */ jsx(
129
129
  ControlRow,
130
130
  {
@@ -167,7 +167,7 @@ function ControlPanel({
167
167
  };
168
168
  const pairable = (path) => {
169
169
  const found = schemaNodeAtPath(resolved.group, path);
170
- if (!found || !c3(found)) return void 0;
170
+ if (!found || !c4(found)) return void 0;
171
171
  const pair = extra(found, "pair");
172
172
  if (pair === void 0) return void 0;
173
173
  if (!isLeafVisible(resolved, path, config, showHidden))
@@ -237,7 +237,7 @@ function ControlPanel({
237
237
  ] });
238
238
  };
239
239
  const list = /* @__PURE__ */ jsx(
240
- se,
240
+ oe,
241
241
  {
242
242
  pack: gridPack,
243
243
  density,
@@ -247,7 +247,7 @@ function ControlPanel({
247
247
  }
248
248
  );
249
249
  if (title === void 0 && stance === void 0 && tone === void 0) return list;
250
- return /* @__PURE__ */ jsx(oe, { title, stance, tone, density, children: list });
250
+ return /* @__PURE__ */ jsx(ae2, { title, stance, tone, density, children: list });
251
251
  }
252
252
  function sectionKey(section) {
253
253
  return section.at === "" ? section.label : `${section.at}.${section.label}`;
@@ -301,7 +301,7 @@ function ControlRow({
301
301
  description,
302
302
  ...autoProps,
303
303
  children: () => /* @__PURE__ */ jsx(
304
- l5,
304
+ l6,
305
305
  {
306
306
  "aria-label": label,
307
307
  value: entries,
@@ -319,11 +319,11 @@ function ControlRow({
319
319
  case "string":
320
320
  return /* @__PURE__ */ jsx(DebouncedTextRow, { leaf, field, span: wide, ...row });
321
321
  case "number":
322
- return /* @__PURE__ */ jsx(R, { ...field, ...row, span: field.control === "slider" && wide });
322
+ return /* @__PURE__ */ jsx(de, { ...field, ...row, span: field.control === "slider" && wide });
323
323
  case "enum":
324
- return /* @__PURE__ */ jsx(R, { ...field, ...row, span: field.control === "toggle" && wide });
324
+ return /* @__PURE__ */ jsx(de, { ...field, ...row, span: field.control === "toggle" && wide });
325
325
  default:
326
- return /* @__PURE__ */ jsx(R, { ...field, ...row });
326
+ return /* @__PURE__ */ jsx(de, { ...field, ...row });
327
327
  }
328
328
  }
329
329
  function labField(leaf, value, write) {
@@ -362,7 +362,7 @@ function UnwiredRow({
362
362
  kind,
363
363
  description
364
364
  }) {
365
- return /* @__PURE__ */ jsx(F2, { label, description, children: /* @__PURE__ */ jsxs("span", { className: "lk-control-panel__unknown", children: [
365
+ return /* @__PURE__ */ jsx(L2, { label, description, children: /* @__PURE__ */ jsxs("span", { className: "lk-control-panel__unknown", children: [
366
366
  "no control for \u201C",
367
367
  kind,
368
368
  "\u201D"
@@ -378,7 +378,7 @@ function DebouncedTextRow({
378
378
  field.onChange,
379
379
  extra(leaf, "debounceMs") ?? 150
380
380
  );
381
- return /* @__PURE__ */ jsx(R, { ...field, ...row, value: text.local, onChange: text.type });
381
+ return /* @__PURE__ */ jsx(de, { ...field, ...row, value: text.local, onChange: text.type });
382
382
  }
383
383
  function PairedRow({
384
384
  label,
@@ -388,7 +388,7 @@ function PairedRow({
388
388
  layout,
389
389
  span
390
390
  }) {
391
- return /* @__PURE__ */ jsx(F2, { group: true, span, label, layout, children: cells.map(({ path, leaf }) => (
391
+ return /* @__PURE__ */ jsx(L2, { group: true, span, label, layout, children: cells.map(({ path, leaf }) => (
392
392
  // The row is named by the pair, so a cell that shares it says which
393
393
  // knob it is — without a caption a paired switch reads only to a
394
394
  // screen reader. A cell whose leaf is deliberately unnamed keeps none.
@@ -419,13 +419,13 @@ function PairCell({
419
419
  if (field === null) return null;
420
420
  switch (field.kind) {
421
421
  case "string":
422
- return /* @__PURE__ */ jsx(z2, { ...field, name: leaf.name, value: text.local, onChange: text.type });
422
+ return /* @__PURE__ */ jsx(fe2, { ...field, name: leaf.name, value: text.local, onChange: text.type });
423
423
  case "number":
424
- return /* @__PURE__ */ jsx(z2, { ...field, name: leaf.name, control: "input", unit: void 0 });
424
+ return /* @__PURE__ */ jsx(fe2, { ...field, name: leaf.name, control: "input", unit: void 0 });
425
425
  case "color": {
426
426
  const stored = typeof value === "string" ? toHex8(value) : "#000000";
427
427
  return /* @__PURE__ */ jsx(
428
- z2,
428
+ fe2,
429
429
  {
430
430
  ...field,
431
431
  name: leaf.name,
@@ -435,7 +435,7 @@ function PairCell({
435
435
  );
436
436
  }
437
437
  default:
438
- return /* @__PURE__ */ jsx(z2, { ...field, name: leaf.name });
438
+ return /* @__PURE__ */ jsx(fe2, { ...field, name: leaf.name });
439
439
  }
440
440
  }
441
441
  function useDebouncedText(value, write, debounceMs) {
@@ -469,6 +469,6 @@ function useDebouncedText(value, write, debounceMs) {
469
469
  };
470
470
  }
471
471
 
472
- export { ControlPanel, inDialog, summarizeValue };
473
- //# sourceMappingURL=chunk-JFOJESJF.js.map
474
- //# sourceMappingURL=chunk-JFOJESJF.js.map
472
+ export { ControlPanel, ControlRow, inDialog, summarizeValue };
473
+ //# sourceMappingURL=chunk-WWJDPNZZ.js.map
474
+ //# sourceMappingURL=chunk-WWJDPNZZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/controls/inDialog.tsx","../src/controls/ControlPanel.tsx"],"names":["auto","c","jsx","Fragment","b","ae","value","l","h","L","fe"],"mappings":"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","file":"chunk-WWJDPNZZ.js","sourcesContent":["import { DialogRow } from '@weasel-js/ui';\nimport type { ControlRenderer, InDialogOptions } from '../config/types';\n\nexport type { InDialogOptions };\n\n/** The one-line summary a dialog row shows when it is given none. */\nexport function summarizeValue(value: unknown): string {\n if (Array.isArray(value)) return value.length === 0 ? 'None' : value.join(', ');\n if (value === undefined || value === null || value === '') return 'None';\n return typeof value === 'object' ? JSON.stringify(value) : String(value);\n}\n\n/**\n * Moves a control into a modal: the row becomes a button showing a summary of\n * the value, and the button opens a dialog whose body is `body`, handed the\n * same context a row renderer gets. For a leaf whose editor will never fit a\n * sidebar row.\n */\nexport function inDialog(body: ControlRenderer, opts: InDialogOptions = {}): ControlRenderer {\n const summary = opts.summary ?? summarizeValue;\n return (ctx) => {\n const { pref, value, auto, setAuto } = ctx;\n const manual = (pref as { manual?: boolean }).manual === true;\n return (\n <DialogRow\n label={pref.name}\n description={pref.description}\n summary={summary(value)}\n title={opts.title}\n readout={auto ? 'auto' : undefined}\n auto={auto}\n onAutoChange={manual ? undefined : setAuto}\n >\n {() => body(ctx)}\n </DialogRow>\n );\n };\n}\n","import { getAlpha01, isBuiltinToolPref, toHex8, withAlpha01 } from '@weasel-js/core';\nimport {\n Button,\n DialogRow,\n isPrefLeaf,\n ListEditor,\n type PrefGroup,\n type PrefLeaf,\n type PropertyAlign,\n PropertyControl,\n type PropertyControlProps,\n type PropertyDensity,\n PropertyField,\n PropertyGroup,\n PropertyList,\n type PropertyListPack,\n PropertyPanel,\n PropertyRow,\n type PropertyRowLayout,\n prefFieldProps,\n ResetIcon,\n type StanceProps,\n} from '@weasel-js/ui';\nimport { Fragment, type ReactNode, useEffect, useMemo, useRef, useState } from 'react';\nimport { auto as autoValue } from '../config/auto';\nimport { resolveAutoConfig } from '../config/autoConfig';\nimport { fromConfigFields } from '../config/fromConfigField';\nimport { schemaNodeAtPath, valueAtPath } from '../config/path';\nimport type { ControlRenderer, ResolvedConfig, SectionSpec } from '../config/types';\nimport { isLeafVisible } from '../config/visible';\nimport { inDialog, summarizeValue } from './inDialog';\nimport type { ConfigField } from './types';\n\n/** How a panel packs its rows into the two-column property grid.\n * - `'auto'`: narrow controls (numbers, checkboxes, dropdowns, colors) sit\n * two per row; the ones that need the width — text, sliders, segmented\n * toggles — span it.\n * - `'pairs'`: every row pairs. A control that needs the full width says so\n * itself, with `<PropertyRow span>`.\n * - `'one-up'`: one control per row, colors excepted.\n */\nexport type ControlPack = 'auto' | 'pairs' | 'one-up';\n\n/** How the rows under one heading are laid out: the panel's, or a section's own. */\ninterface Rows {\n pack: ControlPack;\n layout: PropertyRowLayout | undefined;\n grid: PropertyListPack;\n}\n\nconst gridOf = (pack: ControlPack): PropertyListPack =>\n pack === 'one-up' ? 'auto-color' : 'pairs';\n\nfunction sectionRows(section: SectionSpec, rows: Rows): Rows {\n return {\n pack: section.pack ?? rows.pack,\n layout: section.layout ?? rows.layout,\n grid: section.pack ? gridOf(section.pack) : rows.grid,\n };\n}\n\nexport interface ControlPanelProps<TC extends Record<string, unknown>> extends StanceProps {\n /** The instrument's resolved config schema. */\n schema?: ResolvedConfig;\n /** @deprecated Pass `schema`. A field list is adapted into one internally. */\n fields?: ConfigField[];\n config: TC;\n /** Writes one value. The path is dotted for a leaf inside an `f.group`, and\n * the bare key for one at the root. */\n setConfig: (path: string, value: unknown) => void;\n /**\n * Control overrides and app-defined kinds, PrefsForm-style. Keys are config\n * paths (checked first) or leaf kinds. A renderer returning `null` collapses\n * the row; entries override the built-in rows on collision.\n */\n renderers?: Record<string, ControlRenderer>;\n /** How rows pack into the two-column grid. Defaults to `'pairs'`. */\n pack?: ControlPack;\n /**\n * Where a row's label sits relative to its control. Unset takes each row's\n * own orientation — `block` (label above, which is what leaves a paired row\n * room for its value) for most, `inline` for colors and checkboxes.\n */\n layout?: PropertyRowLayout;\n /** Room the rows get. Passed straight to the property list. */\n density?: PropertyDensity;\n /** Cross-axis alignment of an inline row's label and control. */\n align?: PropertyAlign;\n /**\n * Fold each section away behind a twisty, starting `'open'` or `'closed'`.\n * Unset draws the heading alone, as the panel always has — unless a section\n * in the schema declares how it opens, which makes that section foldable on\n * its own and outranks this for that one section.\n */\n collapse?: 'open' | 'closed';\n /**\n * Which sections are folded, keyed as `onCollapse` reports them. Given, the\n * panel keeps no state of its own: every toggle arrives at `onCollapse`\n * instead, which is where a lab that remembers a trial's sections writes\n * them.\n */\n collapsed?: Readonly<Record<string, boolean>>;\n /** A fold moved. The key is a section's label — prefixed by its group's\n * dotted path when the section sits inside one — or a group's own path. */\n onCollapse?: (key: string, collapsed: boolean) => void;\n /** Dotted paths currently unpinned. A row in this set hides its control and\n * reads out `auto`, and clicking its label writes the sentinel back through\n * `setConfig`. Omitted, the panel keeps the set itself: the labels still\n * toggle and the sentinel never reaches `setConfig`, which would otherwise\n * store it as the row's value. */\n auto?: ReadonlySet<string>;\n /** Draw leaves marked `hidden`. */\n showHidden?: boolean;\n /** Heads the panel. With `title`, `stance` or `tone` given, the rows sit in a\n * `<PropertyPanel>` carrying them; with none, they are the bare list. */\n title?: ReactNode;\n className?: string;\n}\n\nconst NO_AUTO: ReadonlySet<string> = new Set();\n\n/** Every leaf beneath a group, as its dotted path and its default. */\nfunction leavesUnder(group: PrefGroup, at: string): [string, unknown][] {\n return Object.entries(group.children).flatMap(([key, child]) => {\n const path = at === '' ? key : `${at}.${key}`;\n return isPrefLeaf(child)\n ? [[path, child.default] as [string, unknown]]\n : leavesUnder(child, path);\n });\n}\n\n/** The heading button of a `.resettable()` group: writes each changed leaf's\n * default, and is disabled while nothing has changed. */\nfunction ResetGroup({\n group,\n path,\n config,\n setConfig,\n}: {\n group: PrefGroup;\n path: string;\n config: Record<string, unknown>;\n setConfig: (path: string, value: unknown) => void;\n}) {\n const changed = leavesUnder(group, path).filter(\n ([p, d]) => !Object.is(valueAtPath(config, p), d),\n );\n return (\n <Button\n iconOnly\n variant=\"ghost\"\n size=\"sm\"\n ariaLabel={`Reset ${group.name}`}\n tooltip={`Reset ${group.name} to defaults`}\n disabled={changed.length === 0}\n onClick={() => {\n for (const [p, d] of changed) setConfig(p, d);\n }}\n >\n <ResetIcon />\n </Button>\n );\n}\n\n/** Render an instrument's config schema as a stack of controls, each writing\n * back through `setConfig`. Built on the property rows, so a lab's controls\n * are the same aligned, themed rows the rest of the kit uses. */\nexport function ControlPanel<TC extends Record<string, unknown>>({\n schema,\n fields,\n config,\n setConfig,\n renderers,\n pack = 'pairs',\n layout,\n density,\n align,\n collapse,\n collapsed,\n onCollapse,\n auto: given,\n showHidden = false,\n title,\n stance,\n tone,\n className,\n}: ControlPanelProps<TC>) {\n const resolved = useMemo(() => schema ?? fromConfigFields(fields ?? []), [schema, fields]);\n\n // An owner that tracks the set decides what a dot means; one that does not\n // gets a panel that decides for itself, because the alternative is handing it\n // a sentinel it would write into the config as though it were a value.\n const [ownAuto, setOwnAuto] = useState<ReadonlySet<string>>(NO_AUTO);\n const auto = given ?? ownAuto;\n const setRowAuto = (path: string, next: boolean, value: unknown): void => {\n if (given) {\n setConfig(path, next ? autoValue : value);\n return;\n }\n setOwnAuto((prev) => {\n const now = new Set(prev);\n if (next) now.add(path);\n else now.delete(path);\n return now;\n });\n // Pinning keeps whatever the row was showing, the same value the controlled\n // path writes back.\n if (!next) setConfig(path, value);\n };\n\n // What the instrument is reading. A row draws and reports from this rather\n // than calling its own resolver against the raw config, which would disagree\n // with the instrument whenever a resolver depends on another auto path.\n const shown = useMemo(\n () => (auto && auto.size > 0 ? resolveAutoConfig(resolved, config, auto) : config),\n [resolved, config, auto],\n );\n\n const gridPack = gridOf(pack);\n // A section that declares how it opens is foldable whether or not the lab\n // asked for folds — there is nothing else for the declaration to mean.\n const folds =\n collapse !== undefined ||\n collapsed !== undefined ||\n onCollapse !== undefined ||\n resolved.sections.some((s) => s.collapsed !== undefined);\n const startsFolded = collapse === 'closed';\n\n const fold = (key: string, declared?: boolean, grid: PropertyListPack = gridPack) => ({\n pack: grid,\n collapsible: folds,\n defaultCollapsed: declared ?? startsFolded,\n collapsed: collapsed ? (collapsed[key] ?? declared ?? startsFolded) : undefined,\n onCollapsedChange: onCollapse ? (next: boolean) => onCollapse(key, next) : undefined,\n });\n\n /** One node, which is either a group to recurse into or a row to draw. */\n const node = (path: string, rows: Rows): ReactNode => {\n const found = schemaNodeAtPath(resolved.group, path);\n if (!found) return null;\n if (!isLeafVisible(resolved, path, config as Record<string, unknown>, showHidden)) return null;\n if (isPrefLeaf(found)) {\n return (\n <ControlRow\n key={path}\n path={path}\n leaf={found}\n resolved={resolved}\n config={config}\n shown={shown}\n setConfig={setConfig}\n renderers={renderers}\n pack={rows.pack}\n layout={rows.layout}\n auto={auto}\n setRowAuto={setRowAuto}\n />\n );\n }\n // A group with no name organizes without heading it — core's rule for an\n // empty `PrefGroup.name` — so it contributes its rows and no chrome.\n if (found.name === '') return <Fragment key={path}>{body(found, path, rows)}</Fragment>;\n return (\n <PropertyGroup\n key={path}\n title={found.name}\n description={found.description}\n // A nested group is a block of rows, not a control: half of a\n // two-column grid leaves it laying its own rows out inside a cell,\n // which overlaps them.\n span\n actions={\n resolved.resettable?.has(path) ? (\n <ResetGroup\n group={found}\n path={path}\n config={config as Record<string, unknown>}\n setConfig={setConfig}\n />\n ) : undefined\n }\n {...fold(path, undefined, rows.grid)}\n >\n {body(found, path, rows)}\n </PropertyGroup>\n );\n };\n\n /**\n * The leaf at `path` if it may share a row with its neighbours: `pair` is\n * presentational, so a leaf whose control the lab draws itself, or one whose\n * control needs the whole row, keeps its own row instead.\n */\n const pairable = (path: string): { leaf: PrefLeaf; pair: string } | undefined => {\n const found = schemaNodeAtPath(resolved.group, path);\n if (!found || !isPrefLeaf(found)) return undefined;\n const pair = extra<string>(found, 'pair');\n if (pair === undefined) return undefined;\n if (!isLeafVisible(resolved, path, config as Record<string, unknown>, showHidden))\n return undefined;\n if (\n renderers?.[path] ??\n resolved.renderers[path] ??\n resolved.dialogs[path] ??\n renderers?.[found.kind]\n )\n return undefined;\n if (!isBuiltinToolPref(found)) return undefined;\n if (found.kind === 'paint' || found.kind === 'object' || isSliderLeaf(found)) return undefined;\n return { leaf: found, pair };\n };\n\n /** A run of sibling paths as rows, merging each run of adjacent leaves\n * sharing a `pair` id into one row named by the pair. */\n const rowsFor = (paths: readonly string[], rows: Rows): ReactNode[] => {\n const out: ReactNode[] = [];\n for (let i = 0; i < paths.length; ) {\n const head = pairable(paths[i]);\n if (!head) {\n out.push(node(paths[i], rows));\n i += 1;\n continue;\n }\n const { pair } = head;\n const cells = [{ path: paths[i], leaf: head.leaf }];\n let j = i + 1;\n for (; j < paths.length; j += 1) {\n const next = pairable(paths[j]);\n if (!next || next.pair !== pair) break;\n cells.push({ path: paths[j], leaf: next.leaf });\n }\n out.push(\n <PairedRow\n key={paths[i]}\n label={pair}\n cells={cells}\n shown={shown}\n setConfig={setConfig}\n layout={rows.layout}\n // A segmented cell carries every choice at once, so a pair holding\n // one needs the whole row the way a segmented row of its own does.\n span={cells.some(({ leaf }) => extra<string>(leaf, 'control') === 'radio')}\n />,\n );\n i = j;\n }\n return out;\n };\n\n /** One group's children: its loose nodes, then its sections. */\n const body = (group: PrefGroup, at: string, rows: Rows): ReactNode => {\n const sections = resolved.sections.filter((s) => s.at === at);\n const sectioned = new Set(sections.flatMap((s) => s.paths));\n const paths = Object.keys(group.children).map((key) => (at === '' ? key : `${at}.${key}`));\n return (\n <>\n {rowsFor(\n paths.filter((p) => !sectioned.has(p)),\n rows,\n )}\n {sections.map((section) => {\n const inner = sectionRows(section, rows);\n return (\n <PropertyGroup\n key={sectionKey(section)}\n title={section.label}\n {...fold(sectionKey(section), section.collapsed, inner.grid)}\n >\n {rowsFor(section.paths, inner)}\n </PropertyGroup>\n );\n })}\n </>\n );\n };\n\n const list = (\n <PropertyList\n pack={gridPack}\n density={density}\n align={align}\n className={className ? `lk-control-panel ${className}` : 'lk-control-panel'}\n >\n {body(resolved.group, '', { pack, layout, grid: gridPack })}\n </PropertyList>\n );\n if (title === undefined && stance === undefined && tone === undefined) return list;\n return (\n <PropertyPanel title={title} stance={stance} tone={tone} density={density}>\n {list}\n </PropertyPanel>\n );\n}\n\n/** How a section is keyed for folding: its label at the root, and its group's\n * path in front of it anywhere else, so two groups may both have an\n * `Advanced`. */\nfunction sectionKey(section: SectionSpec): string {\n return section.at === '' ? section.label : `${section.at}.${section.label}`;\n}\n\nexport interface ControlRowProps<TC extends Record<string, unknown>> {\n path: string;\n leaf: PrefLeaf;\n resolved: ResolvedConfig;\n config: TC;\n /** `config` with every auto path resolved -- what the instrument reads. */\n shown: TC;\n setConfig: (path: string, value: unknown) => void;\n renderers?: Record<string, ControlRenderer>;\n pack: ControlPack;\n layout?: PropertyRowLayout;\n auto?: ReadonlySet<string>;\n setRowAuto: (path: string, next: boolean, value: unknown) => void;\n}\n\n/** Whether this leaf draws as a slider, mirroring the condition the `number`\n * arm below branches on. A slider is the one control whose value cannot be\n * read off the control itself. */\nfunction isSliderLeaf(leaf: PrefLeaf): boolean {\n return (\n leaf.kind === 'number' &&\n extra<string>(leaf, 'control') === 'slider' &&\n extra<number>(leaf, 'min') !== undefined &&\n extra<number>(leaf, 'max') !== undefined\n );\n}\n\n/** Reads a labkit-only extra off a leaf. `PrefLeaf` has no field for these,\n * and extra keys survive the resolve pass at runtime. */\nfunction extra<T>(leaf: PrefLeaf, key: string): T | undefined {\n return (leaf as unknown as Record<string, T | undefined>)[key];\n}\n\n/** One leaf's row, as the panel draws it. Shared with `ControlMatrix`, whose\n * popover edits one cell with exactly this row. */\nexport function ControlRow<TC extends Record<string, unknown>>({\n path,\n leaf,\n resolved,\n config,\n shown,\n setConfig,\n renderers,\n pack,\n layout,\n auto,\n setRowAuto,\n}: ControlRowProps<TC>) {\n const write = (value: unknown): void => setConfig(path, value);\n const fallback = extra<unknown>(leaf, 'default');\n const pinned = valueAtPath(config, path) ?? fallback;\n\n const isAutoRow = auto?.has(path) ?? false;\n const canAuto = !extra<boolean>(leaf, 'manual');\n // Read out of the resolved config rather than re-running this leaf's own\n // resolver, so the row reports the value the instrument actually got — the\n // two diverge as soon as a resolver reads another auto path.\n const resolvedValue = isAutoRow ? valueAtPath(shown, path) : undefined;\n // An auto row draws what the resolver decided, not the value underneath it —\n // a handle sitting at the pinned number while the readout says something else\n // reads as a rendering bug. Pinning then keeps what you were looking at.\n const value = resolvedValue ?? pinned;\n const setAuto = (next: boolean): void => setRowAuto(path, next, value);\n const onAutoChange = canAuto ? setAuto : undefined;\n // An auto row hides its control, so the word is all the row has to say.\n const autoReadout = isAutoRow ? 'auto' : undefined;\n const autoProps = { auto: isAutoRow, onAutoChange };\n\n // Most specific wins, and within a tier the lab's entry beats the\n // instrument's: controls[path] -> node .render/.dialog -> controls[kind] -> built-in.\n const dialog = resolved.dialogs[path];\n const custom =\n renderers?.[path] ??\n resolved.renderers[path] ??\n (dialog ? inDialog(dialog.body, dialog) : undefined) ??\n renderers?.[leaf.kind];\n // A custom row places itself like any other; one that needs the full width\n // says so with `<PropertyRow span>`, which is the same opt-out a built-in has.\n if (custom) return custom({ path, pref: leaf, value, setValue: write, auto: isAutoRow, setAuto });\n\n const label = leaf.name;\n const description = leaf.description;\n // `auto` gives the whole width to the controls that read badly at half of a\n // sidebar's: free text, a slider track, a segmented toggle. `pairs` doesn't.\n const wide = pack === 'auto';\n const row = { label, description, layout, readout: autoReadout, ...autoProps };\n\n if (leaf.kind === 'list') {\n const entries = Array.isArray(value) ? (value as string[]) : [];\n return (\n <DialogRow\n label={label}\n summary={summarizeValue(entries)}\n readout={autoReadout}\n layout={layout}\n description={description}\n {...autoProps}\n >\n {() => (\n <ListEditor\n aria-label={label}\n value={entries}\n onChange={write}\n placeholder={extra<string>(leaf, 'placeholder')}\n />\n )}\n </DialogRow>\n );\n }\n\n const field = labField(leaf, value, write);\n if (field === null)\n return <UnwiredRow label={label} kind={leaf.kind} description={description} />;\n switch (field.kind) {\n case 'string':\n return <DebouncedTextRow leaf={leaf} field={field} span={wide} {...row} />;\n case 'number':\n return <PropertyField {...field} {...row} span={field.control === 'slider' && wide} />;\n case 'enum':\n return <PropertyField {...field} {...row} span={field.control === 'toggle' && wide} />;\n default:\n return <PropertyField {...field} {...row} />;\n }\n}\n\n/**\n * A leaf as the field it draws, with the labkit-only extras `prefFieldProps`\n * knows nothing of. `null` for a kind the panel declines: a paint, which a\n * hex swatch would flatten to a solid, and an object, which a flat row would\n * write one field of. Override with `render` to edit either.\n */\nfunction labField(\n leaf: PrefLeaf,\n value: unknown,\n write: (value: unknown) => void,\n): PropertyControlProps | null {\n if (!isBuiltinToolPref(leaf) || leaf.kind === 'paint' || leaf.kind === 'object') return null;\n const field = prefFieldProps(leaf, { value, setValue: write });\n if (field === null) return null;\n switch (field.kind) {\n case 'number':\n // `prefFieldProps` clamps what it stores, so an instrument is never\n // handed a value outside the range it asked for.\n return {\n ...field,\n control: isSliderLeaf(leaf) ? 'slider' : 'input',\n unit: extra<string>(leaf, 'suffix') ?? field.unit,\n };\n case 'boolean':\n return {\n ...field,\n control: extra<string>(leaf, 'control') === 'switch' ? 'switch' : 'checkbox',\n };\n case 'enum':\n // `.radio()` asks for every option at once, as segments.\n return {\n ...field,\n control: extra<string>(leaf, 'control') === 'radio' ? 'toggle' : 'select',\n };\n case 'string':\n return {\n ...field,\n placeholder: extra<string>(leaf, 'placeholder'),\n maxLength: extra<number>(leaf, 'maxLength'),\n };\n default:\n return field;\n }\n}\n\n/** A leaf this panel has no control for is named rather than dropped: a silent\n * gap reads as \"this control does not exist\". */\nfunction UnwiredRow({\n label,\n kind,\n description,\n}: {\n label: string;\n kind: string;\n description?: string;\n}) {\n return (\n <PropertyRow label={label} description={description}>\n <span className=\"lk-control-panel__unknown\">no control for “{kind}”</span>\n </PropertyRow>\n );\n}\n\n/** A text row whose writes are debounced — see {@link useDebouncedText}. */\nfunction DebouncedTextRow({\n leaf,\n field,\n ...row\n}: {\n leaf: PrefLeaf;\n field: PropertyControlProps & { kind: 'string' };\n label: string;\n layout?: PropertyRowLayout;\n span?: boolean;\n description?: string;\n readout?: ReactNode;\n auto?: boolean;\n onAutoChange?: (next: boolean) => void;\n}) {\n const text = useDebouncedText(\n field.value ?? '',\n field.onChange,\n extra<number>(leaf, 'debounceMs') ?? 150,\n );\n return <PropertyField {...field} {...row} value={text.local} onChange={text.type} />;\n}\n\n/** One cell of a paired row, with its path and the leaf it draws. */\ninterface PairCellSpec {\n path: string;\n leaf: PrefLeaf;\n}\n\n/**\n * Leaves sharing a `pair` id, side by side on one row the pair names — the\n * compact `X` / `Y` idiom `SelectionPanel` draws for the same annotation.\n *\n * The cells are bare controls: a row holds one label column, so each leaf's\n * own name stays with its control as the accessible name and its description\n * as a title. For the same reason the row's label does not toggle auto — it\n * names one path, and this row has several.\n */\nfunction PairedRow<TC extends Record<string, unknown>>({\n label,\n cells,\n shown,\n setConfig,\n layout,\n span,\n}: {\n label: string;\n cells: readonly PairCellSpec[];\n shown: TC;\n setConfig: (path: string, value: unknown) => void;\n layout?: PropertyRowLayout;\n span?: boolean;\n}) {\n return (\n <PropertyRow group span={span} label={label} layout={layout}>\n {cells.map(({ path, leaf }) => (\n // The row is named by the pair, so a cell that shares it says which\n // knob it is — without a caption a paired switch reads only to a\n // screen reader. A cell whose leaf is deliberately unnamed keeps none.\n <span key={path} className=\"lk-pair-cell\" title={leaf.description || undefined}>\n {leaf.name ? <span className=\"lk-pair-label\">{leaf.name}</span> : null}\n <PairCell\n leaf={leaf}\n value={valueAtPath(shown, path) ?? extra<unknown>(leaf, 'default')}\n write={(value) => setConfig(path, value)}\n />\n </span>\n ))}\n </PropertyRow>\n );\n}\n\n/** The control a paired cell holds, without the row chrome a whole row of its\n * own would bring. */\nfunction PairCell({\n leaf,\n value,\n write,\n}: {\n leaf: PrefLeaf;\n value: unknown;\n write: (value: unknown) => void;\n}) {\n const text = useDebouncedText(\n typeof value === 'string' ? value : '',\n write,\n extra<number>(leaf, 'debounceMs') ?? 150,\n );\n const field = labField(leaf, value, write);\n // Unreachable for null: `pairable` admits only kinds with a field.\n if (field === null) return null;\n switch (field.kind) {\n case 'string':\n return (\n <PropertyControl {...field} name={leaf.name} value={text.local} onChange={text.type} />\n );\n case 'number':\n // The pair names the row, so a cell has no room for a unit.\n return <PropertyControl {...field} name={leaf.name} control=\"input\" unit={undefined} />;\n case 'color': {\n // The alpha track needs a row of its own to sit under, so a paired\n // swatch edits the color and carries the stored alpha through untouched.\n const stored = typeof value === 'string' ? toHex8(value) : '#000000';\n return (\n <PropertyControl\n {...field}\n name={leaf.name}\n alpha={undefined}\n onChange={(rgb: string) =>\n write(field.alpha ? withAlpha01(rgb, getAlpha01(stored)) : rgb)\n }\n />\n );\n }\n default:\n return <PropertyControl {...field} name={leaf.name} />;\n }\n}\n\n/**\n * Live text held locally between debounced commits, so typing does not re-run\n * the instrument on every keystroke. Locally controlled between commits, which\n * means it has to notice the value changing underneath it.\n */\nfunction useDebouncedText(\n value: string,\n write: (value: string) => void,\n debounceMs: number,\n): { local: string; type: (next: string) => void } {\n const [local, setLocal] = useState(value);\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const lastExternal = useRef(value);\n\n useEffect(() => {\n if (value !== lastExternal.current) {\n lastExternal.current = value;\n setLocal(value);\n }\n }, [value]);\n\n useEffect(\n () => () => {\n if (timer.current) clearTimeout(timer.current);\n },\n [],\n );\n\n return {\n local,\n type: (next) => {\n setLocal(next);\n if (timer.current) clearTimeout(timer.current);\n const commit = () => {\n lastExternal.current = next;\n write(next);\n };\n if (debounceMs === 0) commit();\n else timer.current = setTimeout(commit, debounceMs);\n },\n };\n}\n"]}
@@ -1,11 +1,11 @@
1
1
  import { CanvasStackContext } from './chunk-ZQIHJXP4.js';
2
- import { c2, S, y } from './chunk-4KSC7NXL.js';
2
+ import { c3, S, y } from './chunk-U6UQVGFP.js';
3
3
  import { jsx, jsxs } from 'react/jsx-runtime';
4
4
  import { useVisibleRaf, normalizeZoom } from '@weasel-js/core';
5
5
  import { useState, useRef, useEffect, useContext } from 'react';
6
6
 
7
7
  function Toolbar({ children, "aria-label": ariaLabel }) {
8
- const { rootRef, onKeyDown } = c2({ orientation: "horizontal" });
8
+ const { rootRef, onKeyDown } = c3({ orientation: "horizontal" });
9
9
  return /* @__PURE__ */ jsx(
10
10
  "div",
11
11
  {
@@ -213,5 +213,5 @@ function Section({ children, end }) {
213
213
  StatusBar.Section = Section;
214
214
 
215
215
  export { FpsMeter, ScaleIndicator, StatusBar, Toolbar, ZoomControl };
216
- //# sourceMappingURL=chunk-CEGFXTBD.js.map
217
- //# sourceMappingURL=chunk-CEGFXTBD.js.map
216
+ //# sourceMappingURL=chunk-XRX5S5NT.js.map
217
+ //# sourceMappingURL=chunk-XRX5S5NT.js.map