@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.
- package/dist/chrome/index.js +4 -4
- package/dist/{chunk-GAHELLJT.js → chunk-RODIY7HI.js} +7 -7
- package/dist/{chunk-GAHELLJT.js.map → chunk-RODIY7HI.js.map} +1 -1
- package/dist/{chunk-4KSC7NXL.js → chunk-U6UQVGFP.js} +1984 -1892
- package/dist/chunk-U6UQVGFP.js.map +1 -0
- package/dist/chunk-WFALF2X2.js +302 -0
- package/dist/chunk-WFALF2X2.js.map +1 -0
- package/dist/{chunk-JFOJESJF.js → chunk-WWJDPNZZ.js} +22 -22
- package/dist/chunk-WWJDPNZZ.js.map +1 -0
- package/dist/{chunk-CEGFXTBD.js → chunk-XRX5S5NT.js} +4 -4
- package/dist/{chunk-CEGFXTBD.js.map → chunk-XRX5S5NT.js.map} +1 -1
- package/dist/{chunk-FB4MIZOO.js → chunk-XZDCEMEL.js} +6 -6
- package/dist/chunk-XZDCEMEL.js.map +1 -0
- package/dist/controls/index.d.ts +55 -3
- package/dist/controls/index.js +3 -2
- package/dist/fonts/oswald-tabular-digits.woff2 +0 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +135 -134
- package/dist/index.js.map +1 -1
- package/dist/layers/index.js +1 -1
- package/dist/passthrough/weasel-ui.js +1 -1
- package/dist/primitives/index.js +3 -3
- package/dist/styles.css +228 -11
- package/package.json +11 -11
- package/src/annotations/capture.browser.test.ts +9 -3
- package/src/canvas/Stage.test.tsx +34 -25
- package/src/chrome/labRegions.test.tsx +37 -26
- package/src/chrome/regions/PaletteRegion.test.tsx +2 -2
- package/src/controls/ControlMatrix.less +245 -0
- package/src/controls/ControlMatrix.stories.less +13 -0
- package/src/controls/ControlMatrix.stories.tsx +135 -0
- package/src/controls/ControlMatrix.test.tsx +206 -0
- package/src/controls/ControlMatrix.tsx +446 -0
- package/src/controls/ControlPanel.tsx +4 -2
- package/src/controls/index.ts +6 -0
- package/src/dragdrop/dragDrop.test.tsx +34 -33
- package/src/index.ts +6 -0
- package/src/lab/Lab.chrome.test.tsx +15 -10
- package/src/lab/Lab.nebula.test.tsx +5 -5
- package/src/lab/Lab.surface.test.tsx +30 -21
- package/src/lab/Lab.test.tsx +75 -74
- package/src/lab/Lab.undock.test.tsx +15 -10
- package/src/lab/LabHeader.test.tsx +15 -14
- package/src/lab/LabPalette.test.tsx +12 -7
- package/src/lab/LabShell.less +1 -2
- package/src/lab/LabZoom.test.tsx +55 -44
- package/src/lab/Workspace.surface.test.tsx +16 -13
- package/src/lab/Workspace.test.tsx +32 -27
- package/src/overview/OverviewMarks.test.tsx +9 -8
- package/src/overview/TrialOverview.test.tsx +18 -17
- package/src/primitives/FpsMeter.less +1 -2
- package/src/primitives/JobProgress.less +1 -2
- package/src/primitives/ScaleIndicator.less +1 -1
- package/src/primitives/StatusBar.less +1 -1
- package/src/specimen/Specimen.less +1 -0
- package/src/styles.less +3 -0
- package/src/trial/Trial.annotations.persist.test.tsx +20 -9
- package/src/trial/Trial.annotations.test.tsx +46 -41
- package/src/trial/Trial.canvas.test.tsx +21 -17
- package/src/trial/Trial.config.test.tsx +34 -27
- package/src/trial/Trial.loupe.test.tsx +27 -18
- package/src/trial/Trial.targets.test.tsx +9 -8
- package/src/trial/Trial.test.tsx +51 -46
- package/src/trial/Trial.trialId.test.tsx +7 -6
- package/dist/chunk-4KSC7NXL.js.map +0 -1
- package/dist/chunk-FB4MIZOO.js.map +0 -1
- 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,
|
|
3
|
-
import { v,
|
|
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
|
|
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
|
|
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 (
|
|
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 || !
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
322
|
+
return /* @__PURE__ */ jsx(de, { ...field, ...row, span: field.control === "slider" && wide });
|
|
323
323
|
case "enum":
|
|
324
|
-
return /* @__PURE__ */ jsx(
|
|
324
|
+
return /* @__PURE__ */ jsx(de, { ...field, ...row, span: field.control === "toggle" && wide });
|
|
325
325
|
default:
|
|
326
|
-
return /* @__PURE__ */ jsx(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
422
|
+
return /* @__PURE__ */ jsx(fe2, { ...field, name: leaf.name, value: text.local, onChange: text.type });
|
|
423
423
|
case "number":
|
|
424
|
-
return /* @__PURE__ */ jsx(
|
|
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
|
-
|
|
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(
|
|
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-
|
|
474
|
-
//# sourceMappingURL=chunk-
|
|
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":";;;;;;;AAMO,SAAS,eAAe,KAAA,EAAwB;AACrD,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG,OAAO,KAAA,CAAM,MAAA,KAAW,CAAA,GAAI,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAC9E,EAAA,IAAI,UAAU,MAAA,IAAa,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,IAAI,OAAO,MAAA;AAClE,EAAA,OAAO,OAAO,UAAU,QAAA,GAAW,IAAA,CAAK,UAAU,KAAK,CAAA,GAAI,OAAO,KAAK,CAAA;AACzE;AAQO,SAAS,QAAA,CAAS,IAAA,EAAuB,IAAA,GAAwB,EAAC,EAAoB;AAC3F,EAAA,MAAM,OAAA,GAAU,KAAK,OAAA,IAAW,cAAA;AAChC,EAAA,OAAO,CAAC,GAAA,KAAQ;AACd,IAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAO,IAAA,EAAAA,KAAAA,EAAM,SAAQ,GAAI,GAAA;AACvC,IAAA,MAAM,MAAA,GAAU,KAA8B,MAAA,KAAW,IAAA;AACzD,IAAA,uBACE,GAAA;AAAA,MAAC,CAAA;AAAA,MAAA;AAAA,QACC,OAAO,IAAA,CAAK,IAAA;AAAA,QACZ,aAAa,IAAA,CAAK,WAAA;AAAA,QAClB,OAAA,EAAS,QAAQ,KAAK,CAAA;AAAA,QACtB,OAAO,IAAA,CAAK,KAAA;AAAA,QACZ,OAAA,EAASA,QAAO,MAAA,GAAS,MAAA;AAAA,QACzB,IAAA,EAAMA,KAAAA;AAAA,QACN,YAAA,EAAc,SAAS,MAAA,GAAY,OAAA;AAAA,QAElC,QAAA,EAAA,MAAM,KAAK,GAAG;AAAA;AAAA,KACjB;AAAA,EAEJ,CAAA;AACF;ACaA,IAAM,MAAA,GAAS,CAAC,IAAA,KACd,IAAA,KAAS,WAAW,YAAA,GAAe,OAAA;AAErC,SAAS,WAAA,CAAY,SAAsB,IAAA,EAAkB;AAC3D,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,OAAA,CAAQ,IAAA,IAAQ,IAAA,CAAK,IAAA;AAAA,IAC3B,MAAA,EAAQ,OAAA,CAAQ,MAAA,IAAU,IAAA,CAAK,MAAA;AAAA,IAC/B,MAAM,OAAA,CAAQ,IAAA,GAAO,OAAO,OAAA,CAAQ,IAAI,IAAI,IAAA,CAAK;AAAA,GACnD;AACF;AA4DA,IAAM,OAAA,uBAAmC,GAAA,EAAI;AAG7C,SAAS,WAAA,CAAY,OAAkB,EAAA,EAAiC;AACtE,EAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,KAAA,CAAM,QAAQ,CAAA,CAAE,QAAQ,CAAC,CAAC,GAAA,EAAK,KAAK,CAAA,KAAM;AAC9D,IAAA,MAAM,OAAO,EAAA,KAAO,EAAA,GAAK,MAAM,CAAA,EAAG,EAAE,IAAI,GAAG,CAAA,CAAA;AAC3C,IAAA,OAAOC,EAAAA,CAAW,KAAK,CAAA,GACnB,CAAC,CAAC,IAAA,EAAM,KAAA,CAAM,OAAO,CAAsB,CAAA,GAC3C,WAAA,CAAY,KAAA,EAAO,IAAI,CAAA;AAAA,EAC7B,CAAC,CAAA;AACH;AAIA,SAAS,UAAA,CAAW;AAAA,EAClB,KAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAKG;AACD,EAAA,MAAM,OAAA,GAAU,WAAA,CAAY,KAAA,EAAO,IAAI,CAAA,CAAE,MAAA;AAAA,IACvC,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM,CAAC,MAAA,CAAO,EAAA,CAAG,WAAA,CAAY,MAAA,EAAQ,CAAC,CAAA,EAAG,CAAC;AAAA,GAClD;AACA,EAAA,uBACEC,GAAAA;AAAA,IAAC,CAAA;AAAA,IAAA;AAAA,MACC,QAAA,EAAQ,IAAA;AAAA,MACR,OAAA,EAAQ,OAAA;AAAA,MACR,IAAA,EAAK,IAAA;AAAA,MACL,SAAA,EAAW,CAAA,MAAA,EAAS,KAAA,CAAM,IAAI,CAAA,CAAA;AAAA,MAC9B,OAAA,EAAS,CAAA,MAAA,EAAS,KAAA,CAAM,IAAI,CAAA,YAAA,CAAA;AAAA,MAC5B,QAAA,EAAU,QAAQ,MAAA,KAAW,CAAA;AAAA,MAC7B,SAAS,MAAM;AACb,QAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,OAAA,EAAS,SAAA,CAAU,GAAG,CAAC,CAAA;AAAA,MAC9C,CAAA;AAAA,MAEA,QAAA,kBAAAA,IAAC,CAAA,EAAA,EAAU;AAAA;AAAA,GACb;AAEJ;AAKO,SAAS,YAAA,CAAiD;AAAA,EAC/D,MAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,IAAA,GAAO,OAAA;AAAA,EACP,MAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA;AAAA,EACA,IAAA,EAAM,KAAA;AAAA,EACN,UAAA,GAAa,KAAA;AAAA,EACb,KAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA,EAA0B;AACxB,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,MAAM,MAAA,IAAU,gBAAA,CAAiB,MAAA,IAAU,EAAE,CAAA,EAAG,CAAC,MAAA,EAAQ,MAAM,CAAC,CAAA;AAKzF,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAA8B,OAAO,CAAA;AACnE,EAAA,MAAMF,QAAO,KAAA,IAAS,OAAA;AACtB,EAAA,MAAM,UAAA,GAAa,CAAC,IAAA,EAAc,IAAA,EAAe,KAAA,KAAyB;AACxE,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,SAAA,CAAU,IAAA,EAAM,IAAA,GAAO,IAAA,GAAY,KAAK,CAAA;AACxC,MAAA;AAAA,IACF;AACA,IAAA,UAAA,CAAW,CAAC,IAAA,KAAS;AACnB,MAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,IAAI,CAAA;AACxB,MAAA,IAAI,IAAA,EAAM,GAAA,CAAI,GAAA,CAAI,IAAI,CAAA;AAAA,WACjB,GAAA,CAAI,OAAO,IAAI,CAAA;AACpB,MAAA,OAAO,GAAA;AAAA,IACT,CAAC,CAAA;AAGD,IAAA,IAAI,CAAC,IAAA,EAAM,SAAA,CAAU,IAAA,EAAM,KAAK,CAAA;AAAA,EAClC,CAAA;AAKA,EAAA,MAAM,KAAA,GAAQ,OAAA;AAAA,IACZ,MAAOA,SAAQA,KAAAA,CAAK,IAAA,GAAO,IAAI,iBAAA,CAAkB,QAAA,EAAU,MAAA,EAAQA,KAAI,CAAA,GAAI,MAAA;AAAA,IAC3E,CAAC,QAAA,EAAU,MAAA,EAAQA,KAAI;AAAA,GACzB;AAEA,EAAA,MAAM,QAAA,GAAW,OAAO,IAAI,CAAA;AAG5B,EAAA,MAAM,KAAA,GACJ,QAAA,KAAa,MAAA,IACb,SAAA,KAAc,UACd,UAAA,KAAe,MAAA,IACf,QAAA,CAAS,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,cAAc,MAAS,CAAA;AACzD,EAAA,MAAM,eAAe,QAAA,KAAa,QAAA;AAElC,EAAA,MAAM,IAAA,GAAO,CAAC,GAAA,EAAa,QAAA,EAAoB,OAAyB,QAAA,MAAc;AAAA,IACpF,IAAA,EAAM,IAAA;AAAA,IACN,WAAA,EAAa,KAAA;AAAA,IACb,kBAAkB,QAAA,IAAY,YAAA;AAAA,IAC9B,WAAW,SAAA,GAAa,SAAA,CAAU,GAAG,CAAA,IAAK,YAAY,YAAA,GAAgB,MAAA;AAAA,IACtE,mBAAmB,UAAA,GAAa,CAAC,SAAkB,UAAA,CAAW,GAAA,EAAK,IAAI,CAAA,GAAI;AAAA,GAC7E,CAAA;AAGA,EAAA,MAAM,IAAA,GAAO,CAAC,IAAA,EAAc,IAAA,KAA0B;AACpD,IAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,QAAA,CAAS,KAAA,EAAO,IAAI,CAAA;AACnD,IAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AACnB,IAAA,IAAI,CAAC,aAAA,CAAc,QAAA,EAAU,MAAM,MAAA,EAAmC,UAAU,GAAG,OAAO,IAAA;AAC1F,IAAA,IAAIC,EAAAA,CAAW,KAAK,CAAA,EAAG;AACrB,MAAA,uBACEC,GAAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UAEC,IAAA;AAAA,UACA,IAAA,EAAM,KAAA;AAAA,UACN,QAAA;AAAA,UACA,MAAA;AAAA,UACA,KAAA;AAAA,UACA,SAAA;AAAA,UACA,SAAA;AAAA,UACA,MAAM,IAAA,CAAK,IAAA;AAAA,UACX,QAAQ,IAAA,CAAK,MAAA;AAAA,UACb,IAAA,EAAMF,KAAAA;AAAA,UACN;AAAA,SAAA;AAAA,QAXK;AAAA,OAYP;AAAA,IAEJ;AAGA,IAAA,IAAI,KAAA,CAAM,IAAA,KAAS,EAAA,EAAI,uBAAOE,GAAAA,CAACC,UAAA,EAAA,EAAqB,QAAA,EAAA,IAAA,CAAK,KAAA,EAAO,IAAA,EAAM,IAAI,CAAA,EAAA,EAA7B,IAA+B,CAAA;AAC5E,IAAA,uBACED,GAAAA;AAAA,MAACE,EAAA;AAAA,MAAA;AAAA,QAEC,OAAO,KAAA,CAAM,IAAA;AAAA,QACb,aAAa,KAAA,CAAM,WAAA;AAAA,QAInB,IAAA,EAAI,IAAA;AAAA,QACJ,SACE,QAAA,CAAS,UAAA,EAAY,GAAA,CAAI,IAAI,oBAC3BF,GAAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAO,KAAA;AAAA,YACP,IAAA;AAAA,YACA,MAAA;AAAA,YACA;AAAA;AAAA,SACF,GACE,MAAA;AAAA,QAEL,GAAG,IAAA,CAAK,IAAA,EAAM,MAAA,EAAW,KAAK,IAAI,CAAA;AAAA,QAElC,QAAA,EAAA,IAAA,CAAK,KAAA,EAAO,IAAA,EAAM,IAAI;AAAA,OAAA;AAAA,MAnBlB;AAAA,KAoBP;AAAA,EAEJ,CAAA;AAOA,EAAA,MAAM,QAAA,GAAW,CAAC,IAAA,KAA+D;AAC/E,IAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,QAAA,CAAS,KAAA,EAAO,IAAI,CAAA;AACnD,IAAA,IAAI,CAAC,KAAA,IAAS,CAACD,EAAAA,CAAW,KAAK,GAAG,OAAO,MAAA;AACzC,IAAA,MAAM,IAAA,GAAO,KAAA,CAAc,KAAA,EAAO,MAAM,CAAA;AACxC,IAAA,IAAI,IAAA,KAAS,QAAW,OAAO,MAAA;AAC/B,IAAA,IAAI,CAAC,aAAA,CAAc,QAAA,EAAU,IAAA,EAAM,QAAmC,UAAU,CAAA;AAC9E,MAAA,OAAO,MAAA;AACT,IAAA,IACE,SAAA,GAAY,IAAI,CAAA,IAChB,QAAA,CAAS,SAAA,CAAU,IAAI,CAAA,IACvB,QAAA,CAAS,OAAA,CAAQ,IAAI,CAAA,IACrB,SAAA,GAAY,MAAM,IAAI,CAAA;AAEtB,MAAA,OAAO,MAAA;AACT,IAAA,IAAI,CAAC,iBAAA,CAAkB,KAAK,CAAA,EAAG,OAAO,MAAA;AACtC,IAAA,IAAI,KAAA,CAAM,SAAS,OAAA,IAAW,KAAA,CAAM,SAAS,QAAA,IAAY,YAAA,CAAa,KAAK,CAAA,EAAG,OAAO,MAAA;AACrF,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,IAAA,EAAK;AAAA,EAC7B,CAAA;AAIA,EAAA,MAAM,OAAA,GAAU,CAAC,KAAA,EAA0B,IAAA,KAA4B;AACrE,IAAA,MAAM,MAAmB,EAAC;AAC1B,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,MAAA,IAAU;AAClC,MAAA,MAAM,IAAA,GAAO,QAAA,CAAS,KAAA,CAAM,CAAC,CAAC,CAAA;AAC9B,MAAA,IAAI,CAAC,IAAA,EAAM;AACT,QAAA,GAAA,CAAI,KAAK,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,EAAG,IAAI,CAAC,CAAA;AAC7B,QAAA,CAAA,IAAK,CAAA;AACL,QAAA;AAAA,MACF;AACA,MAAA,MAAM,EAAE,MAAK,GAAI,IAAA;AACjB,MAAA,MAAM,KAAA,GAAQ,CAAC,EAAE,IAAA,EAAM,KAAA,CAAM,CAAC,CAAA,EAAG,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,CAAA;AAClD,MAAA,IAAI,IAAI,CAAA,GAAI,CAAA;AACZ,MAAA,OAAO,CAAA,GAAI,KAAA,CAAM,MAAA,EAAQ,CAAA,IAAK,CAAA,EAAG;AAC/B,QAAA,MAAM,IAAA,GAAO,QAAA,CAAS,KAAA,CAAM,CAAC,CAAC,CAAA;AAC9B,QAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,CAAK,IAAA,KAAS,IAAA,EAAM;AACjC,QAAA,KAAA,CAAM,IAAA,CAAK,EAAE,IAAA,EAAM,KAAA,CAAM,CAAC,CAAA,EAAG,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,CAAA;AAAA,MAChD;AACA,MAAA,GAAA,CAAI,IAAA;AAAA,wBACFC,GAAAA;AAAA,UAAC,SAAA;AAAA,UAAA;AAAA,YAEC,KAAA,EAAO,IAAA;AAAA,YACP,KAAA;AAAA,YACA,KAAA;AAAA,YACA,SAAA;AAAA,YACA,QAAQ,IAAA,CAAK,MAAA;AAAA,YAGb,IAAA,EAAM,KAAA,CAAM,IAAA,CAAK,CAAC,EAAE,IAAA,EAAK,KAAM,KAAA,CAAc,IAAA,EAAM,SAAS,CAAA,KAAM,OAAO;AAAA,WAAA;AAAA,UARpE,MAAM,CAAC;AAAA;AASd,OACF;AACA,MAAA,CAAA,GAAI,CAAA;AAAA,IACN;AACA,IAAA,OAAO,GAAA;AAAA,EACT,CAAA;AAGA,EAAA,MAAM,IAAA,GAAO,CAAC,KAAA,EAAkB,EAAA,EAAY,IAAA,KAA0B;AACpE,IAAA,MAAM,QAAA,GAAW,SAAS,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,EAAE,CAAA;AAC5D,IAAA,MAAM,SAAA,GAAY,IAAI,GAAA,CAAI,QAAA,CAAS,QAAQ,CAAC,CAAA,KAAM,CAAA,CAAE,KAAK,CAAC,CAAA;AAC1D,IAAA,MAAM,QAAQ,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,QAAQ,EAAE,GAAA,CAAI,CAAC,GAAA,KAAS,EAAA,KAAO,KAAK,GAAA,GAAM,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,GAAG,CAAA,CAAG,CAAA;AACzF,IAAA,uBACE,IAAA,CAAAC,UAAA,EACG,QAAA,EAAA;AAAA,MAAA,OAAA;AAAA,QACC,KAAA,CAAM,OAAO,CAAC,CAAA,KAAM,CAAC,SAAA,CAAU,GAAA,CAAI,CAAC,CAAC,CAAA;AAAA,QACrC;AAAA,OACF;AAAA,MACC,QAAA,CAAS,GAAA,CAAI,CAAC,OAAA,KAAY;AACzB,QAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,OAAA,EAAS,IAAI,CAAA;AACvC,QAAA,uBACED,GAAAA;AAAA,UAACE,EAAA;AAAA,UAAA;AAAA,YAEC,OAAO,OAAA,CAAQ,KAAA;AAAA,YACd,GAAG,KAAK,UAAA,CAAW,OAAO,GAAG,OAAA,CAAQ,SAAA,EAAW,MAAM,IAAI,CAAA;AAAA,YAE1D,QAAA,EAAA,OAAA,CAAQ,OAAA,CAAQ,KAAA,EAAO,KAAK;AAAA,WAAA;AAAA,UAJxB,WAAW,OAAO;AAAA,SAKzB;AAAA,MAEJ,CAAC;AAAA,KAAA,EACH,CAAA;AAAA,EAEJ,CAAA;AAEA,EAAA,MAAM,uBACJF,GAAAA;AAAA,IAAC,EAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,QAAA;AAAA,MACN,OAAA;AAAA,MACA,KAAA;AAAA,MACA,SAAA,EAAW,SAAA,GAAY,CAAA,iBAAA,EAAoB,SAAS,CAAA,CAAA,GAAK,kBAAA;AAAA,MAExD,QAAA,EAAA,IAAA,CAAK,SAAS,KAAA,EAAO,EAAA,EAAI,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAU;AAAA;AAAA,GAC5D;AAEF,EAAA,IAAI,UAAU,MAAA,IAAa,MAAA,KAAW,MAAA,IAAa,IAAA,KAAS,QAAW,OAAO,IAAA;AAC9E,EAAA,uBACEA,GAAAA,CAACG,GAAA,EAAA,EAAc,OAAc,MAAA,EAAgB,IAAA,EAAY,SACtD,QAAA,EAAA,IAAA,EACH,CAAA;AAEJ;AAKA,SAAS,WAAW,OAAA,EAA8B;AAChD,EAAA,OAAO,OAAA,CAAQ,EAAA,KAAO,EAAA,GAAK,OAAA,CAAQ,KAAA,GAAQ,GAAG,OAAA,CAAQ,EAAE,CAAA,CAAA,EAAI,OAAA,CAAQ,KAAK,CAAA,CAAA;AAC3E;AAoBA,SAAS,aAAa,IAAA,EAAyB;AAC7C,EAAA,OACE,KAAK,IAAA,KAAS,QAAA,IACd,KAAA,CAAc,IAAA,EAAM,SAAS,CAAA,KAAM,QAAA,IACnC,KAAA,CAAc,IAAA,EAAM,KAAK,CAAA,KAAM,MAAA,IAC/B,KAAA,CAAc,IAAA,EAAM,KAAK,CAAA,KAAM,MAAA;AAEnC;AAIA,SAAS,KAAA,CAAS,MAAgB,GAAA,EAA4B;AAC5D,EAAA,OAAQ,KAAkD,GAAG,CAAA;AAC/D;AAIO,SAAS,UAAA,CAA+C;AAAA,EAC7D,IAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA,EAAAL,KAAAA;AAAA,EACA;AACF,CAAA,EAAwB;AACtB,EAAA,MAAM,KAAA,GAAQ,CAACM,MAAAA,KAAyB,SAAA,CAAU,MAAMA,MAAK,CAAA;AAC7D,EAAA,MAAM,QAAA,GAAW,KAAA,CAAe,IAAA,EAAM,SAAS,CAAA;AAC/C,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,MAAA,EAAQ,IAAI,CAAA,IAAK,QAAA;AAE5C,EAAA,MAAM,SAAA,GAAYN,KAAAA,EAAM,GAAA,CAAI,IAAI,CAAA,IAAK,KAAA;AACrC,EAAA,MAAM,OAAA,GAAU,CAAC,KAAA,CAAe,IAAA,EAAM,QAAQ,CAAA;AAI9C,EAAA,MAAM,aAAA,GAAgB,SAAA,GAAY,WAAA,CAAY,KAAA,EAAO,IAAI,CAAA,GAAI,MAAA;AAI7D,EAAA,MAAM,QAAQ,aAAA,IAAiB,MAAA;AAC/B,EAAA,MAAM,UAAU,CAAC,IAAA,KAAwB,UAAA,CAAW,IAAA,EAAM,MAAM,KAAK,CAAA;AACrE,EAAA,MAAM,YAAA,GAAe,UAAU,OAAA,GAAU,MAAA;AAEzC,EAAA,MAAM,WAAA,GAAc,YAAY,MAAA,GAAS,MAAA;AACzC,EAAA,MAAM,SAAA,GAAY,EAAE,IAAA,EAAM,SAAA,EAAW,YAAA,EAAa;AAIlD,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,OAAA,CAAQ,IAAI,CAAA;AACpC,EAAA,MAAM,SACJ,SAAA,GAAY,IAAI,CAAA,IAChB,QAAA,CAAS,UAAU,IAAI,CAAA,KACtB,MAAA,GAAS,QAAA,CAAS,OAAO,IAAA,EAAM,MAAM,IAAI,MAAA,CAAA,IAC1C,SAAA,GAAY,KAAK,IAAI,CAAA;AAGvB,EAAA,IAAI,MAAA,EAAQ,OAAO,MAAA,CAAO,EAAE,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,KAAA,EAAO,QAAA,EAAU,KAAA,EAAO,IAAA,EAAM,SAAA,EAAW,SAAS,CAAA;AAEhG,EAAA,MAAM,QAAQ,IAAA,CAAK,IAAA;AACnB,EAAA,MAAM,cAAc,IAAA,CAAK,WAAA;AAGzB,EAAA,MAAM,OAAO,IAAA,KAAS,MAAA;AACtB,EAAA,MAAM,GAAA,GAAM,EAAE,KAAA,EAAO,WAAA,EAAa,QAAQ,OAAA,EAAS,WAAA,EAAa,GAAG,SAAA,EAAU;AAE7E,EAAA,IAAI,IAAA,CAAK,SAAS,MAAA,EAAQ;AACxB,IAAA,MAAM,UAAU,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GAAK,QAAqB,EAAC;AAC9D,IAAA,uBACEE,GAAAA;AAAA,MAAC,CAAA;AAAA,MAAA;AAAA,QACC,KAAA;AAAA,QACA,OAAA,EAAS,eAAe,OAAO,CAAA;AAAA,QAC/B,OAAA,EAAS,WAAA;AAAA,QACT,MAAA;AAAA,QACA,WAAA;AAAA,QACC,GAAG,SAAA;AAAA,QAEH,gCACCA,GAAAA;AAAA,UAACK,EAAA;AAAA,UAAA;AAAA,YACC,YAAA,EAAY,KAAA;AAAA,YACZ,KAAA,EAAO,OAAA;AAAA,YACP,QAAA,EAAU,KAAA;AAAA,YACV,WAAA,EAAa,KAAA,CAAc,IAAA,EAAM,aAAa;AAAA;AAAA;AAChD;AAAA,KAEJ;AAAA,EAEJ;AAEA,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,IAAA,EAAM,KAAA,EAAO,KAAK,CAAA;AACzC,EAAA,IAAI,KAAA,KAAU,IAAA;AACZ,IAAA,uBAAOL,GAAAA,CAAC,UAAA,EAAA,EAAW,OAAc,IAAA,EAAM,IAAA,CAAK,MAAM,WAAA,EAA0B,CAAA;AAC9E,EAAA,QAAQ,MAAM,IAAA;AAAM,IAClB,KAAK,QAAA;AACH,MAAA,uBAAOA,IAAC,gBAAA,EAAA,EAAiB,IAAA,EAAY,OAAc,IAAA,EAAM,IAAA,EAAO,GAAG,GAAA,EAAK,CAAA;AAAA,IAC1E,KAAK,QAAA;AACH,MAAA,uBAAOA,GAAAA,CAAC,EAAA,EAAA,EAAe,GAAG,KAAA,EAAQ,GAAG,GAAA,EAAK,IAAA,EAAM,KAAA,CAAM,OAAA,KAAY,QAAA,IAAY,IAAA,EAAM,CAAA;AAAA,IACtF,KAAK,MAAA;AACH,MAAA,uBAAOA,GAAAA,CAAC,EAAA,EAAA,EAAe,GAAG,KAAA,EAAQ,GAAG,GAAA,EAAK,IAAA,EAAM,KAAA,CAAM,OAAA,KAAY,QAAA,IAAY,IAAA,EAAM,CAAA;AAAA,IACtF;AACE,MAAA,uBAAOA,GAAAA,CAAC,EAAA,EAAA,EAAe,GAAG,KAAA,EAAQ,GAAG,GAAA,EAAK,CAAA;AAAA;AAEhD;AAQA,SAAS,QAAA,CACP,IAAA,EACA,KAAA,EACA,KAAA,EAC6B;AAC7B,EAAA,IAAI,CAAC,iBAAA,CAAkB,IAAI,CAAA,IAAK,IAAA,CAAK,SAAS,OAAA,IAAW,IAAA,CAAK,IAAA,KAAS,QAAA,EAAU,OAAO,IAAA;AACxF,EAAA,MAAM,QAAQM,EAAA,CAAe,IAAA,EAAM,EAAE,KAAA,EAAO,QAAA,EAAU,OAAO,CAAA;AAC7D,EAAA,IAAI,KAAA,KAAU,MAAM,OAAO,IAAA;AAC3B,EAAA,QAAQ,MAAM,IAAA;AAAM,IAClB,KAAK,QAAA;AAGH,MAAA,OAAO;AAAA,QACL,GAAG,KAAA;AAAA,QACH,OAAA,EAAS,YAAA,CAAa,IAAI,CAAA,GAAI,QAAA,GAAW,OAAA;AAAA,QACzC,IAAA,EAAM,KAAA,CAAc,IAAA,EAAM,QAAQ,KAAK,KAAA,CAAM;AAAA,OAC/C;AAAA,IACF,KAAK,SAAA;AACH,MAAA,OAAO;AAAA,QACL,GAAG,KAAA;AAAA,QACH,SAAS,KAAA,CAAc,IAAA,EAAM,SAAS,CAAA,KAAM,WAAW,QAAA,GAAW;AAAA,OACpE;AAAA,IACF,KAAK,MAAA;AAEH,MAAA,OAAO;AAAA,QACL,GAAG,KAAA;AAAA,QACH,SAAS,KAAA,CAAc,IAAA,EAAM,SAAS,CAAA,KAAM,UAAU,QAAA,GAAW;AAAA,OACnE;AAAA,IACF,KAAK,QAAA;AACH,MAAA,OAAO;AAAA,QACL,GAAG,KAAA;AAAA,QACH,WAAA,EAAa,KAAA,CAAc,IAAA,EAAM,aAAa,CAAA;AAAA,QAC9C,SAAA,EAAW,KAAA,CAAc,IAAA,EAAM,WAAW;AAAA,OAC5C;AAAA,IACF;AACE,MAAA,OAAO,KAAA;AAAA;AAEb;AAIA,SAAS,UAAA,CAAW;AAAA,EAClB,KAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,uBACEN,IAACO,EAAA,EAAA,EAAY,KAAA,EAAc,aACzB,QAAA,kBAAA,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,2BAAA,EAA4B,QAAA,EAAA;AAAA,IAAA,uBAAA;AAAA,IAAiB,IAAA;AAAA,IAAK;AAAA,GAAA,EAAC,CAAA,EACrE,CAAA;AAEJ;AAGA,SAAS,gBAAA,CAAiB;AAAA,EACxB,IAAA;AAAA,EACA,KAAA;AAAA,EACA,GAAG;AACL,CAAA,EAUG;AACD,EAAA,MAAM,IAAA,GAAO,gBAAA;AAAA,IACX,MAAM,KAAA,IAAS,EAAA;AAAA,IACf,KAAA,CAAM,QAAA;AAAA,IACN,KAAA,CAAc,IAAA,EAAM,YAAY,CAAA,IAAK;AAAA,GACvC;AACA,EAAA,uBAAOP,GAAAA,CAAC,EAAA,EAAA,EAAe,GAAG,KAAA,EAAQ,GAAG,GAAA,EAAK,KAAA,EAAO,IAAA,CAAK,KAAA,EAAO,QAAA,EAAU,IAAA,CAAK,IAAA,EAAM,CAAA;AACpF;AAiBA,SAAS,SAAA,CAA8C;AAAA,EACrD,KAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA,SAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAOG;AACD,EAAA,uBACEA,GAAAA,CAACO,EAAA,EAAA,EAAY,KAAA,EAAK,IAAA,EAAC,IAAA,EAAY,KAAA,EAAc,MAAA,EAC1C,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,EAAE,MAAM,IAAA,EAAK;AAAA;AAAA;AAAA;AAAA,yBAItB,MAAA,EAAA,EAAgB,SAAA,EAAU,gBAAe,KAAA,EAAO,IAAA,CAAK,eAAe,MAAA,EAClE,QAAA,EAAA;AAAA,MAAA,IAAA,CAAK,IAAA,mBAAOP,GAAAA,CAAC,MAAA,EAAA,EAAK,WAAU,eAAA,EAAiB,QAAA,EAAA,IAAA,CAAK,MAAK,CAAA,GAAU,IAAA;AAAA,sBAClEA,GAAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA;AAAA,UACA,OAAO,WAAA,CAAY,KAAA,EAAO,IAAI,CAAA,IAAK,KAAA,CAAe,MAAM,SAAS,CAAA;AAAA,UACjE,KAAA,EAAO,CAAC,KAAA,KAAU,SAAA,CAAU,MAAM,KAAK;AAAA;AAAA;AACzC,KAAA,EAAA,EANS,IAOX;AAAA,GACD,CAAA,EACH,CAAA;AAEJ;AAIA,SAAS,QAAA,CAAS;AAAA,EAChB,IAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,MAAM,IAAA,GAAO,gBAAA;AAAA,IACX,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,EAAA;AAAA,IACpC,KAAA;AAAA,IACA,KAAA,CAAc,IAAA,EAAM,YAAY,CAAA,IAAK;AAAA,GACvC;AACA,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,IAAA,EAAM,KAAA,EAAO,KAAK,CAAA;AAEzC,EAAA,IAAI,KAAA,KAAU,MAAM,OAAO,IAAA;AAC3B,EAAA,QAAQ,MAAM,IAAA;AAAM,IAClB,KAAK,QAAA;AACH,MAAA,uBACEA,GAAAA,CAACQ,GAAA,EAAA,EAAiB,GAAG,KAAA,EAAO,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,KAAA,EAAO,IAAA,CAAK,KAAA,EAAO,QAAA,EAAU,KAAK,IAAA,EAAM,CAAA;AAAA,IAEzF,KAAK,QAAA;AAEH,MAAA,uBAAOR,GAAAA,CAACQ,GAAA,EAAA,EAAiB,GAAG,KAAA,EAAO,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,OAAA,EAAQ,OAAA,EAAQ,IAAA,EAAM,MAAA,EAAW,CAAA;AAAA,IACvF,KAAK,OAAA,EAAS;AAGZ,MAAA,MAAM,SAAS,OAAO,KAAA,KAAU,QAAA,GAAW,MAAA,CAAO,KAAK,CAAA,GAAI,SAAA;AAC3D,MAAA,uBACER,GAAAA;AAAA,QAACQ,GAAA;AAAA,QAAA;AAAA,UACE,GAAG,KAAA;AAAA,UACJ,MAAM,IAAA,CAAK,IAAA;AAAA,UACX,KAAA,EAAO,MAAA;AAAA,UACP,QAAA,EAAU,CAAC,GAAA,KACT,KAAA,CAAM,KAAA,CAAM,KAAA,GAAQ,WAAA,CAAY,GAAA,EAAK,UAAA,CAAW,MAAM,CAAC,CAAA,GAAI,GAAG;AAAA;AAAA,OAElE;AAAA,IAEJ;AAAA,IACA;AACE,MAAA,uBAAOR,GAAAA,CAACQ,GAAA,EAAA,EAAiB,GAAG,KAAA,EAAO,IAAA,EAAM,KAAK,IAAA,EAAM,CAAA;AAAA;AAE1D;AAOA,SAAS,gBAAA,CACP,KAAA,EACA,KAAA,EACA,UAAA,EACiD;AACjD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAS,KAAK,CAAA;AACxC,EAAA,MAAM,KAAA,GAAQ,OAA6C,IAAI,CAAA;AAC/D,EAAA,MAAM,YAAA,GAAe,OAAO,KAAK,CAAA;AAEjC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,KAAA,KAAU,aAAa,OAAA,EAAS;AAClC,MAAA,YAAA,CAAa,OAAA,GAAU,KAAA;AACvB,MAAA,QAAA,CAAS,KAAK,CAAA;AAAA,IAChB;AAAA,EACF,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAEV,EAAA,SAAA;AAAA,IACE,MAAM,MAAM;AACV,MAAA,IAAI,KAAA,CAAM,OAAA,EAAS,YAAA,CAAa,KAAA,CAAM,OAAO,CAAA;AAAA,IAC/C,CAAA;AAAA,IACA;AAAC,GACH;AAEA,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,IAAA,EAAM,CAAC,IAAA,KAAS;AACd,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA,IAAI,KAAA,CAAM,OAAA,EAAS,YAAA,CAAa,KAAA,CAAM,OAAO,CAAA;AAC7C,MAAA,MAAM,SAAS,MAAM;AACnB,QAAA,YAAA,CAAa,OAAA,GAAU,IAAA;AACvB,QAAA,KAAA,CAAM,IAAI,CAAA;AAAA,MACZ,CAAA;AACA,MAAA,IAAI,UAAA,KAAe,GAAG,MAAA,EAAO;AAAA,WACxB,KAAA,CAAM,OAAA,GAAU,UAAA,CAAW,MAAA,EAAQ,UAAU,CAAA;AAAA,IACpD;AAAA,GACF;AACF","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 {
|
|
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 } =
|
|
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-
|
|
217
|
-
//# sourceMappingURL=chunk-
|
|
216
|
+
//# sourceMappingURL=chunk-XRX5S5NT.js.map
|
|
217
|
+
//# sourceMappingURL=chunk-XRX5S5NT.js.map
|