dsh-motion-ui 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +19 -1
- package/VERIFICATION.md +10 -0
- package/client.js +391 -222
- package/index.js +31 -16
- package/lib/author-expression.js +7 -7
- package/lib/authoring-guide.js +3 -17
- package/lib/build-info.js +1 -1
- package/lib/canvas-design.js +2 -2
- package/lib/canvas-system.js +1 -1
- package/lib/catalog.js +1 -2
- package/lib/delivery.js +1 -1
- package/lib/export-runtime-bundle.js +1 -1
- package/lib/fence-feedback.js +8 -2
- package/lib/freeform.js +2 -8
- package/lib/inspection.js +11 -6
- package/lib/motion-library.js +2 -3
- package/lib/normalize-authoring.js +9 -0
- package/lib/prompt-contract.js +22 -0
- package/lib/protocol.js +3 -3
- package/lib/refinement.js +3 -2
- package/lib/scene-entry.js +41 -0
- package/lib/style-system.js +2 -2
- package/lib/text-guide.js +9 -13
- package/lib/third-party/taste-skill-NOTICE.md +10 -0
- package/lib/tool-schema.js +7 -7
- package/lib/ui-intent.js +4 -15
- package/lib/ui-skill.js +19 -26
- package/lib/visual-audit.js +15 -4
- package/lib/visual-styles.js +1 -1
- package/package.json +1 -1
- package/skills/intelligent-ui/SKILL.md +14 -107
package/client.js
CHANGED
|
@@ -72,7 +72,7 @@ function Icon({ name = "info", className = "" }) {
|
|
|
72
72
|
|
|
73
73
|
// src/expressive-controls.js
|
|
74
74
|
var h2 = import_react2.default.createElement;
|
|
75
|
-
function ExpressiveAction({ tag = "button", text:
|
|
75
|
+
function ExpressiveAction({ tag = "button", text: text3, icon = "arrow", ...props }) {
|
|
76
76
|
const ref = (0, import_react2.useRef)(null);
|
|
77
77
|
function move(e) {
|
|
78
78
|
if (matchMedia("(prefers-reduced-motion: reduce)").matches || props.disabled) return;
|
|
@@ -84,7 +84,7 @@ function ExpressiveAction({ tag = "button", text: text2, icon = "arrow", ...prop
|
|
|
84
84
|
e.currentTarget.style.setProperty("--du-mx", "0px");
|
|
85
85
|
e.currentTarget.style.setProperty("--du-my", "0px");
|
|
86
86
|
}
|
|
87
|
-
return h2(tag, { ...props, ref, "aria-label":
|
|
87
|
+
return h2(tag, { ...props, ref, "aria-label": text3, className: (props.className ?? "") + " dgui-expressive-action", onPointerMove: move, onPointerLeave: leave }, h2("span", { className: "dgui-action-fill", "aria-hidden": true }), h2("span", { className: "dgui-action-label", "aria-hidden": true }, h2("span", null, text3), h2("span", null, text3)), h2("span", { className: "dgui-action-orb", "aria-hidden": true }, h2(Icon, { name: icon })));
|
|
88
88
|
}
|
|
89
89
|
function ElasticToggle({ id: id2, checked, disabled, onChange }) {
|
|
90
90
|
const [stretch, setStretch] = (0, import_react2.useState)(false), timer = (0, import_react2.useRef)(), drag = (0, import_react2.useRef)(null), skip = (0, import_react2.useRef)(false);
|
|
@@ -226,12 +226,27 @@ var MECHANISM_RUNTIME = 'var __MotionMechanism=(()=>{var it=Object.definePropert
|
|
|
226
226
|
// lib/visual-audit.js
|
|
227
227
|
function measureVisual(root2, nodeId = "") {
|
|
228
228
|
const issues = [], seen = /* @__PURE__ */ new Set(), coverage = { nodeId, elements: 0, truncated: false, contrastChecked: 0, contrastUncovered: 0 };
|
|
229
|
+
const styleCache = /* @__PURE__ */ new WeakMap(), styleOf = (el2) => {
|
|
230
|
+
let css = styleCache.get(el2);
|
|
231
|
+
if (!css) {
|
|
232
|
+
css = getComputedStyle(el2);
|
|
233
|
+
styleCache.set(el2, css);
|
|
234
|
+
}
|
|
235
|
+
return css;
|
|
236
|
+
};
|
|
237
|
+
const target = (el2) => {
|
|
238
|
+
if (!el2) return void 0;
|
|
239
|
+
const tag = el2.tagName.toLowerCase(), id2 = el2.id;
|
|
240
|
+
return { selector: id2 && id2.length <= 64 ? "#" + CSS.escape(id2) : tag, text: (el2.textContent ?? "").trim().replace(/\s+/g, " ").slice(0, 120), tag };
|
|
241
|
+
};
|
|
229
242
|
const add2 = (code, value, el2) => {
|
|
243
|
+
if (issues.length >= 40) return;
|
|
230
244
|
const id2 = el2?.closest("[data-ui-node]")?.getAttribute("data-ui-node") ?? nodeId;
|
|
231
|
-
const
|
|
245
|
+
const location2 = target(el2);
|
|
246
|
+
const k2 = id2 + ":" + code + ":" + (location2?.selector ?? "") + ":" + (location2?.text ?? "") + ":" + Math.round(value ?? 0);
|
|
232
247
|
if (!seen.has(k2) && issues.length < 40) {
|
|
233
248
|
seen.add(k2);
|
|
234
|
-
issues.push({ code, nodeId: id2, ...value === void 0 ? {} : { value: Number(value.toFixed(2)) } });
|
|
249
|
+
issues.push({ code, nodeId: id2, ...location2 ? { target: location2 } : {}, ...value === void 0 ? {} : { value: Number(value.toFixed(2)) } });
|
|
235
250
|
}
|
|
236
251
|
};
|
|
237
252
|
const color = (s) => {
|
|
@@ -248,6 +263,25 @@ function measureVisual(root2, nodeId = "") {
|
|
|
248
263
|
return null;
|
|
249
264
|
};
|
|
250
265
|
const luminance = (c) => c.slice(0, 3).map((v2) => v2 <= 0.04045 ? v2 / 12.92 : ((v2 + 0.055) / 1.055) ** 2.4).reduce((s, v2, i) => s + v2 * [0.2126, 0.7152, 0.0722][i], 0);
|
|
266
|
+
const blend = (front, back) => front.slice(0, 3).map((v2, i) => v2 * front[3] + back[i] * (1 - front[3])).concat(1);
|
|
267
|
+
const background = (el2) => {
|
|
268
|
+
const layers = [];
|
|
269
|
+
let n2 = el2;
|
|
270
|
+
for (let i = 0; n2 && i < 64; i++, n2 = n2.parentElement) {
|
|
271
|
+
const c = styleOf(n2);
|
|
272
|
+
if (c.backgroundImage !== "none") return null;
|
|
273
|
+
const colorValue = color(c.backgroundColor);
|
|
274
|
+
if (!colorValue) return null;
|
|
275
|
+
if (colorValue[3] > 0) layers.push(colorValue);
|
|
276
|
+
if (colorValue[3] === 1) {
|
|
277
|
+
let out = layers.pop();
|
|
278
|
+
while (layers.length) out = blend(layers.pop(), out);
|
|
279
|
+
return out;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return null;
|
|
283
|
+
};
|
|
284
|
+
let contentBottom = root2.getBoundingClientRect().top;
|
|
251
285
|
const widthRoot = root2.id === "canvas" ? document.documentElement : root2;
|
|
252
286
|
if (widthRoot.scrollWidth > widthRoot.clientWidth + 2) add2("overflow", widthRoot.scrollWidth - widthRoot.clientWidth);
|
|
253
287
|
const walker = document.createTreeWalker(root2, NodeFilter.SHOW_ELEMENT);
|
|
@@ -259,37 +293,49 @@ function measureVisual(root2, nodeId = "") {
|
|
|
259
293
|
}
|
|
260
294
|
coverage.elements++;
|
|
261
295
|
if (el.matches("[data-canvas-phase=error]")) add2("runtimeError", void 0, el);
|
|
262
|
-
const css =
|
|
296
|
+
const css = styleOf(el), box2 = el.getBoundingClientRect();
|
|
263
297
|
if (!box2.width || !box2.height || css.visibility === "hidden" || css.display === "none") continue;
|
|
264
|
-
const
|
|
265
|
-
if (
|
|
298
|
+
const text3 = [...el.childNodes].some((n2) => n2.nodeType === 3 && n2.textContent.trim());
|
|
299
|
+
if (text3) {
|
|
266
300
|
let size = parseFloat(css.fontSize);
|
|
267
301
|
if (el instanceof SVGElement && el.getScreenCTM) {
|
|
268
302
|
const m2 = el.getScreenCTM();
|
|
269
303
|
if (m2) size *= Math.hypot(m2.c, m2.d);
|
|
270
304
|
}
|
|
271
305
|
if (size < 11.9) add2("smallText", size, el);
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
306
|
+
if (!(el instanceof SVGElement)) {
|
|
307
|
+
const fg = color(css.color), bg = background(el);
|
|
308
|
+
let opacitySafe = true, opacityDepth = 0;
|
|
309
|
+
for (let a2 = el; a2; a2 = a2.parentElement) {
|
|
310
|
+
if (++opacityDepth > 64 || parseFloat(styleOf(a2).opacity) < 1) {
|
|
311
|
+
opacitySafe = false;
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (fg && bg && opacitySafe) {
|
|
316
|
+
coverage.contrastChecked++;
|
|
317
|
+
const a2 = luminance(blend(fg, bg)), b2 = luminance(bg), ratio = (Math.max(a2, b2) + 0.05) / (Math.min(a2, b2) + 0.05);
|
|
318
|
+
if (ratio < (size >= 24 || size >= 18.66 && parseFloat(css.fontWeight) >= 700 ? 3 : 4.5)) add2("contrast", ratio, el);
|
|
319
|
+
} else coverage.contrastUncovered++;
|
|
320
|
+
const range = document.createRange();
|
|
321
|
+
range.selectNodeContents(el);
|
|
322
|
+
const bounds = range.getBoundingClientRect();
|
|
323
|
+
let a = el, depth = 0;
|
|
324
|
+
while (a && a !== root2.parentElement && depth++ < 24) {
|
|
325
|
+
const c = styleOf(a), clip = a.getBoundingClientRect();
|
|
326
|
+
if (["hidden", "clip"].includes(c.overflowX) && (bounds.left < clip.left - 2 || bounds.right > clip.right + 2) || ["hidden", "clip"].includes(c.overflowY) && (bounds.top < clip.top - 2 || bounds.bottom > clip.bottom + 2)) {
|
|
327
|
+
add2("clippedText", void 0, el);
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
a = a.parentElement;
|
|
281
331
|
}
|
|
282
|
-
if (c?.[3] > 0) break;
|
|
283
|
-
ancestor = ancestor.parentElement;
|
|
284
|
-
}
|
|
285
|
-
if (!(el instanceof SVGElement) && fg?.[3] === 1 && bg) {
|
|
286
|
-
coverage.contrastChecked++;
|
|
287
|
-
const a = luminance(fg), b2 = luminance(bg), ratio = (Math.max(a, b2) + 0.05) / (Math.min(a, b2) + 0.05);
|
|
288
|
-
if (ratio < (size >= 24 || size >= 18.66 && parseFloat(css.fontWeight) >= 700 ? 3 : 4.5)) add2("contrast", ratio, el);
|
|
289
332
|
} else coverage.contrastUncovered++;
|
|
290
333
|
}
|
|
334
|
+
if (text3 || el.matches("svg,canvas,img,video,input,select,textarea,button")) contentBottom = Math.max(contentBottom, box2.bottom);
|
|
291
335
|
if (el.matches("input:not([type=hidden]),select,textarea,button,[role=button]") && !el.getAttribute("aria-label") && !el.getAttribute("aria-labelledby") && !el.labels?.length && !el.textContent.trim() && !el.getAttribute("title")) add2("missingLabel", void 0, el);
|
|
292
336
|
}
|
|
337
|
+
const rect = root2.getBoundingClientRect(), gap = rect.bottom - contentBottom;
|
|
338
|
+
if (!coverage.truncated && root2.id === "canvas" && rect.height > 320 && gap > Math.max(96, rect.height * 0.25)) add2("bottomWhitespace", gap, root2);
|
|
293
339
|
Object.defineProperty(issues, "coverage", { value: coverage });
|
|
294
340
|
return issues;
|
|
295
341
|
}
|
|
@@ -315,9 +361,9 @@ svg .ui-node{fill:var(--canvas-soft,#f3f5f8);stroke:var(--canvas-line,#ced4df);s
|
|
|
315
361
|
|
|
316
362
|
// lib/sandbox.js
|
|
317
363
|
var SANDBOX_LIMITS = Object.freeze({ source: 49152, height: 1e3, message: 16384, rate: 30 });
|
|
318
|
-
function canvasSnapshot(node,
|
|
364
|
+
function canvasSnapshot(node, state2, data, derived, disabled, theme) {
|
|
319
365
|
const pick = (keys, values) => Object.fromEntries((keys ?? []).map((k2) => [k2, values[k2]]));
|
|
320
|
-
return { state: pick(node.stateKeys,
|
|
366
|
+
return { state: pick(node.stateKeys, state2), data: pick(node.dataKeys, data), derived: pick(node.derivedKeys, derived), disabled, theme };
|
|
321
367
|
}
|
|
322
368
|
function canvasPatch(message, node) {
|
|
323
369
|
if (!message || typeof message !== "object" || Array.isArray(message)) throw new Error("Invalid canvas patch");
|
|
@@ -364,7 +410,7 @@ function sandboxDocument(node, channel, nonce) {
|
|
|
364
410
|
}
|
|
365
411
|
|
|
366
412
|
// lib/components.js
|
|
367
|
-
var define = (
|
|
413
|
+
var define = (fields3, purpose, presentation = "") => Object.freeze({ fields: Object.freeze(fields3), purpose, presentation });
|
|
368
414
|
var COMPONENTS = Object.freeze({
|
|
369
415
|
visual: define(["spec", "stateKey", "warnings"], "Extended native charts, tables, plots, quiz, forms, diagrams, media and 3D"),
|
|
370
416
|
heading: define(["text", "spans", "size", "weight", "color", "align", "lineHeight"], "Section heading", "tone"),
|
|
@@ -402,10 +448,10 @@ var validIdentifier = (value) => typeof value === "string" && pattern.test(value
|
|
|
402
448
|
|
|
403
449
|
// lib/author-expression.js
|
|
404
450
|
function compileExpression(source) {
|
|
405
|
-
const
|
|
451
|
+
const fail4 = () => {
|
|
406
452
|
throw new Error("DSH UI: invalid formula; use state.x, data.x, derived.x, item.x, numbers, strings, + - * /, comparisons, ?: and min/max/round/ceil/floor/abs");
|
|
407
453
|
};
|
|
408
|
-
if (typeof source !== "string" || !source.trim() || source.length > 2048)
|
|
454
|
+
if (typeof source !== "string" || !source.trim() || source.length > 2048) fail4();
|
|
409
455
|
const tokens = [];
|
|
410
456
|
let offset = 0;
|
|
411
457
|
const token = new RegExp(String.raw`\s*(?:(\d+(?:\.\d*)?|\.\d+)([eE][+-]?\d+)?|("(?:[^"\\]|\\.)*")|(${IDENTIFIER_SOURCE}(?:\.${IDENTIFIER_SOURCE})?)|(===|!==|<=|>=|==|!=|[+*/()?,:<>-]))`, "uy");
|
|
@@ -413,18 +459,18 @@ function compileExpression(source) {
|
|
|
413
459
|
if (!source.slice(offset).trim()) break;
|
|
414
460
|
token.lastIndex = offset;
|
|
415
461
|
const m2 = token.exec(source);
|
|
416
|
-
if (!m2)
|
|
462
|
+
if (!m2) fail4();
|
|
417
463
|
offset = token.lastIndex;
|
|
418
464
|
tokens.push(m2[1] ? { number: Number(m2[1] + (m2[2] ?? "")) } : m2[3] ? { string: JSON.parse(m2[3]) } : m2[4] ?? m2[5]);
|
|
419
|
-
if (tokens.length > 256)
|
|
465
|
+
if (tokens.length > 256) fail4();
|
|
420
466
|
}
|
|
421
467
|
let pos = 0;
|
|
422
468
|
const operators = { "==": ["eq", 1], "===": ["eq", 1], "!=": ["neq", 1], "!==": ["neq", 1], "<": ["lt", 2], "<=": ["lte", 2], ">": ["gt", 2], ">=": ["gte", 2], "+": ["add", 3], "-": ["sub", 3], "*": ["mul", 4], "/": ["div", 4] };
|
|
423
469
|
const take = (t) => {
|
|
424
|
-
if (tokens[pos++] !== t)
|
|
470
|
+
if (tokens[pos++] !== t) fail4();
|
|
425
471
|
};
|
|
426
472
|
function parse(min = 0, depth = 0) {
|
|
427
|
-
if (depth > 12)
|
|
473
|
+
if (depth > 12) fail4();
|
|
428
474
|
const t = tokens[pos++];
|
|
429
475
|
let out;
|
|
430
476
|
if (t && typeof t === "object") out = { const: Object.hasOwn(t, "number") ? t.number : t.string };
|
|
@@ -442,11 +488,11 @@ function compileExpression(source) {
|
|
|
442
488
|
while (tokens[pos] === ",") {
|
|
443
489
|
pos++;
|
|
444
490
|
args.push(parse(0, depth + 1));
|
|
445
|
-
if (args.length > 8)
|
|
491
|
+
if (args.length > 8) fail4();
|
|
446
492
|
}
|
|
447
493
|
take(")");
|
|
448
494
|
out = { op: t, args };
|
|
449
|
-
} else
|
|
495
|
+
} else fail4();
|
|
450
496
|
while (typeof tokens[pos] === "string" && Object.hasOwn(operators, tokens[pos]) && operators[tokens[pos]][1] >= min) {
|
|
451
497
|
const [op, precedence] = operators[tokens[pos++]];
|
|
452
498
|
out = { op, args: [out, parse(precedence + 1, depth + 1)] };
|
|
@@ -460,28 +506,34 @@ function compileExpression(source) {
|
|
|
460
506
|
return out;
|
|
461
507
|
}
|
|
462
508
|
const result = parse();
|
|
463
|
-
if (pos !== tokens.length)
|
|
509
|
+
if (pos !== tokens.length) fail4();
|
|
464
510
|
return result;
|
|
465
511
|
}
|
|
466
512
|
function expandExpressions(doc) {
|
|
467
|
-
const expression2 = (e) => {
|
|
513
|
+
const expression2 = (e, at2) => {
|
|
468
514
|
if (!e || typeof e !== "object" || Array.isArray(e)) return e;
|
|
469
515
|
if (Object.hasOwn(e, "expr")) {
|
|
470
516
|
if (Object.keys(e).length !== 1) throw new Error("DSH UI: expr must be the only formula field");
|
|
471
|
-
|
|
517
|
+
try {
|
|
518
|
+
return compileExpression(e.expr);
|
|
519
|
+
} catch (error) {
|
|
520
|
+
error.message = "DSH UI: " + at2 + ": " + error.message.replace(/^DSH UI: /, "");
|
|
521
|
+
error.path = at2;
|
|
522
|
+
throw error;
|
|
523
|
+
}
|
|
472
524
|
}
|
|
473
|
-
if (Array.isArray(e.args)) e.args = e.args.map(expression2);
|
|
474
|
-
if (e.map?.fields) for (const k2 of Object.keys(e.map.fields)) e.map.fields[k2] = expression2(e.map.fields[k2]);
|
|
525
|
+
if (Array.isArray(e.args)) e.args = e.args.map((v2, i) => expression2(v2, at2 + ".args[" + i + "]"));
|
|
526
|
+
if (e.map?.fields) for (const k2 of Object.keys(e.map.fields)) e.map.fields[k2] = expression2(e.map.fields[k2], at2 + ".map.fields." + k2);
|
|
475
527
|
return e;
|
|
476
528
|
};
|
|
477
|
-
if (doc.derived && typeof doc.derived === "object") for (const k2 of Object.keys(doc.derived)) doc.derived[k2] = expression2(doc.derived[k2]);
|
|
529
|
+
if (doc.derived && typeof doc.derived === "object") for (const k2 of Object.keys(doc.derived)) doc.derived[k2] = expression2(doc.derived[k2], "derived." + k2);
|
|
478
530
|
const walk = (nodes) => {
|
|
479
531
|
if (!Array.isArray(nodes)) return;
|
|
480
532
|
for (const node of nodes) {
|
|
481
533
|
if (!node || typeof node !== "object") continue;
|
|
482
|
-
for (const field of ["text", "value", "max", "rows"]) if (Object.hasOwn(node, field)) node[field] = expression2(node[field]);
|
|
534
|
+
for (const field of ["text", "value", "max", "rows"]) if (Object.hasOwn(node, field)) node[field] = expression2(node[field], "node." + node.id + "." + field);
|
|
483
535
|
if (["table", "chart"].includes(node.type) && Array.isArray(node.rows)) {
|
|
484
|
-
for (const row of node.rows) if (row && typeof row === "object" && !Array.isArray(row)) for (const k2 of Object.keys(row)) row[k2] = expression2(row[k2]);
|
|
536
|
+
for (const [rowIndex, row] of node.rows.entries()) if (row && typeof row === "object" && !Array.isArray(row)) for (const k2 of Object.keys(row)) row[k2] = expression2(row[k2], "node." + node.id + ".rows[" + rowIndex + "]." + k2);
|
|
485
537
|
}
|
|
486
538
|
walk(node.children);
|
|
487
539
|
}
|
|
@@ -2326,6 +2378,10 @@ function number(v2) {
|
|
|
2326
2378
|
var boolean = (v2) => v2 === "true" ? true : v2 === "false" ? false : v2;
|
|
2327
2379
|
function expression(e, numeric = false, logical = false) {
|
|
2328
2380
|
if (!object(e)) return e;
|
|
2381
|
+
if (Object.keys(e).length === 1 && own(e, "expr") && typeof e.expr === "number" && Number.isFinite(e.expr)) {
|
|
2382
|
+
e.const = e.expr;
|
|
2383
|
+
delete e.expr;
|
|
2384
|
+
}
|
|
2329
2385
|
if (own(e, "const")) {
|
|
2330
2386
|
if (numeric) e.const = number(e.const);
|
|
2331
2387
|
if (logical) e.const = boolean(e.const);
|
|
@@ -2340,6 +2396,10 @@ function normalizeAuthoring(doc) {
|
|
|
2340
2396
|
if (object(doc) && !own(doc, "nodes") && (own(doc, "items") || typeof doc.type === "string")) doc = visualDocument(doc);
|
|
2341
2397
|
if (!object(doc)) return doc;
|
|
2342
2398
|
if (own(doc, "version")) doc.version = number(doc.version);
|
|
2399
|
+
if (object(doc.presentation) && doc.presentation.layout === "flow" && (!own(doc.presentation, "preset") || doc.presentation.preset === "flow")) {
|
|
2400
|
+
doc.presentation.layout = "guide";
|
|
2401
|
+
doc.presentation.preset = "flow";
|
|
2402
|
+
}
|
|
2343
2403
|
if (object(doc.state)) for (const k2 of Object.keys(doc.state)) {
|
|
2344
2404
|
let s = doc.state[k2];
|
|
2345
2405
|
if (typeof s === "string" && s.trim().startsWith("{")) {
|
|
@@ -2370,6 +2430,13 @@ function normalizeAuthoring(doc) {
|
|
|
2370
2430
|
if (!Array.isArray(list)) return list;
|
|
2371
2431
|
for (const node of list) {
|
|
2372
2432
|
if (!object(node)) continue;
|
|
2433
|
+
if (node.type === "code" && (node.copyable === true || node.copyable === "true")) delete node.copyable;
|
|
2434
|
+
if (["slider", "input"].includes(node.type) && typeof node.bind === "string" && node.bind.startsWith("state.")) {
|
|
2435
|
+
const spec = doc.state?.[node.bind.slice(6)];
|
|
2436
|
+
if (spec?.type === "number") {
|
|
2437
|
+
for (const field of ["min", "max", "step"]) if (own(node, field) && number(node[field]) === spec[field]) delete node[field];
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2373
2440
|
if (["text", "heading", "callout"].includes(node.type) && own(node, "content")) {
|
|
2374
2441
|
if (!own(node, "text")) {
|
|
2375
2442
|
node.text = node.content;
|
|
@@ -2430,6 +2497,9 @@ function normalizeAuthoring(doc) {
|
|
|
2430
2497
|
if (node.type === "details" && own(node, "open")) node.open = boolean(node.open);
|
|
2431
2498
|
if (node.type === "text" && own(node, "copyable")) node.copyable = boolean(node.copyable);
|
|
2432
2499
|
if (node.type === "code" && own(node, "wrap")) node.wrap = boolean(node.wrap);
|
|
2500
|
+
if (["table", "chart"].includes(node.type) && Array.isArray(node.rows)) {
|
|
2501
|
+
for (const row of node.rows) if (object(row)) for (const cell of Object.values(row)) expression(cell);
|
|
2502
|
+
}
|
|
2433
2503
|
for (const field of ["text", "value", "max", "rows"]) if (own(node, field)) expression(node[field], node.type === "progress");
|
|
2434
2504
|
if (["row", "column", "card", "details"].includes(node.type) && own(node, "children")) node.children = nodes(node.children);
|
|
2435
2505
|
}
|
|
@@ -2445,14 +2515,14 @@ var TYPE_FIELDS = Object.freeze(["size", "weight", "color", "align", "lineHeight
|
|
|
2445
2515
|
var TEXT_SIZES = Object.freeze({ sm: 14, md: 16, lg: 20, xl: 26, hero: 36 });
|
|
2446
2516
|
var TEXT_COLORS = Object.freeze({ default: "var(--du-ink)", muted: "var(--du-muted)", accent: "var(--du-accent)", success: "var(--du-green)", warning: "var(--du-amber)", danger: "var(--du-red)", violet: "var(--du-violet)" });
|
|
2447
2517
|
function validateTypography(value, at2 = "text") {
|
|
2448
|
-
const
|
|
2518
|
+
const fail4 = (message) => {
|
|
2449
2519
|
throw Error(`DSH UI: ${at2}.${message}`);
|
|
2450
2520
|
};
|
|
2451
|
-
if (value.size !== void 0 && !(typeof value.size === "number" && Number.isFinite(value.size) && value.size >= 12 && value.size <= 48) && !Object.hasOwn(TEXT_SIZES, value.size))
|
|
2452
|
-
if (value.weight !== void 0 && ![400, 500, 600, 700, 800].includes(value.weight))
|
|
2453
|
-
if (value.color !== void 0 && (typeof value.color !== "string" || !Object.hasOwn(TEXT_COLORS, value.color) && !/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(value.color)))
|
|
2454
|
-
if (value.align !== void 0 && !["left", "center", "right"].includes(value.align))
|
|
2455
|
-
if (value.lineHeight !== void 0 && !(typeof value.lineHeight === "number" && value.lineHeight >= 1.2 && value.lineHeight <= 2.4))
|
|
2521
|
+
if (value.size !== void 0 && !(typeof value.size === "number" && Number.isFinite(value.size) && value.size >= 12 && value.size <= 48) && !Object.hasOwn(TEXT_SIZES, value.size)) fail4("size must be 12..48 px or sm/md/lg/xl/hero");
|
|
2522
|
+
if (value.weight !== void 0 && ![400, 500, 600, 700, 800].includes(value.weight)) fail4("weight must be 400/500/600/700/800");
|
|
2523
|
+
if (value.color !== void 0 && (typeof value.color !== "string" || !Object.hasOwn(TEXT_COLORS, value.color) && !/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(value.color))) fail4("color must be default/muted/accent/success/warning/danger/violet or #RGB/#RRGGBB");
|
|
2524
|
+
if (value.align !== void 0 && !["left", "center", "right"].includes(value.align)) fail4("align must be left/center/right");
|
|
2525
|
+
if (value.lineHeight !== void 0 && !(typeof value.lineHeight === "number" && value.lineHeight >= 1.2 && value.lineHeight <= 2.4)) fail4("lineHeight must be 1.2..2.4");
|
|
2456
2526
|
}
|
|
2457
2527
|
function typographyStyle(value) {
|
|
2458
2528
|
return { fontSize: value.size === void 0 ? void 0 : TEXT_SIZES[value.size] ?? value.size, fontWeight: value.weight, color: value.color === void 0 ? void 0 : TEXT_COLORS[value.color] ?? value.color, textAlign: value.align, lineHeight: value.lineHeight };
|
|
@@ -2460,23 +2530,23 @@ function typographyStyle(value) {
|
|
|
2460
2530
|
|
|
2461
2531
|
// lib/links.js
|
|
2462
2532
|
function validateLink(node) {
|
|
2463
|
-
const
|
|
2533
|
+
const fail4 = (message) => {
|
|
2464
2534
|
throw Error("DSH UI: " + message);
|
|
2465
2535
|
};
|
|
2466
|
-
if ([node.href, node.path, node.action].filter((v2) => v2 !== void 0).length !== 1)
|
|
2467
|
-
if (node.variant !== void 0 && !["primary", "secondary", "text"].includes(node.variant))
|
|
2536
|
+
if ([node.href, node.path, node.action].filter((v2) => v2 !== void 0).length !== 1) fail4(`node.${node.id}: choose exactly one href (http/https), path (file), or action (Agent follow-up)`);
|
|
2537
|
+
if (node.variant !== void 0 && !["primary", "secondary", "text"].includes(node.variant)) fail4("link/button variant must be primary/secondary/text");
|
|
2468
2538
|
if (node.href !== void 0) {
|
|
2469
|
-
if (typeof node.href !== "string" || node.href.length > 8192 || /[\u0000-\u0020\u007f]/.test(node.href) || !/^https?:\/\//i.test(node.href))
|
|
2539
|
+
if (typeof node.href !== "string" || node.href.length > 8192 || /[\u0000-\u0020\u007f]/.test(node.href) || !/^https?:\/\//i.test(node.href)) fail4("href must be an absolute http/https URL; encode spaces");
|
|
2470
2540
|
let url;
|
|
2471
2541
|
try {
|
|
2472
2542
|
url = new URL(node.href);
|
|
2473
2543
|
} catch {
|
|
2474
|
-
|
|
2544
|
+
fail4("invalid href URL");
|
|
2475
2545
|
}
|
|
2476
|
-
if (!url.hostname || url.username || url.password)
|
|
2546
|
+
if (!url.hostname || url.username || url.password) fail4("href must have a host and must not contain credentials");
|
|
2477
2547
|
}
|
|
2478
2548
|
if (node.path !== void 0) {
|
|
2479
|
-
if (typeof node.path !== "string" || !node.path.trim() || node.path.length > 8192 || /[\u0000-\u001f\u007f]/.test(node.path) || /^\s*(?:[a-z][a-z\d+.-]*:|[\\/]{2})/i.test(node.path) && !/^\s*[a-z]:[\\/]/i.test(node.path))
|
|
2549
|
+
if (typeof node.path !== "string" || !node.path.trim() || node.path.length > 8192 || /[\u0000-\u001f\u007f]/.test(node.path) || /^\s*(?:[a-z][a-z\d+.-]*:|[\\/]{2})/i.test(node.path) && !/^\s*[a-z]:[\\/]/i.test(node.path)) fail4("path must be a local file path, not a URL, network path or command");
|
|
2480
2550
|
}
|
|
2481
2551
|
}
|
|
2482
2552
|
|
|
@@ -2523,12 +2593,12 @@ function safeJson(value, depth = 0, source = false) {
|
|
|
2523
2593
|
function initialState(doc) {
|
|
2524
2594
|
return Object.fromEntries(Object.entries(doc.state).map(([k2, spec]) => [k2, spec.default]));
|
|
2525
2595
|
}
|
|
2526
|
-
function validateState(doc,
|
|
2527
|
-
if (!object2(
|
|
2596
|
+
function validateState(doc, state2) {
|
|
2597
|
+
if (!object2(state2) || Object.keys(state2).length !== Object.keys(doc.state).length) fail("state keys do not match the document");
|
|
2528
2598
|
const result = {};
|
|
2529
2599
|
for (const [k2, s] of Object.entries(doc.state)) {
|
|
2530
|
-
if (!own2(
|
|
2531
|
-
const v2 =
|
|
2600
|
+
if (!own2(state2, k2)) fail(`missing state.${k2}`);
|
|
2601
|
+
const v2 = state2[k2];
|
|
2532
2602
|
if (s.type === "number") {
|
|
2533
2603
|
if (!finite(v2) || v2 < s.min || v2 > s.max) fail(`state.${k2} is outside its numeric range`);
|
|
2534
2604
|
const offset = (v2 - s.min) / s.step;
|
|
@@ -2551,7 +2621,7 @@ function reference(doc, ref) {
|
|
|
2551
2621
|
if (!own2(doc[group], k2)) fail(`unknown reference ${ref}`);
|
|
2552
2622
|
return [group, k2];
|
|
2553
2623
|
}
|
|
2554
|
-
function evaluate(doc,
|
|
2624
|
+
function evaluate(doc, state2) {
|
|
2555
2625
|
const derived = {}, active = /* @__PURE__ */ new Set();
|
|
2556
2626
|
let steps = 0, generatedRows = 0;
|
|
2557
2627
|
const budget = () => {
|
|
@@ -2560,7 +2630,7 @@ function evaluate(doc, state) {
|
|
|
2560
2630
|
const resolve = (ref) => {
|
|
2561
2631
|
budget();
|
|
2562
2632
|
const [group, k2] = reference(doc, ref);
|
|
2563
|
-
if (group !== "derived") return (group === "state" ?
|
|
2633
|
+
if (group !== "derived") return (group === "state" ? state2 : doc.data)[k2];
|
|
2564
2634
|
if (own2(derived, k2)) return derived[k2];
|
|
2565
2635
|
if (active.has(k2)) fail(`cyclic calculation ${k2}`);
|
|
2566
2636
|
active.add(k2);
|
|
@@ -2792,7 +2862,7 @@ function validateDocument(input) {
|
|
|
2792
2862
|
const value = (v2, at2) => {
|
|
2793
2863
|
if (object2(v2)) {
|
|
2794
2864
|
if (own2(v2, "map")) fail("map belongs in derived");
|
|
2795
|
-
validateExpression(v2);
|
|
2865
|
+
validateExpression(v2, 0, void 0, at2);
|
|
2796
2866
|
} else if (!scalar(v2)) fail(`invalid value at ${at2}`);
|
|
2797
2867
|
};
|
|
2798
2868
|
function nodes(list, depth = 0, path2 = "nodes") {
|
|
@@ -2924,7 +2994,7 @@ function validateDocument(input) {
|
|
|
2924
2994
|
break;
|
|
2925
2995
|
case "table": {
|
|
2926
2996
|
if (n2.label !== void 0) text(n2.label, "table label");
|
|
2927
|
-
if (!Array.isArray(n2.rows)) value(n2.rows, "
|
|
2997
|
+
if (!Array.isArray(n2.rows)) value(n2.rows, "node." + n2.id + ".rows");
|
|
2928
2998
|
if (!Array.isArray(n2.columns) || !n2.columns.length || n2.columns.length > 16) fail("invalid table columns");
|
|
2929
2999
|
const cols = /* @__PURE__ */ new Set();
|
|
2930
3000
|
for (const c of n2.columns) {
|
|
@@ -2937,7 +3007,8 @@ function validateDocument(input) {
|
|
|
2937
3007
|
break;
|
|
2938
3008
|
}
|
|
2939
3009
|
case "chart":
|
|
2940
|
-
if (
|
|
3010
|
+
if (n2.rows === void 0) fail("node." + n2.id + '.rows is missing; supply rows:[{label:"\u9879\u76EE",value:123}] or a rows binding, plus labelKey/valueKey matching its fields. Do not invent missing amounts');
|
|
3011
|
+
if (!Array.isArray(n2.rows)) value(n2.rows, "node." + n2.id + ".rows");
|
|
2941
3012
|
if (!["bar", "line"].includes(n2.kind) || !validIdentifier(n2.labelKey) || !validIdentifier(n2.valueKey)) fail("invalid chart");
|
|
2942
3013
|
text(n2.label, "chart label");
|
|
2943
3014
|
if (n2.unit !== void 0) text(n2.unit, "chart unit");
|
|
@@ -2966,8 +3037,8 @@ function validateDocument(input) {
|
|
|
2966
3037
|
evaluate(doc, defaults);
|
|
2967
3038
|
return doc;
|
|
2968
3039
|
}
|
|
2969
|
-
function followupPrompt(doc,
|
|
2970
|
-
const values = validateState(doc,
|
|
3040
|
+
function followupPrompt(doc, state2, actionKey, provenance) {
|
|
3041
|
+
const values = validateState(doc, state2), action = doc.actions[actionKey];
|
|
2971
3042
|
if (!action) fail("unknown follow-up action");
|
|
2972
3043
|
const selected = Object.fromEntries(action.stateKeys.map((k2) => [k2, values[k2]]));
|
|
2973
3044
|
const { derived } = evaluate(doc, values);
|
|
@@ -3050,12 +3121,12 @@ async function request(url, options) {
|
|
|
3050
3121
|
function useSavedState(record, sessionId, preview = false) {
|
|
3051
3122
|
const doc = record.document;
|
|
3052
3123
|
const schemaKey = JSON.stringify(doc.state);
|
|
3053
|
-
const [
|
|
3124
|
+
const [state2, setState] = (0, import_react4.useState)(() => initialState(doc));
|
|
3054
3125
|
const [ready, setReady] = (0, import_react4.useState)(false), [status, setStatus] = (0, import_react4.useState)("\u6B63\u5728\u6062\u590D\u53C2\u6570\u2026");
|
|
3055
3126
|
const [issue, setIssue] = (0, import_react4.useState)(null), [epoch, setEpoch] = (0, import_react4.useState)(0), [tick, wake] = (0, import_react4.useState)(0);
|
|
3056
3127
|
const refs = (0, import_react4.useRef)({ revision: 0, saved: "", saving: false, blocked: true, alive: true, generation: 0, loading: false });
|
|
3057
|
-
const liveState = (0, import_react4.useRef)(
|
|
3058
|
-
liveState.current =
|
|
3128
|
+
const liveState = (0, import_react4.useRef)(state2);
|
|
3129
|
+
liveState.current = state2;
|
|
3059
3130
|
const receive = (0, import_react4.useRef)(null);
|
|
3060
3131
|
(0, import_react4.useEffect)(() => {
|
|
3061
3132
|
if (preview) return;
|
|
@@ -3131,7 +3202,7 @@ function useSavedState(record, sessionId, preview = false) {
|
|
|
3131
3202
|
};
|
|
3132
3203
|
}, [record.documentId, sessionId, schemaKey, preview]);
|
|
3133
3204
|
(0, import_react4.useEffect)(() => {
|
|
3134
|
-
const r = refs.current, signature = JSON.stringify(
|
|
3205
|
+
const r = refs.current, signature = JSON.stringify(state2);
|
|
3135
3206
|
if (!ready || r.blocked || r.saving) return;
|
|
3136
3207
|
if (signature === r.saved) {
|
|
3137
3208
|
setStatus((previous) => /等待保存|准备保存/.test(previous) ? "\u53C2\u6570\u5DF2\u4FDD\u5B58" : previous);
|
|
@@ -3143,7 +3214,7 @@ function useSavedState(record, sessionId, preview = false) {
|
|
|
3143
3214
|
if (r.alive) setStatus("\u6B63\u5728\u4FDD\u5B58\u53C2\u6570\u2026");
|
|
3144
3215
|
const revision2 = r.revision;
|
|
3145
3216
|
try {
|
|
3146
|
-
const saved = checked(await request(STATE_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ documentId: record.documentId, sessionId, revision: revision2, state }) }));
|
|
3217
|
+
const saved = checked(await request(STATE_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ documentId: record.documentId, sessionId, revision: revision2, state: state2 }) }));
|
|
3147
3218
|
if (saved.revision !== revision2 + 1 || JSON.stringify(saved.state) !== signature) throw new Error("Unexpected save response");
|
|
3148
3219
|
r.revision = saved.revision;
|
|
3149
3220
|
r.saved = signature;
|
|
@@ -3164,7 +3235,7 @@ function useSavedState(record, sessionId, preview = false) {
|
|
|
3164
3235
|
}
|
|
3165
3236
|
}, 350);
|
|
3166
3237
|
return () => clearTimeout(timer);
|
|
3167
|
-
}, [
|
|
3238
|
+
}, [state2, ready, tick, record.documentId, sessionId]);
|
|
3168
3239
|
function retry() {
|
|
3169
3240
|
const r = refs.current;
|
|
3170
3241
|
if (r.loading || r.saving) return;
|
|
@@ -3178,7 +3249,7 @@ function useSavedState(record, sessionId, preview = false) {
|
|
|
3178
3249
|
setStatus("\u53C2\u6570\u5DF2\u4FEE\u6539\uFF0C\u7B49\u5F85\u4FDD\u5B58\u2026");
|
|
3179
3250
|
wake((n2) => n2 + 1);
|
|
3180
3251
|
}
|
|
3181
|
-
return { state: preview ? initialState(doc) :
|
|
3252
|
+
return { state: preview ? initialState(doc) : state2, setState, ready: !preview && ready, status: preview ? "\u751F\u6210\u9884\u89C8 \xB7 \u5B8C\u6210\u6821\u9A8C\u540E\u53EF\u64CD\u4F5C" : status, issue, epoch, retry, useRemote: () => load(), keepLocal: () => load(true) };
|
|
3182
3253
|
}
|
|
3183
3254
|
|
|
3184
3255
|
// lib/tool-json.js
|
|
@@ -3498,13 +3569,13 @@ function CanvasPreview({ node }) {
|
|
|
3498
3569
|
var import_react8 = __toESM(require("react"), 1);
|
|
3499
3570
|
|
|
3500
3571
|
// lib/export-runtime-bundle.js
|
|
3501
|
-
var EXPORT_RUNTIME = '(() => {\n // lib/presentation.js\n var UI_ICONS = Object.freeze(["sparkles", "sliders", "layers", "chart", "gauge", "cpu", "database", "info", "check", "warning", "arrow", "target", "external", "file", "globe"]);\n var UI_TONES = Object.freeze(["neutral", "accent", "success", "warning", "danger"]);\n var UI_LAYOUTS = Object.freeze(["dashboard", "workbench", "comparison", "guide", "status", "report"]);\n var UI_ACCENTS = Object.freeze(["blue", "teal", "violet", "amber", "rose"]);\n var UI_SURFACES = Object.freeze(["outline", "soft", "featured"]);\n\n // lib/mechanism-runtime-bundle.js\n var MECHANISM_RUNTIME = \'var __MotionMechanism=(()=>{var it=Object.defineProperty;var Ot=Object.getOwnPropertyDescriptor;var Et=Object.getOwnPropertyNames;var It=Object.prototype.hasOwnProperty;var zt=(t,a)=>{for(var n in a)it(t,n,{get:a[n],enumerable:!0})},Pt=(t,a,n,o)=>{if(a&&typeof a=="object"||typeof a=="function")for(let e of Et(a))!It.call(t,e)&&e!==n&&it(t,e,{get:()=>a[e],enumerable:!(o=Ot(a,e))||o.enumerable});return t};var _t=t=>Pt(it({},"__esModule",{value:!0}),t);var Tt={};zt(Tt,{createMechanismAPI:()=>Ft});var st=Math.PI/180,Ct=Math.sqrt(1.6);function yt({scale:t,azimuth:a=45,elevation:n=30}){let o=a*st,e=n*st;return{sinA:Math.sin(o),cosA:Math.cos(o),sinE:Math.sin(e),cosE:Math.cos(e),k:t*Ct}}function q([t,a,n],o){let{origin:e}=o,{sinA:i,cosA:r,sinE:p,cosE:d,k:m}=yt(o);return[e[0]+(t*i-a*r)*m,e[1]+((t*r+a*i)*p-n*d)*m]}function tt([t,a,n],o){let{sinA:e,cosA:i,sinE:r,cosE:p}=yt(o);return(t*i+a*e)*p+n*r}function vt({x:t,y:a,w:n,d:o,r:e},i=8){let r=Math.max(0,Math.min(e,n/2,o/2)),p=[[t+n-r,a+r,-90],[t+n-r,a+o-r,0],[t+r,a+o-r,90],[t+r,a+r,180]],d=[];for(let[m,s,c]of p){let u=r>0?i:0;for(let f=0;f<=u;f++){let g=(c+(u?90*f/u:45))*st;d.push([m+r*Math.cos(g),s+r*Math.sin(g)])}}return d}function lt(t,a,n,o=40){return Array.from({length:o},(e,i)=>{let r=i/o*Math.PI*2;return[t+n*Math.cos(r),a+n*Math.sin(r)]})}function ct(t,a,n,{pad:o=24,headroom:e=0,azimuth:i=45,elevation:r=30}={}){let p={origin:[0,0],scale:1,azimuth:i,elevation:r},d=t.map(M=>q(M,p)),m=d.map(([M])=>M),s=d.map(([,M])=>M),c=Math.min(...m),u=Math.max(...m),f=Math.min(...s),g=Math.max(...s),h=Math.min((a-o*2)/(u-c),(n-o*2-e)/(g-f));return{origin:[a/2-(c+u)/2*h,e+(n-e)/2-(f+g)/2*h],scale:h,azimuth:i,elevation:r}}var Nt=Object.freeze({parts:96,teeth:64,faces:8192}),Ht=t=>typeof t=="number"&&Number.isFinite(t),y=t=>{throw Error("Motion mechanism: "+t)},v=(t,a,n=-1e4,o=1e4)=>((!Ht(t)||t<n||t>o)&&y(a+" must be a finite number in "+n+".."+o),t),U=(t,a)=>((!Array.isArray(t)||t.length!==3)&&y(a+" must be [x,y,z]"),t.map((n,o)=>v(n,a+"["+o+"]"))),et=t=>typeof t=="string"&&/^[\\\\p{L}_][\\\\p{L}\\\\p{M}\\\\p{N}_]{0,63}$/u.test(t)&&!["constructor","prototype","__proto__"].includes(t),kt=["box","cylinder","gear","rod","spring"],I=(t,a)=>t.map((n,o)=>n+a[o]),B=(t,a)=>t.map((n,o)=>n-a[o]),_=(t,a)=>t.map(n=>n*a),dt=(t,a)=>t.reduce((n,o,e)=>n+o*a[e],0),V=(t,a)=>[t[1]*a[2]-t[2]*a[1],t[2]*a[0]-t[0]*a[2],t[0]*a[1]-t[1]*a[0]],J=t=>{let a=Math.hypot(...t);return a<1e-6&&y("zero-length axis"),_(t,1/a)};function Y(t){(!t||typeof t!="object"||Array.isArray(t))&&y("scene must be an object"),(!Array.isArray(t.parts)||!t.parts.length||t.parts.length>Nt.parts)&&y("parts requires 1..96 objects");let a=new Set,n=new Set;for(let[o,e]of t.parts.entries()){let i="parts["+o+"]";(!e||typeof e!="object"||!et(e.id)||a.has(e.id))&&y(i+".id must be a unique identifier"),a.add(e.id),kt.includes(e.type)||y(i+".type must be "+kt.join("/")),e.group!==void 0&&(et(e.group)||y(i+".group must be an identifier"),n.add(e.group));for(let r of["label","description"])e[r]!==void 0&&(typeof e[r]!="string"||e[r].length>1024)&&y(i+"."+r+" must be short text");if(e.cover!==void 0&&typeof e.cover!="boolean"&&y(i+".cover must be boolean"),e.material!==void 0&&!["metal","dark","accent","warm","cool"].includes(e.material)&&y(i+".material must be metal/dark/accent/warm/cool"),e.at!==void 0&&U(e.at,i+".at"),e.explode!==void 0&&U(e.explode,i+".explode"),e.rotation!==void 0&&v(e.rotation,i+".rotation",-1e9,1e9),e.axis!==void 0&&!["x","y","z"].includes(e.axis)&&y(i+".axis must be x/y/z"),e.type==="box"){let r=U(e.size,i+".size");r.some(p=>p<=0||p>2e3)&&y(i+".size must be positive and <=2000"),e.round!==void 0&&v(e.round,i+".round",0,Math.min(r[0],r[1])/2)}if(["cylinder","gear"].includes(e.type)&&(v(e.radius,i+".radius",.1,1e3),v(e.height??8,i+".height",.1,1e3),e.inner!==void 0&&v(e.inner,i+".inner",0,e.radius-.01)),e.type==="gear"){let r=v(e.teeth,i+".teeth",6,64);Number.isInteger(r)||y(i+".teeth must be an integer"),e.module!==void 0&&v(e.module,i+".module",.1,e.radius/3)}if(["rod","spring"].includes(e.type)&&(U(e.from,i+".from"),U(e.to,i+".to"),Math.hypot(...B(e.to,e.from))<.1&&y(i+" endpoints must differ"),v(e.radius??2,i+".radius",.1,200)),e.type==="spring"){let r=v(e.turns??8,i+".turns",2,24);Number.isInteger(r)||y(i+".turns must be integer")}}if(t.groups!==void 0){(!Array.isArray(t.groups)||t.groups.length>12)&&y("groups must be an array of <=12 labels");let o=new Set;for(let e of t.groups)(!e||!et(e.id)||o.has(e.id)||!n.has(e.id)||typeof e.label!="string"||e.label.length>128)&&y("groups must name unique existing part groups"),o.add(e.id)}if(t.bounds!==void 0){(!Array.isArray(t.bounds)||t.bounds.length!==2)&&y("bounds must be [minXYZ,maxXYZ]");let[o,e]=t.bounds.map((i,r)=>U(i,"bounds["+r+"]"));o.some((i,r)=>i>=e[r])&&y("bounds min must be below max on every axis")}if(t.azimuth!==void 0&&v(t.azimuth,"azimuth",10,80),t.elevation!==void 0&&v(t.elevation,"elevation",15,70),t.title!==void 0&&(typeof t.title!="string"||t.title.length>256)&&y("title must be short text"),t.bind!==void 0){(!t.bind||typeof t.bind!="object"||Array.isArray(t.bind))&&y("bind must be an object");for(let[o,e]of Object.entries(t.bind))(!["explode","selected","cutaway"].includes(o)||!et(e))&&y("bind only accepts declared state keys for explode/selected/cutaway")}return t}function Lt(t){return t==="x"?[[0,1,0],[0,0,1],[1,0,0]]:t==="y"?[[0,0,1],[1,0,0],[0,1,0]]:[[1,0,0],[0,1,0],[0,0,1]]}var at=(t,a,n,o)=>I(I(_(t[0],a),_(t[1],n)),_(t[2],o));function Rt(t,a,n,o){let e=t.map(([m,s])=>at(n,m,s,-a/2)),i=t.map(([m,s])=>at(n,m,s,a/2)),r=[],p=o?.map(([m,s])=>at(n,m,s,a/2)),d=o?.map(([m,s])=>at(n,m,s,-a/2));r.push({points:i,holes:p?[p.slice().reverse()]:[],normal:n[2]},{points:e.slice().reverse(),holes:d?[d]:[],normal:_(n[2],-1)});for(let m=0;m<t.length;m++){let s=(m+1)%t.length;Math.hypot(...B(e[s],e[m]))<1e-6||(r.push({points:[e[m],e[s],i[s],i[m]],normal:J(V(B(e[s],e[m]),n[2]))}),o&&r.push({points:[d[s],d[m],p[m],p[s]],normal:J(V(B(d[m],d[s]),n[2]))}))}return r}function ot(t){let a=Lt(t.axis),n,o,e;if(t.type==="box"&&(n=vt({x:-t.size[0]/2,y:-t.size[1]/2,w:t.size[0],d:t.size[1],r:t.round??Math.min(2,t.size[0]/2,t.size[1]/2)},3),o=t.size[2]),t.type==="cylinder"&&(n=lt(0,0,t.radius,24),o=t.height??8),t.type==="gear"){let s=Math.PI*2/t.teeth,c=t.module??t.radius*2/t.teeth;n=[];for(let u=0;u<t.teeth;u++)for(let[f,g]of[[-.5,t.radius-c*.85],[-.32,t.radius-c*.85],[-.17,t.radius+c*.7],[.17,t.radius+c*.7],[.32,t.radius-c*.85]]){let h=(u+f)*s;n.push([Math.cos(h)*g,Math.sin(h)*g])}o=t.height??8}if(t.type==="rod"){let s=J(B(t.to,t.from)),c=J(V(s,Math.abs(s[2])<.9?[0,0,1]:[0,1,0]));a=[c,V(s,c),s],n=lt(0,0,t.radius??2,16),o=Math.hypot(...B(t.to,t.from))}if(t.type==="spring"){let s=J(B(t.to,t.from)),c=J(V(s,Math.abs(s[2])<.9?[0,0,1]:[0,1,0])),u=V(s,c),f=[];for(let g=0;g<=128;g++){let h=g/128,M=h*(t.turns??8)*Math.PI*2,O=Math.min(1,h*12,(1-h)*12);f.push(I(I(t.from,_(B(t.to,t.from),h)),I(_(c,Math.cos(M)*(t.radius??6)*O),_(u,Math.sin(M)*(t.radius??6)*O))))}return{line:f,points:f}}let i=t.rotation??0,r=Math.cos(i),p=Math.sin(i);n=n.map(([s,c])=>[s*r-c*p,s*p+c*r]);let d=t.inner?n.map(([s,c])=>{let u=Math.atan2(c,s);return[Math.cos(u)*t.inner,Math.sin(u)*t.inner]}):void 0;e=Rt(n,o,a,d);let m=t.type==="rod"?_(I(t.from,t.to),.5):t.at??[0,0,0];return e=e.map(s=>({...s,points:s.points.map(c=>I(c,m)),holes:s.holes?.map(c=>c.map(u=>I(u,m)))})),{faces:e,points:e.flatMap(s=>s.points)}}function wt(t){if(t.bounds){let[a,n]=t.bounds;return Array.from({length:8},(o,e)=>[e&1?n[0]:a[0],e&2?n[1]:a[1],e&4?n[2]:a[2]])}return t.parts.flatMap(a=>ot(a).points.flatMap(o=>[o,I(o,a.explode??[0,0,0])]))}function W({driverTeeth:t=16,drivenTeeth:a=32,rpm:n=30,angle:o=0,module:e=2}={}){for(let[i,r]of Object.entries({driverTeeth:t,drivenTeeth:a}))(!Number.isInteger(r)||r<6||r>64)&&y(i+" must be integer 6..64");return v(n,"rpm",-600,600),v(o,"angle",-1e9,1e9),v(e,"module",.1,10),{driverRadius:t*e/2,drivenRadius:a*e/2,centerDistance:(t+a)*e/2,driverAngle:o,drivenAngle:-o*t/a+Math.PI-Math.PI/a,driverRpm:n,drivenRpm:-n*t/a,ratio:a/t}}function X({angle:t=0,radius:a=20,rod:n=70,z:o=20}={}){v(t,"angle",-1e9,1e9),v(a,"radius",.1,200),v(n,"rod",.1,1e3),v(o,"z"),n<=a&&y("connecting rod length must exceed crank radius");let e=[a*Math.cos(t),a*Math.sin(t),o],i=e[0]+Math.sqrt(n*n-e[1]*e[1]);return{crank:e,piston:[i,0,o],position:i,stroke:a*2,angle:t}}function Mt(t,a,n,o=.16){return v(t,"value",-1e9,1e9),v(a,"target",-1e9,1e9),v(n,"delta",0,.1),v(o,"tau",.01,10),t+(a-t)*(1-Math.exp(-n/o))}var $t=Math.PI*2;function nt(t,a){Y(t);let n=a&&!t.bounds?t.parts.filter(o=>!a.cutaway||!o.cover).flatMap(o=>ot(o).points.map(e=>I(e,_(o.explode??[0,0,0],a.explode??0)))):wt(t);return ct(n.length?n:[[0,0,0],[1,1,1]],600,340,{pad:24,azimuth:t.azimuth??45,elevation:t.elevation??30})}var At=t=>t.map(([a,n],o)=>(o?"L":"M")+Math.round(a*10)/10+" "+Math.round(n*10)/10).join("")+"Z";function mt(t,a,{explode:n=0,selected:o="all",cutaway:e=!1,pose:i={}}={},r=new Map){if(typeof n!="number"||!Number.isFinite(n)||n<0||n>1)throw Error("Motion mechanism: explode must be 0..1");if(typeof o!="string"||typeof e!="boolean")throw Error("Motion mechanism: selected must be text and cutaway boolean");if(!i||typeof i!="object"||Array.isArray(i))throw Error("Motion mechanism: pose must be an object");for(let c of Object.keys(i))if(!t.parts.some(u=>u.id===c))throw Error("Motion mechanism: unknown pose part "+c);let p=(a.azimuth??45)*$t/360,d=(a.elevation??30)*$t/360,m=[Math.cos(p)*Math.cos(d),Math.sin(p)*Math.cos(d),Math.sin(d)],s=[];for(let c of t.parts){if(e&&c.cover)continue;let u=i[c.id]??{};for(let $ of Object.keys(u))if(!["at","rotation","from","to"].includes($))throw Error("Motion mechanism: unsupported pose field "+$);let f={...c,...u},g=JSON.stringify(f),h=r.get(c.id);h?.key!==g&&(Y({parts:[f]}),h={key:g,...ot(f)},r.set(c.id,h));let M=_(f.explode??[0,0,0],n),O=Math.min(...h.points.map($=>$[2]))+M[2],N=o==="all"||o===c.id||o===c.group;if(h.line){let $=h.line.map(P=>I(P,M));s.push({floor:O,key:f.id+"_line",part:f.id,group:f.group,d:$.map((P,A)=>(A?"L":"M")+q(P,a).join(" ")).join(""),depth:tt($[Math.floor($.length/2)],a),line:!0,tone:1,material:f.material??"metal",active:N});continue}for(let[$,P]of h.faces.entries()){if(dt(P.normal,m)<=1e-4)continue;let w=P.points.map(S=>I(S,M)),T=P.holes?.map(S=>S.map(H=>I(H,M))),D=_(w.reduce((S,H)=>I(S,H),[0,0,0]),1/w.length),G=dt(P.normal,[-.25,-.4,.88]);s.push({floor:O,key:f.id+"_"+$,part:f.id,group:f.group,d:At(w.map(S=>q(S,a)))+(T??[]).map(S=>At(S.map(H=>q(H,a)))).join(""),depth:tt(D,a),line:!1,tone:G>.5?0:G>.1?1:G>-.4?2:3,material:f.material??"metal",active:N})}}if(s.length>8192)throw Error("Motion mechanism: face budget exceeded");return s.sort((c,u)=>c.floor-u.floor||c.depth-u.depth||c.key.localeCompare(u.key))}var z=(t,a,n,o,e,i={})=>({id:t,type:"box",label:a,at:n,size:o,group:e,...i}),F=(t,a,n,o,e,i,r={})=>({id:t,type:"cylinder",label:a,at:n,radius:o,height:e,group:i,...r});function ut(t,a,n,o,e=3,i=18){return[[-1,-1],[-1,1],[1,-1],[1,1]].map(([r,p],d)=>F(o+"_bolt_"+d,"\\\\u56FA\\\\u5B9A\\\\u87BA\\\\u6813",[t+r*i,a+p*i,n],e,3,o,{material:"dark",explode:[0,0,26]}))}function ft(){return{title:"\\\\u5206\\\\u5C42\\\\u7ED3\\\\u6784 \\\\xB7 \\\\u793A\\\\u610F\\\\u88C5\\\\u914D",groups:[{id:"base",label:"\\\\u5E95\\\\u5EA7",description:"\\\\u652F\\\\u6491\\\\u6574\\\\u4F53\\\\uFF0C\\\\u5E76\\\\u63D0\\\\u4F9B\\\\u5B89\\\\u88C5\\\\u4F4D\\\\u7F6E\\\\u3002"},{id:"board",label:"\\\\u529F\\\\u80FD\\\\u677F",description:"\\\\u8FDE\\\\u63A5\\\\u8F93\\\\u5165\\\\u4E0E\\\\u5904\\\\u7406\\\\u6A21\\\\u5757\\\\uFF1B\\\\u793A\\\\u610F\\\\u7ED3\\\\u6784\\\\uFF0C\\\\u4E0D\\\\u5BF9\\\\u5E94\\\\u7279\\\\u5B9A\\\\u4EA7\\\\u54C1\\\\u3002"},{id:"sink",label:"\\\\u6563\\\\u70ED\\\\u5C42",description:"\\\\u5C06\\\\u70ED\\\\u91CF\\\\u4F20\\\\u5230\\\\u66F4\\\\u5927\\\\u7684\\\\u8868\\\\u9762\\\\u79EF\\\\u3002"},{id:"cover",label:"\\\\u5916\\\\u58F3",description:"\\\\u4FDD\\\\u62A4\\\\u5185\\\\u90E8\\\\uFF1B\\\\u5256\\\\u5F00\\\\u9009\\\\u9879\\\\u901A\\\\u8FC7\\\\u9690\\\\u85CF\\\\u5916\\\\u58F3\\\\u5C55\\\\u793A\\\\u7ED3\\\\u6784\\\\u3002"}],parts:[z("base","\\\\u5B89\\\\u88C5\\\\u5E95\\\\u5EA7",[0,0,0],[120,85,10],"base",{round:6,material:"metal"}),...[-1,1].flatMap((t,a)=>[-1,1].map((n,o)=>F("foot_"+a+o,"\\\\u9632\\\\u6ED1\\\\u811A",[t*46,n*30,-8],6,7,"base",{material:"dark"}))),z("board","\\\\u529F\\\\u80FD\\\\u677F",[0,0,15],[96,62,4],"board",{round:3,material:"cool",explode:[0,0,35]}),z("chip","\\\\u5904\\\\u7406\\\\u6A21\\\\u5757",[-16,0,22],[25,24,10],"board",{round:2,material:"dark",explode:[0,0,35]}),z("connector","\\\\u8FDE\\\\u63A5\\\\u7AEF\\\\u53E3",[32,0,24],[16,36,14],"board",{round:2,material:"warm",explode:[0,0,35]}),...ut(0,0,20,"board",2,24),z("spreader","\\\\u5BFC\\\\u70ED\\\\u5E95\\\\u677F",[-16,0,32],[44,42,5],"sink",{round:2,material:"metal",explode:[-10,0,65]}),...Array.from({length:7},(t,a)=>z("fin_"+a,"\\\\u6563\\\\u70ED\\\\u9CCD\\\\u7247",[-34+a*6,0,44],[2.4,40,20],"sink",{round:1,material:"metal",explode:[-10,0,65]})),z("top","\\\\u9876\\\\u76D6",[0,0,61],[124,89,5],"cover",{round:6,cover:!0,material:"metal",explode:[12,0,85]}),z("side","\\\\u4FA7\\\\u677F",[0,-44,32],[124,4,58],"cover",{round:2,cover:!0,material:"metal",explode:[12,-22,50]})]}}function pt({driverTeeth:t=16,drivenTeeth:a=32,module:n=1.5}={}){let o=W({driverTeeth:t,drivenTeeth:a,module:n}),e=o.centerDistance;return{title:"\\\\u9F7F\\\\u8F6E\\\\u4F20\\\\u52A8 \\\\xB7 \\\\u7B80\\\\u5316\\\\u76F4\\\\u9F7F\\\\u8F6E\\\\u793A\\\\u610F",azimuth:70,elevation:55,groups:[{id:"frame",label:"\\\\u652F\\\\u67B6",description:"\\\\u56FA\\\\u5B9A\\\\u8F74\\\\u5FC3\\\\u4F4D\\\\u7F6E\\\\uFF1B\\\\u4E24\\\\u8F74\\\\u4E2D\\\\u5FC3\\\\u8DDD\\\\u7531\\\\u9F7F\\\\u6570\\\\u4E0E\\\\u6A21\\\\u6570\\\\u5171\\\\u540C\\\\u786E\\\\u5B9A\\\\u3002"},{id:"driver",label:"\\\\u4E3B\\\\u52A8\\\\u8F6E",description:"\\\\u8F93\\\\u5165\\\\u8F6C\\\\u901F\\\\uFF0C\\\\u7531\\\\u9F7F\\\\u6570\\\\u51B3\\\\u5B9A\\\\u8282\\\\u5706\\\\u534A\\\\u5F84\\\\u3002"},{id:"driven",label:"\\\\u4ECE\\\\u52A8\\\\u8F6E",description:"\\\\u5916\\\\u556E\\\\u5408\\\\u8F6C\\\\u5411\\\\u76F8\\\\u53CD\\\\uFF0C\\\\u8F6C\\\\u901F\\\\u6309\\\\u9F7F\\\\u6570\\\\u6BD4\\\\u53D8\\\\u5316\\\\u3002"},{id:"cover",label:"\\\\u5916\\\\u58F3",description:"\\\\u9690\\\\u85CF\\\\u76D6\\\\u677F\\\\u4EE5\\\\u89C2\\\\u5BDF\\\\u4F20\\\\u52A8\\\\uFF1B\\\\u4E0D\\\\u662F\\\\u52A0\\\\u5DE5\\\\u6216\\\\u53D7\\\\u529B\\\\u4EFF\\\\u771F\\\\u3002"}],parts:[z("base","\\\\u5B89\\\\u88C5\\\\u5E95\\\\u5EA7",[30,0,-8],[140,90,10],"frame",{round:6,material:"metal"}),...ut(30,0,0,"frame",3,32),...[0,e].flatMap((i,r)=>[F("bearing_"+r,"\\\\u8F74\\\\u627F\\\\u5EA7",[i,0,4],10,12,"frame",{inner:4,material:"dark"}),F("shaft_"+r,"\\\\u4F20\\\\u52A8\\\\u8F74",[i,0,16],3.8,28,r?"driven":"driver",{material:"metal",explode:[r?24:-24,0,20]}),F("hub_"+r,"\\\\u8F6E\\\\u6BC2",[i,0,27],6,6,r?"driven":"driver",{inner:3.8,material:"warm",explode:[r?24:-24,0,20]})]),{id:"driverGear",type:"gear",label:"\\\\u4E3B\\\\u52A8\\\\u9F7F\\\\u8F6E",group:"driver",at:[0,0,20],radius:o.driverRadius,teeth:t,module:n,height:7,inner:4,material:"accent",explode:[-24,0,20]},{id:"drivenGear",type:"gear",label:"\\\\u4ECE\\\\u52A8\\\\u9F7F\\\\u8F6E",group:"driven",at:[e,0,20],radius:o.drivenRadius,teeth:a,module:n,height:7,inner:4,material:"cool",rotation:o.drivenAngle,explode:[24,0,20]},z("cover","\\\\u9632\\\\u62A4\\\\u76D6\\\\u677F",[30,0,36],[140,90,4],"cover",{round:6,cover:!0,material:"metal",explode:[0,0,62]})]}}function ht({radius:t=20,rod:a=70,angle:n=0}={}){let o=X({radius:t,rod:a,angle:n,z:28});return{title:"\\\\u66F2\\\\u67C4\\\\u8FDE\\\\u6746 \\\\xB7 \\\\u65CB\\\\u8F6C\\\\u8F6C\\\\u4E3A\\\\u5F80\\\\u590D",groups:[{id:"frame",label:"\\\\u652F\\\\u67B6\\\\u4E0E\\\\u5BFC\\\\u8F68",description:"\\\\u652F\\\\u6491\\\\u8F74\\\\u5FC3\\\\uFF0C\\\\u9650\\\\u5236\\\\u6ED1\\\\u5757\\\\u6CBF\\\\u540C\\\\u4E00\\\\u65B9\\\\u5411\\\\u8FD0\\\\u52A8\\\\u3002"},{id:"crank",label:"\\\\u66F2\\\\u67C4",description:"\\\\u66F2\\\\u67C4\\\\u7ED5\\\\u56FA\\\\u5B9A\\\\u8F74\\\\u5FC3\\\\u65CB\\\\u8F6C\\\\u3002"},{id:"rod",label:"\\\\u8FDE\\\\u6746",description:"\\\\u8FDE\\\\u63A5\\\\u66F2\\\\u67C4\\\\u9500\\\\u548C\\\\u6ED1\\\\u5757\\\\uFF0C\\\\u957F\\\\u5EA6\\\\u4FDD\\\\u6301\\\\u4E0D\\\\u53D8\\\\u3002"},{id:"piston",label:"\\\\u6ED1\\\\u5757",description:"\\\\u6CBF\\\\u5BFC\\\\u8F68\\\\u5F80\\\\u590D\\\\uFF1B\\\\u5B8C\\\\u6574\\\\u884C\\\\u7A0B\\\\u7B49\\\\u4E8E\\\\u66F2\\\\u67C4\\\\u534A\\\\u5F84\\\\u7684\\\\u4E24\\\\u500D\\\\u3002"}],parts:[z("base","\\\\u5B89\\\\u88C5\\\\u5E95\\\\u5EA7",[35,0,-6],[175,80,10],"frame",{round:6,material:"metal"}),...ut(35,0,1,"frame",3,30),F("bearing","\\\\u66F2\\\\u8F74\\\\u8F74\\\\u627F",[0,0,7],11,15,"frame",{inner:4,material:"dark"}),F("axle","\\\\u66F2\\\\u8F74",[0,0,15],3.8,26,"crank",{material:"metal",explode:[0,-18,18]}),F("flywheel","\\\\u66F2\\\\u67C4\\\\u76D8",[0,0,20],t+6,6,"crank",{inner:4,material:"accent",explode:[0,-18,18]}),z("railA","\\\\u5BFC\\\\u8F68",[74,-16,13],[85,5,6],"frame",{round:1,material:"dark"}),z("railB","\\\\u5BFC\\\\u8F68",[74,16,13],[85,5,6],"frame",{round:1,material:"dark"}),F("crankPin","\\\\u66F2\\\\u67C4\\\\u9500",o.crank,3,12,"crank",{material:"warm",explode:[0,-18,18]}),{id:"link",type:"rod",label:"\\\\u8FDE\\\\u6746",from:o.crank,to:o.piston,radius:2.4,group:"rod",material:"metal",explode:[0,0,45]},z("piston","\\\\u6ED1\\\\u5757",[o.position,0,22],[18,24,16],"piston",{round:3,material:"cool",explode:[20,0,18]}),F("pistonPin","\\\\u6ED1\\\\u5757\\\\u9500",o.piston,3,10,"piston",{material:"warm",explode:[20,0,18]})]}}var St=`\\n.mui-mechanism{font:15px/1.7 system-ui,sans-serif;color:var(--canvas-ink);background:var(--canvas-bg);border:1px solid var(--canvas-line);border-radius:24px;padding:20px;max-width:100%;box-sizing:border-box}.mui-mechanism *{box-sizing:border-box}.mui-mechanism h2{font-size:22px;line-height:1.35;margin:0 0 8px;font-weight:750}.mui-mechanism p{margin:0;color:var(--canvas-muted)}\\n.mui-mechanism-svg{display:block;width:100%;height:auto;max-height:420px;touch-action:pan-y}.mui-mechanism-svg path{stroke:color-mix(in srgb,var(--canvas-ink) 38%,var(--canvas-bg));stroke-width:.8;stroke-linejoin:round;vector-effect:non-scaling-stroke;cursor:pointer;fill:var(--mech-base,var(--canvas-soft))}.mui-mechanism-svg [data-material=metal]{--mech-base:color-mix(in srgb,var(--canvas-muted) 32%,var(--canvas-bg))}.mui-mechanism-svg [data-material=dark]{--mech-base:color-mix(in srgb,var(--canvas-ink) 78%,var(--canvas-bg))}.mui-mechanism-svg [data-material=accent]{--mech-base:var(--canvas-accent)}.mui-mechanism-svg [data-material=cool]{--mech-base:color-mix(in srgb,#22998a 70%,var(--canvas-bg))}.mui-mechanism-svg [data-material=warm]{--mech-base:color-mix(in srgb,#dd9c42 75%,var(--canvas-bg))}\\n.mui-mechanism-svg [data-tone="0"]{fill:color-mix(in srgb,var(--mech-base) 74%,var(--canvas-bg))}.mui-mechanism-svg [data-tone="1"]{fill:var(--mech-base)}.mui-mechanism-svg [data-tone="2"]{fill:color-mix(in srgb,var(--mech-base) 85%,var(--canvas-ink))}.mui-mechanism-svg [data-tone="3"]{fill:color-mix(in srgb,var(--mech-base) 68%,var(--canvas-ink))}.mui-mechanism-svg [data-line]{fill:none;stroke:var(--mech-base);stroke-width:2}.mui-mechanism-svg [data-active=false]{opacity:.2}.mui-mechanism-svg [data-active=true]{opacity:1}\\n.mui-mechanism-nav{display:flex;flex-wrap:wrap;gap:7px;margin:8px 0 12px}.mui-mechanism button{font:inherit;color:var(--canvas-ink);background:var(--canvas-bg);border:1px solid var(--canvas-line);border-radius:999px;padding:6px 13px;cursor:pointer;min-height:36px}.mui-mechanism button[aria-pressed=true]{color:var(--canvas-bg);background:var(--canvas-ink);border-color:var(--canvas-ink)}.mui-mechanism button:focus-visible,.mui-mechanism input:focus-visible{outline:2px solid var(--canvas-accent);outline-offset:3px}.mui-mechanism button:disabled{opacity:.5;cursor:default}\\n.mui-mechanism-controls{display:flex;align-items:center;flex-wrap:wrap;gap:14px;padding:12px 14px;border-radius:16px;background:var(--canvas-soft);margin:8px 0}.mui-mechanism-controls label{display:flex;align-items:center;gap:9px;flex:1 1 180px;min-width:0}.mui-mechanism-controls input[type=range]{flex:1;min-width:70px;accent-color:var(--canvas-accent)}.mui-mechanism-controls input[type=checkbox]{accent-color:var(--canvas-accent)}.mui-mechanism-controls output{font-variant-numeric:tabular-nums;min-width:40px;text-align:right;font-weight:650}.mui-mechanism-readout{display:block;padding:10px 0;font-weight:700;font-variant-numeric:tabular-nums;color:var(--canvas-ink)}.mui-mechanism-description{min-height:0;font-size:14px}\\n.mui-mechanism[data-style=editorial]{border:0;border-top:1px solid var(--canvas-line);border-radius:0;padding:16px 0}.mui-mechanism[data-style=editorial] h2{font-family:ui-serif,Georgia,serif;font-weight:650}.mui-mechanism[data-style=editorial] .mui-mechanism-controls{border-radius:0;background:transparent;border-block:1px solid var(--canvas-line)}\\n.mui-mechanism[data-style=technical]{border-radius:10px}.mui-mechanism[data-style=technical] button,.mui-mechanism[data-style=technical] .mui-mechanism-controls{border-radius:6px}.mui-mechanism[data-style=technical] .mui-mechanism-readout{font-family:ui-monospace,Consolas,monospace}\\n.mui-mechanism[data-style=soft]{border:0;background:var(--canvas-soft);border-radius:28px 28px 28px 10px}.mui-mechanism[data-style=soft] .mui-mechanism-controls{background:var(--canvas-bg);border-radius:22px}.mui-mechanism[data-style=expressive] h2{font-size:28px;font-weight:850;border-left:5px solid var(--canvas-accent);padding-left:14px}.mui-mechanism[data-style=expressive]{border:0;border-radius:0}.mui-mechanism[data-style=prismframe]{border:1.5px solid var(--canvas-line);box-shadow:4px 5px 0 color-mix(in srgb,var(--canvas-accent) 14%,var(--canvas-bg))}.mui-mechanism[data-style=aurora]{border-radius:28px;box-shadow:0 16px 30px -25px #30204d66}.mui-mechanism[data-style=aurora] .mui-mechanism-controls{border-radius:24px}\\n@media(max-width:500px){.mui-mechanism{padding:14px;border-radius:20px}.mui-mechanism h2{font-size:20px}.mui-mechanism-controls{padding:10px}.mui-mechanism-nav{gap:5px}.mui-mechanism button{padding:6px 10px;font-size:14px}}\\n@media(prefers-reduced-motion:reduce){.mui-mechanism *{animation:none!important;transition:none!important}}\\n@media(forced-colors:active){.mui-mechanism-svg path{fill:Canvas;stroke:CanvasText}.mui-mechanism button[aria-pressed=true]{background:Highlight;color:HighlightText}}\\n`;var xt="http://www.w3.org/2000/svg",C=(t,a,n)=>{let o=document.createElement(t);return a&&(o.className=a),n!==void 0&&(o.textContent=n),o};function Ft(t){function a(o,e){let i=typeof o=="string"?document.querySelector(o):o;if(!i||!i.replaceChildren)throw Error("Motion mechanism: target element not found");Y(e);let r=structuredClone({...e,onSelect:void 0}),p=nt(r),d={explode:0,selected:"all",cutaway:!1,pose:{}},m=!1,s="",c="",u=0,f=new Map,g=new Map,h=new Map,M=[],O=C("section","mui-mechanism"),N=C("h2",null,r.title??"\\\\u7ED3\\\\u6784\\\\u56FE\\\\u89E3"),$=document.createElementNS(xt,"svg"),P=document.createElementNS(xt,"g"),A=C("div","mui-mechanism-nav"),w=C("div","mui-mechanism-controls"),T=C("p","mui-mechanism-description"),D=C("output","mui-mechanism-readout"),G=C("style");G.textContent=St,N.hidden=r.title==="",O.setAttribute("aria-label",r.title??"\\\\u7ED3\\\\u6784\\\\u56FE\\\\u89E3"),$.setAttribute("class","mui-mechanism-svg"),$.setAttribute("viewBox","0 0 600 340"),$.setAttribute("role","img"),$.setAttribute("aria-label","\\\\u53EF\\\\u62C6\\\\u89E3\\\\u7684\\\\u7ED3\\\\u6784\\\\u793A\\\\u610F\\\\u56FE\\\\uFF1B\\\\u4F7F\\\\u7528\\\\u4E0B\\\\u65B9\\\\u6309\\\\u94AE\\\\u9009\\\\u62E9\\\\u90E8\\\\u4EF6"),$.append(P),O.append(G,N,$,A,w,D,T),i.replaceChildren(O);let S=()=>r.groups?.length?r.groups:r.parts.map(l=>({id:l.id,label:l.label??l.id,description:l.description??""}));function H(l){r.bind?.selected?t.setState({[r.bind.selected]:l}):typeof e.onSelect=="function"?e.onSelect(l):Q({selected:l})}function K(){if(A.replaceChildren(),h.clear(),!r.bind?.selected&&typeof e.onSelect!="function"){A.hidden=!0;return}A.hidden=!1;for(let l of[{id:"all",label:"\\\\u5168\\\\u90E8",description:""},...S()]){let b=C("button",null,l.label);b.type="button",b.setAttribute("aria-pressed",String(d.selected===l.id)),b.addEventListener("click",()=>H(l.id)),h.set(l.id,b),A.append(b)}}let x,rt,L;if(r.bind?.explode){let l=C("label",null,"\\\\u62C6\\\\u89E3\\\\u8FDB\\\\u5EA6");x=C("input"),x.type="range",x.min="0",x.max="1",x.step=".01",x.setAttribute("aria-label","\\\\u62C6\\\\u89E3\\\\u8FDB\\\\u5EA6"),rt=C("output"),x.addEventListener("input",()=>t.setState({[r.bind.explode]:Number(x.value)})),l.append(x,rt),w.append(l)}if(r.bind?.cutaway&&r.parts.some(l=>l.cover)){let l=C("label",null,"\\\\u5256\\\\u5F00\\\\u5916\\\\u58F3");L=C("input"),L.type="checkbox",L.setAttribute("aria-label","\\\\u5256\\\\u5F00\\\\u5916\\\\u58F3"),L.addEventListener("change",()=>t.setState({[r.bind.cutaway]:L.checked})),l.prepend(L),w.append(l)}w.hidden=!w.childNodes.length;function jt(l){let b=JSON.stringify([l.explode,l.cutaway]);b!==s&&(p=nt(r,l),s=b);let E=mt(r,p,l,f),k=new Set;for(let j of E){k.add(j.key);let R=g.get(j.key);R||(R=document.createElementNS(xt,"path"),R.setAttribute("fill-rule","evenodd"),g.set(j.key,R));for(let[gt,bt]of Object.entries({d:j.d,"data-part":j.part,"data-material":j.material,"data-tone":j.tone,"data-active":j.active}))R.getAttribute(gt)!==String(bt)&&R.setAttribute(gt,String(bt));j.line?R.setAttribute("data-line",""):R.removeAttribute("data-line")}for(let[j,R]of g)k.has(j)||(R.remove(),g.delete(j));let Z=E.map(j=>j.key).join("|");if(Z!==c){for(let j of E)P.append(g.get(j.key));c=Z}u++}function Q(l={}){if(m)return;for(let k of Object.keys(l))if(!["explode","selected","cutaway","pose","parts","readout"].includes(k))throw Error("Motion mechanism: unknown update field "+k);if(l.parts){let k={...r,parts:l.parts};Y(k);let Z=nt(k);mt(k,Z,{...d,...l},new Map),r=k,p=Z,f.clear(),c="",s=""}let b={...d,...l};l.pose&&(b.pose=l.pose),jt(b),d=b;for(let[k,Z]of h)Z.setAttribute("aria-pressed",String(b.selected===k));let E=S().find(k=>k.id===b.selected)??r.parts.find(k=>k.id===b.selected);T.textContent=E?.description??(b.selected==="all"?"\\\\u9009\\\\u62E9\\\\u4E00\\\\u4E2A\\\\u90E8\\\\u4EF6\\\\uFF0C\\\\u67E5\\\\u770B\\\\u5B83\\\\u7684\\\\u804C\\\\u8D23\\\\uFF1B\\\\u62C6\\\\u89E3\\\\u53EA\\\\u5C55\\\\u793A\\\\u88C5\\\\u914D\\\\u5173\\\\u7CFB\\\\u3002":""),x&&(x.value=String(b.explode),rt.textContent=Math.round(b.explode*100)+"%"),L&&(L.checked=b.cutaway),l.readout!==void 0&&(D.textContent=String(l.readout))}return $.addEventListener("click",l=>{let b=l.target.closest("[data-part]");if(!b)return;let E=r.parts.find(k=>k.id===b.getAttribute("data-part"));E&&H(r.groups?.length?E.group??E.id:E.id)}),K(),M.push(t.subscribe(l=>{if(m)return;let b={};for(let[E,k]of Object.entries(r.bind??{})){if(!Object.hasOwn(l.state,k))throw Error("Motion mechanism: bind."+E+" names undeclared state "+k);b[E]=l.state[k]}O.dataset.style=l.theme?.visualStyle??"";for(let E of h.values())E.disabled=l.disabled;x&&(x.disabled=l.disabled),L&&(L.disabled=l.disabled),Q(b)})),Object.freeze({update:Q,pose:l=>Q({pose:l}),stats:()=>({frames:u,faces:g.size,parts:r.parts.length}),destroy(){m||(m=!0,M.forEach(l=>l()),g.clear(),f.clear(),i.replaceChildren())}})}function n(o,e,i={}){if(!["assembly","gears","crank"].includes(e))throw Error("Motion mechanism: demo must be assembly/gears/crank");let r=i.bind??{},p=()=>t.snapshot.state,d=(A,w)=>Object.hasOwn(r,A)?p()[r[A]]:w;for(let[A,w]of Object.entries(r))if(!["explode","selected","cutaway","rpm","teeth","running","angle","radius"].includes(A)||typeof w!="string"||!Object.hasOwn(p(),w))throw Error("Motion mechanism: invalid demo binding "+A);let m=d("angle",0)*Math.PI/180,s=m,c="",u=!1,f=Object.fromEntries(Object.entries(r).filter(([A])=>["explode","selected","cutaway"].includes(A)));function g(){return e==="assembly"?ft():e==="gears"?pt({driverTeeth:i.driverTeeth??16,drivenTeeth:d("teeth",32),module:i.module??1.5}):ht({radius:d("radius",20),rod:i.rod??70})}let h=a(o,{...g(),...i.title===void 0?{}:{title:i.title},bind:f}),M=!1;function O(A=0,w=!1,T=!0){if(M)return;let D=d("rpm",30),G=d("running",!1),S=d("angle",0)*Math.PI/180,H=s;S!==m?(H=S,m=S):G&&T&&!w&&(H+=D*Math.PI*2/60*A),s=H;let K=JSON.stringify([e,d("teeth",32),d("radius",20)]);if(K!==c&&(h.update({parts:g().parts}),c=K),e==="gears"){let x=W({driverTeeth:i.driverTeeth??16,drivenTeeth:d("teeth",32),rpm:D,angle:s,module:i.module??1.5});h.update({pose:{driverGear:{rotation:x.driverAngle},drivenGear:{rotation:x.drivenAngle}},readout:"\\\\u4E3B\\\\u52A8\\\\u8F6E "+t.formatNumber(x.driverRpm,0)+" rpm \\\\xB7 \\\\u4ECE\\\\u52A8\\\\u8F6E "+t.formatNumber(x.drivenRpm,2)+" rpm \\\\xB7 \\\\u9F7F\\\\u6570\\\\u6BD4 "+t.formatNumber(x.ratio,2)+"\\\\uFF08\\\\u8D1F\\\\u53F7\\\\u8868\\\\u793A\\\\u53CD\\\\u5411\\\\uFF09"})}else if(e==="crank"){let x=X({angle:s,radius:d("radius",20),rod:i.rod??70,z:28});h.update({pose:{crankPin:{at:x.crank},link:{from:x.crank,to:x.piston},piston:{at:[x.position,0,22]},pistonPin:{at:x.piston}},readout:"\\\\u66F2\\\\u67C4\\\\u89D2 "+t.formatNumber((s*180/Math.PI%360+360)%360,1)+"\\\\xB0 \\\\xB7 \\\\u6ED1\\\\u5757\\\\u4F4D\\\\u7F6E "+t.formatNumber(x.position,2)+" \\\\xB7 \\\\u884C\\\\u7A0B "+t.formatNumber(x.stroke,1)+"\\\\uFF08\\\\u793A\\\\u610F\\\\u957F\\\\u5EA6\\\\u5355\\\\u4F4D\\\\uFF09"})}u=w}let N=null,$=()=>{O(0,u,!0),e!=="assembly"&&(d("running",!1)&&!N?N=t.animate(({delta:A,reducedMotion:w,visible:T})=>{T&&!w?O(A,!1,!0):u!==w&&O(0,w,T)}):!d("running",!1)&&N&&(N(),N=null))},P=t.subscribe($);return O(),Object.freeze({...h,destroy(){M||(M=!0,N?.(),P(),h.destroy())}})}return Object.freeze({mount:a,mountDemo:n,gearPair:W,sliderCrank:X,follow:Mt,scenes:Object.freeze({assembly:ft,gears:pt,crank:ht})})}return _t(Tt);})();\\n\';\n\n // lib/visual-audit.js\n function measureVisual(root, nodeId = "") {\n const issues = [], seen = /* @__PURE__ */ new Set(), coverage = { nodeId, elements: 0, truncated: false, contrastChecked: 0, contrastUncovered: 0 };\n const add = (code, value, el2) => {\n const id = el2?.closest("[data-ui-node]")?.getAttribute("data-ui-node") ?? nodeId;\n const k2 = id + ":" + code + ":" + Math.round(value ?? 0);\n if (!seen.has(k2) && issues.length < 40) {\n seen.add(k2);\n issues.push({ code, nodeId: id, ...value === void 0 ? {} : { value: Number(value.toFixed(2)) } });\n }\n };\n const color = (s) => {\n let m2 = s.match(/^rgba?\\(([^)]+)\\)/);\n if (m2) {\n const a = m2[1].split(/[\\s,\\/]+/).map(Number);\n return [a[0] / 255, a[1] / 255, a[2] / 255, a[3] ?? 1];\n }\n m2 = s.match(/^color\\(srgb ([^)]+)\\)/);\n if (m2) {\n const a = m2[1].split(/[\\s\\/]+/).map(Number);\n return [a[0], a[1], a[2], a[3] ?? 1];\n }\n return null;\n };\n const luminance = (c) => c.slice(0, 3).map((v2) => v2 <= 0.04045 ? v2 / 12.92 : ((v2 + 0.055) / 1.055) ** 2.4).reduce((s, v2, i) => s + v2 * [0.2126, 0.7152, 0.0722][i], 0);\n const widthRoot = root.id === "canvas" ? document.documentElement : root;\n if (widthRoot.scrollWidth > widthRoot.clientWidth + 2) add("overflow", widthRoot.scrollWidth - widthRoot.clientWidth);\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n let el;\n while (el = walker.nextNode()) {\n if (coverage.elements >= 2e3) {\n coverage.truncated = true;\n break;\n }\n coverage.elements++;\n if (el.matches("[data-canvas-phase=error]")) add("runtimeError", void 0, el);\n const css = getComputedStyle(el), box = el.getBoundingClientRect();\n if (!box.width || !box.height || css.visibility === "hidden" || css.display === "none") continue;\n const text2 = [...el.childNodes].some((n) => n.nodeType === 3 && n.textContent.trim());\n if (text2) {\n let size = parseFloat(css.fontSize);\n if (el instanceof SVGElement && el.getScreenCTM) {\n const m2 = el.getScreenCTM();\n if (m2) size *= Math.hypot(m2.c, m2.d);\n }\n if (size < 11.9) add("smallText", size, el);\n const fg = color(css.color);\n let ancestor = el, bg = null, depth = 0;\n while (ancestor && depth++ < 64) {\n const style = getComputedStyle(ancestor);\n if (style.backgroundImage !== "none") break;\n const c = color(style.backgroundColor);\n if (c?.[3] === 1) {\n bg = c;\n break;\n }\n if (c?.[3] > 0) break;\n ancestor = ancestor.parentElement;\n }\n if (!(el instanceof SVGElement) && fg?.[3] === 1 && bg) {\n coverage.contrastChecked++;\n const a = luminance(fg), b2 = luminance(bg), ratio = (Math.max(a, b2) + 0.05) / (Math.min(a, b2) + 0.05);\n if (ratio < (size >= 24 || size >= 18.66 && parseFloat(css.fontWeight) >= 700 ? 3 : 4.5)) add("contrast", ratio, el);\n } else coverage.contrastUncovered++;\n }\n if (el.matches("input:not([type=hidden]),select,textarea,button,[role=button]") && !el.getAttribute("aria-label") && !el.getAttribute("aria-labelledby") && !el.labels?.length && !el.textContent.trim() && !el.getAttribute("title")) add("missingLabel", void 0, el);\n }\n Object.defineProperty(issues, "coverage", { value: coverage });\n return issues;\n }\n\n // lib/format-number.js\n function formatNumber(value, decimals = 2) {\n if (typeof value !== "number" || !Number.isFinite(value)) throw new Error("DSH UI: formatNumber requires a finite number");\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > 6) throw new Error("DSH UI: formatNumber decimals must be an integer from 0 to 6");\n return value.toLocaleString("en-US", { minimumFractionDigits: decimals, maximumFractionDigits: decimals });\n }\n\n // lib/canvas-system.js\n var CANVAS_SYSTEM_CSS = `\n:root{--canvas-radius:16px;--canvas-gap:16px;--canvas-positive:#167456;--canvas-negative:#b13b3b;--canvas-warning:#875b15}\n:root[data-canvas-scheme=dark]{--canvas-positive:#78d9b4;--canvas-negative:#ffaaaa;--canvas-warning:#edc87e}\n#canvas{display:flow-root}html,body{margin:0;min-width:0;background:var(--canvas-bg,#fff);color:var(--canvas-ink,#182537);font:14px/1.6 system-ui,"Microsoft YaHei",sans-serif}*{box-sizing:border-box}svg{max-width:100%;height:auto}button,input,select,textarea{font:inherit;color:inherit}button,input,select,textarea{border:1px solid var(--canvas-line,#ced4df);border-radius:8px;background:var(--canvas-bg,#fff);padding:8px 12px;max-width:100%}button{cursor:pointer}button:disabled{cursor:default;opacity:.55}input[type=range]{padding:0;accent-color:var(--canvas-accent,#3e60d3)}input[type=checkbox],input[type=radio]{accent-color:var(--canvas-accent,#3e60d3)}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--canvas-accent,#3e60d3);outline-offset:3px}\n.ui-stack{display:grid;gap:var(--canvas-gap)}.ui-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:var(--canvas-gap)}.ui-surface{padding:20px;border:1px solid var(--canvas-line,#ced4df);border-radius:var(--canvas-radius);background:var(--canvas-soft,#f3f5f8)}.ui-title{margin:0;font-size:clamp(20px,3vw,28px);line-height:1.3;letter-spacing:-.02em}.ui-caption{color:var(--canvas-muted,#526176);margin:8px 0;font-size:14px}.ui-value{font-size:clamp(24px,4vw,36px);font-variant-numeric:tabular-nums;line-height:1.2}.ui-controls{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.ui-field{display:grid;gap:6px;min-width:0}.ui-legend{display:flex;gap:16px;flex-wrap:wrap;font-size:13px}.ui-status{min-height:1.6em}.ui-error{color:var(--canvas-negative)}.ui-primary{background:var(--canvas-accent,#3e60d3);color:var(--canvas-accent-ink,#fff);border-color:transparent}\nsvg .ui-node{fill:var(--canvas-soft,#f3f5f8);stroke:var(--canvas-line,#ced4df);stroke-width:1}svg .ui-edge{fill:none;stroke:var(--canvas-muted,#526176);stroke-width:1.5}svg .ui-label{fill:var(--canvas-ink,#182537);font:500 14px system-ui,sans-serif}svg .ui-note{fill:var(--canvas-muted,#526176);font:400 13px system-ui,sans-serif}svg .ui-leader{fill:none;stroke:var(--canvas-muted,#526176);stroke-dasharray:3 4}svg .ui-accent{fill:color-mix(in srgb,var(--canvas-accent,#3e60d3) 12%,var(--canvas-bg,#fff));stroke:var(--canvas-accent,#3e60d3)}\n.ui-flow{display:flex;align-items:center;justify-content:center;gap:16px;padding:24px 8px;flex-wrap:wrap}.ui-step{display:grid;gap:6px;min-width:130px;max-width:240px;padding:16px 20px;border:1px solid var(--canvas-line);border-radius:6px;background:var(--canvas-bg)}.ui-step strong{font-size:16px;font-weight:600}.ui-step span{font-size:14px;color:var(--canvas-muted)}.ui-arrow{color:var(--canvas-muted);font-size:22px}.ui-callout{border-inline-start:3px solid var(--canvas-accent);padding:8px 16px;color:var(--canvas-ink)}\n.ui-surface,.ui-step{border-radius:var(--canvas-radius);background:var(--canvas-bg,#fff)}button,input:not([type=checkbox]):not([type=radio]):not([type=range]),select,textarea{border-radius:12px}button{border-radius:999px}.ui-primary{background:var(--canvas-ink,#182537);color:var(--canvas-bg,#fff)}.ui-callout{border-radius:0 12px 12px 0;background:color-mix(in srgb,var(--canvas-accent,#3e60d3) 5%,var(--canvas-bg,#fff))}\n@media(max-width:480px){.ui-flow{flex-direction:column;padding:16px 8px;gap:12px}.ui-step{width:100%;max-width:none}.ui-arrow{transform:rotate(90deg)}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}`;\n\n // lib/sandbox.js\n var SANDBOX_LIMITS = Object.freeze({ source: 49152, height: 1e3, message: 16384, rate: 30 });\n function canvasSnapshot(node2, state2, data, derived, disabled, theme) {\n const pick = (keys, values) => Object.fromEntries((keys ?? []).map((k2) => [k2, values[k2]]));\n return { state: pick(node2.stateKeys, state2), data: pick(node2.dataKeys, data), derived: pick(node2.derivedKeys, derived), disabled, theme };\n }\n function canvasPatch(message, node2) {\n if (!message || typeof message !== "object" || Array.isArray(message)) throw new Error("Invalid canvas patch");\n const keys = Object.keys(message);\n if (!keys.length || keys.length > 64 || keys.some((k2) => !(node2.stateKeys ?? []).includes(k2))) throw new Error("Canvas state key is not declared");\n if (JSON.stringify(message).length > SANDBOX_LIMITS.message) throw new Error("Canvas patch is too large");\n return message;\n }\n function sandboxDocument(node2, channel2, nonce2) {\n const json = (value) => JSON.stringify(value).replace(/</g, "\\\\u003c").replace(/\\u2028/g, "\\\\u2028").replace(/\\u2029/g, "\\\\u2029");\n return `<!doctype html><html><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src \'none\'; script-src \'nonce-${nonce2}\'; style-src \'unsafe-inline\'; img-src data:; font-src \'none\'; connect-src \'none\'; media-src \'none\'; object-src \'none\'; frame-src \'none\'; worker-src \'none\'; base-uri \'none\'; form-action \'none\'"><meta name="viewport" content="width=device-width,initial-scale=1"><style>${CANVAS_SYSTEM_CSS}</style></head><body><main id="canvas"></main><script nonce="${nonce2}">(()=>{\n const channel=${json(channel2)}, source=${json({ html: node2.html, css: node2.css ?? "", script: node2.script ?? "" })};\n let snapshot={state:{},data:{},derived:{},disabled:true,theme:{}}, started=false;\n const listeners=new Set(), send=(type,payload)=>parent.postMessage({dshCanvas:1,channel,type,payload},\'*\');\n const report=e=>send(\'error\',String(e?.message??e).slice(0,1000));\n const audit=${measureVisual.toString()};let auditTimer;const scheduleAudit=()=>{clearTimeout(auditTimer);auditTimer=setTimeout(()=>{const issues=audit(document.getElementById(\'canvas\'),${json(node2.id ?? "")});send(\'audit\',{issues,coverage:issues.coverage})},400)};\n addEventListener(\'resize\',scheduleAudit);\n addEventListener(\'error\',e=>report(e.error??e.message));addEventListener(\'unhandledrejection\',e=>report(e.reason));\n const animations=new Set(), motion=matchMedia(\'(prefers-reduced-motion: reduce)\');\n let raf=0,last=0,time=0;\n const visible=()=>snapshot.visible!==false&&!document.hidden;\n const canAnimate=()=>visible()&&!snapshot.disabled&&!motion.matches;\n const draw=delta=>{for(const fn of animations)try{fn({time,delta,reducedMotion:motion.matches,visible:visible()})}catch(e){animations.delete(fn);report(e)}};\n const tick=t=>{raf=0;if(!canAnimate()||!animations.size){last=0;draw(0);return}const delta=last?Math.min(.05,(t-last)/1000):0;last=t;time+=delta;draw(delta);if(animations.size)raf=requestAnimationFrame(tick)};\n const refresh=()=>{draw(0);if(canAnimate()&&animations.size){if(!raf){last=0;raf=requestAnimationFrame(tick)}}else{cancelAnimationFrame(raf);raf=0;last=0}};\n motion.addEventListener(\'change\',refresh);document.addEventListener(\'visibilitychange\',refresh);\n const formatNumber=${formatNumber.toString()};\n const api={formatNumber,get snapshot(){return structuredClone(snapshot)},subscribe(fn){if(typeof fn!==\'function\')throw Error(\'Listener required\');listeners.add(fn);fn(api.snapshot);return()=>listeners.delete(fn)},setState(patch){if(!snapshot.disabled)send(\'patch\',patch)},animate(fn){if(typeof fn!==\'function\')throw Error(\'Animation callback required\');animations.add(fn);refresh();return()=>{animations.delete(fn);if(!animations.size){cancelAnimationFrame(raf);raf=0;last=0}}}};\n ${node2.libraries?.includes("mechanism") ? MECHANISM_RUNTIME.replace(/<\\/script/gi, "<\\\\/script") + ";api.mechanism=__MotionMechanism.createMechanismAPI(api);" : ""}\n Object.defineProperty(window,\'DSHUI\',{value:Object.freeze(api),writable:false});\n for(const type of [\'click\',\'input\',\'change\',\'keydown\',\'pointerdown\'])document.addEventListener(type,e=>{if(snapshot.disabled){e.preventDefault();e.stopImmediatePropagation()}},true);\n addEventListener(\'message\',event=>{\n const m=event.data;if(event.source!==parent||m?.dshCanvas!==1||m.channel!==channel||m.type!==\'snapshot\')return;\n snapshot=m.payload;for(const [k,v] of Object.entries(snapshot.theme??{}))document.documentElement.style.setProperty(\'--canvas-\'+k,v);\n document.documentElement.style.colorScheme=snapshot.theme?.scheme??\'light\';document.documentElement.dataset.canvasScheme=snapshot.theme?.scheme??\'light\';\n const wasStarted=started;\n if(!started){started=true;document.getElementById(\'canvas\').innerHTML=source.html;const style=document.createElement(\'style\');style.textContent=source.css;document.head.append(style);const script=document.createElement(\'script\');script.nonce=${json(nonce2)};script.textContent=source.script;document.body.append(script)}\n if(wasStarted)for(const fn of listeners)try{fn(api.snapshot)}catch(e){report(e)}\n refresh();if(!wasStarted)send(\'mounted\');scheduleAudit();\n });\n let resizePending=false;new ResizeObserver(()=>{if(!started||resizePending)return;resizePending=true;requestAnimationFrame(()=>{resizePending=false;send(\'height\',Math.ceil(document.getElementById(\'canvas\').getBoundingClientRect().height))})}).observe(document.getElementById(\'canvas\'));\n send(\'ready\');\n})();<\\/script></body></html>`;\n }\n\n // lib/components.js\n var define = (fields2, purpose, presentation = "") => Object.freeze({ fields: Object.freeze(fields2), purpose, presentation });\n var COMPONENTS = Object.freeze({\n visual: define(["spec", "stateKey", "warnings"], "Extended native charts, tables, plots, quiz, forms, diagrams, media and 3D"),\n heading: define(["text", "spans", "size", "weight", "color", "align", "lineHeight"], "Section heading", "tone"),\n text: define(["text", "spans", "size", "weight", "color", "align", "lineHeight", "copyable", "title"], "Readable explanation; copyable:true adds a reusable text panel", "tone"),\n code: define(["code", "lang", "title", "wrap"], "Literal copyable code; displayed only, never executed"),\n callout: define(["text", "spans", "size", "weight", "color", "align", "lineHeight"], "A short emphasized paragraph", "tone"),\n row: define(["children", "columns", "gap"], "Wrapping parallel content"),\n column: define(["children", "gap"], "Ordered vertical content"),\n card: define(["title", "children", "surface"], "Meaningful grouped section", "tone"),\n details: define(["title", "children", "open"], "Collapsible supporting content", "tone"),\n badge: define(["text"], "Short explicit status label", "tone"),\n progress: define(["label", "value", "max", "unit"], "Declared numeric progress snapshot", "tone"),\n steps: define(["title", "items"], "Ordered declared steps with an optional heading"),\n metric: define(["label", "value", "unit", "decimals"], "Number with units, or a literal/bound status string", "tone"),\n input: define(["label", "bind"], "String or numeric state input"),\n slider: define(["label", "bind"], "Numeric state control"),\n select: define(["label", "bind", "variant"], "Selection from declared state options; variant:segmented for 2..8 short options, dropdown otherwise"),\n toggle: define(["label", "bind"], "Boolean state control"),\n button: define(["text", "action", "href", "path", "variant"], "Agent follow-up, web link or host file opener", "icon"),\n link: define(["text", "href", "path", "variant"], "User-clicked webpage or local file button", "icon"),\n divider: define(["label"], "Quiet section divider"),\n table: define(["label", "rows", "columns"], "Supplied or derived values; inline rows or data/derived reference"),\n chart: define(["kind", "rows", "labelKey", "valueKey", "label", "unit", "xScale"], "Bar/line comparison with accessible data"),\n sandbox: define(["title", "html", "css", "script", "fallback", "height", "libraries", "stateKeys", "dataKeys", "derivedKeys"], "Freeform isolated HTML/SVG/CSS/JavaScript visualization")\n });\n function componentFields(type) {\n const c = Object.hasOwn(COMPONENTS, type) ? COMPONENTS[type] : void 0;\n return c && ["id", "type", ...c.fields, ...c.presentation ? ["icon"] : [], ...c.presentation === "tone" ? ["tone"] : []];\n }\n\n // lib/identifiers.js\n var IDENTIFIER_SOURCE = "[\\\\p{L}_][\\\\p{L}\\\\p{M}\\\\p{N}_]{0,63}";\n var pattern = new RegExp(`^${IDENTIFIER_SOURCE}$`, "u");\n var validIdentifier = (value) => typeof value === "string" && pattern.test(value) && !["constructor", "prototype", "__proto__"].includes(value);\n\n // lib/author-expression.js\n function compileExpression(source) {\n const fail2 = () => {\n throw new Error("DSH UI: invalid formula; use state.x, data.x, derived.x, item.x, numbers, strings, + - * /, comparisons, ?: and min/max/round/ceil/floor/abs");\n };\n if (typeof source !== "string" || !source.trim() || source.length > 2048) fail2();\n const tokens = [];\n let offset = 0;\n const token2 = new RegExp(String.raw`\\s*(?:(\\d+(?:\\.\\d*)?|\\.\\d+)([eE][+-]?\\d+)?|("(?:[^"\\\\]|\\\\.)*")|(${IDENTIFIER_SOURCE}(?:\\.${IDENTIFIER_SOURCE})?)|(===|!==|<=|>=|==|!=|[+*/()?,:<>-]))`, "uy");\n while (offset < source.length) {\n if (!source.slice(offset).trim()) break;\n token2.lastIndex = offset;\n const m2 = token2.exec(source);\n if (!m2) fail2();\n offset = token2.lastIndex;\n tokens.push(m2[1] ? { number: Number(m2[1] + (m2[2] ?? "")) } : m2[3] ? { string: JSON.parse(m2[3]) } : m2[4] ?? m2[5]);\n if (tokens.length > 256) fail2();\n }\n let pos = 0;\n const operators = { "==": ["eq", 1], "===": ["eq", 1], "!=": ["neq", 1], "!==": ["neq", 1], "<": ["lt", 2], "<=": ["lte", 2], ">": ["gt", 2], ">=": ["gte", 2], "+": ["add", 3], "-": ["sub", 3], "*": ["mul", 4], "/": ["div", 4] };\n const take = (t) => {\n if (tokens[pos++] !== t) fail2();\n };\n function parse(min = 0, depth = 0) {\n if (depth > 12) fail2();\n const t = tokens[pos++];\n let out;\n if (t && typeof t === "object") out = { const: Object.hasOwn(t, "number") ? t.number : t.string };\n else if (t === "true" || t === "false") out = { const: t === "true" };\n else if (t === "(") {\n out = parse(0, depth + 1);\n take(")");\n } else if (t === "-" || t === "+") {\n const arg = parse(5, depth + 1);\n out = t === "-" ? { op: "sub", args: [{ const: 0 }, arg] } : arg;\n } else if (typeof t === "string" && t.split(".").length === 2 && ["state", "data", "derived", "item"].includes(t.split(".")[0]) && validIdentifier(t.split(".")[1])) out = { ref: t };\n else if (["min", "max", "round", "ceil", "floor", "abs"].includes(t)) {\n take("(");\n const args = [parse(0, depth + 1)];\n while (tokens[pos] === ",") {\n pos++;\n args.push(parse(0, depth + 1));\n if (args.length > 8) fail2();\n }\n take(")");\n out = { op: t, args };\n } else fail2();\n while (typeof tokens[pos] === "string" && Object.hasOwn(operators, tokens[pos]) && operators[tokens[pos]][1] >= min) {\n const [op, precedence] = operators[tokens[pos++]];\n out = { op, args: [out, parse(precedence + 1, depth + 1)] };\n }\n if (min === 0 && tokens[pos] === "?") {\n pos++;\n const yes = parse(0, depth + 1);\n take(":");\n out = { op: "if", args: [out, yes, parse(0, depth + 1)] };\n }\n return out;\n }\n const result = parse();\n if (pos !== tokens.length) fail2();\n return result;\n }\n function expandExpressions(doc2) {\n const expression2 = (e) => {\n if (!e || typeof e !== "object" || Array.isArray(e)) return e;\n if (Object.hasOwn(e, "expr")) {\n if (Object.keys(e).length !== 1) throw new Error("DSH UI: expr must be the only formula field");\n return compileExpression(e.expr);\n }\n if (Array.isArray(e.args)) e.args = e.args.map(expression2);\n if (e.map?.fields) for (const k2 of Object.keys(e.map.fields)) e.map.fields[k2] = expression2(e.map.fields[k2]);\n return e;\n };\n if (doc2.derived && typeof doc2.derived === "object") for (const k2 of Object.keys(doc2.derived)) doc2.derived[k2] = expression2(doc2.derived[k2]);\n const walk = (nodes) => {\n if (!Array.isArray(nodes)) return;\n for (const node2 of nodes) {\n if (!node2 || typeof node2 !== "object") continue;\n for (const field of ["text", "value", "max", "rows"]) if (Object.hasOwn(node2, field)) node2[field] = expression2(node2[field]);\n if (["table", "chart"].includes(node2.type) && Array.isArray(node2.rows)) {\n for (const row of node2.rows) if (row && typeof row === "object" && !Array.isArray(row)) for (const k2 of Object.keys(row)) row[k2] = expression2(row[k2]);\n }\n walk(node2.children);\n }\n };\n walk(doc2.nodes);\n return doc2;\n }\n\n // lib/visual-guard.js\n var ne = ["h1", "h2", "h3", "body", "muted", "caption"];\n var te = ["primary", "danger", "success", "ghost"];\n var ie = ["success", "warn", "danger", "accent"];\n var re = ["text", "email", "password", "color"];\n var se = ["info", "success", "warning", "error"];\n var U = ["bars", "line", "donut"];\n var oe = ["line", "area", "scatter"];\n var ae = ["16:9", "4:3", "1:1", "9:16"];\n var ue = ["box", "sphere", "cone", "cylinder", "torus"];\n var le = ["file", "dir"];\n var de = ["architecture", "it-state", "flowchart", "sequence", "state", "er", "timeline", "swimlane", "quadrant", "radar", "loop", "nested", "tree", "org-chart", "layers", "venn", "pyramid", "bar", "line", "gantt", "scatter", "high-level", "process", "medallion", "data-flow", "dp-integration", "dp-security-matrix"];\n var ce = ["focal", "backend", "store", "external", "input", "optional", "security"];\n var fe = ["light", "dark", "editorial"];\n var pe = ["solid", "dashed", "accent", "link"];\n var me = ["auto", "orthogonal", "straight"];\n var ge = ["bar", "line", "area", "pie", "scatter", "radar", "gauge", "funnel", "treemap", "sankey", "graph", "heatmap", "bigline", "wordCloud"];\n var tn = ["hero"];\n var ye = ["bar", "ring"];\n var be = ["info", "success", "warning", "danger"];\n var he = ["accent", "success", "warning", "danger"];\n var Ee = ["text", "num", "delta", "bar", "badge", "spark", "ring", "index", "group"];\n var b = (t, i, r = {}, e = {}) => {\n let s = Object.fromEntries(Object.entries(i).filter(([u]) => u !== "type" && !t.includes(u))), n = e.oneOfRequired ?? [], o = e.conditionalRequired ?? [], a = [...n.map((u) => ({ kind: "one-of-required", fields: u })), ...o];\n return { required: t, fields: i, optional: s, aliases: r, valueAliases: e.valueAliases ?? {}, oneOfRequired: n, conditionalRequired: o, rules: a, enums: e.enums ?? {}, nested: e.nested ?? {}, ...e.validator === void 0 ? {} : { validator: e.validator } };\n };\n var G = (t, i, r = {}, e = {}, s = {}) => ({ required: t, fields: i, enums: e, nested: r, aliases: s });\n var h = { type: "string", span: "number", id: "string" };\n var De = G(["label", "value"], { label: "string", value: "number", color: "string" });\n var rn = G(["label", "data"], { label: "string", color: "string", data: "array" }, { data: De });\n var sn = G(["title"], { title: "string", desc: "string" });\n var on = G(["key", "value"], { key: "string", value: "string" }, {}, {}, { label: "key" });\n var an = G(["title"], { title: "string", desc: "string", time: "string" });\n var un = G(["path", "newText"], { path: "string", oldText: "string-or-null", newText: "string" });\n var ln = G(["name", "value"], { name: "string", value: "number", min: "number", max: "number", step: "number", animateTo: "number", durationMs: "number", loop: "boolean" });\n var dn = G(["expr"], { expr: "string", label: "string", color: "string", kind: "string", params: "array" }, { params: ln }, { kind: oe });\n var cn = G(["shape"], { shape: "string", color: "string", position: "array", rotation: "array", scale: "unknown", size: "unknown" }, {}, { shape: ue });\n function Oe(t) {\n return G(["name"], { name: "string", type: "string", children: "array" }, t > 0 ? { children: Oe(t - 1) } : {}, { type: le }, { label: "name" });\n }\n var fn = Oe(6);\n var pn = G(["label", "items"], { label: "string", items: "nodes", content: "nodes" });\n var mn = G(["title", "items"], { title: "string", items: "nodes" });\n var gn = G(["id", "label"], { id: "string", label: "string", sub: "string", type: "string", x: "number", y: "number", w: "number", h: "number", tag: "string" }, {}, { type: ce });\n var yn = G(["from", "to"], { from: "string", to: "string", label: "string", kind: "string", route: "string" }, {}, { kind: pe, route: me });\n var bn = G(["label"], { label: "string", x: "number", y: "number", w: "number", h: "number" });\n var hn = G([], { paper: "string", "paper-2": "string", ink: "string", muted: "string", soft: "string", rule: "string", accent: "string", "accent-tint": "string", link: "string" });\n var V = b(["items"], { title: "string", gap: "number", panel: "boolean", append: "boolean", items: "nodes" });\n var T = { accordion: b(["items"], { ...h, items: "array" }, {}, { nested: { items: mn } }), audio: b(["src"], { ...h, src: "string", alt: "string", loop: "boolean" }, { url: "src", link: "src" }), avatar: b(["name"], { ...h, name: "string", color: "string" }), badge: b(["label"], { ...h, label: "string", tone: "string", icon: "string" }, { text: "label", value: "label" }, { enums: { tone: ie } }), breadcrumb: b(["items"], { ...h, items: "array" }), button: b(["label"], { ...h, label: "string", tone: "string", full: "boolean", small: "boolean", icon: "string", action: "string" }, {}, { enums: { tone: te } }), callout: b(["content"], { ...h, title: "string", content: "string", tone: "string" }, { kind: "tone", text: "content", body: "content", desc: "content" }, { enums: { tone: se }, valueAliases: { tone: { danger: "error", warn: "warning" } } }), card: b(["items"], { ...h, title: "string", items: "nodes", tone: "string", accent: "string" }, { label: "title", content: "items" }, { enums: { tone: be } }), chart: b([], { ...h, kind: "string", data: "array", series: "array", horizontal: "boolean", stacked: "boolean", filter: "string", palette: "array" }, {}, { oneOfRequired: [["data", "series"]], conditionalRequired: [{ kind: "required-if", when: { field: "kind", equals: "donut" }, required: ["data"] }], nested: { data: De, series: rn }, enums: { kind: U }, validator: { name: "chart-renderability" } }), checkbox: b(["label"], { ...h, label: "string", checked: "boolean", action: "string", group: "string" }), code: b(["code"], { ...h, lang: "string", code: "string", title: "string", wrap: "boolean" }, { content: "code", text: "code" }), col: b(["items"], { ...h, items: "nodes", gap: "number" }), copy: b(["text"], { ...h, label: "string", text: "string" }, { content: "text", code: "text", value: "text" }), diagram: b(["kind", "nodes"], { ...h, kind: "string", variant: "string", title: "string", nodes: "array", edges: "array", zones: "array", theme: "object" }, {}, { nested: { nodes: gn, edges: yn, zones: bn, theme: hn }, enums: { kind: de, variant: fe } }), diff: b(["diffs"], { ...h, diffs: "array" }, { items: "diffs", files: "diffs" }, { nested: { diffs: un } }), divider: b([], h), echart: b([], { ...h, title: "string", height: "number", preset: "string", data: "array", series: "array", links: "array", palette: "array", option: "object" }, {}, { oneOfRequired: [["option", "data", "series", "links"]], enums: { preset: ge } }), "file-tree": b(["items"], { ...h, items: "array" }, { nodes: "items" }, { nested: { items: fn } }), grid: b(["items"], { ...h, cols: "number", items: "nodes" }), image: b(["src"], { ...h, src: "string", alt: "string" }, { url: "src", link: "src" }), input: b([], { ...h, label: "string", placeholder: "string", value: "string", inputType: "string", action: "string", id: "string" }, {}, { enums: { inputType: re } }), json: b(["value"], { ...h, value: "unknown" }), keyvalue: b(["pairs"], { ...h, pairs: "array" }, { items: "pairs", rows: "pairs", entries: "pairs" }, { nested: { pairs: on } }), link: b(["label"], { ...h, label: "string", href: "string" }), list: b(["items"], { ...h, items: "array", filter: "string" }), mermaid: b(["code"], { ...h, code: "string" }), svg: b(["code"], { ...h, code: "string", title: "string", height: "number" }), plot: b(["series"], { ...h, series: "array", xMin: "number", xMax: "number", yMin: "number", yMax: "number", title: "string" }, {}, { nested: { series: dn } }), progress: b(["value"], { ...h, value: "number", label: "string", valueLabel: "string", variant: "string", target: "number" }, {}, { enums: { variant: ye } }), quiz: b(["question", "options"], { ...h, question: "string", options: "array", explanation: "string", id: "string", action: "string" }, { title: "question", text: "question", choices: "options", items: "options" }), radio: b(["options"], { ...h, label: "string", options: "array", selected: "number", action: "string", group: "string", answer: "unknown", explanation: "string" }, { items: "options" }), row: b(["items"], { ...h, items: "nodes", wrap: "boolean", spacer: "boolean" }), scene3d: b(["meshes"], { ...h, title: "string", meshes: "array", ambient: "number", background: "string" }, {}, { nested: { meshes: cn } }), select: b(["options"], { ...h, label: "string", options: "array", action: "string", selected: "number", id: "string" }, { items: "options" }), slider: b([], { ...h, label: "string", min: "number", max: "number", step: "number", value: "number", action: "string", id: "string" }), spacer: b([], h), hero: b(["title"], { ...h, title: "string", subtitle: "string", value: "string", label: "string", delta: "string", spark: "array", tone: "string" }, {}, { enums: { tone: he } }), stat: b(["label", "value"], { ...h, label: "string", value: "string", delta: "string", spark: "array", size: "string" }, {}, { enums: { size: tn } }), steps: b(["steps"], { ...h, steps: "array", current: "number" }, { items: "steps" }, { nested: { steps: sn } }), submit: b(["label"], { ...h, label: "string", action: "string", resetAction: "string", groups: "array" }), switch: b(["label"], { ...h, label: "string", checked: "boolean", action: "string" }), table: b(["columns", "rows"], { ...h, columns: "array", rows: "array", types: "array", total: "boolean", details: "array", filter: "string", filterColumn: "number", sortField: "string", export: "boolean" }, { headers: "columns", data: "rows", items: "rows" }), tabs: b(["tabs"], { ...h, tabs: "array" }, {}, { nested: { tabs: pn } }), text: b(["content"], { ...h, content: "string", size: "string", center: "boolean", copyable: "boolean", title: "string" }, { text: "content" }, { enums: { size: ne } }), textarea: b([], { ...h, label: "string", placeholder: "string", rows: "number", value: "string", action: "string", id: "string" }), timeline: b(["items"], { ...h, items: "array" }, {}, { nested: { items: an } }), video: b(["src"], { ...h, src: "string", alt: "string", poster: "string", loop: "boolean", muted: "boolean", aspectRatio: "string" }, { url: "src", link: "src" }, { enums: { aspectRatio: ae } }) };\n var q = new Set(Object.keys(T));\n function N(t) {\n if (typeof t != "object" || t === null) return false;\n let i = t;\n return typeof i.type != "string" || i.type === "" ? false : Array.isArray(i.items) ? q.has(i.type) : true;\n }\n function z(t) {\n if (typeof t != "object" || t === null) return null;\n let i = t;\n if (typeof i.type != "string" || i.type === "") return null;\n let r = q.has(i.type) ? T[i.type] : void 0, e = typeof i.title == "string" && r !== void 0 && !("title" in r.fields) ? i.title : void 0, s = { ...t };\n return e !== void 0 && delete s.title, { items: [s], ...e !== void 0 ? { title: e } : {}, ...i.panel === true ? { panel: true } : {}, ...i.append === true ? { append: true } : {} };\n }\n var m = { maxDepth: 8, maxNodes: 200, maxString: 2e3, maxCode: 12e3, maxMermaid: 8e3, maxGridCols: 12, maxTabs: 12, maxAccordionItems: 24, maxListItems: 50, maxOptions: 50, maxTableRows: 50, maxTableCols: 12, maxChartPoints: 60, maxPlotSeries: 8, maxPlotParams: 6, maxMeshes: 5, maxQuizOptions: 8, maxSteps: 24, maxTimelineItems: 24, maxBreadcrumbItems: 12, maxKeyValuePairs: 24, maxTreeDepth: 6, maxDiagramNodes: 9, maxDiagramEdges: 12, maxDiagramZones: 3, maxDiagramFocal: 2, maxDiagramLabel: 14, maxEChartOptionDepth: 10, maxEChartArrayLen: 500, maxEChartOptionNodes: 2e3 };\n function ke(t) {\n let i = t.columns, r = Array.isArray(i) && i.length > 0, e = r && Array.isArray(i) && typeof i[0] == "object" && i[0] !== null ? i.map($n) : i, s = kn(e), n = t.rows !== void 0 ? t.rows : t.data;\n if (Array.isArray(n) && n.length > 0 && typeof n[0] == "object" && n[0] !== null && !Array.isArray(n[0])) {\n let u = Array.isArray(t.columns) && t.columns.length > 0 && typeof t.columns[0] == "object" && t.columns[0] !== null ? t.columns.map(Sn).filter((d) => d !== void 0) : Object.keys(n[0]);\n n = n.map((d) => u.map((c) => wn(d[c])));\n }\n let o = null;\n if (!r && Array.isArray(n) && n.length > 0 && Array.isArray(n[0])) {\n let u = xe(n), d = u.length === 0 ? null : An(u);\n d !== null && xe(d.rows).length === d.rows.length && (o = d, s = d.columns.map((c) => c.slice(0, 128)));\n }\n if (s.length === 0 && !Array.isArray(t.columns)) return null;\n let a = xe(o === null ? n : o.rows);\n return Array.isArray(n) ? { columns: s.slice(0, m.maxTableCols), rows: a } : null;\n }\n function I(t) {\n return ke(t)?.rows ?? [];\n }\n function xn(t, i) {\n return !Array.isArray(t) || !Array.isArray(i) || i[0] !== "group" ? false : String(t[0] ?? "").trim() !== "" && t.slice(1).every((r) => String(r ?? "").trim() === "");\n }\n function C(t, i) {\n let r = I(t);\n return i >= 0 && i < r.length && !xn(r[i], t.types);\n }\n function kn(t) {\n if (!Array.isArray(t)) return [];\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxTableCols) break;\n if (typeof r == "string") i.push(r.slice(0, 128));\n else if (r !== null && typeof r == "object") {\n let e = r, s = typeof e.label == "string" ? e.label : typeof e.value == "string" ? e.value : typeof e.title == "string" ? e.title : JSON.stringify(r);\n i.push(s.slice(0, 128));\n }\n }\n return i;\n }\n function xe(t) {\n if (!Array.isArray(t)) return [];\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxTableRows) break;\n if (!Array.isArray(r)) continue;\n let e = [];\n for (let s of r) {\n if (e.length >= m.maxTableCols) break;\n typeof s == "string" ? e.push(s.slice(0, 256)) : typeof s == "number" && Number.isFinite(s) && e.push(s);\n }\n e.length > 0 && i.push(e);\n }\n return i;\n }\n function An(t) {\n let i = t[0];\n if (i === void 0 || i.length === 0) return null;\n let r = t.slice(1);\n if (r.length === 0) {\n let e = i.map((s) => String(s).trim());\n return e.every((s) => s !== "") ? { columns: e, rows: [] } : null;\n }\n return r.every((e) => e.length === i.length) ? { columns: i.map((e) => String(e).trim()), rows: r } : { columns: Array.from({ length: i.length }, (e, s) => `\\u5217${s + 1}`), rows: t };\n }\n function Sn(t) {\n if (t === null || typeof t != "object" || Array.isArray(t)) return;\n let i = t;\n for (let r of ["key", "dataIndex", "title", "label"]) if (typeof i[r] == "string" && i[r] !== "") return i[r];\n }\n function wn(t) {\n return typeof t == "string" || typeof t == "number" && Number.isFinite(t) ? t : t == null ? "" : JSON.stringify(t);\n }\n function $n(t) {\n if (t === null || typeof t != "object" || Array.isArray(t)) return String(t);\n let i = t;\n for (let r of ["title", "label", "key", "dataIndex"]) if (typeof i[r] == "string" && i[r] !== "") return i[r];\n return JSON.stringify(t);\n }\n function O(t) {\n return typeof t == "object" && t !== null && !Array.isArray(t) ? t : void 0;\n }\n function Ae(t) {\n let i = O(t);\n return i !== void 0 && typeof i.type == "string";\n }\n var Gn = ["label", "value", "delta", "spark", "size"];\n var Rn = { label: "title", name: "title", description: "desc", content: "desc", text: "desc", body: "desc", detail: "desc" };\n function Tn(t, i, r) {\n if (t.length === 0) return null;\n let e = [];\n for (let s = 0; s < t.length; s++) {\n let n = t[s], o = O(n);\n if (o === void 0) return null;\n if (Ae(n)) {\n e.push(r(n, `${i}.items[${s}]`));\n continue;\n }\n if (typeof o.label != "string" && typeof o.value != "string") return null;\n let a = { type: "stat" };\n for (let u of Gn) o[u] !== void 0 && (a[u] = o[u]);\n e.push(a);\n }\n return e;\n }\n function Cn(t, i, r, e) {\n let s = T[r];\n if (s === void 0) return t;\n let n = { ...t };\n for (let [o, a] of Object.entries(s.aliases)) {\n if (!(o in n)) continue;\n let u = `${i}.${o}`, d = a in n;\n d || (n[a] = n[o]), delete n[o], e.push({ kind: "alias", path: u, message: d ? `${u} is ignored because canonical field \'${a}\' is present` : `${u} normalized/adopted as \'${a}\'`, type: r, field: o, canonical: a });\n }\n for (let [o, a] of Object.entries(s.valueAliases)) {\n let u = n[o];\n if (typeof u != "string") continue;\n let d = a[u];\n d === void 0 || d === u || (n[o] = d, e.push({ kind: "alias", path: `${i}.${o}`, message: `${i}.${o} \'${u}\' normalized to \'${d}\'`, type: r, field: o, canonical: d }));\n }\n return n;\n }\n function Se(t, i, r, e, s) {\n if (Array.isArray(t)) return t.map((a, u) => Se(a, i, `${r}[${u}]`, e, s));\n let n = O(t);\n if (n === void 0) return t;\n let o = { ...n };\n for (let [a, u] of Object.entries(i.aliases)) !(a in o) || u in o || (o[u] = o[a], delete o[a], s.push({ kind: "alias", path: `${r}.${a}`, message: `${r}.${a} normalized/adopted as \'${u}\'`, type: e, field: a, canonical: u }));\n for (let [a, u] of Object.entries(i.nested)) o[a] !== void 0 && (o[a] = Se(o[a], u, `${r}.${a}`, e, s));\n return o;\n }\n function we(t) {\n if (Array.isArray(t)) return t.map(we);\n let i = O(t);\n if (i === void 0) return t;\n let r = { ...i };\n return r.type === void 0 && Array.isArray(r.children) && (r.type = "dir"), r.children !== void 0 && (r.children = we(r.children)), r;\n }\n function $e(t, i, r) {\n if (!Ae(t)) return t;\n let e = t.type, s = T[e];\n if (s === void 0) return t;\n let n = Cn(t, i, e, r);\n for (let [u, d] of Object.entries(s.nested)) n[u] !== void 0 && (n[u] = Se(n[u], d, `${i}.${u}`, e, r));\n let o = (u, d) => $e(u, d, r), a = (u, d) => Array.isArray(u) ? u.map((c, f) => o(c, `${d}[${f}]`)) : u;\n if (e === "file-tree" && n.items !== void 0 && (n.items = we(n.items)), e === "stat" && Array.isArray(n.items) && n.label === void 0 && n.value === void 0) {\n let u = Tn(n.items, i, o);\n if (u !== null) return r.push({ kind: "alias", path: `${i}.items`, message: `${i}.items normalized into a row of \'stat\' nodes`, type: e, field: "items", canonical: "row" }), { type: "row", items: u, ...n.span !== void 0 ? { span: n.span } : {} };\n }\n if (e === "row" || e === "col" || e === "grid" || e === "card" || e === "file-tree" || e === "timeline" || e === "breadcrumb") e !== "file-tree" && e !== "timeline" && e !== "breadcrumb" && (n.items = a(n.items, `${i}.items`));\n else if (e === "list" && Array.isArray(n.items)) n.items = n.items.map((u, d) => {\n if (Ae(u)) return o(u, `${i}.items[${d}]`);\n if (Array.isArray(u) && u.length === 1 && typeof u[0] == "string") return u[0];\n let c = O(u);\n if (c === void 0) return u;\n let f = { ...c }, g = `${i}.items[${d}]`;\n for (let [x, $] of Object.entries(Rn)) {\n if (!(x in f)) continue;\n let J = $ in f;\n J || (f[$] = f[x]), delete f[x], r.push({ kind: "alias", path: `${g}.${x}`, type: e, field: x, canonical: $, message: J ? `${g}.${x} is ignored because canonical field \'${$}\' is present` : `${g}.${x} normalized/adopted as \'${$}\'` });\n }\n return !("title" in f) && typeof f.desc == "string" && (f.title = f.desc, delete f.desc, r.push({ kind: "alias", path: `${g}.desc`, type: e, field: "desc", canonical: "title", message: `${g}.desc normalized/adopted as \'title\'` })), f;\n });\n else if (e === "keyvalue" && Array.isArray(n.pairs)) n.pairs.length > 0 && n.pairs.every((u) => Array.isArray(u)) && (n.pairs = n.pairs.map((u) => {\n let d = u;\n return { key: d[0], value: d.length > 1 ? d[1] : "" };\n }));\n else if (e === "tabs" && Array.isArray(n.tabs)) n.tabs = n.tabs.map((u, d) => {\n let c = O(u);\n if (c === void 0) return u;\n let f = { ...c };\n if ("content" in f) {\n let g = `${i}.tabs[${d}].content`, x = "items" in f;\n x || (f.items = f.content), delete f.content, r.push({ kind: "alias", path: g, message: x ? `${g} is ignored because canonical field \'items\' is present` : `${g} normalized/adopted as \'items\'`, type: e, field: "content", canonical: "items" });\n }\n return f.items = Array.isArray(f.items) ? f.items.map((g, x) => o(g, `${i}.tabs[${d}].items[${x}]`)) : f.items === void 0 ? [] : [o(f.items, `${i}.tabs[${d}].items[0]`)], f;\n });\n else if (e === "accordion" && Array.isArray(n.items)) n.items = n.items.map((u, d) => {\n let c = O(u);\n return c === void 0 ? u : { ...c, items: Array.isArray(c.items) ? c.items.map((f, g) => o(f, `${i}.items[${d}].items[${g}]`)) : c.items };\n });\n else if (e === "table" && Array.isArray(n.details)) {\n let u = { columns: n.columns, rows: n.rows, types: n.types };\n n.details = n.details.map((d, c) => !Array.isArray(d) || !C(u, c) ? d : d.map((f, g) => o(f, `${i}.details[${c}][${g}]`)));\n }\n return n;\n }\n function Ie(t) {\n let i = [];\n if (typeof t == "string") try {\n let s = JSON.parse(t);\n (O(s) !== void 0 || Array.isArray(s)) && (t = s, i.push({ kind: "alias", path: "spec", message: "double-encoded JSON string unwrapped into a spec value" }));\n } catch {\n }\n Array.isArray(t) && t.length > 0 && (t = { items: t }, i.push({ kind: "alias", path: "items", message: "root array normalized into an items envelope" }));\n let r = O(t);\n if (r === void 0) return { value: t, warnings: i };\n let e = { ...r };\n return N(e) ? { value: $e(e, "spec", i), warnings: i } : (Array.isArray(e.items) && (e.items = e.items.map((s, n) => $e(s, `items[${n}]`, i))), { value: e, warnings: i });\n }\n function F(t) {\n return typeof t == "object" && t !== null && !Array.isArray(t) ? t : void 0;\n }\n function _e(t) {\n let i = F(t);\n return i !== void 0 && typeof i.type == "string";\n }\n function Ge(t, i, r) {\n if (!_e(t)) return;\n let e = t.type, s = T[e];\n if (s === void 0) return;\n r(t, i, s);\n let n = (o, a) => Ge(o, a, r);\n if ((e === "row" || e === "col" || e === "grid" || e === "card") && Array.isArray(t.items)) t.items.forEach((o, a) => n(o, `${i}.items[${a}]`));\n else if (e === "list" && Array.isArray(t.items)) t.items.forEach((o, a) => n(o, `${i}.items[${a}]`));\n else if (e === "tabs" && Array.isArray(t.tabs)) t.tabs.forEach((o, a) => {\n let u = F(o);\n u !== void 0 && (Array.isArray(u.items) ? u.items.forEach((d, c) => n(d, `${i}.tabs[${a}].items[${c}]`)) : n(u.items, `${i}.tabs[${a}].items`));\n });\n else if (e === "accordion" && Array.isArray(t.items)) t.items.forEach((o, a) => {\n let u = F(o);\n u?.items !== void 0 && Array.isArray(u.items) && u.items.forEach((d, c) => n(d, `${i}.items[${a}].items[${c}]`));\n });\n else if (e === "table" && Array.isArray(t.details)) {\n let o = { columns: t.columns, rows: t.rows, types: t.types };\n t.details.forEach((a, u) => {\n Array.isArray(a) && C(o, u) && a.forEach((d, c) => n(d, `${i}.details[${u}][${c}]`));\n });\n }\n }\n function B(t, i, r, e) {\n t.push({ kind: "unknown-field", path: `${i}.${r}`, message: `${i}.${r}: unknown field for \'${e}\'`, type: e, field: r });\n }\n function Y(t, i, r, e, s) {\n let n = F(t);\n if (n !== void 0) {\n for (let o of Object.keys(n)) o in r.fields || B(s, i, o, e);\n for (let [o, a] of Object.entries(r.nested)) {\n let u = n[o];\n Array.isArray(u) ? u.forEach((d, c) => Y(d, `${i}.${o}[${c}]`, a, e, s)) : u !== void 0 && Y(u, `${i}.${o}`, a, e, s);\n }\n }\n }\n function Nn(t, i, r, e) {\n for (let [s, n] of Object.entries(r.nested)) {\n let o = t[s];\n Array.isArray(o) ? o.forEach((a, u) => Y(a, `${i}.${s}[${u}]`, n, t.type, e)) : o !== void 0 && Y(o, `${i}.${s}`, n, t.type, e);\n }\n }\n function Pe(t) {\n let i = [], r = F(t);\n if (r === void 0) return i;\n let e = (s, n, o) => {\n for (let a of Object.keys(s)) a === "type" || a in o.fields || B(i, n, a, s.type);\n Nn(s, n, o, i), s.type === "list" && Array.isArray(s.items) && s.items.forEach((a, u) => {\n if (_e(a)) return;\n let d = F(a);\n if (d !== void 0) for (let c of Object.keys(d)) {\n if (c === "title" || c === "desc") continue;\n let f = `${n}.items[${u}]`;\n i.push({ kind: "unknown-field", path: `${f}.${c}`, message: `${f}.${c}: list items render \'title\' and \'desc\' only \\u2014 \'${c}\' is dropped`, type: "list", field: c });\n }\n });\n };\n if (Array.isArray(r.items) && !N(r)) {\n for (let s of Object.keys(r)) s in V.fields || B(i, "spec", s, "spec");\n r.items.forEach((s, n) => Ge(s, `items[${n}]`, e));\n } else if (typeof r.type == "string") Ge(r, "spec", e);\n else for (let s of Object.keys(r)) s in V.fields || B(i, "spec", s, "spec");\n return i;\n }\n function ve(t, i) {\n let r = (s, n, o) => {\n o > m.maxDepth || s.forEach((a, u) => e(a, `${n}[${u}]`, o));\n }, e = (s, n, o) => {\n if (!(o > m.maxDepth) && (i(s, n), !(o >= m.maxDepth))) switch (s.type) {\n case "row":\n case "col":\n case "grid":\n case "card":\n r(s.items, `${n}.items`, o + 1);\n break;\n case "tabs":\n s.tabs.forEach((a, u) => r(a.items, `${n}.tabs[${u}].items`, o + 1));\n break;\n case "accordion":\n s.items.forEach((a, u) => r(a.items, `${n}.items[${u}].items`, o + 1));\n break;\n case "list":\n s.items.forEach((a, u) => {\n a !== null && typeof a == "object" && "type" in a && e(a, `${n}.items[${u}]`, o + 1);\n });\n break;\n case "table":\n s.details?.slice(0, I(s).length).forEach((a, u) => {\n a !== null && C(s, u) && r(a, `${n}.details[${u}]`, o + 1);\n });\n break;\n }\n };\n r(t.items, "items", 0);\n }\n function Re(t) {\n let i = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), e = [], s = [];\n ve(t, (n, o) => {\n if (n.type === "submit") {\n n.groups !== void 0 && s.push({ groups: n.groups, path: o });\n return;\n }\n let a, u;\n switch (n.type) {\n case "radio":\n if (n.group === void 0) return;\n a = { kind: "radio", key: n.group, label: n.label ?? n.group, options: n.options.slice(0, m.maxOptions), ...n.answer === void 0 ? {} : { answer: n.answer }, ...n.explanation === void 0 ? {} : { explanation: n.explanation } }, u = `${o}.group`;\n break;\n case "checkbox":\n if (n.group === void 0) return;\n a = { kind: "checkbox", key: n.group }, u = `${o}.group`;\n break;\n case "input":\n case "textarea":\n case "select":\n case "slider":\n if (n.id === void 0) return;\n a = { kind: "field", key: n.id, fieldType: n.type, secret: n.type === "input" && n.inputType === "password" }, u = `${o}.id`;\n break;\n default:\n return;\n }\n if (a === void 0) return;\n let d = i.get(a.key);\n if (d !== void 0) {\n (d.kind !== "checkbox" || a.kind !== "checkbox") && e.push(`${u} conflicts with ${r.get(a.key)}: submission key \'${a.key}\' is already used`);\n return;\n }\n i.set(a.key, a), r.set(a.key, u);\n });\n for (let { groups: n, path: o } of s) {\n let a = /* @__PURE__ */ new Set();\n n.forEach((u, d) => {\n let c = `${o}.groups[${d}]`;\n a.has(u) && e.push(`${c}: duplicate submission member \'${u}\'`), a.add(u);\n let f = i.get(u);\n f === void 0 ? e.push(`${c}: submit.groups references unknown submission member \'${u}\'`) : f.kind === "field" && f.secret && e.push(`${c}: submit.groups cannot require secret field \'${u}\'`);\n });\n }\n return { registry: { members: i }, diagnostics: e };\n }\n function En(t, i) {\n return typeof t == "string" && i.includes(t);\n }\n function p(t, i) {\n return typeof t == "string" ? t.slice(0, i) : void 0;\n }\n var Dn = /^(?:#[\\da-fA-F]{3,8}|rgba?\\([^)]{0,64}\\)|hsla?\\([^)]{0,64}\\)|var\\(--dsw-[\\w-]+(?:,\\s*#[0-9a-fA-F]{3,8})?\\))$/;\n function E(t) {\n if (typeof t != "string") return;\n let i = t.trim();\n return i.length <= 64 && Dn.test(i) ? i : void 0;\n }\n function qe(t) {\n if (typeof t != "string") return;\n let i = t.trim();\n if (!(i.length > 2048)) return /^https?:\\/\\//i.test(i) || /^mailto:[^@\\s]+@[^@\\s]+$/i.test(i) ? i : void 0;\n }\n function K(t) {\n if (typeof t != "string") return;\n let i = t.trim();\n if (!(i === "" || i.length > 2048)) {\n if (/^https?:\\/\\//i.test(i)) return i;\n if (!(/^[a-z][a-z0-9+.-]*:/i.test(i) || /^[/\\\\]{2}/.test(i))) return i;\n }\n }\n function k(t, i, r) {\n return typeof t == "number" && Number.isFinite(t) ? Math.min(r, Math.max(i, t)) : void 0;\n }\n function D(t, i, r) {\n return typeof t == "number" && Number.isFinite(t) ? Math.min(r, Math.max(i, Math.trunc(t))) : void 0;\n }\n function w(t, i) {\n return En(t, i) ? t : void 0;\n }\n function y(t) {\n return typeof t == "object" && t !== null && !Array.isArray(t) ? t : void 0;\n }\n function l(t, i) {\n return i === void 0 ? {} : { [t]: i };\n }\n function On(t) {\n if (t.length > 2048) return;\n let i = t.indexOf("#"), r = i < 0 ? t : t.slice(0, i);\n if (r.includes("?")) return;\n let e;\n try {\n e = decodeURIComponent(r);\n } catch {\n return;\n }\n if (e === "" || /[\\u0000-\\u001f\\u007f]/.test(e) || /^[\\\\/]{2}/.test(e) || /^[a-z][a-z\\d+.-]*:/i.test(e) && !/^[a-z]:[\\\\/]/i.test(e)) return;\n if (i < 0) return { path: e };\n let s = /^L([1-9]\\d*)(?:-L([1-9]\\d*))?$/.exec(t.slice(i + 1));\n if (s === null) return;\n let n = Number(s[1]), o = s[2] === void 0 ? n : Number(s[2]);\n if (!(!Number.isSafeInteger(n) || !Number.isSafeInteger(o) || o < n)) return { path: e, line: n };\n }\n function ze(t) {\n let i = qe(t);\n if (i !== void 0) return { type: "external", href: i };\n if (typeof t != "string") return { type: "invalid" };\n let r = On(t.trim());\n return r === void 0 ? { type: "invalid" } : { type: "file", file: r };\n }\n function H(t, i) {\n switch (i) {\n case "string":\n return typeof t == "string";\n case "string-or-null":\n return t === null || typeof t == "string";\n case "number":\n return typeof t == "number" && Number.isFinite(t);\n case "boolean":\n return typeof t == "boolean";\n case "nodes":\n return Array.isArray(t);\n case "array":\n return Array.isArray(t);\n case "object":\n return y(t) !== void 0;\n case "unknown":\n return true;\n }\n }\n function j(t) {\n switch (t) {\n case "string-or-null":\n return "a string or null";\n case "number":\n return "a finite number";\n case "boolean":\n return "a boolean";\n case "nodes":\n case "array":\n return "an array";\n case "object":\n return "an object";\n case "unknown":\n return "a value";\n default:\n return "a string";\n }\n }\n function v(t, i, r) {\n return t.some((e) => e.startsWith(`${i}.${r} `) || e.includes(`\'${r}\'`) || e.includes(`requires ${r}`));\n }\n function Ke(t, i, r, e, s = []) {\n for (let [n, o] of Object.entries(r.fields)) s.includes(n) || t[n] === void 0 || !H(t[n], o) && !v(e, i, n) && e.push(`${i}.${n} must be ${j(o)}`);\n for (let [n, o] of Object.entries(r.enums)) s.includes(n) || t[n] === void 0 || !H(t[n], "string") || !o.includes(t[n]) && !v(e, i, n) && e.push(`${i}.${n} must be one of ${o.join(", ")}`);\n }\n function W(t, i, r, e) {\n let s = y(t);\n if (s === void 0) {\n e.push(`${i} must be an object`);\n return;\n }\n for (let n of r.required) {\n let o = r.fields[n];\n s[n] === void 0 ? v(e, i, n) || e.push(`${i}: requires ${n}${o === void 0 ? "" : ` (${j(o)})`}`) : o !== void 0 && !H(s[n], o) && (v(e, i, n) || e.push(`${i}.${n} must be ${j(o)}`));\n }\n for (let [n, o] of Object.entries(r.fields)) s[n] !== void 0 && !H(s[n], o) && (v(e, i, n) || e.push(`${i}.${n} must be ${j(o)}`));\n for (let [n, o] of Object.entries(r.enums)) s[n] !== void 0 && typeof s[n] == "string" && !o.includes(s[n]) && (v(e, i, n) || e.push(`${i}.${n} must be one of ${o.join(", ")}`));\n for (let [n, o] of Object.entries(r.nested)) {\n let a = s[n];\n a !== void 0 && (Array.isArray(a) ? a.forEach((u, d) => W(u, `${i}.${n}[${d}]`, o, e)) : W(a, `${i}.${n}`, o, e));\n }\n }\n function Mn(t, i, r, e) {\n for (let [s, n] of Object.entries(r.nested)) {\n let o = t[s];\n o !== void 0 && (Array.isArray(o) ? o.forEach((a, u) => W(a, `${i}.${s}[${u}]`, n, e)) : W(o, `${i}.${s}`, n, e));\n }\n }\n function He(t) {\n let i = t.rows !== void 0 ? t.rows : t.data;\n return !Array.isArray(i) || i.length === 0 ? false : Array.isArray(i[0]);\n }\n function In(t, i, r, e) {\n let s = String(t.type), n = (a) => v(e, i, a), o = s === "table" && He(t) ? "columns" : null;\n for (let a of r.required) {\n let u = r.fields[a];\n if (u === void 0 || t[a] === void 0) {\n a !== o && !n(a) && e.push(`${i}: type \'${s}\' requires ${a}${u === void 0 ? "" : ` (${j(u)})`}`);\n continue;\n }\n !H(t[a], u) && !n(a) && e.push(`${i}.${a} must be ${j(u)}`);\n }\n Ke(t, i, r, e, ["type"]);\n for (let a of r.oneOfRequired) !a.some((u) => t[u] !== void 0) && !e.some((u) => u.includes(`requires ${a.join(" or ")}`)) && e.push(`${i}: type \'${s}\' requires one of ${a.join(" or ")}`);\n for (let a of r.conditionalRequired) if (t[a.when.field] === a.when.equals) for (let u of a.required) t[u] === void 0 && !n(u) && e.push(`${i}: type \'${s}\' requires ${u}${a.message === void 0 ? "" : ` (${a.message})`}`);\n Mn(t, i, r, e);\n }\n function _(t, i, r) {\n if (!Array.isArray(t)) return [];\n let e = [];\n for (let s of t) {\n if (i.remaining <= 0) break;\n i.remaining -= 1;\n let n = Je(s, i, r);\n n !== null && e.push(n);\n }\n return e;\n }\n function Fe(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t.slice(0, 12)) {\n let e = E(r);\n e !== void 0 && i.push(e);\n }\n return i.length > 0 ? i : void 0;\n }\n function je(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t.slice(0, 60)) {\n let e = typeof r == "number" ? r : Number(r);\n if (!Number.isFinite(e)) return;\n i.push(e);\n }\n return i.length >= 2 ? i : void 0;\n }\n function Je(t, i, r) {\n let e = _n(t, i, r);\n if (e === null) return null;\n let s = D(y(t)?.span, 2, 12), n = p(y(t)?.id, 64);\n return { ...e, ...l("span", s), ...l("id", n) };\n }\n function _n(t, i, r) {\n if (r > m.maxDepth) return null;\n let e = y(t);\n if (e === void 0) return null;\n let s = e.type;\n if (typeof s != "string") return null;\n switch (s) {\n case "text": {\n let n = p(e.content, m.maxString) ?? p(e.text, m.maxString);\n return n === void 0 ? null : { type: "text", content: n, ...l("copyable", e.copyable === true ? true : void 0), ...l("title", p(e.title, m.maxString)), ...l("size", w(e.size, ne)), ...l("center", e.center === true ? true : void 0) };\n }\n case "row":\n return { type: "row", items: _(e.items, i, r + 1), ...l("wrap", e.wrap === true ? true : void 0), ...l("spacer", e.spacer === true ? true : void 0) };\n case "col":\n return { type: "col", items: _(e.items, i, r + 1), ...l("gap", k(e.gap, 0, 96)) };\n case "grid":\n return { type: "grid", cols: D(e.cols, 1, m.maxGridCols) ?? 1, items: _(e.items, i, r + 1) };\n case "card":\n return { type: "card", items: _(e.items, i, r + 1), ...l("title", p(e.title, m.maxString)), ...l("tone", w(e.tone, be)), ...l("accent", E(e.accent)) };\n case "button": {\n let n = p(e.label, m.maxString);\n return n === void 0 ? null : { type: "button", label: n, ...l("tone", w(e.tone, te)), ...l("full", e.full === true ? true : void 0), ...l("small", e.small === true ? true : void 0), ...l("icon", p(e.icon, 64)), ...l("action", p(e.action, 200)) };\n }\n case "input":\n return { type: "input", ...l("label", p(e.label, m.maxString)), ...l("placeholder", p(e.placeholder, m.maxString)), ...l("value", p(e.value, m.maxString)), ...l("inputType", w(e.inputType, re)), ...l("action", p(e.action, 200)), ...l("id", p(e.id, 200)) };\n case "select": {\n let n = Q(e.options, m.maxOptions, m.maxString);\n return n === void 0 ? null : { type: "select", options: n, ...l("label", p(e.label, m.maxString)), ...l("action", p(e.action, 200)), ...l("selected", D(e.selected, 0, n.length - 1)), ...l("id", p(e.id, 200)) };\n }\n case "checkbox": {\n let n = p(e.label, m.maxString);\n return n === void 0 ? null : { type: "checkbox", label: n, ...l("checked", e.checked === true ? true : void 0), ...l("action", p(e.action, 200)), ...l("group", p(e.group, 200)) };\n }\n case "link": {\n let n = p(e.label, m.maxString);\n if (n === void 0) return null;\n let o = ze(e.href), a = o.type === "external" ? o.href : o.type === "file" ? String(e.href).trim() : void 0;\n return { type: "link", label: n, ...l("href", a) };\n }\n case "image": {\n let n = K(e.src);\n return n === void 0 ? null : { type: "image", src: n, ...l("alt", p(e.alt, m.maxString)) };\n }\n case "audio": {\n let n = K(e.src);\n return n === void 0 ? null : { type: "audio", src: n, ...l("alt", p(e.alt, m.maxString)), ...l("loop", e.loop === true ? true : void 0) };\n }\n case "video": {\n let n = K(e.src);\n return n === void 0 ? null : { type: "video", src: n, ...l("alt", p(e.alt, m.maxString)), ...l("poster", K(e.poster)), ...l("loop", e.loop === true ? true : void 0), ...l("muted", e.muted === true ? true : void 0), ...l("aspectRatio", w(e.aspectRatio, ae)) };\n }\n case "badge": {\n let n = p(e.label, m.maxString) ?? p(e.text, m.maxString) ?? p(e.value, m.maxString);\n return n === void 0 ? null : { type: "badge", label: n, ...l("tone", w(e.tone, ie)), ...l("icon", p(e.icon, 64)) };\n }\n case "hero": {\n let n = p(e.title, m.maxString);\n return n === void 0 ? null : { type: "hero", title: n, ...l("subtitle", p(e.subtitle, m.maxString)), ...l("value", p(e.value, 128)), ...l("label", p(e.label, m.maxString)), ...l("delta", p(e.delta, 64)), ...l("spark", je(e.spark)), ...l("tone", w(e.tone, he)) };\n }\n case "stat": {\n let n = p(e.label, m.maxString), o = p(e.value, 128);\n return n === void 0 || o === void 0 ? null : { type: "stat", label: n, value: o, ...l("delta", p(e.delta, 64)), ...l("spark", je(e.spark)), ...l("size", e.size === "hero" ? "hero" : void 0) };\n }\n case "progress": {\n let n = k(e.value, 0, 100);\n return n === void 0 ? null : { type: "progress", value: n, ...l("label", p(e.label, m.maxString)), ...l("valueLabel", p(e.valueLabel, 64)), ...l("variant", w(e.variant, ye)), ...l("target", k(e.target, 0, 100)) };\n }\n case "divider":\n return { type: "divider" };\n case "spacer":\n return { type: "spacer" };\n case "avatar": {\n let n = p(e.name, 64);\n return n === void 0 ? null : { type: "avatar", name: n, ...l("color", E(e.color)) };\n }\n case "list": {\n let n = Pn(e.items, m.maxListItems, i, r + 1);\n return n === void 0 ? null : { type: "list", items: n, ...l("filter", p(e.filter, 64)) };\n }\n case "table": {\n let n = ke(e);\n if (n === null) return null;\n let { columns: o, rows: a } = n, u = Array.isArray(e.types) ? e.types : void 0, d = u === void 0 ? void 0 : o.map((g, x) => {\n let $ = u[x];\n return typeof $ == "string" && Ee.includes($) ? $ : "text";\n }), c = Array.isArray(e.details) ? e.details : void 0, f = c === void 0 ? void 0 : a.map((g, x) => {\n if (!C({ columns: o, rows: a, types: d }, x)) return null;\n let $ = _(c[x], i, r + 1);\n return $.length === 0 ? null : $;\n });\n return { type: "table", columns: o, rows: a, ...l("types", d), ...l("total", e.total === true ? true : void 0), ...l("export", e.export === true ? true : void 0), ...l("filter", p(e.filter, 64)), ...l("filterColumn", D(e.filterColumn, 0, m.maxTableCols - 1)), ...l("sortField", p(e.sortField, 64)), ...l("details", f !== void 0 && f.some((g) => g !== null) ? f : void 0) };\n }\n case "chart": {\n let n = Te(e.data, m.maxChartPoints), o = Array.isArray(e.series) ? Le(e.series, m.maxPlotSeries, m.maxChartPoints) : void 0;\n return n === void 0 && o === void 0 ? null : { type: "chart", data: n ?? [], ...l("kind", w(e.kind, U)), ...l("series", o), ...l("horizontal", e.horizontal === true ? true : void 0), ...l("stacked", e.stacked === true ? true : void 0), ...l("filter", p(e.filter, 64)), ...l("palette", Fe(e.palette)) };\n }\n case "tabs": {\n let n = vn(e.tabs, i, r);\n return n === void 0 ? null : { type: "tabs", tabs: n };\n }\n case "plot": {\n let n = qn(e.series, m.maxPlotSeries);\n return n === void 0 ? null : { type: "plot", series: n, ...l("xMin", k(e.xMin, -1e6, 1e6)), ...l("xMax", k(e.xMax, -1e6, 1e6)), ...l("yMin", k(e.yMin, -1e9, 1e9)), ...l("yMax", k(e.yMax, -1e9, 1e9)), ...l("title", p(e.title, m.maxString)) };\n }\n case "callout": {\n let n = p(e.content, m.maxString);\n return n === void 0 ? null : { type: "callout", content: n, ...l("tone", w(e.tone, se)), ...l("title", p(e.title, m.maxString)) };\n }\n case "steps": {\n let n = zn(e.steps);\n return n === void 0 ? null : { type: "steps", steps: n, ...l("current", D(e.current, 0, n.length)) };\n }\n case "keyvalue": {\n let n = Fn(e.pairs, m.maxKeyValuePairs);\n return n === void 0 ? null : { type: "keyvalue", pairs: n };\n }\n case "diff": {\n let n = jn(e.diffs);\n return n === void 0 ? null : { type: "diff", diffs: n };\n }\n case "json":\n return "value" in e ? { type: "json", value: e.value } : null;\n case "code": {\n let n = p(e.code, m.maxCode);\n return n === void 0 ? null : { type: "code", code: n, ...l("lang", p(e.lang, 64)), ...l("title", p(e.title, m.maxString)), ...l("wrap", e.wrap === true ? true : void 0) };\n }\n case "radio": {\n let n = Q(e.options, m.maxOptions, m.maxString);\n return n === void 0 ? null : { type: "radio", options: n, ...l("label", p(e.label, m.maxString)), ...l("selected", D(e.selected, 0, n.length - 1)), ...l("action", p(e.action, 200)), ...l("group", p(e.group, 200)), ...l("answer", typeof e.answer == "number" && Number.isFinite(e.answer) && e.answer >= 0 && e.answer < n.length ? Math.trunc(e.answer) : typeof e.answer == "string" ? e.answer.slice(0, 512) : void 0), ...l("explanation", p(e.explanation, m.maxString)) };\n }\n case "submit": {\n let n = p(e.label, m.maxString), o = p(e.action, 200);\n return n === void 0 ? null : { type: "submit", label: n, ...l("action", o), ...l("resetAction", p(e.resetAction, 200)), ...l("groups", Q(e.groups, m.maxOptions, 200)) };\n }\n case "switch": {\n let n = p(e.label, m.maxString);\n return n === void 0 ? null : { type: "switch", label: n, ...l("checked", e.checked === true ? true : void 0), ...l("action", p(e.action, 200)) };\n }\n case "slider": {\n let n = k(e.min, -1e9, 1e9) ?? 0, o = k(e.max, -1e9, 1e9) ?? 100, a = Math.min(n, o), u = Math.max(n, o), d = k(e.step, 1e-9, Math.max(u - a, 1e-9)), c = k(e.value, a, u) ?? a;\n return { type: "slider", min: a, max: u, ...l("step", d), value: c, ...l("label", p(e.label, m.maxString)), ...l("action", p(e.action, 200)), ...l("id", p(e.id, 200)) };\n }\n case "textarea":\n return { type: "textarea", ...l("label", p(e.label, m.maxString)), ...l("placeholder", p(e.placeholder, m.maxString)), ...l("rows", D(e.rows, 1, 30)), ...l("value", p(e.value, m.maxString)), ...l("action", p(e.action, 200)), ...l("id", p(e.id, 200)) };\n case "accordion": {\n let n = Ln(e.items, i, r);\n return n === void 0 ? null : { type: "accordion", items: n };\n }\n case "copy": {\n let n = p(e.text, m.maxCode);\n return n === void 0 ? null : { type: "copy", text: n, ...l("label", p(e.label, 128)) };\n }\n case "svg": {\n let n = p(e.code, m.maxCode);\n return n === void 0 ? null : { type: "svg", code: n, ...l("title", p(e.title, m.maxString)), ...l("height", D(e.height, 100, 800)) };\n }\n case "mermaid": {\n let n = p(e.code, m.maxMermaid);\n return n === void 0 ? null : { type: "mermaid", code: n };\n }\n case "scene3d": {\n let n = Vn(e.meshes);\n return n === void 0 ? null : { type: "scene3d", meshes: n, ...l("title", p(e.title, m.maxString)), ...l("ambient", k(e.ambient, 0, 2)), ...l("background", E(e.background)) };\n }\n case "diagram":\n return Bn(e);\n case "timeline": {\n let n = Yn(e.items, m.maxTimelineItems);\n return n === void 0 ? null : { type: "timeline", items: n };\n }\n case "file-tree": {\n let n = Qn(e.items, m.maxListItems);\n return n === void 0 ? null : { type: "file-tree", items: n };\n }\n case "breadcrumb": {\n let n = Q(e.items, m.maxBreadcrumbItems, m.maxString);\n return n === void 0 ? null : { type: "breadcrumb", items: n };\n }\n case "quiz": {\n let n = p(e.question, m.maxString), o = Zn(e.options, e.answer);\n return n === void 0 || o === void 0 ? null : { type: "quiz", question: n, options: o, ...l("explanation", p(e.explanation, m.maxString)), ...l("id", p(e.id, 200)), ...l("action", p(e.action, 200)) };\n }\n case "echart": {\n let n = e.data !== void 0 ? Te(e.data, m.maxChartPoints) : void 0, o = e.series !== void 0 && Array.isArray(e.series) ? Le(e.series, m.maxPlotSeries, m.maxChartPoints) : void 0, a = Array.isArray(e.links) ? e.links.slice(0, m.maxChartPoints).flatMap((c) => {\n let f = y(c), g = f === void 0 ? void 0 : p(f.from, 64), x = f === void 0 ? void 0 : p(f.to, 64);\n return g === void 0 || x === void 0 ? [] : [{ from: g, to: x, ...l("value", k(f.value, 0, 1e9)) }];\n }) : void 0, u = e.option !== void 0 ? Ce(e.option, 0, { count: m.maxEChartOptionNodes }) : void 0, d = u === void 0 || typeof u != "object" || u === null || Array.isArray(u) ? void 0 : u;\n return d === void 0 && n === void 0 && o === void 0 && (a === void 0 || a.length === 0) ? null : { type: "echart", ...l("title", p(e.title, m.maxString)), ...l("height", D(e.height, 100, 800)), ...l("preset", w(e.preset, ge)), ...l("data", n), ...l("series", o), ...l("links", a !== void 0 && a.length > 0 ? a : void 0), ...l("palette", Fe(e.palette)), ...l("option", d) };\n }\n default:\n return t;\n }\n }\n function Q(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= i) break;\n if (typeof s == "string") e.push(s.slice(0, r));\n else if (s !== null && typeof s == "object") {\n let n = s, o = typeof n.label == "string" ? n.label : typeof n.value == "string" ? n.value : typeof n.title == "string" ? n.title : JSON.stringify(s);\n e.push(o.slice(0, r));\n }\n }\n return e;\n }\n function Pn(t, i, r, e) {\n if (!Array.isArray(t)) return;\n let s = [];\n for (let n of t) {\n if (s.length >= i) break;\n if (typeof n == "string") {\n s.push(n.slice(0, m.maxString));\n continue;\n }\n let o = y(n);\n if (o !== void 0 && typeof o.type == "string") {\n if (r.remaining <= 0) break;\n r.remaining -= 1;\n let u = Je(o, r, e);\n u !== null && s.push(u);\n continue;\n }\n let a = o === void 0 ? void 0 : p(o.title, m.maxString);\n a !== void 0 && s.push({ title: a, ...l("desc", p(o?.desc, m.maxString)) });\n }\n return s;\n }\n function Te(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.label, 128), o = s === void 0 ? void 0 : k(s.value, -1e12, 1e12);\n n === void 0 || o === void 0 || r.push({ label: n, value: o, ...l("color", s === void 0 ? void 0 : E(s.color)) });\n }\n return r;\n }\n function Le(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= i) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.label, 128), a = n === void 0 ? void 0 : Te(n.data, r);\n o === void 0 || a === void 0 || e.push({ label: o, data: a, ...l("color", n === void 0 ? void 0 : E(n.color)) });\n }\n return e;\n }\n function vn(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= m.maxTabs) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.label, 128);\n if (o === void 0 || n === void 0) continue;\n let a = n.items !== void 0 ? n.items : n.content !== void 0 ? Array.isArray(n.content) ? n.content : [n.content] : void 0;\n e.push({ label: o, items: _(a, i, r + 1) });\n }\n return e;\n }\n function qn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.expr, 512);\n if (n === void 0 || s === void 0) continue;\n let o = [];\n if (Array.isArray(s.params)) for (let a of s.params) {\n if (o.length >= m.maxPlotParams) break;\n let u = y(a), d = u === void 0 ? void 0 : p(u.name, 64), c = u === void 0 ? void 0 : k(u.value, -1e9, 1e9);\n d === void 0 || c === void 0 || o.push({ name: d, value: c, ...l("min", u === void 0 ? void 0 : k(u.min, -1e9, 1e9)), ...l("max", u === void 0 ? void 0 : k(u.max, -1e9, 1e9)), ...l("step", u === void 0 ? void 0 : k(u.step, 1e-9, 1e9)), ...l("animateTo", u === void 0 ? void 0 : k(u.animateTo, -1e9, 1e9)), ...l("durationMs", u === void 0 ? void 0 : k(u.durationMs, 1, 12e4)), ...l("loop", u === void 0 ? void 0 : u.loop === true ? true : void 0) });\n }\n r.push({ expr: n, ...l("label", p(s.label, 128)), ...l("color", E(s.color)), ...l("kind", w(s.kind, oe)), ...l("params", o.length > 0 ? o : void 0) });\n }\n return r;\n }\n function zn(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxSteps) break;\n let e = y(r), s = e === void 0 ? void 0 : p(e.title, 256);\n s !== void 0 && i.push({ title: s, ...l("desc", e === void 0 ? void 0 : p(e.desc, m.maxString)) });\n }\n return i;\n }\n function Fn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.key, 256), o = s === void 0 ? void 0 : p(s.value, m.maxString);\n n === void 0 || o === void 0 || r.push({ key: n, value: o });\n }\n return r;\n }\n function jn(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= 24) break;\n let e = y(r), s = e === void 0 ? void 0 : p(e.path, 1024), n = e === void 0 ? void 0 : p(e.newText, 2e4);\n if (s === void 0 || n === void 0) continue;\n let o = e === void 0 ? void 0 : e.oldText;\n i.push({ path: s, newText: n, oldText: o === null || typeof o != "string" ? null : o.slice(0, 2e4) });\n }\n return i;\n }\n function Ln(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= m.maxAccordionItems) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.title, 256);\n o === void 0 || n === void 0 || e.push({ title: o, items: _(n.items, i, r + 1) });\n }\n return e;\n }\n function Vn(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxMeshes) break;\n let e = y(r), s = e === void 0 ? void 0 : w(e.shape, ue);\n if (s === void 0) continue;\n let n = e === void 0 ? void 0 : k(e.scale, -1e6, 1e6) ?? Z(e.scale), o = e === void 0 ? void 0 : k(e.size, -1e6, 1e6) ?? Z(e.size);\n i.push({ shape: s, ...l("color", e === void 0 ? void 0 : E(e.color)), ...l("position", e === void 0 ? void 0 : Z(e.position)), ...l("rotation", e === void 0 ? void 0 : Z(e.rotation)), ...l("scale", n), ...l("size", o) });\n }\n return i;\n }\n function Z(t) {\n if (!Array.isArray(t) || t.length !== 3) return;\n let [i, r, e] = t;\n if (!(typeof i != "number" || !Number.isFinite(i) || typeof r != "number" || !Number.isFinite(r) || typeof e != "number" || !Number.isFinite(e))) return [Math.min(1e6, Math.max(-1e6, i)), Math.min(1e6, Math.max(-1e6, r)), Math.min(1e6, Math.max(-1e6, e))];\n }\n function P(t, i, r) {\n return Math.min(r, Math.max(i, Math.round(t / 4) * 4));\n }\n function Kn(t) {\n if (!Array.isArray(t)) return;\n let i = [], r = /* @__PURE__ */ new Set();\n for (let e of t) {\n if (i.length >= m.maxDiagramNodes) break;\n let s = y(e);\n if (s === void 0) continue;\n let n = p(s.id, 128), o = p(s.label, m.maxString);\n if (n === void 0 || o === void 0 || r.has(n)) continue;\n r.add(n);\n let a = w(s.type, ce), u = s.x === void 0 ? void 0 : P(k(s.x, -1e6, 1e6) ?? 0, 0, 1e6), d = s.y === void 0 ? void 0 : P(k(s.y, -1e6, 1e6) ?? 0, 0, 1e6), c = s.w === void 0 ? void 0 : P(k(s.w, -1e6, 1e6) ?? 96, 40, 2e3), f = s.h === void 0 ? void 0 : P(k(s.h, -1e6, 1e6) ?? 48, 24, 1200);\n i.push({ id: n, label: o, ...l("sub", p(s.sub, 256)), ...l("type", a), ...l("x", u), ...l("y", d), ...l("w", c), ...l("h", f), ...l("tag", p(s.tag, 32)) });\n }\n return i;\n }\n function Hn(t) {\n if (t === void 0) return [];\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxDiagramEdges) break;\n let e = y(r);\n if (e === void 0) continue;\n let s = p(e.from, 128), n = p(e.to, 128);\n s === void 0 || n === void 0 || i.push({ from: s, to: n, ...l("label", p(e.label, m.maxDiagramLabel)), ...l("kind", w(e.kind, pe)), ...l("route", w(e.route, me)) });\n }\n return i;\n }\n function Jn(t) {\n let i = y(t);\n if (i === void 0) return;\n let r = {};\n for (let e of ["paper", "paper-2", "ink", "muted", "soft", "rule", "accent", "accent-tint", "link"]) {\n let s = E(i[e]);\n s !== void 0 && (r[e] = s);\n }\n return Object.keys(r).length === 0 ? void 0 : r;\n }\n function Un(t) {\n if (t === void 0) return [];\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxDiagramZones) break;\n let e = y(r);\n if (e === void 0) continue;\n let s = p(e.label, 64);\n s !== void 0 && i.push({ label: s, ...l("x", e.x === void 0 ? void 0 : P(k(e.x, -1e6, 1e6) ?? 0, 0, 1e6)), ...l("y", e.y === void 0 ? void 0 : P(k(e.y, -1e6, 1e6) ?? 0, 0, 1e6)), ...l("w", e.w === void 0 ? void 0 : P(k(e.w, -1e6, 1e6) ?? 100, 40, 2e3)), ...l("h", e.h === void 0 ? void 0 : P(k(e.h, -1e6, 1e6) ?? 100, 40, 1200)) });\n }\n return i;\n }\n function Bn(t) {\n let i = y(t);\n if (i === void 0) return null;\n let r = w(i.kind, de);\n if (r === void 0) return null;\n let e = Kn(i.nodes);\n if (e === void 0) return null;\n let s = Hn(i.edges);\n if (s === void 0) return null;\n let n = Un(i.zones);\n return n === void 0 ? null : { type: "diagram", kind: r, nodes: e, edges: s, ...l("zones", n.length > 0 ? n : void 0), ...l("variant", w(i.variant, fe)), ...l("title", p(i.title, 256)), ...l("theme", Jn(i.theme)) };\n }\n function Yn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.title, 256);\n n !== void 0 && r.push({ title: n, ...l("desc", s === void 0 ? void 0 : p(s.desc, m.maxString)), ...l("time", s === void 0 ? void 0 : p(s.time, 128)) });\n }\n return r;\n }\n function Qn(t, i) {\n return Ue(t, i, m.maxTreeDepth);\n }\n function Ue(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= i) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.name, 256);\n if (o === void 0) continue;\n let a = n !== void 0 && r > 0 && Array.isArray(n.children) ? Ue(n.children, i, r - 1) : void 0;\n e.push({ name: o, ...l("type", n === void 0 ? void 0 : w(n.type, le)), ...l("children", a) });\n }\n return e;\n }\n function Zn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let s of t) {\n if (r.length >= m.maxQuizOptions) break;\n let n = y(s), o = typeof s == "string" ? p(s, 512) : n === void 0 ? void 0 : p(n.label, 512);\n o !== void 0 && r.push({ label: o, ...l("correct", n === void 0 ? void 0 : n.correct === true ? true : void 0), ...l("feedback", n === void 0 ? void 0 : p(n.feedback, m.maxString)) });\n }\n if (r.length === 0) return;\n if (r.some((s) => s.correct === true)) return r;\n let e = typeof i == "number" && Number.isFinite(i) ? Math.trunc(i) : typeof i == "string" ? r.findIndex((s) => s.label === i.slice(0, 512)) : -1;\n return e < 0 || e >= r.length ? r : r.map((s, n) => n === e ? { ...s, correct: true } : s);\n }\n var Wn = /<(?:script|img|svg|iframe|video|audio|object|embed|source)\\b|on[a-z]+\\s*=|javascript:/i;\n function Ce(t, i, r) {\n if (r.count <= 0 || (r.count -= 1, i > m.maxEChartOptionDepth)) return;\n if (typeof t == "string") {\n let n = t.slice(0, m.maxString);\n return n.toLowerCase().includes("url(") || Wn.test(n) ? void 0 : n;\n }\n if (typeof t == "number" && Number.isFinite(t) || typeof t == "boolean") return t;\n if (t === null) return null;\n if (Array.isArray(t)) {\n let n = Math.min(t.length, m.maxEChartArrayLen), o = [];\n for (let a = 0; a < n; a++) {\n let u = Ce(t[a], i + 1, r);\n u !== void 0 && o.push(u);\n }\n return o.length > 0 || t.length === 0 ? o : void 0;\n }\n let e = y(t);\n if (e === void 0) return;\n let s = {};\n for (let [n, o] of Object.entries(e)) {\n let a = Ce(o, i + 1, r);\n a !== void 0 && (n === "tooltip" && typeof a == "object" && a !== null && !Array.isArray(a) && (a.renderMode = "richText"), s[n] = a);\n }\n return Object.keys(s).length > 0 || Object.keys(e).length === 0 ? s : void 0;\n }\n function Be(t) {\n let i = y(t);\n if (i === void 0) return null;\n if (N(t)) {\n let e = z(t);\n return e === null ? null : Be(e);\n }\n if (!Array.isArray(i.items)) return null;\n let r = { remaining: m.maxNodes };\n return { ...l("title", p(i.title, m.maxString)), ...l("gap", k(i.gap, 0, 96)), ...l("panel", i.panel === true ? true : void 0), ...l("append", i.append === true ? true : void 0), items: _(i.items, r, 0) };\n }\n function Xn(t, i = Number.POSITIVE_INFINITY) {\n let r = 0, e = (n) => {\n if (Array.isArray(n)) for (let o of n) {\n if (r >= i) return;\n r += 1;\n let a = y(o);\n if (a !== void 0) {\n if (a.type === "tabs" && Array.isArray(a.tabs)) for (let u of a.tabs) {\n if (r >= i) return;\n let d = y(u);\n d !== void 0 && e(d.items);\n }\n else if (a.type === "accordion" && Array.isArray(a.items)) for (let u of a.items) {\n if (r >= i) return;\n let d = y(u);\n d !== void 0 && e(d.items);\n }\n else if ((a.type === "row" || a.type === "col" || a.type === "grid" || a.type === "card") && Array.isArray(a.items)) e(a.items);\n else if (a.type !== "file-tree") {\n if (a.type === "list" && Array.isArray(a.items)) for (let u of a.items) {\n if (r >= i) return;\n let d = y(u);\n d !== void 0 && typeof d.type == "string" && e([d]);\n }\n else if (a.type === "table" && Array.isArray(a.details)) {\n let u = I(a).length;\n for (let d = 0; d < Math.min(a.details.length, u); d++) {\n if (r >= i) return;\n let c = a.details[d];\n Array.isArray(c) && C(a, d) && e(c);\n }\n }\n }\n }\n }\n }, s = y(t);\n return e(s === void 0 ? [] : s.items), r;\n }\n var et = q;\n function nt(t, i, r) {\n let e = 0, s = (d) => {\n let c = y(d);\n return c !== void 0 && typeof c.type == "string" && et.has(c.type);\n };\n function n(d, c) {\n if (Array.isArray(d)) {\n for (let f = 0; f < d.length; f++) if (o(d[f], `${c}[${f}]`), e >= i) return;\n }\n }\n function o(d, c) {\n if (e >= i || !s(d)) return;\n let f = y(d);\n if (f !== void 0) {\n if (e += 1, r(f, c), f.type === "tabs" && Array.isArray(f.tabs)) for (let g = 0; g < f.tabs.length; g++) a(f.tabs[g], `${c}.tabs[${g}]`);\n else if (f.type === "accordion" && Array.isArray(f.items)) for (let g = 0; g < f.items.length; g++) a(f.items[g], `${c}.items[${g}]`);\n else if ((f.type === "row" || f.type === "col" || f.type === "grid" || f.type === "card") && Array.isArray(f.items)) n(f.items, `${c}.items`);\n else if (f.type === "list" && Array.isArray(f.items)) for (let g = 0; g < f.items.length; g++) o(f.items[g], `${c}.items[${g}]`);\n else if (f.type === "table" && Array.isArray(f.details)) {\n let g = I(f).length;\n for (let x = 0; x < Math.min(f.details.length, g); x++) Array.isArray(f.details[x]) && C(f, x) && n(f.details[x], `${c}.details[${x}]`);\n }\n }\n }\n function a(d, c) {\n let f = y(d);\n if (f === void 0) return;\n let g = f.items !== void 0 ? f.items : f.content;\n Array.isArray(g) ? n(g, `${c}.items`) : o(g, `${c}.items`);\n }\n let u = y(t);\n return u === void 0 || (N(u) && s(t) ? o(t, "spec") : n(u.items, "items")), e;\n }\n function Ye(t, i = Number.POSITIVE_INFINITY) {\n return nt(t, i, () => {\n });\n }\n function tt(t, i = Number.POSITIVE_INFINITY) {\n return Ye(t, i);\n }\n function Qe(t) {\n let i = [], r = y(t);\n if (r === void 0) return { ok: false, errors: ["spec root must be an object"] };\n if (N(t)) {\n let a = z(t);\n return a !== null ? Qe(a) : { ok: false, errors: ["spec.items must be an array"] };\n }\n if (!Array.isArray(r.items)) return { ok: false, errors: ["spec.items must be an array"] };\n Ke(r, "spec", V, i, ["items"]);\n let e = 0, s = false, n = (a, u, d) => {\n if (!s) {\n if (!Array.isArray(a)) {\n i.push(`${d} must be an array`);\n return;\n }\n for (let c = 0; c < a.length; c++) {\n if (s || e >= m.maxNodes) {\n s || (i.push(`spec exceeds ${m.maxNodes} nodes; tail elided`), s = true);\n return;\n }\n e += 1;\n let f = `${d}[${c}]`;\n Xe(a[c], u, f, i, n);\n }\n }\n };\n n(r.items, 0, "items"), i.length === 0 && i.push(...Re(r).diagnostics);\n let o = [...new Set(i)];\n return { ok: o.length === 0, errors: o };\n }\n function Ze(t) {\n let i = Ie(t), r = Be(i.value), e = Qe(i.value), s = Ye(i.value, m.maxNodes + 1), n = r === null ? 0 : tt(r), o = r === null ? 0 : Xn(r), a = e.errors.filter((u) => !u.includes(": unknown type "));\n return r !== null && a.length === 0 && a.push(...Re(r).diagnostics), s > n && a.push(`repair dropped ${s - n} declared native node(s): declared ${s}, rendered ${n}`), { value: i.value, normalized: i.value, repaired: r, spec: r, errors: [...new Set(a)], warnings: [...i.warnings, ...Pe(i.value)], declaredCount: s, renderedCount: o, declaredNativeCount: s, renderedNativeCount: n, renderedTotalCount: o };\n }\n function it(t) {\n return t.errors.length > 0 && t.errors.every((i) => i.startsWith("spec exceeds ") || i.startsWith("repair dropped ")) && t.renderedNativeCount === m.maxNodes && t.declaredNativeCount === m.maxNodes + 1;\n }\n function Ne(t) {\n return t.spec !== null && (t.errors.length === 0 || it(t));\n }\n var rt = /^(items\\[\\d+\\](?:\\.(?:items\\[\\d+\\]|tabs\\[\\d+\\]\\.items\\[\\d+\\]|details\\[\\d+\\](?:\\[\\d+\\])?))*)/;\n function st(t) {\n let i = rt.exec(t);\n return i === null ? null : i[1] ?? null;\n }\n function Ve(t, i) {\n let r = [...i.matchAll(/(?:^|\\.)(items|tabs|details)\\[(\\d+)\\]|\\[(\\d+)\\]/g)];\n if (r.length === 0 || r[r.length - 1][1] === "tabs") return;\n let e = t;\n for (let s = 0; s < r.length; s++) {\n let n = r[s], o = n[1] === void 0 ? e : y(e)?.[n[1]], a = Number(n[2] ?? n[3]);\n if (!Array.isArray(o) || a >= o.length) return;\n if (s === r.length - 1) return { array: o, index: a, preserveIndex: n[1] === "details" };\n if (e = o[a], e === void 0) return;\n }\n }\n function ot(t) {\n try {\n return y(JSON.parse(JSON.stringify(t))) ?? null;\n } catch {\n return null;\n }\n }\n function at(t) {\n if (Ne(t)) return t.spec;\n if (t.spec === null) return null;\n let i = y(t.value);\n if (i === void 0) return null;\n let r = /* @__PURE__ */ new Set(), e = /* @__PURE__ */ new Set();\n for (let d of t.errors) {\n if (d.startsWith("spec exceeds ")) continue;\n let c = st(d);\n c !== null && (d === `${c}.details must not contain more entries than rows` ? e.add(c) : r.add(c));\n }\n if (r.size === 0 && e.size === 0) return null;\n let s = ot(N(i) ? z(i) : i);\n if (s === null) return null;\n let n = [...r].map((d) => Ve(s, d)).filter((d) => d !== void 0), o = [...e].map((d) => Ve(s, d)).filter((d) => d !== void 0);\n for (let { array: d, index: c } of o) {\n let f = y(d[c]);\n f?.type === "table" && Array.isArray(f.details) && (f.details.length = Math.min(f.details.length, I(f).length));\n }\n let a = /* @__PURE__ */ new Map();\n for (let { array: d, index: c, preserveIndex: f } of n) {\n if (f) {\n d[c] = null;\n continue;\n }\n let g = a.get(d);\n g === void 0 ? a.set(d, [c]) : g.push(c);\n }\n for (let [d, c] of a) {\n c.sort((f, g) => g - f);\n for (let f of c) d.splice(f, 1);\n }\n let u = Ze(s);\n return !Ne(u) || u.renderedNativeCount === 0 ? null : u.spec;\n }\n function We(t, i, r) {\n if (Array.isArray(t)) for (let e = 0; e < t.length; e++) {\n let s = y(t[e]), n = `${i}[${e}]`;\n if (s === void 0) {\n r.push(`${n} must be an object`);\n continue;\n }\n typeof s.label != "string" && r.push(`${n}.label must be a string`), (typeof s.value != "number" || !Number.isFinite(s.value)) && r.push(`${n}.value must be a finite number`), s.color !== void 0 && typeof s.color != "string" && r.push(`${n}.color must be a string`);\n }\n }\n function ut(t, i, r) {\n if (Array.isArray(t)) for (let e = 0; e < t.length; e++) {\n let s = y(t[e]), n = `${i}[${e}]`;\n if (s === void 0) {\n r.push(`${n} must be an object`);\n continue;\n }\n typeof s.label != "string" && r.push(`${n}.label must be a string`), s.color !== void 0 && typeof s.color != "string" && r.push(`${n}.color must be a string`), Array.isArray(s.data) || r.push(`${n}.data must be an array`), We(s.data, `${n}.data`, r);\n }\n }\n function lt(t, i, r) {\n !Array.isArray(t.data) && !Array.isArray(t.series) && r.push(`${i}: type \'chart\' requires data or series (array)`), t.variant !== void 0 && r.push(`${i}.variant is unsupported; use kind`), t.data !== void 0 && !Array.isArray(t.data) && r.push(`${i}.data must be an array`), t.series !== void 0 && !Array.isArray(t.series) && r.push(`${i}.series must be an array`), t.kind !== void 0 && (typeof t.kind != "string" || !U.includes(t.kind)) && r.push(`${i}.kind must be bars, line, or donut`);\n let e = t.kind === void 0 ? "bars" : t.kind, s = Array.isArray(t.series) ? t.series : void 0;\n if (Array.isArray(t.data) && t.data.length === 0 && (s === void 0 || s.length === 0) && r.push(`${i}.data must not be empty`), s !== void 0) {\n s.length === 0 && r.push(`${i}.series must not be empty`), e === "donut" && r.push(`${i}.series is only supported for bars and line`);\n for (let n = 0; n < s.length; n++) {\n let o = y(s[n]);\n o !== void 0 && Array.isArray(o.data) && o.data.length === 0 && r.push(`${i}.series[${n}].data must not be empty`);\n }\n }\n e === "donut" && t.data === void 0 && r.push(`${i}.data is required for donut`), e === "line" && t.data === void 0 && (s === void 0 || s.length === 0) && r.push(`${i}.data is required for line (or provide series)`), We(t.data, `${i}.data`, r), ut(t.series, `${i}.series`, r);\n }\n function dt(t, i, r) {\n if (Array.isArray(t)) for (let e = 0; e < t.length; e++) {\n let s = t[e];\n if (y(s) === void 0) {\n if (!Array.isArray(s)) {\n r.push(`${i}[${e}] must be an array or object`);\n continue;\n }\n for (let n = 0; n < s.length; n++) {\n let o = s[n];\n typeof o != "string" && (typeof o != "number" || !Number.isFinite(o)) && r.push(`${i}[${e}][${n}] must be a string or finite number`);\n }\n }\n }\n }\n function Xe(t, i, r, e, s) {\n if (i > m.maxDepth) {\n e.push(`${r}: exceeds max depth ${m.maxDepth}`);\n return;\n }\n let n = y(t);\n if (n === void 0) {\n e.push(`${r}: must be an object`);\n return;\n }\n let o = n.type;\n if (typeof o != "string") {\n e.push(`${r}: missing string \'type\'`);\n return;\n }\n let a = (c) => {\n n[c] !== void 0 && typeof n[c] != "string" && e.push(`${r}: \'${c}\' must be a string`);\n }, u = (c) => {\n n[c] !== void 0 && (typeof n[c] != "number" || !Number.isFinite(n[c])) && e.push(`${r}: \'${c}\' must be a finite number`);\n };\n switch (o) {\n case "text":\n typeof n.content != "string" && typeof n.text != "string" && e.push(`${r}: type \'text\' requires content or text (string)`), a("content"), a("text");\n break;\n case "row":\n case "col":\n case "card":\n case "grid":\n Array.isArray(n.items) || e.push(`${r}: type \'${o}\' requires items (array)`), s(n.items, i + 1, `${r}.items`), o === "grid" && u("cols");\n break;\n case "button":\n case "checkbox":\n case "link":\n case "switch":\n typeof n.label != "string" && e.push(`${r}: type \'${o}\' requires label (string)`), a("label");\n break;\n case "image":\n case "audio":\n case "video":\n typeof n.src != "string" && e.push(`${r}: type \'${o}\' requires src (string)`), a("src"), a("alt"), o === "video" && a("poster");\n break;\n case "slider":\n a("label"), u("min"), u("max"), u("step"), u("value");\n break;\n case "input":\n case "textarea":\n a("label"), a("placeholder"), a("value");\n break;\n case "select":\n case "radio":\n Array.isArray(n.options) || e.push(`${r}: type \'${o}\' requires options (array)`);\n break;\n case "submit":\n typeof n.label != "string" && e.push(`${r}: type \'submit\' requires label (string)`);\n break;\n case "badge":\n typeof n.label != "string" && typeof n.text != "string" && typeof n.value != "string" && e.push(`${r}: type \'badge\' requires label, text, or value (string)`), a("label"), a("text"), a("value");\n break;\n case "hero":\n typeof n.title != "string" && e.push(`${r}: type \'hero\' requires title (string)`), a("subtitle");\n break;\n case "stat":\n typeof n.label != "string" && e.push(`${r}: type \'stat\' requires label (string)`), typeof n.value != "string" && e.push(`${r}: type \'stat\' requires value (string)`), a("delta");\n break;\n case "progress":\n (typeof n.value != "number" || !Number.isFinite(n.value) || n.value < 0 || n.value > 100) && e.push(`${r}: type \'progress\' requires value (number 0..100)`), u("value");\n break;\n case "avatar":\n typeof n.name != "string" && e.push(`${r}: type \'avatar\' requires name (string)`);\n break;\n case "list":\n if (Array.isArray(n.items) || e.push(`${r}: type \'list\' requires items (array)`), Array.isArray(n.items)) for (let c = 0; c < n.items.length; c++) {\n let f = y(n.items[c]);\n f !== void 0 && typeof f.type == "string" && Xe(f, i + 1, `${r}.items[${c}]`, e, s);\n }\n break;\n case "table":\n if (!Array.isArray(n.columns) && !He(n) && e.push(`${r}: type \'table\' requires columns (array)`), Array.isArray(n.rows) || e.push(`${r}: type \'table\' requires rows (array)`), n.types !== void 0 && !Array.isArray(n.types) && e.push(`${r}.types must be an array of column cell types`), n.details !== void 0 && !Array.isArray(n.details) && e.push(`${r}.details must be an array aligned with rows`), Array.isArray(n.details)) {\n let c = { columns: n.columns, rows: n.rows, types: n.types }, f = I(c).length;\n n.details.length > f && e.push(`${r}.details must not contain more entries than rows`);\n for (let g = 0; g < Math.min(n.details.length, f); g++) {\n let x = n.details[g];\n if (!(x === null || !C(c, g))) {\n if (!Array.isArray(x)) {\n e.push(`${r}.details[${g}] must be an array or null`);\n continue;\n }\n s(x, i + 1, `${r}.details[${g}]`);\n }\n }\n }\n dt(n.rows, `${r}.rows`, e);\n break;\n case "chart":\n lt(n, r, e);\n break;\n case "tabs": {\n if (Array.isArray(n.tabs) || e.push(`${r}: type \'tabs\' requires tabs (array)`), Array.isArray(n.tabs)) for (let c = 0; c < n.tabs.length; c++) {\n let f = y(n.tabs[c]);\n if (f === void 0) {\n e.push(`${r}.tabs[${c}] must be an object`);\n continue;\n }\n typeof f.label != "string" && e.push(`${r}.tabs[${c}].label must be a string`), s(f.items, i + 1, `${r}.tabs[${c}].items`);\n }\n break;\n }\n case "plot":\n Array.isArray(n.series) || e.push(`${r}: type \'plot\' requires series (array)`);\n break;\n case "callout":\n typeof n.content != "string" && e.push(`${r}: type \'callout\' requires content (string)`);\n break;\n case "steps":\n Array.isArray(n.steps) || e.push(`${r}: type \'steps\' requires steps (array)`);\n break;\n case "keyvalue":\n Array.isArray(n.pairs) || e.push(`${r}: type \'keyvalue\' requires pairs (array)`);\n break;\n case "diff":\n Array.isArray(n.diffs) || e.push(`${r}: type \'diff\' requires diffs (array)`);\n break;\n case "json":\n "value" in n || e.push(`${r}: type \'json\' requires value`);\n break;\n case "code":\n typeof n.code != "string" && e.push(`${r}: type \'code\' requires code (string)`);\n break;\n case "accordion":\n if (Array.isArray(n.items) || e.push(`${r}: type \'accordion\' requires items (array)`), Array.isArray(n.items)) for (let c = 0; c < n.items.length; c++) {\n let f = y(n.items[c]);\n if (f === void 0) {\n e.push(`${r}.items[${c}] must be an object`);\n continue;\n }\n typeof f.title != "string" && e.push(`${r}.items[${c}].title must be a string`), s(f.items, i + 1, `${r}.items[${c}].items`);\n }\n break;\n case "copy":\n typeof n.text != "string" && e.push(`${r}: type \'copy\' requires text (string)`);\n break;\n case "svg":\n typeof n.code != "string" && e.push(`${r}: type \'svg\' requires code (string)`), u("height");\n break;\n case "mermaid":\n typeof n.code != "string" && e.push(`${r}: type \'mermaid\' requires code (string)`);\n break;\n case "scene3d":\n Array.isArray(n.meshes) || e.push(`${r}: type \'scene3d\' requires meshes (array)`);\n break;\n case "timeline":\n Array.isArray(n.items) || e.push(`${r}: type \'timeline\' requires items (array)`);\n break;\n case "file-tree":\n Array.isArray(n.items) || e.push(`${r}: type \'file-tree\' requires items (array)`);\n break;\n case "breadcrumb":\n Array.isArray(n.items) || e.push(`${r}: type \'breadcrumb\' requires items (array)`);\n break;\n case "quiz":\n typeof n.question != "string" && e.push(`${r}: type \'quiz\' requires question (string)`), Array.isArray(n.options) || e.push(`${r}: type \'quiz\' requires options (array)`);\n break;\n case "diagram":\n typeof n.kind != "string" && e.push(`${r}: type \'diagram\' requires kind (string)`), Array.isArray(n.nodes) || e.push(`${r}: type \'diagram\' requires nodes (array)`), n.edges !== void 0 && !Array.isArray(n.edges) && e.push(`${r}: type \'diagram\' requires edges (array) when present`);\n break;\n case "echart":\n n.option === void 0 && n.data === void 0 && n.series === void 0 && (!Array.isArray(n.links) || n.links.length === 0) && e.push(`${r}: type \'echart\' requires option, data, series, or links`), u("height");\n break;\n default:\n e.push(`${r}: unknown type \'${o}\' (custom renderer?)`);\n }\n let d = T[o];\n d !== void 0 && In(n, r, d, e);\n }\n\n // lib/normalize-visual.js\n function normalizeVisual(value, schemas) {\n const unwrap = (v2) => v2 && typeof v2 === "object" && !Array.isArray(v2) && Object.keys(v2).length === 1 && Array.isArray(v2.item) ? v2.item : v2;\n const scalar2 = (v2, kind) => kind === "number" && typeof v2 === "string" && v2.trim() !== "" && Number.isFinite(Number(v2)) ? Number(v2) : kind === "boolean" && (v2 === "true" || v2 === "false") ? v2 === "true" : v2;\n function record(input, schema, depth = 0) {\n if (!input || typeof input !== "object" || Array.isArray(input) || depth > 32) return input;\n const out2 = { ...input };\n for (const [key, v2] of Object.entries(input)) {\n const target = schema.aliases?.[key] ?? key, kind = schema.fields?.[target];\n if (kind === "array" || kind === "nodes") {\n let array2 = unwrap(v2);\n if (Array.isArray(array2)) array2 = array2.map((x) => kind === "nodes" ? node2(x, depth + 1) : schema.nested?.[target] ? record(x, schema.nested[target], depth + 1) : x);\n out2[key] = array2;\n } else out2[key] = scalar2(v2, kind);\n }\n return out2;\n }\n function node2(v2, depth) {\n if (!v2 || typeof v2 !== "object" || Array.isArray(v2)) return v2;\n if (v2.type === "heading") {\n v2 = { ...v2, type: "text", content: v2.content ?? v2.text ?? v2.title, size: v2.size ?? "h3" };\n delete v2.text;\n delete v2.title;\n }\n if (["card", "row", "col", "grid"].includes(v2.type) && v2.items === void 0 && Array.isArray(unwrap(v2.children))) {\n v2 = { ...v2, items: unwrap(v2.children) };\n delete v2.children;\n }\n const out2 = record(v2, schemas[v2.type] ?? {}, depth);\n if (v2.type === "quiz" && Array.isArray(out2.options)) out2.options = out2.options.map((x) => record(x, { fields: { correct: "boolean" } }));\n if (v2.type === "table") {\n for (const key of ["rows", "data", "items", "details"]) if (Array.isArray(out2[key])) out2[key] = out2[key].map((row) => {\n row = unwrap(row);\n return key === "details" && Array.isArray(row) ? row.map((x) => node2(x, depth + 1)) : row;\n });\n }\n if (v2.type === "echart") {\n for (const key of ["data", "series", "links"]) if (Array.isArray(out2[key])) out2[key] = out2[key].map((x) => record(x, { fields: { value: "number", data: "array" }, nested: { data: { fields: { value: "number" } } } }));\n }\n return out2;\n }\n if (Array.isArray(value)) return { items: value.map((x) => node2(x, 0)) };\n if (!value || typeof value !== "object") return value;\n const out = { ...value }, items = unwrap(value.items);\n if (Array.isArray(items)) out.items = items.map((x) => node2(x, 0));\n return out;\n }\n\n // lib/visual.js\n var VISUAL_TYPES = Object.freeze([...q]);\n function validateVisual(value) {\n const encoded = JSON.stringify(value);\n if (!encoded || new TextEncoder().encode(encoded).length > 131072) throw Error("DSH UI: visual spec exceeds 128 KiB");\n const processed = Ze(normalizeVisual(value, T)), spec = Ne(processed) ? processed.spec : at(processed);\n if (!spec || !processed.renderedNativeCount) throw Error("DSH UI: visual spec: " + (processed.errors.slice(0, 4).join("; ") || "requires registered components"));\n const critical = /* @__PURE__ */ new Set(["quiz", "radio", "submit", "input", "textarea", "select", "slider", "checkbox", "switch"]);\n const inventory = (items, path = "items", result = []) => {\n for (const [n, v2] of (Array.isArray(items) ? items : []).entries()) {\n if (!v2 || typeof v2 !== "object") continue;\n const at2 = path + "[" + n + "]";\n if (critical.has(v2.type)) result.push({ type: v2.type, id: v2.id ?? v2.group ?? v2.question ?? v2.label, path: at2 });\n if (["row", "col", "grid", "card"].includes(v2.type)) inventory(v2.items, at2 + ".items", result);\n if (v2.type === "tabs") for (const [i, t] of (v2.tabs ?? []).entries()) inventory(t.items, at2 + ".tabs[" + i + "].items", result);\n if (v2.type === "accordion") for (const [i, t] of (v2.items ?? []).entries()) inventory(t.items, at2 + ".items[" + i + "].items", result);\n }\n return result;\n };\n const source = normalizeVisual(value, T), before = inventory(source.items), after = inventory(spec.items);\n const available = [...after], missing = before.filter((v2) => {\n const i = available.findIndex((n) => n.type === v2.type && n.id === v2.id);\n if (i < 0) return true;\n available.splice(i, 1);\n return false;\n });\n if (missing.length) throw Error("DSH UI: critical component was rejected at " + missing.map((v2) => v2.path + " (" + v2.type + ")").join(", ") + ". " + processed.errors.slice(0, 4).join("; "));\n const stableIds = /* @__PURE__ */ new Set();\n function walk(items) {\n for (const n of items) {\n if (n.id !== void 0) {\n if (stableIds.has(n.id)) throw Error("DSH UI: duplicate extended component id " + n.id);\n stableIds.add(n.id);\n }\n if (!VISUAL_TYPES.includes(n.type)) throw Error("DSH UI: unsupported visual component " + n.type);\n if (n.type === "input" && n.inputType === "password") throw Error("DSH UI: do not collect passwords or secrets in a UI");\n if (n.type !== "file-tree" && Array.isArray(n.items)) walk(n.items.filter((x) => x && typeof x === "object" && "type" in x));\n for (const t of n.tabs ?? []) walk(t.items ?? []);\n if (n.type === "table") {\n for (const d of n.details ?? []) if (d) walk(d);\n }\n }\n }\n walk(spec.items);\n delete spec.panel;\n delete spec.append;\n return { spec, warnings: processed.errors.slice(0, 12), count: processed.renderedNativeCount };\n }\n function visualDocument(value) {\n if (Array.isArray(value)) value = { items: value };\n const { spec, warnings } = validateVisual(value), title = spec.title || "\\u53EF\\u89C6\\u5316";\n const texts = [];\n function gather(v2) {\n if (!v2 || typeof v2 !== "object") return;\n for (const [k2, x] of Object.entries(v2)) {\n if (["title", "content", "label", "question", "explanation", "alt"].includes(k2) && typeof x === "string") texts.push(x);\n else if (x && typeof x === "object") Array.isArray(x) ? x.forEach(gather) : gather(x);\n }\n }\n gather(spec);\n return { version: 1, title, fallback: texts.join("\\n").slice(0, 8192) || title, nodes: [{ id: "visual", type: "visual", spec, warnings }] };\n }\n\n // lib/normalize-authoring.js\n var object = (v2) => v2 !== null && typeof v2 === "object" && !Array.isArray(v2);\n var own = (v2, k2) => Object.hasOwn(v2, k2);\n var singleItem = (v2) => object(v2) && Object.keys(v2).length === 1 && own(v2, "item");\n var array = (v2) => {\n let candidate = v2;\n for (let i = 0; i < 8 && singleItem(candidate); i++) candidate = candidate.item;\n return Array.isArray(candidate) ? candidate : v2;\n };\n var numericOps = /* @__PURE__ */ new Set(["add", "sub", "mul", "div", "min", "max", "round", "ceil", "floor", "abs", "lt", "lte", "gt", "gte"]);\n function number(v2) {\n if (typeof v2 !== "string" || !/^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:e[+-]?\\d+)?$/i.test(v2.trim())) return v2;\n const n = Number(v2);\n return Number.isFinite(n) && (!Number.isInteger(n) || Number.isSafeInteger(n)) ? n : v2;\n }\n var boolean = (v2) => v2 === "true" ? true : v2 === "false" ? false : v2;\n function expression(e, numeric = false, logical = false) {\n if (!object(e)) return e;\n if (own(e, "const")) {\n if (numeric) e.const = number(e.const);\n if (logical) e.const = boolean(e.const);\n }\n if (own(e, "args")) e.args = array(e.args);\n if (Array.isArray(e.args)) e.args.forEach((arg, i) => expression(arg, numericOps.has(e.op) || e.op === "if" && i > 0 && numeric, e.op === "if" && i === 0));\n if (object(e.map?.fields)) Object.values(e.map.fields).forEach((e2) => expression(e2));\n return e;\n }\n function normalizeAuthoring(doc2) {\n if (Array.isArray(doc2)) doc2 = visualDocument(doc2);\n if (object(doc2) && !own(doc2, "nodes") && (own(doc2, "items") || typeof doc2.type === "string")) doc2 = visualDocument(doc2);\n if (!object(doc2)) return doc2;\n if (own(doc2, "version")) doc2.version = number(doc2.version);\n if (object(doc2.state)) for (const k2 of Object.keys(doc2.state)) {\n let s = doc2.state[k2];\n if (typeof s === "string" && s.trim().startsWith("{")) {\n try {\n const parsed = JSON.parse(s);\n if (object(parsed)) s = parsed;\n } catch {\n }\n }\n if (singleItem(s) && object(s.item)) s = s.item;\n doc2.state[k2] = s;\n if (!object(s)) continue;\n if (own(s, "options")) s.options = array(s.options);\n if (s.type === "number") {\n for (const field of ["default", "min", "max", "step"]) if (own(s, field)) s[field] = number(s[field]);\n if (Array.isArray(s.options)) s.options = s.options.map(number);\n } else if (s.type === "boolean") {\n if (own(s, "default")) s.default = boolean(s.default);\n if (Array.isArray(s.options)) s.options = s.options.map(boolean);\n }\n }\n if (object(doc2.derived)) Object.values(doc2.derived).forEach((e) => expression(e));\n if (object(doc2.actions)) {\n for (const action of Object.values(doc2.actions)) if (object(action) && own(action, "stateKeys")) action.stateKeys = array(action.stateKeys);\n }\n function nodes(list) {\n list = array(list);\n if (!Array.isArray(list)) return list;\n for (const node2 of list) {\n if (!object(node2)) continue;\n if (["text", "heading", "callout"].includes(node2.type) && own(node2, "content")) {\n if (!own(node2, "text")) {\n node2.text = node2.content;\n delete node2.content;\n } else if (node2.text === node2.content) delete node2.content;\n }\n if (["text", "heading", "callout"].includes(node2.type) && typeof node2.text === "string") {\n const spans = array(node2.spans);\n if (Array.isArray(spans) && spans.every((s) => object(s) && typeof s.text === "string") && spans.map((s) => s.text).join("") === node2.text) delete node2.text;\n }\n if (node2.type === "table" && own(node2, "types")) {\n const columns = array(node2.columns), rows = array(node2.rows), types = array(node2.types);\n const allowed = ["id", "type", "label", "columns", "rows", "types"];\n if (Object.keys(node2).every((k2) => allowed.includes(k2)) && Array.isArray(columns) && columns.length && columns.every((c) => object(c) && typeof c.key === "string" && typeof c.label === "string" && Object.keys(c).every((k2) => ["key", "label", "unit"].includes(k2))) && new Set(columns.map((c) => c.key)).size === columns.length && Array.isArray(rows) && rows.every(object) && Array.isArray(types) && types.length === columns.length && types.every((t) => ["text", "num", "delta", "bar", "badge"].includes(t))) {\n const spec = { ...node2.label ? { title: node2.label } : {}, items: [{ type: "table", columns: columns.map((c) => c.label + (c.unit ? ` (${c.unit})` : "")), rows: rows.map((row) => columns.map((c) => row[c.key] ?? null)), types }] }, id = node2.id;\n for (const k2 of Object.keys(node2)) delete node2[k2];\n Object.assign(node2, { ...id !== void 0 ? { id } : {}, type: "visual", spec });\n }\n }\n if (typeof node2.id === "string" && VISUAL_TYPES.includes(node2.type) && !own(COMPONENTS, node2.type)) {\n const spec = { items: [{ ...node2 }] }, id = node2.id;\n for (const k2 of Object.keys(node2)) delete node2[k2];\n Object.assign(node2, { id, type: "visual", spec });\n }\n if (node2.type === "table" && Array.isArray(node2.columns) && node2.columns.length && node2.columns.every((c) => object(c) && typeof c.key === "string") && new Set(node2.columns.map((c) => c.key)).size === node2.columns.length && Array.isArray(node2.rows) && node2.rows.every((row) => Array.isArray(row) && row.length === node2.columns.length)) {\n node2.rows = node2.rows.map((row) => Object.fromEntries(node2.columns.map((c, i) => [c.key, row[i]])));\n }\n if (node2.type === "table" && Array.isArray(node2.columns) && node2.columns.length && Array.isArray(node2.rows) && node2.rows.every(Array.isArray) && node2.columns.every((c) => object(c) && Number.isInteger(c.key) && c.key >= 0) && new Set(node2.columns.map((c) => c.key)).size === node2.columns.length) {\n const columns = node2.columns.map((c) => ({ ...c, key: "col_" + c.key }));\n node2.rows = node2.rows.map((row) => Object.fromEntries(node2.columns.map((c) => ["col_" + c.key, row[c.key] ?? null])));\n node2.columns = columns;\n }\n if (node2.type === "visual" && typeof node2.id === "string") {\n node2.stateKey ??= "visual_" + node2.id;\n doc2.state ??= {};\n if (!own(doc2.state, node2.stateKey)) doc2.state[node2.stateKey] = { type: "json", default: {} };\n }\n if (node2.type === "sandbox") {\n if (!own(node2, "title")) node2.title = doc2.title;\n if (!own(node2, "fallback")) node2.fallback = doc2.fallback;\n }\n for (const field of ["children", "items", "columns", "libraries", "stateKeys", "dataKeys", "derivedKeys"]) if (own(node2, field)) node2[field] = array(node2[field]);\n if (["table", "chart"].includes(node2.type) && own(node2, "rows")) node2.rows = array(node2.rows);\n for (const field of ["decimals", "height"]) if (own(node2, field)) node2[field] = number(node2[field]);\n if (["row", "column"].includes(node2.type)) {\n if (own(node2, "gap")) node2.gap = number(node2.gap);\n if (node2.type === "row" && own(node2, "columns")) node2.columns = number(node2.columns);\n }\n if (["text", "heading", "callout"].includes(node2.type)) {\n for (const field of ["size", "weight", "lineHeight"]) if (own(node2, field)) node2[field] = number(node2[field]);\n if (own(node2, "spans")) node2.spans = array(node2.spans);\n if (Array.isArray(node2.spans)) {\n for (const span of node2.spans) if (object(span)) {\n for (const field of ["size", "weight", "lineHeight"]) if (own(span, field)) span[field] = number(span[field]);\n }\n }\n }\n if (node2.type === "details" && own(node2, "open")) node2.open = boolean(node2.open);\n if (node2.type === "text" && own(node2, "copyable")) node2.copyable = boolean(node2.copyable);\n if (node2.type === "code" && own(node2, "wrap")) node2.wrap = boolean(node2.wrap);\n for (const field of ["text", "value", "max", "rows"]) if (own(node2, field)) expression(node2[field], node2.type === "progress");\n if (["row", "column", "card", "details"].includes(node2.type) && own(node2, "children")) node2.children = nodes(node2.children);\n }\n return list;\n }\n if (own(doc2, "nodes")) doc2.nodes = nodes(doc2.nodes);\n return doc2;\n }\n\n // lib/typography.js\n var TEXT_PRESETS = Object.freeze(["reading", "brief", "comparison", "list", "callout", "scorecard", "flow", "minimal"]);\n var TYPE_FIELDS = Object.freeze(["size", "weight", "color", "align", "lineHeight"]);\n var TEXT_SIZES = Object.freeze({ sm: 14, md: 16, lg: 20, xl: 26, hero: 36 });\n var TEXT_COLORS = Object.freeze({ default: "var(--du-ink)", muted: "var(--du-muted)", accent: "var(--du-accent)", success: "var(--du-green)", warning: "var(--du-amber)", danger: "var(--du-red)", violet: "var(--du-violet)" });\n function validateTypography(value, at2 = "text") {\n const fail2 = (message) => {\n throw Error(`DSH UI: ${at2}.${message}`);\n };\n if (value.size !== void 0 && !(typeof value.size === "number" && Number.isFinite(value.size) && value.size >= 12 && value.size <= 48) && !Object.hasOwn(TEXT_SIZES, value.size)) fail2("size must be 12..48 px or sm/md/lg/xl/hero");\n if (value.weight !== void 0 && ![400, 500, 600, 700, 800].includes(value.weight)) fail2("weight must be 400/500/600/700/800");\n if (value.color !== void 0 && (typeof value.color !== "string" || !Object.hasOwn(TEXT_COLORS, value.color) && !/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(value.color))) fail2("color must be default/muted/accent/success/warning/danger/violet or #RGB/#RRGGBB");\n if (value.align !== void 0 && !["left", "center", "right"].includes(value.align)) fail2("align must be left/center/right");\n if (value.lineHeight !== void 0 && !(typeof value.lineHeight === "number" && value.lineHeight >= 1.2 && value.lineHeight <= 2.4)) fail2("lineHeight must be 1.2..2.4");\n }\n\n // lib/links.js\n function validateLink(node2) {\n const fail2 = (message) => {\n throw Error("DSH UI: " + message);\n };\n if ([node2.href, node2.path, node2.action].filter((v2) => v2 !== void 0).length !== 1) fail2(`node.${node2.id}: choose exactly one href (http/https), path (file), or action (Agent follow-up)`);\n if (node2.variant !== void 0 && !["primary", "secondary", "text"].includes(node2.variant)) fail2("link/button variant must be primary/secondary/text");\n if (node2.href !== void 0) {\n if (typeof node2.href !== "string" || node2.href.length > 8192 || /[\\u0000-\\u0020\\u007f]/.test(node2.href) || !/^https?:\\/\\//i.test(node2.href)) fail2("href must be an absolute http/https URL; encode spaces");\n let url;\n try {\n url = new URL(node2.href);\n } catch {\n fail2("invalid href URL");\n }\n if (!url.hostname || url.username || url.password) fail2("href must have a host and must not contain credentials");\n }\n if (node2.path !== void 0) {\n if (typeof node2.path !== "string" || !node2.path.trim() || node2.path.length > 8192 || /[\\u0000-\\u001f\\u007f]/.test(node2.path) || /^\\s*(?:[a-z][a-z\\d+.-]*:|[\\\\/]{2})/i.test(node2.path) && !/^\\s*[a-z]:[\\\\/]/i.test(node2.path)) fail2("path must be a local file path, not a URL, network path or command");\n }\n }\n\n // lib/protocol.js\n var LIMITS = Object.freeze({ bytes: 131072, nodes: 160, depth: 12, rows: 500, expressions: 128, steps: 4096 });\n var own2 = (o, k2) => Object.hasOwn(o, k2);\n var fail = (message) => {\n throw new Error(`DSH UI: ${message}`);\n };\n var object2 = (x) => x !== null && typeof x === "object" && !Array.isArray(x);\n var finite = (x) => typeof x === "number" && Number.isFinite(x);\n var scalar = (x) => typeof x === "string" || typeof x === "boolean" || finite(x);\n var text = (x, at2) => {\n if (typeof x !== "string" || x.length > 8192) fail(`${at2} must be a string of at most 8192 characters`);\n };\n function fields(value, allowed, at2) {\n if (!object2(value)) fail(`${at2} must be an object`);\n for (const k2 of Object.keys(value)) if (!allowed.includes(k2)) {\n const hint = at2 === "document" ? " Controls and visual components belong in nodes as registered typed nodes, not extra document fields." : "";\n fail(`unknown field ${at2}.${k2}; allowed fields at ${at2}: ${allowed.join(", ")}.${hint}`);\n }\n }\n function safeJson(value, depth = 0, source = false) {\n if (depth > 48) fail("JSON nesting is too deep");\n if (value === null || typeof value === "boolean") return;\n if (typeof value === "string") {\n if (source) {\n if (value.length > SANDBOX_LIMITS.source) fail("canvas source exceeds 48 Ki characters");\n return;\n }\n return text(value, "value");\n }\n if (typeof value === "number") {\n if (!finite(value)) fail("numbers must be finite");\n return;\n }\n if (typeof value !== "object") fail("only JSON values are accepted");\n if (Array.isArray(value) && value.length > LIMITS.rows) fail("too many array items");\n for (const k2 of Object.keys(value)) {\n if (["__proto__", "prototype", "constructor"].includes(k2)) fail("unsafe property name");\n safeJson(value[k2], depth + 1, value.type === "sandbox" && ["html", "css", "script"].includes(k2));\n }\n }\n function initialState(doc2) {\n return Object.fromEntries(Object.entries(doc2.state).map(([k2, spec]) => [k2, spec.default]));\n }\n function validateState(doc2, state2) {\n if (!object2(state2) || Object.keys(state2).length !== Object.keys(doc2.state).length) fail("state keys do not match the document");\n const result = {};\n for (const [k2, s] of Object.entries(doc2.state)) {\n if (!own2(state2, k2)) fail(`missing state.${k2}`);\n const v2 = state2[k2];\n if (s.type === "number") {\n if (!finite(v2) || v2 < s.min || v2 > s.max) fail(`state.${k2} is outside its numeric range`);\n const offset = (v2 - s.min) / s.step;\n if (Math.abs(offset - Math.round(offset)) > 1e-6) fail(`state.${k2} does not match its step`);\n } else if (s.type === "json") {\n if (!object2(v2) && !Array.isArray(v2)) fail(`state.${k2} must be an array or object for type json`);\n safeJson(v2);\n if (new TextEncoder().encode(JSON.stringify(v2)).length > 16384) fail(`state.${k2} JSON exceeds 16 KiB`);\n } else if (s.type === "string") text(v2, `state.${k2}`);\n else if (typeof v2 !== "boolean") fail(`state.${k2} must be boolean`);\n if (s.options && !s.options.includes(v2)) fail(`invalid option for state.${k2}`);\n result[k2] = v2;\n }\n return result;\n }\n var ARITY = { add: [1, 8], sub: [2, 2], mul: [1, 8], div: [2, 2], min: [1, 8], max: [1, 8], round: [1, 1], ceil: [1, 1], floor: [1, 1], abs: [1, 1], eq: [2, 2], neq: [2, 2], lt: [2, 2], lte: [2, 2], gt: [2, 2], gte: [2, 2], if: [3, 3] };\n function reference(doc2, ref) {\n if (typeof ref !== "string" || !["state", "data", "derived"].includes(ref.split(".")[0]) || ref.split(".").length !== 2 || !validIdentifier(ref.split(".")[1])) fail(`invalid reference ${JSON.stringify(ref)}; use state.key, data.key or derived.key with a letter/underscore identifier`);\n const [group, k2] = ref.split(".");\n if (!own2(doc2[group], k2)) fail(`unknown reference ${ref}`);\n return [group, k2];\n }\n function evaluate(doc2, state2) {\n const derived = {}, active = /* @__PURE__ */ new Set();\n let steps = 0, generatedRows = 0;\n const budget = () => {\n if (++steps > LIMITS.steps) fail("calculation budget exceeded");\n };\n const resolve = (ref) => {\n budget();\n const [group, k2] = reference(doc2, ref);\n if (group !== "derived") return (group === "state" ? state2 : doc2.data)[k2];\n if (own2(derived, k2)) return derived[k2];\n if (active.has(k2)) fail(`cyclic calculation ${k2}`);\n active.add(k2);\n const result2 = expression2(doc2.derived[k2]);\n active.delete(k2);\n derived[k2] = result2;\n return result2;\n };\n const expression2 = (e, item) => {\n budget();\n if (own2(e, "map")) {\n const rows = resolve(e.map.source);\n if ((generatedRows += rows.length) > LIMITS.rows) fail("generated row limit exceeded");\n return rows.map((row) => Object.fromEntries(Object.entries(e.map.fields).map(([k2, value]) => {\n const out2 = expression2(value, row);\n if (!scalar(out2)) fail("generated cells must be scalar");\n return [k2, out2];\n })));\n }\n if (own2(e, "const")) return e.const;\n if (own2(e, "ref")) {\n if (e.ref.startsWith("item.")) {\n const k2 = e.ref.slice(5);\n if (!item || !own2(item, k2) || !scalar(item[k2])) fail("invalid item reference");\n return item[k2];\n }\n return resolve(e.ref);\n }\n if (e.op === "if") {\n const condition = expression2(e.args[0], item);\n if (typeof condition !== "boolean") fail("if condition must be boolean");\n return expression2(e.args[condition ? 1 : 2], item);\n }\n const a = e.args.map((arg) => expression2(arg, item));\n if (e.op === "eq") return a[0] === a[1];\n if (e.op === "neq") return a[0] !== a[1];\n if (!a.every(finite)) fail(`operator ${e.op} requires finite numbers`);\n let out;\n switch (e.op) {\n case "add":\n out = a.reduce((x, y2) => x + y2, 0);\n break;\n case "sub":\n out = a[0] - a[1];\n break;\n case "mul":\n out = a.reduce((x, y2) => x * y2, 1);\n break;\n case "div":\n if (a[1] === 0) fail("division by zero");\n out = a[0] / a[1];\n break;\n case "min":\n out = Math.min(...a);\n break;\n case "max":\n out = Math.max(...a);\n break;\n case "round":\n out = Math.round(a[0]);\n break;\n case "ceil":\n out = Math.ceil(a[0]);\n break;\n case "floor":\n out = Math.floor(a[0]);\n break;\n case "abs":\n out = Math.abs(a[0]);\n break;\n case "lt":\n return a[0] < a[1];\n case "lte":\n return a[0] <= a[1];\n case "gt":\n return a[0] > a[1];\n case "gte":\n return a[0] >= a[1];\n default:\n fail(`unsupported operator ${e.op}`);\n }\n if (!finite(out)) fail("non-finite calculation result");\n return out;\n };\n for (const k2 of Object.keys(doc2.derived)) resolve(`derived.${k2}`);\n if (new TextEncoder().encode(JSON.stringify(derived)).length > LIMITS.bytes) fail("derived output exceeds 128 KiB");\n const resolveCell = (cell) => {\n const out = expression2(cell);\n if (!scalar(out)) fail("inline row formula cells must resolve to a string, boolean or finite number");\n return out;\n };\n const result = { derived, resolveValue: (value) => {\n if (Array.isArray(value)) return value.map((row) => object2(row) ? Object.fromEntries(Object.entries(row).map(([k2, cell]) => [k2, object2(cell) && ["const", "ref", "op"].some((field) => own2(cell, field)) ? resolveCell(cell) : cell])) : row);\n if (!object2(value)) return value;\n return expression2(value);\n } };\n checkViewValues(doc2, result);\n return result;\n }\n function checkViewValues(doc2, evaluated) {\n function walk(list) {\n for (const n of list) {\n if (n.type === "table" || n.type === "chart") {\n const rows = evaluated.resolveValue(n.rows);\n if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object2)) fail("table/chart rows must reference an array of objects");\n if (n.type === "chart") {\n const index = rows.findIndex((r) => !own2(r, n.labelKey) || !scalar(r[n.labelKey]) || !own2(r, n.valueKey) || !finite(r[n.valueKey]));\n if (index >= 0) {\n const row = rows[index], missing = [n.labelKey, n.valueKey].filter((k2) => !own2(row, k2));\n fail("chart requires labels and finite numeric values. node." + n.id + ".rows[" + index + "]: " + (missing.length ? "missing field(s) " + missing.join(", ") : n.valueKey + " must resolve to a finite number") + ". Available keys: " + Object.keys(row).slice(0, 16).join(", ") + ". For live values use inline rows:[{" + n.labelKey + \':"\\u9879\\u76EE",\' + n.valueKey + \':{ref:"derived.amount"}}]; static data labels alone contain no amounts. Keep all nodes/state/derived when correcting the document\');\n }\n }\n if (n.type === "chart" && n.xScale === "linear" && rows.some((r) => !finite(r[n.labelKey]))) fail("linear chart requires numeric x values");\n }\n if (n.type === "metric" && !scalar(evaluated.resolveValue(n.value))) fail(`node.${n.id}.value must resolve to a number, string or boolean; use table for rows or a canvas for structured data`);\n if (n.type === "progress") {\n const v2 = evaluated.resolveValue(n.value), max = evaluated.resolveValue(n.max);\n if (!finite(v2) || !finite(max) || max <= 0 || v2 < 0 || v2 > max) fail("progress requires 0 <= value <= positive max");\n }\n if (n.children) walk(n.children);\n }\n }\n walk(doc2.nodes);\n }\n function validateDocument(input) {\n safeJson(input);\n const json = JSON.stringify(input);\n if (new TextEncoder().encode(json).length > LIMITS.bytes) fail("document exceeds 128 KiB");\n const normalized = normalizeAuthoring(JSON.parse(json));\n safeJson(normalized);\n const doc2 = expandExpressions(normalized);\n fields(doc2, ["version", "title", "fallback", "state", "data", "derived", "nodes", "actions", "presentation"], "document");\n if (doc2.presentation !== void 0) {\n fields(doc2.presentation, ["layout", "accent", "density", "preset"], "presentation");\n if (doc2.presentation.preset !== void 0 && !TEXT_PRESETS.includes(doc2.presentation.preset)) fail("unknown presentation preset; use " + TEXT_PRESETS.join("/"));\n for (const [k2, allowed] of Object.entries({ layout: UI_LAYOUTS, accent: UI_ACCENTS, density: ["comfortable", "compact"] }))\n if (doc2.presentation[k2] !== void 0 && !allowed.includes(doc2.presentation[k2])) fail(`unknown presentation ${k2}`);\n }\n if (doc2.version !== 1) fail(own2(doc2, "version") ? "document.version must be 1" : "document.version is missing. render_ui creates a complete document, not a partial patch: send {version:1,title,fallback,nodes:[...]} for shared controls/formulas, or {title,items:[...]} for extended visuals. Include all content, not only data/derived");\n text(doc2.title, "title");\n text(doc2.fallback, "fallback");\n if (!doc2.title.trim() || !doc2.fallback.trim()) fail("title and fallback cannot be empty");\n for (const group of ["state", "data", "derived", "actions"]) {\n doc2[group] ??= {};\n if (!object2(doc2[group]) || Object.keys(doc2[group]).length > 64) fail(`invalid ${group}`);\n for (const k2 of Object.keys(doc2[group])) if (!validIdentifier(k2)) fail(`invalid key in ${group}: ${JSON.stringify(k2)}; use 1..64 letters, numbers or underscores, starting with a letter/underscore (Chinese letters supported); no spaces, dots or hyphens. Put display labels in label/text`);\n }\n for (const [k2, s] of Object.entries(doc2.state)) {\n fields(s, ["type", "default", "min", "max", "step", "options"], `state.${k2}`);\n if (s.type === "string" && (Array.isArray(s.default) || object2(s.default)) && !own2(s, "options")) s.type = "json";\n if (!["number", "string", "boolean", "json"].includes(s.type)) fail(`unsupported state type ${k2}; use number, string, boolean or json (arrays/objects)`);\n if (s.type === "json" && own2(s, "options")) fail(`state.${k2}: json state does not support select options; use scalar options or a canvas`);\n if (s.type === "number") {\n for (const field of ["default", "min", "max", "step"]) if (!finite(s[field])) fail(`state.${k2}.${field} must be a finite JSON number; received ${s[field] === null ? "null" : typeof s[field]}. Supply {type:"number",default:2,min:1,max:12,step:1}; do not omit limits or include units in numeric fields`);\n if (s.min >= s.max || s.step <= 0) fail(`invalid numeric limits for state.${k2}: require min < max and step > 0; received min=${s.min}, max=${s.max}, step=${s.step}`);\n if ((s.max - s.min) / s.step > 1e9) fail(`numeric step too small for ${k2}`);\n } else if (["min", "max", "step"].some((p2) => own2(s, p2))) fail(`numeric limits on non-number ${k2}`);\n if (s.options !== void 0 && (!Array.isArray(s.options) || !s.options.length || s.options.length > 64 || !s.options.every(scalar))) fail(`state.${k2}.options must be a direct array of 1..64 scalar values, e.g. options:["3","5","7"], not {item:[...]}`);\n }\n const defaults = validateState(doc2, initialState(doc2));\n let expressions = 0;\n const expressionShapes = /* @__PURE__ */ new Set();\n for (const [k2, spec] of Object.entries(doc2.state))\n for (const option of spec.options ?? []) validateState(doc2, { ...defaults, [k2]: option });\n function validateExpression(e, depth = 0, itemRows, at2 = "expression") {\n if (depth > LIMITS.depth) fail(at2 + ": expression nesting exceeds " + LIMITS.depth);\n const shape = JSON.stringify(e);\n if (!expressionShapes.has(shape)) {\n expressionShapes.add(shape);\n if (++expressions > LIMITS.expressions) fail(at2 + ": expression limit exceeded (128 distinct expressions). Reuse derived references instead of expanding long formulas; keep the complete document when retrying");\n }\n if (!object2(e)) fail(`${at2}: expression must be an object`);\n if (own2(e, "map")) {\n if (depth !== 0) fail("map is only allowed at the root of a derived value");\n fields(e, ["map"], "expression");\n fields(e.map, ["source", "fields"], "map");\n if (typeof e.map.source !== "string" || !e.map.source.startsWith("data.")) fail(\'map source must reference static data using a string such as "data.samples"; put object rows in document.data.samples, not inline in map.source\');\n const [, k2] = reference(doc2, e.map.source), rows = doc2.data[k2];\n if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object2)) fail("map source must be object rows");\n if (!object2(e.map.fields) || !Object.keys(e.map.fields).length || Object.keys(e.map.fields).length > 16) fail("map requires 1..16 fields");\n for (const [k3, value2] of Object.entries(e.map.fields)) {\n if (!validIdentifier(k3)) fail(`invalid map field ${JSON.stringify(k3).slice(0, 100)}; use a letter/underscore identifier such as powerW or \\u529F\\u7387, without spaces, dots or hyphens`);\n validateExpression(value2, depth + 1, rows, `${at2}.map.fields.${k3}`);\n }\n return;\n }\n if (own2(e, "const")) {\n fields(e, ["const"], "expression");\n if (!scalar(e.const)) fail("constant must be scalar");\n return;\n }\n if (own2(e, "ref")) {\n fields(e, ["ref"], "expression");\n if (typeof e.ref === "string" && e.ref.startsWith("item.")) {\n const k2 = e.ref.slice(5);\n if (!itemRows || !validIdentifier(k2) || itemRows.some((row) => !own2(row, k2) || !scalar(row[k2]))) fail("invalid or unscoped item reference");\n } else reference(doc2, e.ref);\n return;\n }\n fields(e, ["op", "args"], "expression");\n const arity = ARITY[e.op];\n if (!arity || !Array.isArray(e.args) || e.args.length < arity[0] || e.args.length > arity[1]) fail(`${at2}: invalid operator or argument count for ${JSON.stringify(e.op)}; args must be a direct array${arity ? ` with ${arity[0]}..${arity[1]} expressions` : " and op must be registered"}. Received ${Array.isArray(e.args) ? e.args.length + " arguments" : typeof e.args}. Prefer {expr:"state.people * state.days"} for arithmetic; missing operands cannot be inferred`);\n e.args.forEach((a, i) => validateExpression(a, depth + 1, itemRows, `${at2}.args[${i}]`));\n }\n Object.entries(doc2.derived).forEach(([k2, e]) => validateExpression(e, 0, void 0, `derived.${k2}`));\n const visited = /* @__PURE__ */ new Set(), active = /* @__PURE__ */ new Set();\n function visit(k2) {\n if (active.has(k2)) fail(`cyclic calculation ${k2}`);\n if (visited.has(k2)) return;\n active.add(k2);\n function walk(e) {\n if (e.ref?.startsWith("derived.")) visit(e.ref.split(".")[1]);\n for (const a of e.args ?? []) walk(a);\n for (const value2 of Object.values(e.map?.fields ?? {})) walk(value2);\n }\n walk(doc2.derived[k2]);\n active.delete(k2);\n visited.add(k2);\n }\n Object.keys(doc2.derived).forEach(visit);\n for (const [k2, a] of Object.entries(doc2.actions)) {\n fields(a, ["type", "intent", "stateKeys"], `actions.${k2}`);\n if (a.type !== "agent.followup") fail("only agent.followup actions are supported");\n text(a.intent, "action intent");\n if (!a.intent.trim() || !Array.isArray(a.stateKeys) || a.stateKeys.length > 64 || new Set(a.stateKeys).size !== a.stateKeys.length || a.stateKeys.some((s) => !own2(doc2.state, s))) fail("invalid action stateKeys");\n }\n const ids = /* @__PURE__ */ new Map();\n let count2 = 0;\n const value = (v2, at2) => {\n if (object2(v2)) {\n if (own2(v2, "map")) fail("map belongs in derived");\n validateExpression(v2);\n } else if (!scalar(v2)) fail(`invalid value at ${at2}`);\n };\n function nodes(list, depth = 0, path = "nodes") {\n if (!Array.isArray(list)) fail(path === "nodes" ? \'document.nodes is missing or is not an array. State/derived define values but do not create visible UI. Include nodes:[{id:"heading",type:"heading",text:"..."},...] and actual controls in the SAME complete document; do not resend state/data/derived alone. Declared state keys: \' + Object.keys(doc2.state).join(", ") : path + " must be an array of child nodes; use children:[{id,type,...}]");\n if (depth > LIMITS.depth) fail(path + " exceeds maximum node depth " + LIMITS.depth);\n for (const [index, n] of list.entries()) {\n const at2 = `${path}[${index}]`;\n if (++count2 > LIMITS.nodes) fail("too many nodes");\n if (!object2(n)) fail(`${at2} must be a node object`);\n if (!own2(n, "id")) fail(`${at2}.id is missing (type=${JSON.stringify(n.type)}). Every node, including sandbox, needs its own id; add e.g. id:"canvas". JSON field order does not matter`);\n if (!validIdentifier(n.id)) fail(`${at2}.id is invalid: ${JSON.stringify(n.id)}. Use 1..64 letters/numbers/underscores starting with a letter/underscore`);\n if (ids.has(n.id)) fail(`${at2}.id duplicates ${JSON.stringify(n.id)} first declared at ${ids.get(n.id)}. Give each node a unique id; state keys and node ids are separate namespaces`);\n ids.set(n.id, `${at2}.id`);\n if (!Object.hasOwn(COMPONENTS, n.type)) fail("unsupported component " + n.type);\n if (["table", "chart"].includes(n.type) && typeof n.rows === "string" && /^(data|derived)\\./.test(n.rows)) n.rows = { ref: n.rows };\n switch (n.type) {\n case "visual": {\n const previous = Array.isArray(n.warnings) ? n.warnings.filter((x) => typeof x === "string").map((x) => x.slice(0, 512)).slice(0, 12) : [];\n const checked = validateVisual(n.spec);\n n.spec = checked.spec;\n n.warnings = [.../* @__PURE__ */ new Set([...previous, ...checked.warnings])].slice(0, 12);\n count2 += checked.count;\n if (count2 > LIMITS.nodes) fail("too many nodes, including visual components");\n if (!validIdentifier(n.stateKey) || doc2.state[n.stateKey]?.type !== "json") fail("visual requires its own json stateKey");\n break;\n }\n case "sandbox": {\n text(n.title, `${at2}.title (canvas title)`);\n text(n.fallback, `${at2}.fallback (canvas fallback)`);\n if (!n.title.trim()) fail(`${at2}.title must not be empty`);\n if (!n.fallback.trim()) fail(`${at2}.fallback must not be empty`);\n if (typeof n.html !== "string" || !n.html.trim()) fail(`${at2}.html must be a non-empty HTML string; script/css/fallback belong beside html on the sandbox node, not inside it`);\n for (const field of ["html", "css", "script"]) if (n[field] !== void 0 && (typeof n[field] !== "string" || n[field].length > SANDBOX_LIMITS.source)) fail("canvas source exceeds 48 Ki characters");\n if (n.libraries !== void 0 && (!Array.isArray(n.libraries) || n.libraries.length > 1 || n.libraries.some((v2) => v2 !== "mechanism"))) fail(\'canvas libraries supports only ["mechanism"] or []\');\n if (n.height !== void 0 && (!Number.isInteger(n.height) || n.height < 160 || n.height > SANDBOX_LIMITS.height)) fail("canvas height must be 160..1000");\n for (const [field, group] of [["stateKeys", "state"], ["dataKeys", "data"], ["derivedKeys", "derived"]]) if (n[field] !== void 0 && (!Array.isArray(n[field]) || n[field].length > 64 || new Set(n[field]).size !== n[field].length || n[field].some((k2) => !own2(doc2[group], k2)))) fail("invalid canvas " + field);\n break;\n }\n case "row":\n case "column":\n if (n.gap !== void 0 && !(typeof n.gap === "number" && Number.isFinite(n.gap) && n.gap >= 0 && n.gap <= 40)) fail("gap must be 0..40 pixels");\n if (n.columns !== void 0 && (!Number.isInteger(n.columns) || n.columns < 1 || n.columns > 4)) fail("columns must be 1..4");\n break;\n case "card":\n if (n.title !== void 0) text(n.title, "card title");\n if (n.surface !== void 0 && !UI_SURFACES.includes(n.surface)) fail("unknown card surface");\n break;\n case "details":\n text(n.title, "details title");\n if (n.open === "true" || n.open === "false") n.open = n.open === "true";\n if (n.open !== void 0 && typeof n.open !== "boolean") fail(`node.${n.id}.open must be boolean true or false`);\n break;\n case "badge":\n value(n.text, "badge text");\n break;\n case "progress":\n text(n.label, "progress label");\n value(n.value, "progress value");\n value(n.max, "progress max");\n if (n.unit !== void 0) text(n.unit, "progress unit");\n break;\n case "steps": {\n if (n.title !== void 0) text(n.title, "steps title");\n const at3 = `node.${n.id}.items`;\n if (!Array.isArray(n.items)) fail(`${at3} must be an array of 1..12 step objects, received ${n.items === null ? "null" : typeof n.items}. Use items:[{"title":"First step","description":"One sentence"}], not items:{item:[...]}. status is optional for a static guide`);\n if (!n.items.length || n.items.length > 12) fail(`${at3} requires 1..12 items; received ${n.items.length}. Split a longer guide into separate steps nodes`);\n for (const [i, item] of n.items.entries()) {\n const stepAt = `${at3}[${i}]`;\n fields(item, ["title", "description", "status"], stepAt);\n text(item.title, `${stepAt}.title`);\n if (item.description !== void 0) text(item.description, `${stepAt}.description`);\n if (item.status !== void 0 && !["pending", "active", "done", "error"].includes(item.status)) fail(`${stepAt}.status must be pending, active, done or error; omit status for a static guide`);\n }\n break;\n }\n case "heading":\n case "text":\n case "callout":\n if (n.type === "text") {\n if (n.title !== void 0) text(n.title, "text block title");\n if (n.copyable !== void 0 && typeof n.copyable !== "boolean") fail("copyable must be boolean");\n }\n validateTypography(n, `node.${n.id}`);\n if (n.spans !== void 0) {\n if (n.text !== void 0) fail(`node.${n.id}: use text or spans, not both`);\n if (!Array.isArray(n.spans) || !n.spans.length || n.spans.length > 80) fail("spans must contain 1..80 text fragments");\n for (const [i, span] of n.spans.entries()) {\n fields(span, ["text", ...TYPE_FIELDS], `node.${n.id}.spans[${i}]`);\n text(span.text, "span text");\n validateTypography(span, `node.${n.id}.spans[${i}]`);\n }\n } else value(n.text, "text");\n break;\n case "metric":\n text(n.label, "metric label");\n value(n.value, "metric value");\n if (n.unit !== void 0) text(n.unit, "unit");\n if (n.decimals !== void 0 && (!Number.isInteger(n.decimals) || n.decimals < 0 || n.decimals > 6)) fail("invalid decimals");\n break;\n case "input":\n case "slider":\n case "select":\n case "toggle": {\n text(n.label, "control label");\n if (typeof n.bind !== "string" || !n.bind.startsWith("state.")) fail("controls must bind state");\n const [, k2] = reference(doc2, n.bind), spec = doc2.state[k2];\n if (n.type === "slider" && spec.type !== "number") fail("slider requires numeric state");\n if (n.type === "toggle" && spec.type !== "boolean") fail("toggle requires boolean state");\n if (["input", "select"].includes(n.type) && spec.type === "json") fail(`node.${n.id}: structured state requires a sandbox with DSHUI.setState; use separate boolean states and toggle nodes for a native checklist`);\n if (n.type === "input" && spec.type === "boolean") fail("use toggle for boolean state");\n if (n.type === "select" && !spec.options) fail("select requires options");\n if (n.type === "select" && n.variant !== void 0 && !["dropdown", "segmented"].includes(n.variant)) fail(`node.${n.id}.variant must be dropdown or segmented`);\n break;\n }\n case "code":\n if (typeof n.code !== "string" || n.code.length > SANDBOX_LIMITS.source) fail("code must be a string of at most 48 Ki characters");\n if (n.lang !== void 0) text(n.lang, "code language");\n if (n.title !== void 0) text(n.title, "code title");\n if (n.wrap !== void 0 && typeof n.wrap !== "boolean") fail("code wrap must be boolean");\n break;\n case "button":\n case "link":\n text(n.text, "button text");\n validateLink(n);\n if (n.action !== void 0 && !own2(doc2.actions, n.action)) fail("unknown action");\n break;\n case "divider":\n if (n.label !== void 0) text(n.label, "divider label");\n break;\n case "table": {\n if (n.label !== void 0) text(n.label, "table label");\n if (!Array.isArray(n.rows)) value(n.rows, "table rows");\n if (!Array.isArray(n.columns) || !n.columns.length || n.columns.length > 16) fail("invalid table columns");\n const cols = /* @__PURE__ */ new Set();\n for (const c of n.columns) {\n fields(c, ["key", "label", "unit"], "column");\n if (!validIdentifier(c.key) || cols.has(c.key)) fail("invalid or duplicate column key");\n cols.add(c.key);\n text(c.label, "column label");\n if (c.unit !== void 0) text(c.unit, "column unit");\n }\n break;\n }\n case "chart":\n if (!Array.isArray(n.rows)) value(n.rows, "chart rows");\n if (!["bar", "line"].includes(n.kind) || !validIdentifier(n.labelKey) || !validIdentifier(n.valueKey)) fail("invalid chart");\n text(n.label, "chart label");\n if (n.unit !== void 0) text(n.unit, "chart unit");\n if (n.xScale !== void 0 && (!["category", "linear"].includes(n.xScale) || n.xScale === "linear" && n.kind !== "line")) fail("invalid xScale");\n break;\n default:\n fail(`unsupported component ${n.type}`);\n }\n if (["heading", "text", "callout", "card", "metric", "button", "link", "badge", "progress", "details"].includes(n.type)) {\n if (n.icon !== void 0 && !UI_ICONS.includes(n.icon)) fail("unknown UI icon");\n if (!["button", "link"].includes(n.type)) {\n if (n.tone !== void 0 && !UI_TONES.includes(n.tone)) fail("unknown UI tone");\n }\n }\n if (["table", "chart"].includes(n.type) && Array.isArray(n.rows)) {\n for (const [i, row] of n.rows.entries()) if (object2(row)) {\n for (const [k2, cell] of Object.entries(row)) if (object2(cell) && ["const", "ref", "op"].some((field) => own2(cell, field))) value(cell, at2 + ".rows[" + i + "]." + k2);\n }\n }\n fields(n, componentFields(n.type), `node.${n.id}`);\n if (["row", "column", "card", "details"].includes(n.type)) nodes(n.children, depth + 1, `${at2}.children`);\n }\n }\n nodes(doc2.nodes);\n if (!count2) fail("at least one node is required");\n evaluate(doc2, defaults);\n return doc2;\n }\n\n // src/export-runtime.js\n var payload = JSON.parse(document.getElementById("dsh-ui-export").textContent);\n var doc = validateDocument(payload.document);\n var node = doc.nodes.flatMap(function flatten(n) {\n return [n, ...(n.children ?? []).flatMap(flatten)];\n }).find((n) => n.id === payload.nodeId && n.type === "sandbox");\n if (!node) throw Error("\\u5BFC\\u51FA\\u7684\\u753B\\u5E03\\u4E0D\\u5B58\\u5728");\n var state = validateState(doc, payload.state);\n var connected = false;\n var start = Date.now();\n var count = 0;\n var token = () => Array.from(crypto.getRandomValues(new Uint8Array(16)), (b2) => b2.toString(16).padStart(2, "0")).join("");\n var channel = token();\n var nonce = payload.nonce;\n var frame = document.createElement("iframe");\n frame.title = node.title;\n frame.sandbox = "allow-scripts";\n frame.referrerPolicy = "no-referrer";\n frame.style.cssText = "display:block;width:100%;height:" + (node.height ?? 420) + "px;border:0";\n var status = document.getElementById("status");\n var publish = () => {\n try {\n frame.contentWindow.postMessage({ dshCanvas: 1, channel, type: "snapshot", payload: { ...canvasSnapshot(node, state, doc.data, evaluate(doc, state).derived, false, payload.theme), visible: !document.hidden } }, "*");\n } catch (e) {\n status.textContent = "\\u8BA1\\u7B97\\u5931\\u8D25\\uFF1A" + e.message;\n }\n };\n addEventListener("message", (event) => {\n const m2 = event.data;\n if (event.source !== frame.contentWindow || m2?.channel !== channel || m2.dshCanvas !== 1) return;\n if (Date.now() - start > 1e3) {\n start = Date.now();\n count = 0;\n }\n if (++count > SANDBOX_LIMITS.rate) return;\n if (m2.type === "ready") {\n connected = true;\n publish();\n } else if (m2.type === "patch" && connected) {\n try {\n const next = validateState(doc, { ...state, ...canvasPatch(m2.payload, node) });\n evaluate(doc, next);\n state = next;\n status.textContent = "\\u672C\\u5730\\u53C2\\u6570\\u5DF2\\u66F4\\u65B0\\uFF1B\\u5237\\u65B0\\u6587\\u4EF6\\u4F1A\\u56DE\\u5230\\u5BFC\\u51FA\\u65F6\\u7684\\u53C2\\u6570\\u3002";\n } catch (e) {\n status.textContent = "\\u53C2\\u6570\\u65E0\\u6548\\uFF1A" + e.message;\n }\n publish();\n } else if (m2.type === "height" && Number.isFinite(m2.payload) && m2.payload >= 0) frame.style.height = Math.max(32, Math.min(1e3, Math.ceil(m2.payload))) + "px";\n else if (m2.type === "error") status.textContent = "\\u753B\\u5E03\\u8FD0\\u884C\\u5F02\\u5E38\\uFF1A" + String(m2.payload).slice(0, 1e3);\n });\n document.addEventListener("visibilitychange", () => {\n if (connected) publish();\n });\n document.getElementById("surface").append(frame);\n frame.srcdoc = sandboxDocument(node, channel, nonce);\n})();\n';
|
|
3572
|
+
var EXPORT_RUNTIME = '(() => {\n // lib/presentation.js\n var UI_ICONS = Object.freeze(["sparkles", "sliders", "layers", "chart", "gauge", "cpu", "database", "info", "check", "warning", "arrow", "target", "external", "file", "globe"]);\n var UI_TONES = Object.freeze(["neutral", "accent", "success", "warning", "danger"]);\n var UI_LAYOUTS = Object.freeze(["dashboard", "workbench", "comparison", "guide", "status", "report"]);\n var UI_ACCENTS = Object.freeze(["blue", "teal", "violet", "amber", "rose"]);\n var UI_SURFACES = Object.freeze(["outline", "soft", "featured"]);\n\n // lib/mechanism-runtime-bundle.js\n var MECHANISM_RUNTIME = \'var __MotionMechanism=(()=>{var it=Object.defineProperty;var Ot=Object.getOwnPropertyDescriptor;var Et=Object.getOwnPropertyNames;var It=Object.prototype.hasOwnProperty;var zt=(t,a)=>{for(var n in a)it(t,n,{get:a[n],enumerable:!0})},Pt=(t,a,n,o)=>{if(a&&typeof a=="object"||typeof a=="function")for(let e of Et(a))!It.call(t,e)&&e!==n&&it(t,e,{get:()=>a[e],enumerable:!(o=Ot(a,e))||o.enumerable});return t};var _t=t=>Pt(it({},"__esModule",{value:!0}),t);var Tt={};zt(Tt,{createMechanismAPI:()=>Ft});var st=Math.PI/180,Ct=Math.sqrt(1.6);function yt({scale:t,azimuth:a=45,elevation:n=30}){let o=a*st,e=n*st;return{sinA:Math.sin(o),cosA:Math.cos(o),sinE:Math.sin(e),cosE:Math.cos(e),k:t*Ct}}function q([t,a,n],o){let{origin:e}=o,{sinA:i,cosA:r,sinE:p,cosE:d,k:m}=yt(o);return[e[0]+(t*i-a*r)*m,e[1]+((t*r+a*i)*p-n*d)*m]}function tt([t,a,n],o){let{sinA:e,cosA:i,sinE:r,cosE:p}=yt(o);return(t*i+a*e)*p+n*r}function vt({x:t,y:a,w:n,d:o,r:e},i=8){let r=Math.max(0,Math.min(e,n/2,o/2)),p=[[t+n-r,a+r,-90],[t+n-r,a+o-r,0],[t+r,a+o-r,90],[t+r,a+r,180]],d=[];for(let[m,s,c]of p){let u=r>0?i:0;for(let f=0;f<=u;f++){let g=(c+(u?90*f/u:45))*st;d.push([m+r*Math.cos(g),s+r*Math.sin(g)])}}return d}function lt(t,a,n,o=40){return Array.from({length:o},(e,i)=>{let r=i/o*Math.PI*2;return[t+n*Math.cos(r),a+n*Math.sin(r)]})}function ct(t,a,n,{pad:o=24,headroom:e=0,azimuth:i=45,elevation:r=30}={}){let p={origin:[0,0],scale:1,azimuth:i,elevation:r},d=t.map(M=>q(M,p)),m=d.map(([M])=>M),s=d.map(([,M])=>M),c=Math.min(...m),u=Math.max(...m),f=Math.min(...s),g=Math.max(...s),h=Math.min((a-o*2)/(u-c),(n-o*2-e)/(g-f));return{origin:[a/2-(c+u)/2*h,e+(n-e)/2-(f+g)/2*h],scale:h,azimuth:i,elevation:r}}var Nt=Object.freeze({parts:96,teeth:64,faces:8192}),Ht=t=>typeof t=="number"&&Number.isFinite(t),y=t=>{throw Error("Motion mechanism: "+t)},v=(t,a,n=-1e4,o=1e4)=>((!Ht(t)||t<n||t>o)&&y(a+" must be a finite number in "+n+".."+o),t),U=(t,a)=>((!Array.isArray(t)||t.length!==3)&&y(a+" must be [x,y,z]"),t.map((n,o)=>v(n,a+"["+o+"]"))),et=t=>typeof t=="string"&&/^[\\\\p{L}_][\\\\p{L}\\\\p{M}\\\\p{N}_]{0,63}$/u.test(t)&&!["constructor","prototype","__proto__"].includes(t),kt=["box","cylinder","gear","rod","spring"],I=(t,a)=>t.map((n,o)=>n+a[o]),B=(t,a)=>t.map((n,o)=>n-a[o]),_=(t,a)=>t.map(n=>n*a),dt=(t,a)=>t.reduce((n,o,e)=>n+o*a[e],0),V=(t,a)=>[t[1]*a[2]-t[2]*a[1],t[2]*a[0]-t[0]*a[2],t[0]*a[1]-t[1]*a[0]],J=t=>{let a=Math.hypot(...t);return a<1e-6&&y("zero-length axis"),_(t,1/a)};function Y(t){(!t||typeof t!="object"||Array.isArray(t))&&y("scene must be an object"),(!Array.isArray(t.parts)||!t.parts.length||t.parts.length>Nt.parts)&&y("parts requires 1..96 objects");let a=new Set,n=new Set;for(let[o,e]of t.parts.entries()){let i="parts["+o+"]";(!e||typeof e!="object"||!et(e.id)||a.has(e.id))&&y(i+".id must be a unique identifier"),a.add(e.id),kt.includes(e.type)||y(i+".type must be "+kt.join("/")),e.group!==void 0&&(et(e.group)||y(i+".group must be an identifier"),n.add(e.group));for(let r of["label","description"])e[r]!==void 0&&(typeof e[r]!="string"||e[r].length>1024)&&y(i+"."+r+" must be short text");if(e.cover!==void 0&&typeof e.cover!="boolean"&&y(i+".cover must be boolean"),e.material!==void 0&&!["metal","dark","accent","warm","cool"].includes(e.material)&&y(i+".material must be metal/dark/accent/warm/cool"),e.at!==void 0&&U(e.at,i+".at"),e.explode!==void 0&&U(e.explode,i+".explode"),e.rotation!==void 0&&v(e.rotation,i+".rotation",-1e9,1e9),e.axis!==void 0&&!["x","y","z"].includes(e.axis)&&y(i+".axis must be x/y/z"),e.type==="box"){let r=U(e.size,i+".size");r.some(p=>p<=0||p>2e3)&&y(i+".size must be positive and <=2000"),e.round!==void 0&&v(e.round,i+".round",0,Math.min(r[0],r[1])/2)}if(["cylinder","gear"].includes(e.type)&&(v(e.radius,i+".radius",.1,1e3),v(e.height??8,i+".height",.1,1e3),e.inner!==void 0&&v(e.inner,i+".inner",0,e.radius-.01)),e.type==="gear"){let r=v(e.teeth,i+".teeth",6,64);Number.isInteger(r)||y(i+".teeth must be an integer"),e.module!==void 0&&v(e.module,i+".module",.1,e.radius/3)}if(["rod","spring"].includes(e.type)&&(U(e.from,i+".from"),U(e.to,i+".to"),Math.hypot(...B(e.to,e.from))<.1&&y(i+" endpoints must differ"),v(e.radius??2,i+".radius",.1,200)),e.type==="spring"){let r=v(e.turns??8,i+".turns",2,24);Number.isInteger(r)||y(i+".turns must be integer")}}if(t.groups!==void 0){(!Array.isArray(t.groups)||t.groups.length>12)&&y("groups must be an array of <=12 labels");let o=new Set;for(let e of t.groups)(!e||!et(e.id)||o.has(e.id)||!n.has(e.id)||typeof e.label!="string"||e.label.length>128)&&y("groups must name unique existing part groups"),o.add(e.id)}if(t.bounds!==void 0){(!Array.isArray(t.bounds)||t.bounds.length!==2)&&y("bounds must be [minXYZ,maxXYZ]");let[o,e]=t.bounds.map((i,r)=>U(i,"bounds["+r+"]"));o.some((i,r)=>i>=e[r])&&y("bounds min must be below max on every axis")}if(t.azimuth!==void 0&&v(t.azimuth,"azimuth",10,80),t.elevation!==void 0&&v(t.elevation,"elevation",15,70),t.title!==void 0&&(typeof t.title!="string"||t.title.length>256)&&y("title must be short text"),t.bind!==void 0){(!t.bind||typeof t.bind!="object"||Array.isArray(t.bind))&&y("bind must be an object");for(let[o,e]of Object.entries(t.bind))(!["explode","selected","cutaway"].includes(o)||!et(e))&&y("bind only accepts declared state keys for explode/selected/cutaway")}return t}function Lt(t){return t==="x"?[[0,1,0],[0,0,1],[1,0,0]]:t==="y"?[[0,0,1],[1,0,0],[0,1,0]]:[[1,0,0],[0,1,0],[0,0,1]]}var at=(t,a,n,o)=>I(I(_(t[0],a),_(t[1],n)),_(t[2],o));function Rt(t,a,n,o){let e=t.map(([m,s])=>at(n,m,s,-a/2)),i=t.map(([m,s])=>at(n,m,s,a/2)),r=[],p=o?.map(([m,s])=>at(n,m,s,a/2)),d=o?.map(([m,s])=>at(n,m,s,-a/2));r.push({points:i,holes:p?[p.slice().reverse()]:[],normal:n[2]},{points:e.slice().reverse(),holes:d?[d]:[],normal:_(n[2],-1)});for(let m=0;m<t.length;m++){let s=(m+1)%t.length;Math.hypot(...B(e[s],e[m]))<1e-6||(r.push({points:[e[m],e[s],i[s],i[m]],normal:J(V(B(e[s],e[m]),n[2]))}),o&&r.push({points:[d[s],d[m],p[m],p[s]],normal:J(V(B(d[m],d[s]),n[2]))}))}return r}function ot(t){let a=Lt(t.axis),n,o,e;if(t.type==="box"&&(n=vt({x:-t.size[0]/2,y:-t.size[1]/2,w:t.size[0],d:t.size[1],r:t.round??Math.min(2,t.size[0]/2,t.size[1]/2)},3),o=t.size[2]),t.type==="cylinder"&&(n=lt(0,0,t.radius,24),o=t.height??8),t.type==="gear"){let s=Math.PI*2/t.teeth,c=t.module??t.radius*2/t.teeth;n=[];for(let u=0;u<t.teeth;u++)for(let[f,g]of[[-.5,t.radius-c*.85],[-.32,t.radius-c*.85],[-.17,t.radius+c*.7],[.17,t.radius+c*.7],[.32,t.radius-c*.85]]){let h=(u+f)*s;n.push([Math.cos(h)*g,Math.sin(h)*g])}o=t.height??8}if(t.type==="rod"){let s=J(B(t.to,t.from)),c=J(V(s,Math.abs(s[2])<.9?[0,0,1]:[0,1,0]));a=[c,V(s,c),s],n=lt(0,0,t.radius??2,16),o=Math.hypot(...B(t.to,t.from))}if(t.type==="spring"){let s=J(B(t.to,t.from)),c=J(V(s,Math.abs(s[2])<.9?[0,0,1]:[0,1,0])),u=V(s,c),f=[];for(let g=0;g<=128;g++){let h=g/128,M=h*(t.turns??8)*Math.PI*2,O=Math.min(1,h*12,(1-h)*12);f.push(I(I(t.from,_(B(t.to,t.from),h)),I(_(c,Math.cos(M)*(t.radius??6)*O),_(u,Math.sin(M)*(t.radius??6)*O))))}return{line:f,points:f}}let i=t.rotation??0,r=Math.cos(i),p=Math.sin(i);n=n.map(([s,c])=>[s*r-c*p,s*p+c*r]);let d=t.inner?n.map(([s,c])=>{let u=Math.atan2(c,s);return[Math.cos(u)*t.inner,Math.sin(u)*t.inner]}):void 0;e=Rt(n,o,a,d);let m=t.type==="rod"?_(I(t.from,t.to),.5):t.at??[0,0,0];return e=e.map(s=>({...s,points:s.points.map(c=>I(c,m)),holes:s.holes?.map(c=>c.map(u=>I(u,m)))})),{faces:e,points:e.flatMap(s=>s.points)}}function wt(t){if(t.bounds){let[a,n]=t.bounds;return Array.from({length:8},(o,e)=>[e&1?n[0]:a[0],e&2?n[1]:a[1],e&4?n[2]:a[2]])}return t.parts.flatMap(a=>ot(a).points.flatMap(o=>[o,I(o,a.explode??[0,0,0])]))}function W({driverTeeth:t=16,drivenTeeth:a=32,rpm:n=30,angle:o=0,module:e=2}={}){for(let[i,r]of Object.entries({driverTeeth:t,drivenTeeth:a}))(!Number.isInteger(r)||r<6||r>64)&&y(i+" must be integer 6..64");return v(n,"rpm",-600,600),v(o,"angle",-1e9,1e9),v(e,"module",.1,10),{driverRadius:t*e/2,drivenRadius:a*e/2,centerDistance:(t+a)*e/2,driverAngle:o,drivenAngle:-o*t/a+Math.PI-Math.PI/a,driverRpm:n,drivenRpm:-n*t/a,ratio:a/t}}function X({angle:t=0,radius:a=20,rod:n=70,z:o=20}={}){v(t,"angle",-1e9,1e9),v(a,"radius",.1,200),v(n,"rod",.1,1e3),v(o,"z"),n<=a&&y("connecting rod length must exceed crank radius");let e=[a*Math.cos(t),a*Math.sin(t),o],i=e[0]+Math.sqrt(n*n-e[1]*e[1]);return{crank:e,piston:[i,0,o],position:i,stroke:a*2,angle:t}}function Mt(t,a,n,o=.16){return v(t,"value",-1e9,1e9),v(a,"target",-1e9,1e9),v(n,"delta",0,.1),v(o,"tau",.01,10),t+(a-t)*(1-Math.exp(-n/o))}var $t=Math.PI*2;function nt(t,a){Y(t);let n=a&&!t.bounds?t.parts.filter(o=>!a.cutaway||!o.cover).flatMap(o=>ot(o).points.map(e=>I(e,_(o.explode??[0,0,0],a.explode??0)))):wt(t);return ct(n.length?n:[[0,0,0],[1,1,1]],600,340,{pad:24,azimuth:t.azimuth??45,elevation:t.elevation??30})}var At=t=>t.map(([a,n],o)=>(o?"L":"M")+Math.round(a*10)/10+" "+Math.round(n*10)/10).join("")+"Z";function mt(t,a,{explode:n=0,selected:o="all",cutaway:e=!1,pose:i={}}={},r=new Map){if(typeof n!="number"||!Number.isFinite(n)||n<0||n>1)throw Error("Motion mechanism: explode must be 0..1");if(typeof o!="string"||typeof e!="boolean")throw Error("Motion mechanism: selected must be text and cutaway boolean");if(!i||typeof i!="object"||Array.isArray(i))throw Error("Motion mechanism: pose must be an object");for(let c of Object.keys(i))if(!t.parts.some(u=>u.id===c))throw Error("Motion mechanism: unknown pose part "+c);let p=(a.azimuth??45)*$t/360,d=(a.elevation??30)*$t/360,m=[Math.cos(p)*Math.cos(d),Math.sin(p)*Math.cos(d),Math.sin(d)],s=[];for(let c of t.parts){if(e&&c.cover)continue;let u=i[c.id]??{};for(let $ of Object.keys(u))if(!["at","rotation","from","to"].includes($))throw Error("Motion mechanism: unsupported pose field "+$);let f={...c,...u},g=JSON.stringify(f),h=r.get(c.id);h?.key!==g&&(Y({parts:[f]}),h={key:g,...ot(f)},r.set(c.id,h));let M=_(f.explode??[0,0,0],n),O=Math.min(...h.points.map($=>$[2]))+M[2],N=o==="all"||o===c.id||o===c.group;if(h.line){let $=h.line.map(P=>I(P,M));s.push({floor:O,key:f.id+"_line",part:f.id,group:f.group,d:$.map((P,A)=>(A?"L":"M")+q(P,a).join(" ")).join(""),depth:tt($[Math.floor($.length/2)],a),line:!0,tone:1,material:f.material??"metal",active:N});continue}for(let[$,P]of h.faces.entries()){if(dt(P.normal,m)<=1e-4)continue;let w=P.points.map(S=>I(S,M)),T=P.holes?.map(S=>S.map(H=>I(H,M))),D=_(w.reduce((S,H)=>I(S,H),[0,0,0]),1/w.length),G=dt(P.normal,[-.25,-.4,.88]);s.push({floor:O,key:f.id+"_"+$,part:f.id,group:f.group,d:At(w.map(S=>q(S,a)))+(T??[]).map(S=>At(S.map(H=>q(H,a)))).join(""),depth:tt(D,a),line:!1,tone:G>.5?0:G>.1?1:G>-.4?2:3,material:f.material??"metal",active:N})}}if(s.length>8192)throw Error("Motion mechanism: face budget exceeded");return s.sort((c,u)=>c.floor-u.floor||c.depth-u.depth||c.key.localeCompare(u.key))}var z=(t,a,n,o,e,i={})=>({id:t,type:"box",label:a,at:n,size:o,group:e,...i}),F=(t,a,n,o,e,i,r={})=>({id:t,type:"cylinder",label:a,at:n,radius:o,height:e,group:i,...r});function ut(t,a,n,o,e=3,i=18){return[[-1,-1],[-1,1],[1,-1],[1,1]].map(([r,p],d)=>F(o+"_bolt_"+d,"\\\\u56FA\\\\u5B9A\\\\u87BA\\\\u6813",[t+r*i,a+p*i,n],e,3,o,{material:"dark",explode:[0,0,26]}))}function ft(){return{title:"\\\\u5206\\\\u5C42\\\\u7ED3\\\\u6784 \\\\xB7 \\\\u793A\\\\u610F\\\\u88C5\\\\u914D",groups:[{id:"base",label:"\\\\u5E95\\\\u5EA7",description:"\\\\u652F\\\\u6491\\\\u6574\\\\u4F53\\\\uFF0C\\\\u5E76\\\\u63D0\\\\u4F9B\\\\u5B89\\\\u88C5\\\\u4F4D\\\\u7F6E\\\\u3002"},{id:"board",label:"\\\\u529F\\\\u80FD\\\\u677F",description:"\\\\u8FDE\\\\u63A5\\\\u8F93\\\\u5165\\\\u4E0E\\\\u5904\\\\u7406\\\\u6A21\\\\u5757\\\\uFF1B\\\\u793A\\\\u610F\\\\u7ED3\\\\u6784\\\\uFF0C\\\\u4E0D\\\\u5BF9\\\\u5E94\\\\u7279\\\\u5B9A\\\\u4EA7\\\\u54C1\\\\u3002"},{id:"sink",label:"\\\\u6563\\\\u70ED\\\\u5C42",description:"\\\\u5C06\\\\u70ED\\\\u91CF\\\\u4F20\\\\u5230\\\\u66F4\\\\u5927\\\\u7684\\\\u8868\\\\u9762\\\\u79EF\\\\u3002"},{id:"cover",label:"\\\\u5916\\\\u58F3",description:"\\\\u4FDD\\\\u62A4\\\\u5185\\\\u90E8\\\\uFF1B\\\\u5256\\\\u5F00\\\\u9009\\\\u9879\\\\u901A\\\\u8FC7\\\\u9690\\\\u85CF\\\\u5916\\\\u58F3\\\\u5C55\\\\u793A\\\\u7ED3\\\\u6784\\\\u3002"}],parts:[z("base","\\\\u5B89\\\\u88C5\\\\u5E95\\\\u5EA7",[0,0,0],[120,85,10],"base",{round:6,material:"metal"}),...[-1,1].flatMap((t,a)=>[-1,1].map((n,o)=>F("foot_"+a+o,"\\\\u9632\\\\u6ED1\\\\u811A",[t*46,n*30,-8],6,7,"base",{material:"dark"}))),z("board","\\\\u529F\\\\u80FD\\\\u677F",[0,0,15],[96,62,4],"board",{round:3,material:"cool",explode:[0,0,35]}),z("chip","\\\\u5904\\\\u7406\\\\u6A21\\\\u5757",[-16,0,22],[25,24,10],"board",{round:2,material:"dark",explode:[0,0,35]}),z("connector","\\\\u8FDE\\\\u63A5\\\\u7AEF\\\\u53E3",[32,0,24],[16,36,14],"board",{round:2,material:"warm",explode:[0,0,35]}),...ut(0,0,20,"board",2,24),z("spreader","\\\\u5BFC\\\\u70ED\\\\u5E95\\\\u677F",[-16,0,32],[44,42,5],"sink",{round:2,material:"metal",explode:[-10,0,65]}),...Array.from({length:7},(t,a)=>z("fin_"+a,"\\\\u6563\\\\u70ED\\\\u9CCD\\\\u7247",[-34+a*6,0,44],[2.4,40,20],"sink",{round:1,material:"metal",explode:[-10,0,65]})),z("top","\\\\u9876\\\\u76D6",[0,0,61],[124,89,5],"cover",{round:6,cover:!0,material:"metal",explode:[12,0,85]}),z("side","\\\\u4FA7\\\\u677F",[0,-44,32],[124,4,58],"cover",{round:2,cover:!0,material:"metal",explode:[12,-22,50]})]}}function pt({driverTeeth:t=16,drivenTeeth:a=32,module:n=1.5}={}){let o=W({driverTeeth:t,drivenTeeth:a,module:n}),e=o.centerDistance;return{title:"\\\\u9F7F\\\\u8F6E\\\\u4F20\\\\u52A8 \\\\xB7 \\\\u7B80\\\\u5316\\\\u76F4\\\\u9F7F\\\\u8F6E\\\\u793A\\\\u610F",azimuth:70,elevation:55,groups:[{id:"frame",label:"\\\\u652F\\\\u67B6",description:"\\\\u56FA\\\\u5B9A\\\\u8F74\\\\u5FC3\\\\u4F4D\\\\u7F6E\\\\uFF1B\\\\u4E24\\\\u8F74\\\\u4E2D\\\\u5FC3\\\\u8DDD\\\\u7531\\\\u9F7F\\\\u6570\\\\u4E0E\\\\u6A21\\\\u6570\\\\u5171\\\\u540C\\\\u786E\\\\u5B9A\\\\u3002"},{id:"driver",label:"\\\\u4E3B\\\\u52A8\\\\u8F6E",description:"\\\\u8F93\\\\u5165\\\\u8F6C\\\\u901F\\\\uFF0C\\\\u7531\\\\u9F7F\\\\u6570\\\\u51B3\\\\u5B9A\\\\u8282\\\\u5706\\\\u534A\\\\u5F84\\\\u3002"},{id:"driven",label:"\\\\u4ECE\\\\u52A8\\\\u8F6E",description:"\\\\u5916\\\\u556E\\\\u5408\\\\u8F6C\\\\u5411\\\\u76F8\\\\u53CD\\\\uFF0C\\\\u8F6C\\\\u901F\\\\u6309\\\\u9F7F\\\\u6570\\\\u6BD4\\\\u53D8\\\\u5316\\\\u3002"},{id:"cover",label:"\\\\u5916\\\\u58F3",description:"\\\\u9690\\\\u85CF\\\\u76D6\\\\u677F\\\\u4EE5\\\\u89C2\\\\u5BDF\\\\u4F20\\\\u52A8\\\\uFF1B\\\\u4E0D\\\\u662F\\\\u52A0\\\\u5DE5\\\\u6216\\\\u53D7\\\\u529B\\\\u4EFF\\\\u771F\\\\u3002"}],parts:[z("base","\\\\u5B89\\\\u88C5\\\\u5E95\\\\u5EA7",[30,0,-8],[140,90,10],"frame",{round:6,material:"metal"}),...ut(30,0,0,"frame",3,32),...[0,e].flatMap((i,r)=>[F("bearing_"+r,"\\\\u8F74\\\\u627F\\\\u5EA7",[i,0,4],10,12,"frame",{inner:4,material:"dark"}),F("shaft_"+r,"\\\\u4F20\\\\u52A8\\\\u8F74",[i,0,16],3.8,28,r?"driven":"driver",{material:"metal",explode:[r?24:-24,0,20]}),F("hub_"+r,"\\\\u8F6E\\\\u6BC2",[i,0,27],6,6,r?"driven":"driver",{inner:3.8,material:"warm",explode:[r?24:-24,0,20]})]),{id:"driverGear",type:"gear",label:"\\\\u4E3B\\\\u52A8\\\\u9F7F\\\\u8F6E",group:"driver",at:[0,0,20],radius:o.driverRadius,teeth:t,module:n,height:7,inner:4,material:"accent",explode:[-24,0,20]},{id:"drivenGear",type:"gear",label:"\\\\u4ECE\\\\u52A8\\\\u9F7F\\\\u8F6E",group:"driven",at:[e,0,20],radius:o.drivenRadius,teeth:a,module:n,height:7,inner:4,material:"cool",rotation:o.drivenAngle,explode:[24,0,20]},z("cover","\\\\u9632\\\\u62A4\\\\u76D6\\\\u677F",[30,0,36],[140,90,4],"cover",{round:6,cover:!0,material:"metal",explode:[0,0,62]})]}}function ht({radius:t=20,rod:a=70,angle:n=0}={}){let o=X({radius:t,rod:a,angle:n,z:28});return{title:"\\\\u66F2\\\\u67C4\\\\u8FDE\\\\u6746 \\\\xB7 \\\\u65CB\\\\u8F6C\\\\u8F6C\\\\u4E3A\\\\u5F80\\\\u590D",groups:[{id:"frame",label:"\\\\u652F\\\\u67B6\\\\u4E0E\\\\u5BFC\\\\u8F68",description:"\\\\u652F\\\\u6491\\\\u8F74\\\\u5FC3\\\\uFF0C\\\\u9650\\\\u5236\\\\u6ED1\\\\u5757\\\\u6CBF\\\\u540C\\\\u4E00\\\\u65B9\\\\u5411\\\\u8FD0\\\\u52A8\\\\u3002"},{id:"crank",label:"\\\\u66F2\\\\u67C4",description:"\\\\u66F2\\\\u67C4\\\\u7ED5\\\\u56FA\\\\u5B9A\\\\u8F74\\\\u5FC3\\\\u65CB\\\\u8F6C\\\\u3002"},{id:"rod",label:"\\\\u8FDE\\\\u6746",description:"\\\\u8FDE\\\\u63A5\\\\u66F2\\\\u67C4\\\\u9500\\\\u548C\\\\u6ED1\\\\u5757\\\\uFF0C\\\\u957F\\\\u5EA6\\\\u4FDD\\\\u6301\\\\u4E0D\\\\u53D8\\\\u3002"},{id:"piston",label:"\\\\u6ED1\\\\u5757",description:"\\\\u6CBF\\\\u5BFC\\\\u8F68\\\\u5F80\\\\u590D\\\\uFF1B\\\\u5B8C\\\\u6574\\\\u884C\\\\u7A0B\\\\u7B49\\\\u4E8E\\\\u66F2\\\\u67C4\\\\u534A\\\\u5F84\\\\u7684\\\\u4E24\\\\u500D\\\\u3002"}],parts:[z("base","\\\\u5B89\\\\u88C5\\\\u5E95\\\\u5EA7",[35,0,-6],[175,80,10],"frame",{round:6,material:"metal"}),...ut(35,0,1,"frame",3,30),F("bearing","\\\\u66F2\\\\u8F74\\\\u8F74\\\\u627F",[0,0,7],11,15,"frame",{inner:4,material:"dark"}),F("axle","\\\\u66F2\\\\u8F74",[0,0,15],3.8,26,"crank",{material:"metal",explode:[0,-18,18]}),F("flywheel","\\\\u66F2\\\\u67C4\\\\u76D8",[0,0,20],t+6,6,"crank",{inner:4,material:"accent",explode:[0,-18,18]}),z("railA","\\\\u5BFC\\\\u8F68",[74,-16,13],[85,5,6],"frame",{round:1,material:"dark"}),z("railB","\\\\u5BFC\\\\u8F68",[74,16,13],[85,5,6],"frame",{round:1,material:"dark"}),F("crankPin","\\\\u66F2\\\\u67C4\\\\u9500",o.crank,3,12,"crank",{material:"warm",explode:[0,-18,18]}),{id:"link",type:"rod",label:"\\\\u8FDE\\\\u6746",from:o.crank,to:o.piston,radius:2.4,group:"rod",material:"metal",explode:[0,0,45]},z("piston","\\\\u6ED1\\\\u5757",[o.position,0,22],[18,24,16],"piston",{round:3,material:"cool",explode:[20,0,18]}),F("pistonPin","\\\\u6ED1\\\\u5757\\\\u9500",o.piston,3,10,"piston",{material:"warm",explode:[20,0,18]})]}}var St=`\\n.mui-mechanism{font:15px/1.7 system-ui,sans-serif;color:var(--canvas-ink);background:var(--canvas-bg);border:1px solid var(--canvas-line);border-radius:24px;padding:20px;max-width:100%;box-sizing:border-box}.mui-mechanism *{box-sizing:border-box}.mui-mechanism h2{font-size:22px;line-height:1.35;margin:0 0 8px;font-weight:750}.mui-mechanism p{margin:0;color:var(--canvas-muted)}\\n.mui-mechanism-svg{display:block;width:100%;height:auto;max-height:420px;touch-action:pan-y}.mui-mechanism-svg path{stroke:color-mix(in srgb,var(--canvas-ink) 38%,var(--canvas-bg));stroke-width:.8;stroke-linejoin:round;vector-effect:non-scaling-stroke;cursor:pointer;fill:var(--mech-base,var(--canvas-soft))}.mui-mechanism-svg [data-material=metal]{--mech-base:color-mix(in srgb,var(--canvas-muted) 32%,var(--canvas-bg))}.mui-mechanism-svg [data-material=dark]{--mech-base:color-mix(in srgb,var(--canvas-ink) 78%,var(--canvas-bg))}.mui-mechanism-svg [data-material=accent]{--mech-base:var(--canvas-accent)}.mui-mechanism-svg [data-material=cool]{--mech-base:color-mix(in srgb,#22998a 70%,var(--canvas-bg))}.mui-mechanism-svg [data-material=warm]{--mech-base:color-mix(in srgb,#dd9c42 75%,var(--canvas-bg))}\\n.mui-mechanism-svg [data-tone="0"]{fill:color-mix(in srgb,var(--mech-base) 74%,var(--canvas-bg))}.mui-mechanism-svg [data-tone="1"]{fill:var(--mech-base)}.mui-mechanism-svg [data-tone="2"]{fill:color-mix(in srgb,var(--mech-base) 85%,var(--canvas-ink))}.mui-mechanism-svg [data-tone="3"]{fill:color-mix(in srgb,var(--mech-base) 68%,var(--canvas-ink))}.mui-mechanism-svg [data-line]{fill:none;stroke:var(--mech-base);stroke-width:2}.mui-mechanism-svg [data-active=false]{opacity:.2}.mui-mechanism-svg [data-active=true]{opacity:1}\\n.mui-mechanism-nav{display:flex;flex-wrap:wrap;gap:7px;margin:8px 0 12px}.mui-mechanism button{font:inherit;color:var(--canvas-ink);background:var(--canvas-bg);border:1px solid var(--canvas-line);border-radius:999px;padding:6px 13px;cursor:pointer;min-height:36px}.mui-mechanism button[aria-pressed=true]{color:var(--canvas-bg);background:var(--canvas-ink);border-color:var(--canvas-ink)}.mui-mechanism button:focus-visible,.mui-mechanism input:focus-visible{outline:2px solid var(--canvas-accent);outline-offset:3px}.mui-mechanism button:disabled{opacity:.5;cursor:default}\\n.mui-mechanism-controls{display:flex;align-items:center;flex-wrap:wrap;gap:14px;padding:12px 14px;border-radius:16px;background:var(--canvas-soft);margin:8px 0}.mui-mechanism-controls label{display:flex;align-items:center;gap:9px;flex:1 1 180px;min-width:0}.mui-mechanism-controls input[type=range]{flex:1;min-width:70px;accent-color:var(--canvas-accent)}.mui-mechanism-controls input[type=checkbox]{accent-color:var(--canvas-accent)}.mui-mechanism-controls output{font-variant-numeric:tabular-nums;min-width:40px;text-align:right;font-weight:650}.mui-mechanism-readout{display:block;padding:10px 0;font-weight:700;font-variant-numeric:tabular-nums;color:var(--canvas-ink)}.mui-mechanism-description{min-height:0;font-size:14px}\\n.mui-mechanism[data-style=editorial]{border:0;border-top:1px solid var(--canvas-line);border-radius:0;padding:16px 0}.mui-mechanism[data-style=editorial] h2{font-family:ui-serif,Georgia,serif;font-weight:650}.mui-mechanism[data-style=editorial] .mui-mechanism-controls{border-radius:0;background:transparent;border-block:1px solid var(--canvas-line)}\\n.mui-mechanism[data-style=technical]{border-radius:10px}.mui-mechanism[data-style=technical] button,.mui-mechanism[data-style=technical] .mui-mechanism-controls{border-radius:6px}.mui-mechanism[data-style=technical] .mui-mechanism-readout{font-family:ui-monospace,Consolas,monospace}\\n.mui-mechanism[data-style=soft]{border:0;background:var(--canvas-soft);border-radius:28px 28px 28px 10px}.mui-mechanism[data-style=soft] .mui-mechanism-controls{background:var(--canvas-bg);border-radius:22px}.mui-mechanism[data-style=expressive] h2{font-size:28px;font-weight:850;border-left:5px solid var(--canvas-accent);padding-left:14px}.mui-mechanism[data-style=expressive]{border:0;border-radius:0}.mui-mechanism[data-style=prismframe]{border:1.5px solid var(--canvas-line);box-shadow:4px 5px 0 color-mix(in srgb,var(--canvas-accent) 14%,var(--canvas-bg))}.mui-mechanism[data-style=aurora]{border-radius:28px;box-shadow:0 16px 30px -25px #30204d66}.mui-mechanism[data-style=aurora] .mui-mechanism-controls{border-radius:24px}\\n@media(max-width:500px){.mui-mechanism{padding:14px;border-radius:20px}.mui-mechanism h2{font-size:20px}.mui-mechanism-controls{padding:10px}.mui-mechanism-nav{gap:5px}.mui-mechanism button{padding:6px 10px;font-size:14px}}\\n@media(prefers-reduced-motion:reduce){.mui-mechanism *{animation:none!important;transition:none!important}}\\n@media(forced-colors:active){.mui-mechanism-svg path{fill:Canvas;stroke:CanvasText}.mui-mechanism button[aria-pressed=true]{background:Highlight;color:HighlightText}}\\n`;var xt="http://www.w3.org/2000/svg",C=(t,a,n)=>{let o=document.createElement(t);return a&&(o.className=a),n!==void 0&&(o.textContent=n),o};function Ft(t){function a(o,e){let i=typeof o=="string"?document.querySelector(o):o;if(!i||!i.replaceChildren)throw Error("Motion mechanism: target element not found");Y(e);let r=structuredClone({...e,onSelect:void 0}),p=nt(r),d={explode:0,selected:"all",cutaway:!1,pose:{}},m=!1,s="",c="",u=0,f=new Map,g=new Map,h=new Map,M=[],O=C("section","mui-mechanism"),N=C("h2",null,r.title??"\\\\u7ED3\\\\u6784\\\\u56FE\\\\u89E3"),$=document.createElementNS(xt,"svg"),P=document.createElementNS(xt,"g"),A=C("div","mui-mechanism-nav"),w=C("div","mui-mechanism-controls"),T=C("p","mui-mechanism-description"),D=C("output","mui-mechanism-readout"),G=C("style");G.textContent=St,N.hidden=r.title==="",O.setAttribute("aria-label",r.title??"\\\\u7ED3\\\\u6784\\\\u56FE\\\\u89E3"),$.setAttribute("class","mui-mechanism-svg"),$.setAttribute("viewBox","0 0 600 340"),$.setAttribute("role","img"),$.setAttribute("aria-label","\\\\u53EF\\\\u62C6\\\\u89E3\\\\u7684\\\\u7ED3\\\\u6784\\\\u793A\\\\u610F\\\\u56FE\\\\uFF1B\\\\u4F7F\\\\u7528\\\\u4E0B\\\\u65B9\\\\u6309\\\\u94AE\\\\u9009\\\\u62E9\\\\u90E8\\\\u4EF6"),$.append(P),O.append(G,N,$,A,w,D,T),i.replaceChildren(O);let S=()=>r.groups?.length?r.groups:r.parts.map(l=>({id:l.id,label:l.label??l.id,description:l.description??""}));function H(l){r.bind?.selected?t.setState({[r.bind.selected]:l}):typeof e.onSelect=="function"?e.onSelect(l):Q({selected:l})}function K(){if(A.replaceChildren(),h.clear(),!r.bind?.selected&&typeof e.onSelect!="function"){A.hidden=!0;return}A.hidden=!1;for(let l of[{id:"all",label:"\\\\u5168\\\\u90E8",description:""},...S()]){let b=C("button",null,l.label);b.type="button",b.setAttribute("aria-pressed",String(d.selected===l.id)),b.addEventListener("click",()=>H(l.id)),h.set(l.id,b),A.append(b)}}let x,rt,L;if(r.bind?.explode){let l=C("label",null,"\\\\u62C6\\\\u89E3\\\\u8FDB\\\\u5EA6");x=C("input"),x.type="range",x.min="0",x.max="1",x.step=".01",x.setAttribute("aria-label","\\\\u62C6\\\\u89E3\\\\u8FDB\\\\u5EA6"),rt=C("output"),x.addEventListener("input",()=>t.setState({[r.bind.explode]:Number(x.value)})),l.append(x,rt),w.append(l)}if(r.bind?.cutaway&&r.parts.some(l=>l.cover)){let l=C("label",null,"\\\\u5256\\\\u5F00\\\\u5916\\\\u58F3");L=C("input"),L.type="checkbox",L.setAttribute("aria-label","\\\\u5256\\\\u5F00\\\\u5916\\\\u58F3"),L.addEventListener("change",()=>t.setState({[r.bind.cutaway]:L.checked})),l.prepend(L),w.append(l)}w.hidden=!w.childNodes.length;function jt(l){let b=JSON.stringify([l.explode,l.cutaway]);b!==s&&(p=nt(r,l),s=b);let E=mt(r,p,l,f),k=new Set;for(let j of E){k.add(j.key);let R=g.get(j.key);R||(R=document.createElementNS(xt,"path"),R.setAttribute("fill-rule","evenodd"),g.set(j.key,R));for(let[gt,bt]of Object.entries({d:j.d,"data-part":j.part,"data-material":j.material,"data-tone":j.tone,"data-active":j.active}))R.getAttribute(gt)!==String(bt)&&R.setAttribute(gt,String(bt));j.line?R.setAttribute("data-line",""):R.removeAttribute("data-line")}for(let[j,R]of g)k.has(j)||(R.remove(),g.delete(j));let Z=E.map(j=>j.key).join("|");if(Z!==c){for(let j of E)P.append(g.get(j.key));c=Z}u++}function Q(l={}){if(m)return;for(let k of Object.keys(l))if(!["explode","selected","cutaway","pose","parts","readout"].includes(k))throw Error("Motion mechanism: unknown update field "+k);if(l.parts){let k={...r,parts:l.parts};Y(k);let Z=nt(k);mt(k,Z,{...d,...l},new Map),r=k,p=Z,f.clear(),c="",s=""}let b={...d,...l};l.pose&&(b.pose=l.pose),jt(b),d=b;for(let[k,Z]of h)Z.setAttribute("aria-pressed",String(b.selected===k));let E=S().find(k=>k.id===b.selected)??r.parts.find(k=>k.id===b.selected);T.textContent=E?.description??(b.selected==="all"?"\\\\u9009\\\\u62E9\\\\u4E00\\\\u4E2A\\\\u90E8\\\\u4EF6\\\\uFF0C\\\\u67E5\\\\u770B\\\\u5B83\\\\u7684\\\\u804C\\\\u8D23\\\\uFF1B\\\\u62C6\\\\u89E3\\\\u53EA\\\\u5C55\\\\u793A\\\\u88C5\\\\u914D\\\\u5173\\\\u7CFB\\\\u3002":""),x&&(x.value=String(b.explode),rt.textContent=Math.round(b.explode*100)+"%"),L&&(L.checked=b.cutaway),l.readout!==void 0&&(D.textContent=String(l.readout))}return $.addEventListener("click",l=>{let b=l.target.closest("[data-part]");if(!b)return;let E=r.parts.find(k=>k.id===b.getAttribute("data-part"));E&&H(r.groups?.length?E.group??E.id:E.id)}),K(),M.push(t.subscribe(l=>{if(m)return;let b={};for(let[E,k]of Object.entries(r.bind??{})){if(!Object.hasOwn(l.state,k))throw Error("Motion mechanism: bind."+E+" names undeclared state "+k);b[E]=l.state[k]}O.dataset.style=l.theme?.visualStyle??"";for(let E of h.values())E.disabled=l.disabled;x&&(x.disabled=l.disabled),L&&(L.disabled=l.disabled),Q(b)})),Object.freeze({update:Q,pose:l=>Q({pose:l}),stats:()=>({frames:u,faces:g.size,parts:r.parts.length}),destroy(){m||(m=!0,M.forEach(l=>l()),g.clear(),f.clear(),i.replaceChildren())}})}function n(o,e,i={}){if(!["assembly","gears","crank"].includes(e))throw Error("Motion mechanism: demo must be assembly/gears/crank");let r=i.bind??{},p=()=>t.snapshot.state,d=(A,w)=>Object.hasOwn(r,A)?p()[r[A]]:w;for(let[A,w]of Object.entries(r))if(!["explode","selected","cutaway","rpm","teeth","running","angle","radius"].includes(A)||typeof w!="string"||!Object.hasOwn(p(),w))throw Error("Motion mechanism: invalid demo binding "+A);let m=d("angle",0)*Math.PI/180,s=m,c="",u=!1,f=Object.fromEntries(Object.entries(r).filter(([A])=>["explode","selected","cutaway"].includes(A)));function g(){return e==="assembly"?ft():e==="gears"?pt({driverTeeth:i.driverTeeth??16,drivenTeeth:d("teeth",32),module:i.module??1.5}):ht({radius:d("radius",20),rod:i.rod??70})}let h=a(o,{...g(),...i.title===void 0?{}:{title:i.title},bind:f}),M=!1;function O(A=0,w=!1,T=!0){if(M)return;let D=d("rpm",30),G=d("running",!1),S=d("angle",0)*Math.PI/180,H=s;S!==m?(H=S,m=S):G&&T&&!w&&(H+=D*Math.PI*2/60*A),s=H;let K=JSON.stringify([e,d("teeth",32),d("radius",20)]);if(K!==c&&(h.update({parts:g().parts}),c=K),e==="gears"){let x=W({driverTeeth:i.driverTeeth??16,drivenTeeth:d("teeth",32),rpm:D,angle:s,module:i.module??1.5});h.update({pose:{driverGear:{rotation:x.driverAngle},drivenGear:{rotation:x.drivenAngle}},readout:"\\\\u4E3B\\\\u52A8\\\\u8F6E "+t.formatNumber(x.driverRpm,0)+" rpm \\\\xB7 \\\\u4ECE\\\\u52A8\\\\u8F6E "+t.formatNumber(x.drivenRpm,2)+" rpm \\\\xB7 \\\\u9F7F\\\\u6570\\\\u6BD4 "+t.formatNumber(x.ratio,2)+"\\\\uFF08\\\\u8D1F\\\\u53F7\\\\u8868\\\\u793A\\\\u53CD\\\\u5411\\\\uFF09"})}else if(e==="crank"){let x=X({angle:s,radius:d("radius",20),rod:i.rod??70,z:28});h.update({pose:{crankPin:{at:x.crank},link:{from:x.crank,to:x.piston},piston:{at:[x.position,0,22]},pistonPin:{at:x.piston}},readout:"\\\\u66F2\\\\u67C4\\\\u89D2 "+t.formatNumber((s*180/Math.PI%360+360)%360,1)+"\\\\xB0 \\\\xB7 \\\\u6ED1\\\\u5757\\\\u4F4D\\\\u7F6E "+t.formatNumber(x.position,2)+" \\\\xB7 \\\\u884C\\\\u7A0B "+t.formatNumber(x.stroke,1)+"\\\\uFF08\\\\u793A\\\\u610F\\\\u957F\\\\u5EA6\\\\u5355\\\\u4F4D\\\\uFF09"})}u=w}let N=null,$=()=>{O(0,u,!0),e!=="assembly"&&(d("running",!1)&&!N?N=t.animate(({delta:A,reducedMotion:w,visible:T})=>{T&&!w?O(A,!1,!0):u!==w&&O(0,w,T)}):!d("running",!1)&&N&&(N(),N=null))},P=t.subscribe($);return O(),Object.freeze({...h,destroy(){M||(M=!0,N?.(),P(),h.destroy())}})}return Object.freeze({mount:a,mountDemo:n,gearPair:W,sliderCrank:X,follow:Mt,scenes:Object.freeze({assembly:ft,gears:pt,crank:ht})})}return _t(Tt);})();\\n\';\n\n // lib/visual-audit.js\n function measureVisual(root, nodeId = "") {\n const issues = [], seen = /* @__PURE__ */ new Set(), coverage = { nodeId, elements: 0, truncated: false, contrastChecked: 0, contrastUncovered: 0 };\n const styleCache = /* @__PURE__ */ new WeakMap(), styleOf = (el2) => {\n let css = styleCache.get(el2);\n if (!css) {\n css = getComputedStyle(el2);\n styleCache.set(el2, css);\n }\n return css;\n };\n const target = (el2) => {\n if (!el2) return void 0;\n const tag = el2.tagName.toLowerCase(), id = el2.id;\n return { selector: id && id.length <= 64 ? "#" + CSS.escape(id) : tag, text: (el2.textContent ?? "").trim().replace(/\\s+/g, " ").slice(0, 120), tag };\n };\n const add = (code, value, el2) => {\n if (issues.length >= 40) return;\n const id = el2?.closest("[data-ui-node]")?.getAttribute("data-ui-node") ?? nodeId;\n const location = target(el2);\n const k2 = id + ":" + code + ":" + (location?.selector ?? "") + ":" + (location?.text ?? "") + ":" + Math.round(value ?? 0);\n if (!seen.has(k2) && issues.length < 40) {\n seen.add(k2);\n issues.push({ code, nodeId: id, ...location ? { target: location } : {}, ...value === void 0 ? {} : { value: Number(value.toFixed(2)) } });\n }\n };\n const color = (s) => {\n let m2 = s.match(/^rgba?\\(([^)]+)\\)/);\n if (m2) {\n const a = m2[1].split(/[\\s,\\/]+/).map(Number);\n return [a[0] / 255, a[1] / 255, a[2] / 255, a[3] ?? 1];\n }\n m2 = s.match(/^color\\(srgb ([^)]+)\\)/);\n if (m2) {\n const a = m2[1].split(/[\\s\\/]+/).map(Number);\n return [a[0], a[1], a[2], a[3] ?? 1];\n }\n return null;\n };\n const luminance = (c) => c.slice(0, 3).map((v2) => v2 <= 0.04045 ? v2 / 12.92 : ((v2 + 0.055) / 1.055) ** 2.4).reduce((s, v2, i) => s + v2 * [0.2126, 0.7152, 0.0722][i], 0);\n const blend = (front, back) => front.slice(0, 3).map((v2, i) => v2 * front[3] + back[i] * (1 - front[3])).concat(1);\n const background = (el2) => {\n const layers = [];\n let n = el2;\n for (let i = 0; n && i < 64; i++, n = n.parentElement) {\n const c = styleOf(n);\n if (c.backgroundImage !== "none") return null;\n const colorValue = color(c.backgroundColor);\n if (!colorValue) return null;\n if (colorValue[3] > 0) layers.push(colorValue);\n if (colorValue[3] === 1) {\n let out = layers.pop();\n while (layers.length) out = blend(layers.pop(), out);\n return out;\n }\n }\n return null;\n };\n let contentBottom = root.getBoundingClientRect().top;\n const widthRoot = root.id === "canvas" ? document.documentElement : root;\n if (widthRoot.scrollWidth > widthRoot.clientWidth + 2) add("overflow", widthRoot.scrollWidth - widthRoot.clientWidth);\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n let el;\n while (el = walker.nextNode()) {\n if (coverage.elements >= 2e3) {\n coverage.truncated = true;\n break;\n }\n coverage.elements++;\n if (el.matches("[data-canvas-phase=error]")) add("runtimeError", void 0, el);\n const css = styleOf(el), box = el.getBoundingClientRect();\n if (!box.width || !box.height || css.visibility === "hidden" || css.display === "none") continue;\n const text2 = [...el.childNodes].some((n) => n.nodeType === 3 && n.textContent.trim());\n if (text2) {\n let size = parseFloat(css.fontSize);\n if (el instanceof SVGElement && el.getScreenCTM) {\n const m2 = el.getScreenCTM();\n if (m2) size *= Math.hypot(m2.c, m2.d);\n }\n if (size < 11.9) add("smallText", size, el);\n if (!(el instanceof SVGElement)) {\n const fg = color(css.color), bg = background(el);\n let opacitySafe = true, opacityDepth = 0;\n for (let a2 = el; a2; a2 = a2.parentElement) {\n if (++opacityDepth > 64 || parseFloat(styleOf(a2).opacity) < 1) {\n opacitySafe = false;\n break;\n }\n }\n if (fg && bg && opacitySafe) {\n coverage.contrastChecked++;\n const a2 = luminance(blend(fg, bg)), b2 = luminance(bg), ratio = (Math.max(a2, b2) + 0.05) / (Math.min(a2, b2) + 0.05);\n if (ratio < (size >= 24 || size >= 18.66 && parseFloat(css.fontWeight) >= 700 ? 3 : 4.5)) add("contrast", ratio, el);\n } else coverage.contrastUncovered++;\n const range = document.createRange();\n range.selectNodeContents(el);\n const bounds = range.getBoundingClientRect();\n let a = el, depth = 0;\n while (a && a !== root.parentElement && depth++ < 24) {\n const c = styleOf(a), clip = a.getBoundingClientRect();\n if (["hidden", "clip"].includes(c.overflowX) && (bounds.left < clip.left - 2 || bounds.right > clip.right + 2) || ["hidden", "clip"].includes(c.overflowY) && (bounds.top < clip.top - 2 || bounds.bottom > clip.bottom + 2)) {\n add("clippedText", void 0, el);\n break;\n }\n a = a.parentElement;\n }\n } else coverage.contrastUncovered++;\n }\n if (text2 || el.matches("svg,canvas,img,video,input,select,textarea,button")) contentBottom = Math.max(contentBottom, box.bottom);\n if (el.matches("input:not([type=hidden]),select,textarea,button,[role=button]") && !el.getAttribute("aria-label") && !el.getAttribute("aria-labelledby") && !el.labels?.length && !el.textContent.trim() && !el.getAttribute("title")) add("missingLabel", void 0, el);\n }\n const rect = root.getBoundingClientRect(), gap = rect.bottom - contentBottom;\n if (!coverage.truncated && root.id === "canvas" && rect.height > 320 && gap > Math.max(96, rect.height * 0.25)) add("bottomWhitespace", gap, root);\n Object.defineProperty(issues, "coverage", { value: coverage });\n return issues;\n }\n\n // lib/format-number.js\n function formatNumber(value, decimals = 2) {\n if (typeof value !== "number" || !Number.isFinite(value)) throw new Error("DSH UI: formatNumber requires a finite number");\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > 6) throw new Error("DSH UI: formatNumber decimals must be an integer from 0 to 6");\n return value.toLocaleString("en-US", { minimumFractionDigits: decimals, maximumFractionDigits: decimals });\n }\n\n // lib/canvas-system.js\n var CANVAS_SYSTEM_CSS = `\n:root{--canvas-radius:16px;--canvas-gap:16px;--canvas-positive:#167456;--canvas-negative:#b13b3b;--canvas-warning:#875b15}\n:root[data-canvas-scheme=dark]{--canvas-positive:#78d9b4;--canvas-negative:#ffaaaa;--canvas-warning:#edc87e}\n#canvas{display:flow-root}html,body{margin:0;min-width:0;background:var(--canvas-bg,#fff);color:var(--canvas-ink,#182537);font:14px/1.6 system-ui,"Microsoft YaHei",sans-serif}*{box-sizing:border-box}svg{max-width:100%;height:auto}button,input,select,textarea{font:inherit;color:inherit}button,input,select,textarea{border:1px solid var(--canvas-line,#ced4df);border-radius:8px;background:var(--canvas-bg,#fff);padding:8px 12px;max-width:100%}button{cursor:pointer}button:disabled{cursor:default;opacity:.55}input[type=range]{padding:0;accent-color:var(--canvas-accent,#3e60d3)}input[type=checkbox],input[type=radio]{accent-color:var(--canvas-accent,#3e60d3)}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--canvas-accent,#3e60d3);outline-offset:3px}\n.ui-stack{display:grid;gap:var(--canvas-gap)}.ui-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:var(--canvas-gap)}.ui-surface{padding:20px;border:1px solid var(--canvas-line,#ced4df);border-radius:var(--canvas-radius);background:var(--canvas-soft,#f3f5f8)}.ui-title{margin:0;font-size:clamp(20px,3vw,28px);line-height:1.3;letter-spacing:-.02em}.ui-caption{color:var(--canvas-muted,#526176);margin:8px 0;font-size:14px}.ui-value{font-size:clamp(24px,4vw,36px);font-variant-numeric:tabular-nums;line-height:1.2}.ui-controls{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.ui-field{display:grid;gap:6px;min-width:0}.ui-legend{display:flex;gap:16px;flex-wrap:wrap;font-size:13px}.ui-status{min-height:1.6em}.ui-error{color:var(--canvas-negative)}.ui-primary{background:var(--canvas-accent,#3e60d3);color:var(--canvas-accent-ink,#fff);border-color:transparent}\nsvg .ui-node{fill:var(--canvas-soft,#f3f5f8);stroke:var(--canvas-line,#ced4df);stroke-width:1}svg .ui-edge{fill:none;stroke:var(--canvas-muted,#526176);stroke-width:1.5}svg .ui-label{fill:var(--canvas-ink,#182537);font:500 14px system-ui,sans-serif}svg .ui-note{fill:var(--canvas-muted,#526176);font:400 13px system-ui,sans-serif}svg .ui-leader{fill:none;stroke:var(--canvas-muted,#526176);stroke-dasharray:3 4}svg .ui-accent{fill:color-mix(in srgb,var(--canvas-accent,#3e60d3) 12%,var(--canvas-bg,#fff));stroke:var(--canvas-accent,#3e60d3)}\n.ui-flow{display:flex;align-items:center;justify-content:center;gap:16px;padding:24px 8px;flex-wrap:wrap}.ui-step{display:grid;gap:6px;min-width:130px;max-width:240px;padding:16px 20px;border:1px solid var(--canvas-line);border-radius:6px;background:var(--canvas-bg)}.ui-step strong{font-size:16px;font-weight:600}.ui-step span{font-size:14px;color:var(--canvas-muted)}.ui-arrow{color:var(--canvas-muted);font-size:22px}.ui-callout{border-inline-start:3px solid var(--canvas-accent);padding:8px 16px;color:var(--canvas-ink)}\n.ui-surface,.ui-step{border-radius:var(--canvas-radius);background:var(--canvas-bg,#fff)}button,input:not([type=checkbox]):not([type=radio]):not([type=range]),select,textarea{border-radius:12px}button{border-radius:999px}.ui-primary{background:var(--canvas-ink,#182537);color:var(--canvas-bg,#fff)}.ui-callout{border-radius:0 12px 12px 0;background:color-mix(in srgb,var(--canvas-accent,#3e60d3) 5%,var(--canvas-bg,#fff))}\n@media(max-width:480px){.ui-flow{flex-direction:column;padding:16px 8px;gap:12px}.ui-step{width:100%;max-width:none}.ui-arrow{transform:rotate(90deg)}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}`;\n\n // lib/sandbox.js\n var SANDBOX_LIMITS = Object.freeze({ source: 49152, height: 1e3, message: 16384, rate: 30 });\n function canvasSnapshot(node2, state2, data, derived, disabled, theme) {\n const pick = (keys, values) => Object.fromEntries((keys ?? []).map((k2) => [k2, values[k2]]));\n return { state: pick(node2.stateKeys, state2), data: pick(node2.dataKeys, data), derived: pick(node2.derivedKeys, derived), disabled, theme };\n }\n function canvasPatch(message, node2) {\n if (!message || typeof message !== "object" || Array.isArray(message)) throw new Error("Invalid canvas patch");\n const keys = Object.keys(message);\n if (!keys.length || keys.length > 64 || keys.some((k2) => !(node2.stateKeys ?? []).includes(k2))) throw new Error("Canvas state key is not declared");\n if (JSON.stringify(message).length > SANDBOX_LIMITS.message) throw new Error("Canvas patch is too large");\n return message;\n }\n function sandboxDocument(node2, channel2, nonce2) {\n const json = (value) => JSON.stringify(value).replace(/</g, "\\\\u003c").replace(/\\u2028/g, "\\\\u2028").replace(/\\u2029/g, "\\\\u2029");\n return `<!doctype html><html><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src \'none\'; script-src \'nonce-${nonce2}\'; style-src \'unsafe-inline\'; img-src data:; font-src \'none\'; connect-src \'none\'; media-src \'none\'; object-src \'none\'; frame-src \'none\'; worker-src \'none\'; base-uri \'none\'; form-action \'none\'"><meta name="viewport" content="width=device-width,initial-scale=1"><style>${CANVAS_SYSTEM_CSS}</style></head><body><main id="canvas"></main><script nonce="${nonce2}">(()=>{\n const channel=${json(channel2)}, source=${json({ html: node2.html, css: node2.css ?? "", script: node2.script ?? "" })};\n let snapshot={state:{},data:{},derived:{},disabled:true,theme:{}}, started=false;\n const listeners=new Set(), send=(type,payload)=>parent.postMessage({dshCanvas:1,channel,type,payload},\'*\');\n const report=e=>send(\'error\',String(e?.message??e).slice(0,1000));\n const audit=${measureVisual.toString()};let auditTimer;const scheduleAudit=()=>{clearTimeout(auditTimer);auditTimer=setTimeout(()=>{const issues=audit(document.getElementById(\'canvas\'),${json(node2.id ?? "")});send(\'audit\',{issues,coverage:issues.coverage})},400)};\n addEventListener(\'resize\',scheduleAudit);\n addEventListener(\'error\',e=>report(e.error??e.message));addEventListener(\'unhandledrejection\',e=>report(e.reason));\n const animations=new Set(), motion=matchMedia(\'(prefers-reduced-motion: reduce)\');\n let raf=0,last=0,time=0;\n const visible=()=>snapshot.visible!==false&&!document.hidden;\n const canAnimate=()=>visible()&&!snapshot.disabled&&!motion.matches;\n const draw=delta=>{for(const fn of animations)try{fn({time,delta,reducedMotion:motion.matches,visible:visible()})}catch(e){animations.delete(fn);report(e)}};\n const tick=t=>{raf=0;if(!canAnimate()||!animations.size){last=0;draw(0);return}const delta=last?Math.min(.05,(t-last)/1000):0;last=t;time+=delta;draw(delta);if(animations.size)raf=requestAnimationFrame(tick)};\n const refresh=()=>{draw(0);if(canAnimate()&&animations.size){if(!raf){last=0;raf=requestAnimationFrame(tick)}}else{cancelAnimationFrame(raf);raf=0;last=0}};\n motion.addEventListener(\'change\',refresh);document.addEventListener(\'visibilitychange\',refresh);\n const formatNumber=${formatNumber.toString()};\n const api={formatNumber,get snapshot(){return structuredClone(snapshot)},subscribe(fn){if(typeof fn!==\'function\')throw Error(\'Listener required\');listeners.add(fn);fn(api.snapshot);return()=>listeners.delete(fn)},setState(patch){if(!snapshot.disabled)send(\'patch\',patch)},animate(fn){if(typeof fn!==\'function\')throw Error(\'Animation callback required\');animations.add(fn);refresh();return()=>{animations.delete(fn);if(!animations.size){cancelAnimationFrame(raf);raf=0;last=0}}}};\n ${node2.libraries?.includes("mechanism") ? MECHANISM_RUNTIME.replace(/<\\/script/gi, "<\\\\/script") + ";api.mechanism=__MotionMechanism.createMechanismAPI(api);" : ""}\n Object.defineProperty(window,\'DSHUI\',{value:Object.freeze(api),writable:false});\n for(const type of [\'click\',\'input\',\'change\',\'keydown\',\'pointerdown\'])document.addEventListener(type,e=>{if(snapshot.disabled){e.preventDefault();e.stopImmediatePropagation()}},true);\n addEventListener(\'message\',event=>{\n const m=event.data;if(event.source!==parent||m?.dshCanvas!==1||m.channel!==channel||m.type!==\'snapshot\')return;\n snapshot=m.payload;for(const [k,v] of Object.entries(snapshot.theme??{}))document.documentElement.style.setProperty(\'--canvas-\'+k,v);\n document.documentElement.style.colorScheme=snapshot.theme?.scheme??\'light\';document.documentElement.dataset.canvasScheme=snapshot.theme?.scheme??\'light\';\n const wasStarted=started;\n if(!started){started=true;document.getElementById(\'canvas\').innerHTML=source.html;const style=document.createElement(\'style\');style.textContent=source.css;document.head.append(style);const script=document.createElement(\'script\');script.nonce=${json(nonce2)};script.textContent=source.script;document.body.append(script)}\n if(wasStarted)for(const fn of listeners)try{fn(api.snapshot)}catch(e){report(e)}\n refresh();if(!wasStarted)send(\'mounted\');scheduleAudit();\n });\n let resizePending=false;new ResizeObserver(()=>{if(!started||resizePending)return;resizePending=true;requestAnimationFrame(()=>{resizePending=false;send(\'height\',Math.ceil(document.getElementById(\'canvas\').getBoundingClientRect().height))})}).observe(document.getElementById(\'canvas\'));\n send(\'ready\');\n})();<\\/script></body></html>`;\n }\n\n // lib/components.js\n var define = (fields2, purpose, presentation = "") => Object.freeze({ fields: Object.freeze(fields2), purpose, presentation });\n var COMPONENTS = Object.freeze({\n visual: define(["spec", "stateKey", "warnings"], "Extended native charts, tables, plots, quiz, forms, diagrams, media and 3D"),\n heading: define(["text", "spans", "size", "weight", "color", "align", "lineHeight"], "Section heading", "tone"),\n text: define(["text", "spans", "size", "weight", "color", "align", "lineHeight", "copyable", "title"], "Readable explanation; copyable:true adds a reusable text panel", "tone"),\n code: define(["code", "lang", "title", "wrap"], "Literal copyable code; displayed only, never executed"),\n callout: define(["text", "spans", "size", "weight", "color", "align", "lineHeight"], "A short emphasized paragraph", "tone"),\n row: define(["children", "columns", "gap"], "Wrapping parallel content"),\n column: define(["children", "gap"], "Ordered vertical content"),\n card: define(["title", "children", "surface"], "Meaningful grouped section", "tone"),\n details: define(["title", "children", "open"], "Collapsible supporting content", "tone"),\n badge: define(["text"], "Short explicit status label", "tone"),\n progress: define(["label", "value", "max", "unit"], "Declared numeric progress snapshot", "tone"),\n steps: define(["title", "items"], "Ordered declared steps with an optional heading"),\n metric: define(["label", "value", "unit", "decimals"], "Number with units, or a literal/bound status string", "tone"),\n input: define(["label", "bind"], "String or numeric state input"),\n slider: define(["label", "bind"], "Numeric state control"),\n select: define(["label", "bind", "variant"], "Selection from declared state options; variant:segmented for 2..8 short options, dropdown otherwise"),\n toggle: define(["label", "bind"], "Boolean state control"),\n button: define(["text", "action", "href", "path", "variant"], "Agent follow-up, web link or host file opener", "icon"),\n link: define(["text", "href", "path", "variant"], "User-clicked webpage or local file button", "icon"),\n divider: define(["label"], "Quiet section divider"),\n table: define(["label", "rows", "columns"], "Supplied or derived values; inline rows or data/derived reference"),\n chart: define(["kind", "rows", "labelKey", "valueKey", "label", "unit", "xScale"], "Bar/line comparison with accessible data"),\n sandbox: define(["title", "html", "css", "script", "fallback", "height", "libraries", "stateKeys", "dataKeys", "derivedKeys"], "Freeform isolated HTML/SVG/CSS/JavaScript visualization")\n });\n function componentFields(type) {\n const c = Object.hasOwn(COMPONENTS, type) ? COMPONENTS[type] : void 0;\n return c && ["id", "type", ...c.fields, ...c.presentation ? ["icon"] : [], ...c.presentation === "tone" ? ["tone"] : []];\n }\n\n // lib/identifiers.js\n var IDENTIFIER_SOURCE = "[\\\\p{L}_][\\\\p{L}\\\\p{M}\\\\p{N}_]{0,63}";\n var pattern = new RegExp(`^${IDENTIFIER_SOURCE}$`, "u");\n var validIdentifier = (value) => typeof value === "string" && pattern.test(value) && !["constructor", "prototype", "__proto__"].includes(value);\n\n // lib/author-expression.js\n function compileExpression(source) {\n const fail2 = () => {\n throw new Error("DSH UI: invalid formula; use state.x, data.x, derived.x, item.x, numbers, strings, + - * /, comparisons, ?: and min/max/round/ceil/floor/abs");\n };\n if (typeof source !== "string" || !source.trim() || source.length > 2048) fail2();\n const tokens = [];\n let offset = 0;\n const token2 = new RegExp(String.raw`\\s*(?:(\\d+(?:\\.\\d*)?|\\.\\d+)([eE][+-]?\\d+)?|("(?:[^"\\\\]|\\\\.)*")|(${IDENTIFIER_SOURCE}(?:\\.${IDENTIFIER_SOURCE})?)|(===|!==|<=|>=|==|!=|[+*/()?,:<>-]))`, "uy");\n while (offset < source.length) {\n if (!source.slice(offset).trim()) break;\n token2.lastIndex = offset;\n const m2 = token2.exec(source);\n if (!m2) fail2();\n offset = token2.lastIndex;\n tokens.push(m2[1] ? { number: Number(m2[1] + (m2[2] ?? "")) } : m2[3] ? { string: JSON.parse(m2[3]) } : m2[4] ?? m2[5]);\n if (tokens.length > 256) fail2();\n }\n let pos = 0;\n const operators = { "==": ["eq", 1], "===": ["eq", 1], "!=": ["neq", 1], "!==": ["neq", 1], "<": ["lt", 2], "<=": ["lte", 2], ">": ["gt", 2], ">=": ["gte", 2], "+": ["add", 3], "-": ["sub", 3], "*": ["mul", 4], "/": ["div", 4] };\n const take = (t) => {\n if (tokens[pos++] !== t) fail2();\n };\n function parse(min = 0, depth = 0) {\n if (depth > 12) fail2();\n const t = tokens[pos++];\n let out;\n if (t && typeof t === "object") out = { const: Object.hasOwn(t, "number") ? t.number : t.string };\n else if (t === "true" || t === "false") out = { const: t === "true" };\n else if (t === "(") {\n out = parse(0, depth + 1);\n take(")");\n } else if (t === "-" || t === "+") {\n const arg = parse(5, depth + 1);\n out = t === "-" ? { op: "sub", args: [{ const: 0 }, arg] } : arg;\n } else if (typeof t === "string" && t.split(".").length === 2 && ["state", "data", "derived", "item"].includes(t.split(".")[0]) && validIdentifier(t.split(".")[1])) out = { ref: t };\n else if (["min", "max", "round", "ceil", "floor", "abs"].includes(t)) {\n take("(");\n const args = [parse(0, depth + 1)];\n while (tokens[pos] === ",") {\n pos++;\n args.push(parse(0, depth + 1));\n if (args.length > 8) fail2();\n }\n take(")");\n out = { op: t, args };\n } else fail2();\n while (typeof tokens[pos] === "string" && Object.hasOwn(operators, tokens[pos]) && operators[tokens[pos]][1] >= min) {\n const [op, precedence] = operators[tokens[pos++]];\n out = { op, args: [out, parse(precedence + 1, depth + 1)] };\n }\n if (min === 0 && tokens[pos] === "?") {\n pos++;\n const yes = parse(0, depth + 1);\n take(":");\n out = { op: "if", args: [out, yes, parse(0, depth + 1)] };\n }\n return out;\n }\n const result = parse();\n if (pos !== tokens.length) fail2();\n return result;\n }\n function expandExpressions(doc2) {\n const expression2 = (e, at2) => {\n if (!e || typeof e !== "object" || Array.isArray(e)) return e;\n if (Object.hasOwn(e, "expr")) {\n if (Object.keys(e).length !== 1) throw new Error("DSH UI: expr must be the only formula field");\n try {\n return compileExpression(e.expr);\n } catch (error) {\n error.message = "DSH UI: " + at2 + ": " + error.message.replace(/^DSH UI: /, "");\n error.path = at2;\n throw error;\n }\n }\n if (Array.isArray(e.args)) e.args = e.args.map((v2, i) => expression2(v2, at2 + ".args[" + i + "]"));\n if (e.map?.fields) for (const k2 of Object.keys(e.map.fields)) e.map.fields[k2] = expression2(e.map.fields[k2], at2 + ".map.fields." + k2);\n return e;\n };\n if (doc2.derived && typeof doc2.derived === "object") for (const k2 of Object.keys(doc2.derived)) doc2.derived[k2] = expression2(doc2.derived[k2], "derived." + k2);\n const walk = (nodes) => {\n if (!Array.isArray(nodes)) return;\n for (const node2 of nodes) {\n if (!node2 || typeof node2 !== "object") continue;\n for (const field of ["text", "value", "max", "rows"]) if (Object.hasOwn(node2, field)) node2[field] = expression2(node2[field], "node." + node2.id + "." + field);\n if (["table", "chart"].includes(node2.type) && Array.isArray(node2.rows)) {\n for (const [rowIndex, row] of node2.rows.entries()) if (row && typeof row === "object" && !Array.isArray(row)) for (const k2 of Object.keys(row)) row[k2] = expression2(row[k2], "node." + node2.id + ".rows[" + rowIndex + "]." + k2);\n }\n walk(node2.children);\n }\n };\n walk(doc2.nodes);\n return doc2;\n }\n\n // lib/visual-guard.js\n var ne = ["h1", "h2", "h3", "body", "muted", "caption"];\n var te = ["primary", "danger", "success", "ghost"];\n var ie = ["success", "warn", "danger", "accent"];\n var re = ["text", "email", "password", "color"];\n var se = ["info", "success", "warning", "error"];\n var U = ["bars", "line", "donut"];\n var oe = ["line", "area", "scatter"];\n var ae = ["16:9", "4:3", "1:1", "9:16"];\n var ue = ["box", "sphere", "cone", "cylinder", "torus"];\n var le = ["file", "dir"];\n var de = ["architecture", "it-state", "flowchart", "sequence", "state", "er", "timeline", "swimlane", "quadrant", "radar", "loop", "nested", "tree", "org-chart", "layers", "venn", "pyramid", "bar", "line", "gantt", "scatter", "high-level", "process", "medallion", "data-flow", "dp-integration", "dp-security-matrix"];\n var ce = ["focal", "backend", "store", "external", "input", "optional", "security"];\n var fe = ["light", "dark", "editorial"];\n var pe = ["solid", "dashed", "accent", "link"];\n var me = ["auto", "orthogonal", "straight"];\n var ge = ["bar", "line", "area", "pie", "scatter", "radar", "gauge", "funnel", "treemap", "sankey", "graph", "heatmap", "bigline", "wordCloud"];\n var tn = ["hero"];\n var ye = ["bar", "ring"];\n var be = ["info", "success", "warning", "danger"];\n var he = ["accent", "success", "warning", "danger"];\n var Ee = ["text", "num", "delta", "bar", "badge", "spark", "ring", "index", "group"];\n var b = (t, i, r = {}, e = {}) => {\n let s = Object.fromEntries(Object.entries(i).filter(([u]) => u !== "type" && !t.includes(u))), n = e.oneOfRequired ?? [], o = e.conditionalRequired ?? [], a = [...n.map((u) => ({ kind: "one-of-required", fields: u })), ...o];\n return { required: t, fields: i, optional: s, aliases: r, valueAliases: e.valueAliases ?? {}, oneOfRequired: n, conditionalRequired: o, rules: a, enums: e.enums ?? {}, nested: e.nested ?? {}, ...e.validator === void 0 ? {} : { validator: e.validator } };\n };\n var G = (t, i, r = {}, e = {}, s = {}) => ({ required: t, fields: i, enums: e, nested: r, aliases: s });\n var h = { type: "string", span: "number", id: "string" };\n var De = G(["label", "value"], { label: "string", value: "number", color: "string" });\n var rn = G(["label", "data"], { label: "string", color: "string", data: "array" }, { data: De });\n var sn = G(["title"], { title: "string", desc: "string" });\n var on = G(["key", "value"], { key: "string", value: "string" }, {}, {}, { label: "key" });\n var an = G(["title"], { title: "string", desc: "string", time: "string" });\n var un = G(["path", "newText"], { path: "string", oldText: "string-or-null", newText: "string" });\n var ln = G(["name", "value"], { name: "string", value: "number", min: "number", max: "number", step: "number", animateTo: "number", durationMs: "number", loop: "boolean" });\n var dn = G(["expr"], { expr: "string", label: "string", color: "string", kind: "string", params: "array" }, { params: ln }, { kind: oe });\n var cn = G(["shape"], { shape: "string", color: "string", position: "array", rotation: "array", scale: "unknown", size: "unknown" }, {}, { shape: ue });\n function Oe(t) {\n return G(["name"], { name: "string", type: "string", children: "array" }, t > 0 ? { children: Oe(t - 1) } : {}, { type: le }, { label: "name" });\n }\n var fn = Oe(6);\n var pn = G(["label", "items"], { label: "string", items: "nodes", content: "nodes" });\n var mn = G(["title", "items"], { title: "string", items: "nodes" });\n var gn = G(["id", "label"], { id: "string", label: "string", sub: "string", type: "string", x: "number", y: "number", w: "number", h: "number", tag: "string" }, {}, { type: ce });\n var yn = G(["from", "to"], { from: "string", to: "string", label: "string", kind: "string", route: "string" }, {}, { kind: pe, route: me });\n var bn = G(["label"], { label: "string", x: "number", y: "number", w: "number", h: "number" });\n var hn = G([], { paper: "string", "paper-2": "string", ink: "string", muted: "string", soft: "string", rule: "string", accent: "string", "accent-tint": "string", link: "string" });\n var V = b(["items"], { title: "string", gap: "number", panel: "boolean", append: "boolean", items: "nodes" });\n var T = { accordion: b(["items"], { ...h, items: "array" }, {}, { nested: { items: mn } }), audio: b(["src"], { ...h, src: "string", alt: "string", loop: "boolean" }, { url: "src", link: "src" }), avatar: b(["name"], { ...h, name: "string", color: "string" }), badge: b(["label"], { ...h, label: "string", tone: "string", icon: "string" }, { text: "label", value: "label" }, { enums: { tone: ie } }), breadcrumb: b(["items"], { ...h, items: "array" }), button: b(["label"], { ...h, label: "string", tone: "string", full: "boolean", small: "boolean", icon: "string", action: "string" }, {}, { enums: { tone: te } }), callout: b(["content"], { ...h, title: "string", content: "string", tone: "string" }, { kind: "tone", text: "content", body: "content", desc: "content" }, { enums: { tone: se }, valueAliases: { tone: { danger: "error", warn: "warning" } } }), card: b(["items"], { ...h, title: "string", items: "nodes", tone: "string", accent: "string" }, { label: "title", content: "items" }, { enums: { tone: be } }), chart: b([], { ...h, kind: "string", data: "array", series: "array", horizontal: "boolean", stacked: "boolean", filter: "string", palette: "array" }, {}, { oneOfRequired: [["data", "series"]], conditionalRequired: [{ kind: "required-if", when: { field: "kind", equals: "donut" }, required: ["data"] }], nested: { data: De, series: rn }, enums: { kind: U }, validator: { name: "chart-renderability" } }), checkbox: b(["label"], { ...h, label: "string", checked: "boolean", action: "string", group: "string" }), code: b(["code"], { ...h, lang: "string", code: "string", title: "string", wrap: "boolean" }, { content: "code", text: "code" }), col: b(["items"], { ...h, items: "nodes", gap: "number" }), copy: b(["text"], { ...h, label: "string", text: "string" }, { content: "text", code: "text", value: "text" }), diagram: b(["kind", "nodes"], { ...h, kind: "string", variant: "string", title: "string", nodes: "array", edges: "array", zones: "array", theme: "object" }, {}, { nested: { nodes: gn, edges: yn, zones: bn, theme: hn }, enums: { kind: de, variant: fe } }), diff: b(["diffs"], { ...h, diffs: "array" }, { items: "diffs", files: "diffs" }, { nested: { diffs: un } }), divider: b([], h), echart: b([], { ...h, title: "string", height: "number", preset: "string", data: "array", series: "array", links: "array", palette: "array", option: "object" }, {}, { oneOfRequired: [["option", "data", "series", "links"]], enums: { preset: ge } }), "file-tree": b(["items"], { ...h, items: "array" }, { nodes: "items" }, { nested: { items: fn } }), grid: b(["items"], { ...h, cols: "number", items: "nodes" }), image: b(["src"], { ...h, src: "string", alt: "string" }, { url: "src", link: "src" }), input: b([], { ...h, label: "string", placeholder: "string", value: "string", inputType: "string", action: "string", id: "string" }, {}, { enums: { inputType: re } }), json: b(["value"], { ...h, value: "unknown" }), keyvalue: b(["pairs"], { ...h, pairs: "array" }, { items: "pairs", rows: "pairs", entries: "pairs" }, { nested: { pairs: on } }), link: b(["label"], { ...h, label: "string", href: "string" }), list: b(["items"], { ...h, items: "array", filter: "string" }), mermaid: b(["code"], { ...h, code: "string" }), svg: b(["code"], { ...h, code: "string", title: "string", height: "number" }), plot: b(["series"], { ...h, series: "array", xMin: "number", xMax: "number", yMin: "number", yMax: "number", title: "string" }, {}, { nested: { series: dn } }), progress: b(["value"], { ...h, value: "number", label: "string", valueLabel: "string", variant: "string", target: "number" }, {}, { enums: { variant: ye } }), quiz: b(["question", "options"], { ...h, question: "string", options: "array", explanation: "string", id: "string", action: "string" }, { title: "question", text: "question", choices: "options", items: "options" }), radio: b(["options"], { ...h, label: "string", options: "array", selected: "number", action: "string", group: "string", answer: "unknown", explanation: "string" }, { items: "options" }), row: b(["items"], { ...h, items: "nodes", wrap: "boolean", spacer: "boolean" }), scene3d: b(["meshes"], { ...h, title: "string", meshes: "array", ambient: "number", background: "string" }, {}, { nested: { meshes: cn } }), select: b(["options"], { ...h, label: "string", options: "array", action: "string", selected: "number", id: "string" }, { items: "options" }), slider: b([], { ...h, label: "string", min: "number", max: "number", step: "number", value: "number", action: "string", id: "string" }), spacer: b([], h), hero: b(["title"], { ...h, title: "string", subtitle: "string", value: "string", label: "string", delta: "string", spark: "array", tone: "string" }, {}, { enums: { tone: he } }), stat: b(["label", "value"], { ...h, label: "string", value: "string", delta: "string", spark: "array", size: "string" }, {}, { enums: { size: tn } }), steps: b(["steps"], { ...h, steps: "array", current: "number" }, { items: "steps" }, { nested: { steps: sn } }), submit: b(["label"], { ...h, label: "string", action: "string", resetAction: "string", groups: "array" }), switch: b(["label"], { ...h, label: "string", checked: "boolean", action: "string" }), table: b(["columns", "rows"], { ...h, columns: "array", rows: "array", types: "array", total: "boolean", details: "array", filter: "string", filterColumn: "number", sortField: "string", export: "boolean" }, { headers: "columns", data: "rows", items: "rows" }), tabs: b(["tabs"], { ...h, tabs: "array" }, {}, { nested: { tabs: pn } }), text: b(["content"], { ...h, content: "string", size: "string", center: "boolean", copyable: "boolean", title: "string" }, { text: "content" }, { enums: { size: ne } }), textarea: b([], { ...h, label: "string", placeholder: "string", rows: "number", value: "string", action: "string", id: "string" }), timeline: b(["items"], { ...h, items: "array" }, {}, { nested: { items: an } }), video: b(["src"], { ...h, src: "string", alt: "string", poster: "string", loop: "boolean", muted: "boolean", aspectRatio: "string" }, { url: "src", link: "src" }, { enums: { aspectRatio: ae } }) };\n var q = new Set(Object.keys(T));\n function N(t) {\n if (typeof t != "object" || t === null) return false;\n let i = t;\n return typeof i.type != "string" || i.type === "" ? false : Array.isArray(i.items) ? q.has(i.type) : true;\n }\n function z(t) {\n if (typeof t != "object" || t === null) return null;\n let i = t;\n if (typeof i.type != "string" || i.type === "") return null;\n let r = q.has(i.type) ? T[i.type] : void 0, e = typeof i.title == "string" && r !== void 0 && !("title" in r.fields) ? i.title : void 0, s = { ...t };\n return e !== void 0 && delete s.title, { items: [s], ...e !== void 0 ? { title: e } : {}, ...i.panel === true ? { panel: true } : {}, ...i.append === true ? { append: true } : {} };\n }\n var m = { maxDepth: 8, maxNodes: 200, maxString: 2e3, maxCode: 12e3, maxMermaid: 8e3, maxGridCols: 12, maxTabs: 12, maxAccordionItems: 24, maxListItems: 50, maxOptions: 50, maxTableRows: 50, maxTableCols: 12, maxChartPoints: 60, maxPlotSeries: 8, maxPlotParams: 6, maxMeshes: 5, maxQuizOptions: 8, maxSteps: 24, maxTimelineItems: 24, maxBreadcrumbItems: 12, maxKeyValuePairs: 24, maxTreeDepth: 6, maxDiagramNodes: 9, maxDiagramEdges: 12, maxDiagramZones: 3, maxDiagramFocal: 2, maxDiagramLabel: 14, maxEChartOptionDepth: 10, maxEChartArrayLen: 500, maxEChartOptionNodes: 2e3 };\n function ke(t) {\n let i = t.columns, r = Array.isArray(i) && i.length > 0, e = r && Array.isArray(i) && typeof i[0] == "object" && i[0] !== null ? i.map($n) : i, s = kn(e), n = t.rows !== void 0 ? t.rows : t.data;\n if (Array.isArray(n) && n.length > 0 && typeof n[0] == "object" && n[0] !== null && !Array.isArray(n[0])) {\n let u = Array.isArray(t.columns) && t.columns.length > 0 && typeof t.columns[0] == "object" && t.columns[0] !== null ? t.columns.map(Sn).filter((d) => d !== void 0) : Object.keys(n[0]);\n n = n.map((d) => u.map((c) => wn(d[c])));\n }\n let o = null;\n if (!r && Array.isArray(n) && n.length > 0 && Array.isArray(n[0])) {\n let u = xe(n), d = u.length === 0 ? null : An(u);\n d !== null && xe(d.rows).length === d.rows.length && (o = d, s = d.columns.map((c) => c.slice(0, 128)));\n }\n if (s.length === 0 && !Array.isArray(t.columns)) return null;\n let a = xe(o === null ? n : o.rows);\n return Array.isArray(n) ? { columns: s.slice(0, m.maxTableCols), rows: a } : null;\n }\n function I(t) {\n return ke(t)?.rows ?? [];\n }\n function xn(t, i) {\n return !Array.isArray(t) || !Array.isArray(i) || i[0] !== "group" ? false : String(t[0] ?? "").trim() !== "" && t.slice(1).every((r) => String(r ?? "").trim() === "");\n }\n function C(t, i) {\n let r = I(t);\n return i >= 0 && i < r.length && !xn(r[i], t.types);\n }\n function kn(t) {\n if (!Array.isArray(t)) return [];\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxTableCols) break;\n if (typeof r == "string") i.push(r.slice(0, 128));\n else if (r !== null && typeof r == "object") {\n let e = r, s = typeof e.label == "string" ? e.label : typeof e.value == "string" ? e.value : typeof e.title == "string" ? e.title : JSON.stringify(r);\n i.push(s.slice(0, 128));\n }\n }\n return i;\n }\n function xe(t) {\n if (!Array.isArray(t)) return [];\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxTableRows) break;\n if (!Array.isArray(r)) continue;\n let e = [];\n for (let s of r) {\n if (e.length >= m.maxTableCols) break;\n typeof s == "string" ? e.push(s.slice(0, 256)) : typeof s == "number" && Number.isFinite(s) && e.push(s);\n }\n e.length > 0 && i.push(e);\n }\n return i;\n }\n function An(t) {\n let i = t[0];\n if (i === void 0 || i.length === 0) return null;\n let r = t.slice(1);\n if (r.length === 0) {\n let e = i.map((s) => String(s).trim());\n return e.every((s) => s !== "") ? { columns: e, rows: [] } : null;\n }\n return r.every((e) => e.length === i.length) ? { columns: i.map((e) => String(e).trim()), rows: r } : { columns: Array.from({ length: i.length }, (e, s) => `\\u5217${s + 1}`), rows: t };\n }\n function Sn(t) {\n if (t === null || typeof t != "object" || Array.isArray(t)) return;\n let i = t;\n for (let r of ["key", "dataIndex", "title", "label"]) if (typeof i[r] == "string" && i[r] !== "") return i[r];\n }\n function wn(t) {\n return typeof t == "string" || typeof t == "number" && Number.isFinite(t) ? t : t == null ? "" : JSON.stringify(t);\n }\n function $n(t) {\n if (t === null || typeof t != "object" || Array.isArray(t)) return String(t);\n let i = t;\n for (let r of ["title", "label", "key", "dataIndex"]) if (typeof i[r] == "string" && i[r] !== "") return i[r];\n return JSON.stringify(t);\n }\n function O(t) {\n return typeof t == "object" && t !== null && !Array.isArray(t) ? t : void 0;\n }\n function Ae(t) {\n let i = O(t);\n return i !== void 0 && typeof i.type == "string";\n }\n var Gn = ["label", "value", "delta", "spark", "size"];\n var Rn = { label: "title", name: "title", description: "desc", content: "desc", text: "desc", body: "desc", detail: "desc" };\n function Tn(t, i, r) {\n if (t.length === 0) return null;\n let e = [];\n for (let s = 0; s < t.length; s++) {\n let n = t[s], o = O(n);\n if (o === void 0) return null;\n if (Ae(n)) {\n e.push(r(n, `${i}.items[${s}]`));\n continue;\n }\n if (typeof o.label != "string" && typeof o.value != "string") return null;\n let a = { type: "stat" };\n for (let u of Gn) o[u] !== void 0 && (a[u] = o[u]);\n e.push(a);\n }\n return e;\n }\n function Cn(t, i, r, e) {\n let s = T[r];\n if (s === void 0) return t;\n let n = { ...t };\n for (let [o, a] of Object.entries(s.aliases)) {\n if (!(o in n)) continue;\n let u = `${i}.${o}`, d = a in n;\n d || (n[a] = n[o]), delete n[o], e.push({ kind: "alias", path: u, message: d ? `${u} is ignored because canonical field \'${a}\' is present` : `${u} normalized/adopted as \'${a}\'`, type: r, field: o, canonical: a });\n }\n for (let [o, a] of Object.entries(s.valueAliases)) {\n let u = n[o];\n if (typeof u != "string") continue;\n let d = a[u];\n d === void 0 || d === u || (n[o] = d, e.push({ kind: "alias", path: `${i}.${o}`, message: `${i}.${o} \'${u}\' normalized to \'${d}\'`, type: r, field: o, canonical: d }));\n }\n return n;\n }\n function Se(t, i, r, e, s) {\n if (Array.isArray(t)) return t.map((a, u) => Se(a, i, `${r}[${u}]`, e, s));\n let n = O(t);\n if (n === void 0) return t;\n let o = { ...n };\n for (let [a, u] of Object.entries(i.aliases)) !(a in o) || u in o || (o[u] = o[a], delete o[a], s.push({ kind: "alias", path: `${r}.${a}`, message: `${r}.${a} normalized/adopted as \'${u}\'`, type: e, field: a, canonical: u }));\n for (let [a, u] of Object.entries(i.nested)) o[a] !== void 0 && (o[a] = Se(o[a], u, `${r}.${a}`, e, s));\n return o;\n }\n function we(t) {\n if (Array.isArray(t)) return t.map(we);\n let i = O(t);\n if (i === void 0) return t;\n let r = { ...i };\n return r.type === void 0 && Array.isArray(r.children) && (r.type = "dir"), r.children !== void 0 && (r.children = we(r.children)), r;\n }\n function $e(t, i, r) {\n if (!Ae(t)) return t;\n let e = t.type, s = T[e];\n if (s === void 0) return t;\n let n = Cn(t, i, e, r);\n for (let [u, d] of Object.entries(s.nested)) n[u] !== void 0 && (n[u] = Se(n[u], d, `${i}.${u}`, e, r));\n let o = (u, d) => $e(u, d, r), a = (u, d) => Array.isArray(u) ? u.map((c, f) => o(c, `${d}[${f}]`)) : u;\n if (e === "file-tree" && n.items !== void 0 && (n.items = we(n.items)), e === "stat" && Array.isArray(n.items) && n.label === void 0 && n.value === void 0) {\n let u = Tn(n.items, i, o);\n if (u !== null) return r.push({ kind: "alias", path: `${i}.items`, message: `${i}.items normalized into a row of \'stat\' nodes`, type: e, field: "items", canonical: "row" }), { type: "row", items: u, ...n.span !== void 0 ? { span: n.span } : {} };\n }\n if (e === "row" || e === "col" || e === "grid" || e === "card" || e === "file-tree" || e === "timeline" || e === "breadcrumb") e !== "file-tree" && e !== "timeline" && e !== "breadcrumb" && (n.items = a(n.items, `${i}.items`));\n else if (e === "list" && Array.isArray(n.items)) n.items = n.items.map((u, d) => {\n if (Ae(u)) return o(u, `${i}.items[${d}]`);\n if (Array.isArray(u) && u.length === 1 && typeof u[0] == "string") return u[0];\n let c = O(u);\n if (c === void 0) return u;\n let f = { ...c }, g = `${i}.items[${d}]`;\n for (let [x, $] of Object.entries(Rn)) {\n if (!(x in f)) continue;\n let J = $ in f;\n J || (f[$] = f[x]), delete f[x], r.push({ kind: "alias", path: `${g}.${x}`, type: e, field: x, canonical: $, message: J ? `${g}.${x} is ignored because canonical field \'${$}\' is present` : `${g}.${x} normalized/adopted as \'${$}\'` });\n }\n return !("title" in f) && typeof f.desc == "string" && (f.title = f.desc, delete f.desc, r.push({ kind: "alias", path: `${g}.desc`, type: e, field: "desc", canonical: "title", message: `${g}.desc normalized/adopted as \'title\'` })), f;\n });\n else if (e === "keyvalue" && Array.isArray(n.pairs)) n.pairs.length > 0 && n.pairs.every((u) => Array.isArray(u)) && (n.pairs = n.pairs.map((u) => {\n let d = u;\n return { key: d[0], value: d.length > 1 ? d[1] : "" };\n }));\n else if (e === "tabs" && Array.isArray(n.tabs)) n.tabs = n.tabs.map((u, d) => {\n let c = O(u);\n if (c === void 0) return u;\n let f = { ...c };\n if ("content" in f) {\n let g = `${i}.tabs[${d}].content`, x = "items" in f;\n x || (f.items = f.content), delete f.content, r.push({ kind: "alias", path: g, message: x ? `${g} is ignored because canonical field \'items\' is present` : `${g} normalized/adopted as \'items\'`, type: e, field: "content", canonical: "items" });\n }\n return f.items = Array.isArray(f.items) ? f.items.map((g, x) => o(g, `${i}.tabs[${d}].items[${x}]`)) : f.items === void 0 ? [] : [o(f.items, `${i}.tabs[${d}].items[0]`)], f;\n });\n else if (e === "accordion" && Array.isArray(n.items)) n.items = n.items.map((u, d) => {\n let c = O(u);\n return c === void 0 ? u : { ...c, items: Array.isArray(c.items) ? c.items.map((f, g) => o(f, `${i}.items[${d}].items[${g}]`)) : c.items };\n });\n else if (e === "table" && Array.isArray(n.details)) {\n let u = { columns: n.columns, rows: n.rows, types: n.types };\n n.details = n.details.map((d, c) => !Array.isArray(d) || !C(u, c) ? d : d.map((f, g) => o(f, `${i}.details[${c}][${g}]`)));\n }\n return n;\n }\n function Ie(t) {\n let i = [];\n if (typeof t == "string") try {\n let s = JSON.parse(t);\n (O(s) !== void 0 || Array.isArray(s)) && (t = s, i.push({ kind: "alias", path: "spec", message: "double-encoded JSON string unwrapped into a spec value" }));\n } catch {\n }\n Array.isArray(t) && t.length > 0 && (t = { items: t }, i.push({ kind: "alias", path: "items", message: "root array normalized into an items envelope" }));\n let r = O(t);\n if (r === void 0) return { value: t, warnings: i };\n let e = { ...r };\n return N(e) ? { value: $e(e, "spec", i), warnings: i } : (Array.isArray(e.items) && (e.items = e.items.map((s, n) => $e(s, `items[${n}]`, i))), { value: e, warnings: i });\n }\n function F(t) {\n return typeof t == "object" && t !== null && !Array.isArray(t) ? t : void 0;\n }\n function _e(t) {\n let i = F(t);\n return i !== void 0 && typeof i.type == "string";\n }\n function Ge(t, i, r) {\n if (!_e(t)) return;\n let e = t.type, s = T[e];\n if (s === void 0) return;\n r(t, i, s);\n let n = (o, a) => Ge(o, a, r);\n if ((e === "row" || e === "col" || e === "grid" || e === "card") && Array.isArray(t.items)) t.items.forEach((o, a) => n(o, `${i}.items[${a}]`));\n else if (e === "list" && Array.isArray(t.items)) t.items.forEach((o, a) => n(o, `${i}.items[${a}]`));\n else if (e === "tabs" && Array.isArray(t.tabs)) t.tabs.forEach((o, a) => {\n let u = F(o);\n u !== void 0 && (Array.isArray(u.items) ? u.items.forEach((d, c) => n(d, `${i}.tabs[${a}].items[${c}]`)) : n(u.items, `${i}.tabs[${a}].items`));\n });\n else if (e === "accordion" && Array.isArray(t.items)) t.items.forEach((o, a) => {\n let u = F(o);\n u?.items !== void 0 && Array.isArray(u.items) && u.items.forEach((d, c) => n(d, `${i}.items[${a}].items[${c}]`));\n });\n else if (e === "table" && Array.isArray(t.details)) {\n let o = { columns: t.columns, rows: t.rows, types: t.types };\n t.details.forEach((a, u) => {\n Array.isArray(a) && C(o, u) && a.forEach((d, c) => n(d, `${i}.details[${u}][${c}]`));\n });\n }\n }\n function B(t, i, r, e) {\n t.push({ kind: "unknown-field", path: `${i}.${r}`, message: `${i}.${r}: unknown field for \'${e}\'`, type: e, field: r });\n }\n function Y(t, i, r, e, s) {\n let n = F(t);\n if (n !== void 0) {\n for (let o of Object.keys(n)) o in r.fields || B(s, i, o, e);\n for (let [o, a] of Object.entries(r.nested)) {\n let u = n[o];\n Array.isArray(u) ? u.forEach((d, c) => Y(d, `${i}.${o}[${c}]`, a, e, s)) : u !== void 0 && Y(u, `${i}.${o}`, a, e, s);\n }\n }\n }\n function Nn(t, i, r, e) {\n for (let [s, n] of Object.entries(r.nested)) {\n let o = t[s];\n Array.isArray(o) ? o.forEach((a, u) => Y(a, `${i}.${s}[${u}]`, n, t.type, e)) : o !== void 0 && Y(o, `${i}.${s}`, n, t.type, e);\n }\n }\n function Pe(t) {\n let i = [], r = F(t);\n if (r === void 0) return i;\n let e = (s, n, o) => {\n for (let a of Object.keys(s)) a === "type" || a in o.fields || B(i, n, a, s.type);\n Nn(s, n, o, i), s.type === "list" && Array.isArray(s.items) && s.items.forEach((a, u) => {\n if (_e(a)) return;\n let d = F(a);\n if (d !== void 0) for (let c of Object.keys(d)) {\n if (c === "title" || c === "desc") continue;\n let f = `${n}.items[${u}]`;\n i.push({ kind: "unknown-field", path: `${f}.${c}`, message: `${f}.${c}: list items render \'title\' and \'desc\' only \\u2014 \'${c}\' is dropped`, type: "list", field: c });\n }\n });\n };\n if (Array.isArray(r.items) && !N(r)) {\n for (let s of Object.keys(r)) s in V.fields || B(i, "spec", s, "spec");\n r.items.forEach((s, n) => Ge(s, `items[${n}]`, e));\n } else if (typeof r.type == "string") Ge(r, "spec", e);\n else for (let s of Object.keys(r)) s in V.fields || B(i, "spec", s, "spec");\n return i;\n }\n function ve(t, i) {\n let r = (s, n, o) => {\n o > m.maxDepth || s.forEach((a, u) => e(a, `${n}[${u}]`, o));\n }, e = (s, n, o) => {\n if (!(o > m.maxDepth) && (i(s, n), !(o >= m.maxDepth))) switch (s.type) {\n case "row":\n case "col":\n case "grid":\n case "card":\n r(s.items, `${n}.items`, o + 1);\n break;\n case "tabs":\n s.tabs.forEach((a, u) => r(a.items, `${n}.tabs[${u}].items`, o + 1));\n break;\n case "accordion":\n s.items.forEach((a, u) => r(a.items, `${n}.items[${u}].items`, o + 1));\n break;\n case "list":\n s.items.forEach((a, u) => {\n a !== null && typeof a == "object" && "type" in a && e(a, `${n}.items[${u}]`, o + 1);\n });\n break;\n case "table":\n s.details?.slice(0, I(s).length).forEach((a, u) => {\n a !== null && C(s, u) && r(a, `${n}.details[${u}]`, o + 1);\n });\n break;\n }\n };\n r(t.items, "items", 0);\n }\n function Re(t) {\n let i = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map(), e = [], s = [];\n ve(t, (n, o) => {\n if (n.type === "submit") {\n n.groups !== void 0 && s.push({ groups: n.groups, path: o });\n return;\n }\n let a, u;\n switch (n.type) {\n case "radio":\n if (n.group === void 0) return;\n a = { kind: "radio", key: n.group, label: n.label ?? n.group, options: n.options.slice(0, m.maxOptions), ...n.answer === void 0 ? {} : { answer: n.answer }, ...n.explanation === void 0 ? {} : { explanation: n.explanation } }, u = `${o}.group`;\n break;\n case "checkbox":\n if (n.group === void 0) return;\n a = { kind: "checkbox", key: n.group }, u = `${o}.group`;\n break;\n case "input":\n case "textarea":\n case "select":\n case "slider":\n if (n.id === void 0) return;\n a = { kind: "field", key: n.id, fieldType: n.type, secret: n.type === "input" && n.inputType === "password" }, u = `${o}.id`;\n break;\n default:\n return;\n }\n if (a === void 0) return;\n let d = i.get(a.key);\n if (d !== void 0) {\n (d.kind !== "checkbox" || a.kind !== "checkbox") && e.push(`${u} conflicts with ${r.get(a.key)}: submission key \'${a.key}\' is already used`);\n return;\n }\n i.set(a.key, a), r.set(a.key, u);\n });\n for (let { groups: n, path: o } of s) {\n let a = /* @__PURE__ */ new Set();\n n.forEach((u, d) => {\n let c = `${o}.groups[${d}]`;\n a.has(u) && e.push(`${c}: duplicate submission member \'${u}\'`), a.add(u);\n let f = i.get(u);\n f === void 0 ? e.push(`${c}: submit.groups references unknown submission member \'${u}\'`) : f.kind === "field" && f.secret && e.push(`${c}: submit.groups cannot require secret field \'${u}\'`);\n });\n }\n return { registry: { members: i }, diagnostics: e };\n }\n function En(t, i) {\n return typeof t == "string" && i.includes(t);\n }\n function p(t, i) {\n return typeof t == "string" ? t.slice(0, i) : void 0;\n }\n var Dn = /^(?:#[\\da-fA-F]{3,8}|rgba?\\([^)]{0,64}\\)|hsla?\\([^)]{0,64}\\)|var\\(--dsw-[\\w-]+(?:,\\s*#[0-9a-fA-F]{3,8})?\\))$/;\n function E(t) {\n if (typeof t != "string") return;\n let i = t.trim();\n return i.length <= 64 && Dn.test(i) ? i : void 0;\n }\n function qe(t) {\n if (typeof t != "string") return;\n let i = t.trim();\n if (!(i.length > 2048)) return /^https?:\\/\\//i.test(i) || /^mailto:[^@\\s]+@[^@\\s]+$/i.test(i) ? i : void 0;\n }\n function K(t) {\n if (typeof t != "string") return;\n let i = t.trim();\n if (!(i === "" || i.length > 2048)) {\n if (/^https?:\\/\\//i.test(i)) return i;\n if (!(/^[a-z][a-z0-9+.-]*:/i.test(i) || /^[/\\\\]{2}/.test(i))) return i;\n }\n }\n function k(t, i, r) {\n return typeof t == "number" && Number.isFinite(t) ? Math.min(r, Math.max(i, t)) : void 0;\n }\n function D(t, i, r) {\n return typeof t == "number" && Number.isFinite(t) ? Math.min(r, Math.max(i, Math.trunc(t))) : void 0;\n }\n function w(t, i) {\n return En(t, i) ? t : void 0;\n }\n function y(t) {\n return typeof t == "object" && t !== null && !Array.isArray(t) ? t : void 0;\n }\n function l(t, i) {\n return i === void 0 ? {} : { [t]: i };\n }\n function On(t) {\n if (t.length > 2048) return;\n let i = t.indexOf("#"), r = i < 0 ? t : t.slice(0, i);\n if (r.includes("?")) return;\n let e;\n try {\n e = decodeURIComponent(r);\n } catch {\n return;\n }\n if (e === "" || /[\\u0000-\\u001f\\u007f]/.test(e) || /^[\\\\/]{2}/.test(e) || /^[a-z][a-z\\d+.-]*:/i.test(e) && !/^[a-z]:[\\\\/]/i.test(e)) return;\n if (i < 0) return { path: e };\n let s = /^L([1-9]\\d*)(?:-L([1-9]\\d*))?$/.exec(t.slice(i + 1));\n if (s === null) return;\n let n = Number(s[1]), o = s[2] === void 0 ? n : Number(s[2]);\n if (!(!Number.isSafeInteger(n) || !Number.isSafeInteger(o) || o < n)) return { path: e, line: n };\n }\n function ze(t) {\n let i = qe(t);\n if (i !== void 0) return { type: "external", href: i };\n if (typeof t != "string") return { type: "invalid" };\n let r = On(t.trim());\n return r === void 0 ? { type: "invalid" } : { type: "file", file: r };\n }\n function H(t, i) {\n switch (i) {\n case "string":\n return typeof t == "string";\n case "string-or-null":\n return t === null || typeof t == "string";\n case "number":\n return typeof t == "number" && Number.isFinite(t);\n case "boolean":\n return typeof t == "boolean";\n case "nodes":\n return Array.isArray(t);\n case "array":\n return Array.isArray(t);\n case "object":\n return y(t) !== void 0;\n case "unknown":\n return true;\n }\n }\n function j(t) {\n switch (t) {\n case "string-or-null":\n return "a string or null";\n case "number":\n return "a finite number";\n case "boolean":\n return "a boolean";\n case "nodes":\n case "array":\n return "an array";\n case "object":\n return "an object";\n case "unknown":\n return "a value";\n default:\n return "a string";\n }\n }\n function v(t, i, r) {\n return t.some((e) => e.startsWith(`${i}.${r} `) || e.includes(`\'${r}\'`) || e.includes(`requires ${r}`));\n }\n function Ke(t, i, r, e, s = []) {\n for (let [n, o] of Object.entries(r.fields)) s.includes(n) || t[n] === void 0 || !H(t[n], o) && !v(e, i, n) && e.push(`${i}.${n} must be ${j(o)}`);\n for (let [n, o] of Object.entries(r.enums)) s.includes(n) || t[n] === void 0 || !H(t[n], "string") || !o.includes(t[n]) && !v(e, i, n) && e.push(`${i}.${n} must be one of ${o.join(", ")}`);\n }\n function W(t, i, r, e) {\n let s = y(t);\n if (s === void 0) {\n e.push(`${i} must be an object`);\n return;\n }\n for (let n of r.required) {\n let o = r.fields[n];\n s[n] === void 0 ? v(e, i, n) || e.push(`${i}: requires ${n}${o === void 0 ? "" : ` (${j(o)})`}`) : o !== void 0 && !H(s[n], o) && (v(e, i, n) || e.push(`${i}.${n} must be ${j(o)}`));\n }\n for (let [n, o] of Object.entries(r.fields)) s[n] !== void 0 && !H(s[n], o) && (v(e, i, n) || e.push(`${i}.${n} must be ${j(o)}`));\n for (let [n, o] of Object.entries(r.enums)) s[n] !== void 0 && typeof s[n] == "string" && !o.includes(s[n]) && (v(e, i, n) || e.push(`${i}.${n} must be one of ${o.join(", ")}`));\n for (let [n, o] of Object.entries(r.nested)) {\n let a = s[n];\n a !== void 0 && (Array.isArray(a) ? a.forEach((u, d) => W(u, `${i}.${n}[${d}]`, o, e)) : W(a, `${i}.${n}`, o, e));\n }\n }\n function Mn(t, i, r, e) {\n for (let [s, n] of Object.entries(r.nested)) {\n let o = t[s];\n o !== void 0 && (Array.isArray(o) ? o.forEach((a, u) => W(a, `${i}.${s}[${u}]`, n, e)) : W(o, `${i}.${s}`, n, e));\n }\n }\n function He(t) {\n let i = t.rows !== void 0 ? t.rows : t.data;\n return !Array.isArray(i) || i.length === 0 ? false : Array.isArray(i[0]);\n }\n function In(t, i, r, e) {\n let s = String(t.type), n = (a) => v(e, i, a), o = s === "table" && He(t) ? "columns" : null;\n for (let a of r.required) {\n let u = r.fields[a];\n if (u === void 0 || t[a] === void 0) {\n a !== o && !n(a) && e.push(`${i}: type \'${s}\' requires ${a}${u === void 0 ? "" : ` (${j(u)})`}`);\n continue;\n }\n !H(t[a], u) && !n(a) && e.push(`${i}.${a} must be ${j(u)}`);\n }\n Ke(t, i, r, e, ["type"]);\n for (let a of r.oneOfRequired) !a.some((u) => t[u] !== void 0) && !e.some((u) => u.includes(`requires ${a.join(" or ")}`)) && e.push(`${i}: type \'${s}\' requires one of ${a.join(" or ")}`);\n for (let a of r.conditionalRequired) if (t[a.when.field] === a.when.equals) for (let u of a.required) t[u] === void 0 && !n(u) && e.push(`${i}: type \'${s}\' requires ${u}${a.message === void 0 ? "" : ` (${a.message})`}`);\n Mn(t, i, r, e);\n }\n function _(t, i, r) {\n if (!Array.isArray(t)) return [];\n let e = [];\n for (let s of t) {\n if (i.remaining <= 0) break;\n i.remaining -= 1;\n let n = Je(s, i, r);\n n !== null && e.push(n);\n }\n return e;\n }\n function Fe(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t.slice(0, 12)) {\n let e = E(r);\n e !== void 0 && i.push(e);\n }\n return i.length > 0 ? i : void 0;\n }\n function je(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t.slice(0, 60)) {\n let e = typeof r == "number" ? r : Number(r);\n if (!Number.isFinite(e)) return;\n i.push(e);\n }\n return i.length >= 2 ? i : void 0;\n }\n function Je(t, i, r) {\n let e = _n(t, i, r);\n if (e === null) return null;\n let s = D(y(t)?.span, 2, 12), n = p(y(t)?.id, 64);\n return { ...e, ...l("span", s), ...l("id", n) };\n }\n function _n(t, i, r) {\n if (r > m.maxDepth) return null;\n let e = y(t);\n if (e === void 0) return null;\n let s = e.type;\n if (typeof s != "string") return null;\n switch (s) {\n case "text": {\n let n = p(e.content, m.maxString) ?? p(e.text, m.maxString);\n return n === void 0 ? null : { type: "text", content: n, ...l("copyable", e.copyable === true ? true : void 0), ...l("title", p(e.title, m.maxString)), ...l("size", w(e.size, ne)), ...l("center", e.center === true ? true : void 0) };\n }\n case "row":\n return { type: "row", items: _(e.items, i, r + 1), ...l("wrap", e.wrap === true ? true : void 0), ...l("spacer", e.spacer === true ? true : void 0) };\n case "col":\n return { type: "col", items: _(e.items, i, r + 1), ...l("gap", k(e.gap, 0, 96)) };\n case "grid":\n return { type: "grid", cols: D(e.cols, 1, m.maxGridCols) ?? 1, items: _(e.items, i, r + 1) };\n case "card":\n return { type: "card", items: _(e.items, i, r + 1), ...l("title", p(e.title, m.maxString)), ...l("tone", w(e.tone, be)), ...l("accent", E(e.accent)) };\n case "button": {\n let n = p(e.label, m.maxString);\n return n === void 0 ? null : { type: "button", label: n, ...l("tone", w(e.tone, te)), ...l("full", e.full === true ? true : void 0), ...l("small", e.small === true ? true : void 0), ...l("icon", p(e.icon, 64)), ...l("action", p(e.action, 200)) };\n }\n case "input":\n return { type: "input", ...l("label", p(e.label, m.maxString)), ...l("placeholder", p(e.placeholder, m.maxString)), ...l("value", p(e.value, m.maxString)), ...l("inputType", w(e.inputType, re)), ...l("action", p(e.action, 200)), ...l("id", p(e.id, 200)) };\n case "select": {\n let n = Q(e.options, m.maxOptions, m.maxString);\n return n === void 0 ? null : { type: "select", options: n, ...l("label", p(e.label, m.maxString)), ...l("action", p(e.action, 200)), ...l("selected", D(e.selected, 0, n.length - 1)), ...l("id", p(e.id, 200)) };\n }\n case "checkbox": {\n let n = p(e.label, m.maxString);\n return n === void 0 ? null : { type: "checkbox", label: n, ...l("checked", e.checked === true ? true : void 0), ...l("action", p(e.action, 200)), ...l("group", p(e.group, 200)) };\n }\n case "link": {\n let n = p(e.label, m.maxString);\n if (n === void 0) return null;\n let o = ze(e.href), a = o.type === "external" ? o.href : o.type === "file" ? String(e.href).trim() : void 0;\n return { type: "link", label: n, ...l("href", a) };\n }\n case "image": {\n let n = K(e.src);\n return n === void 0 ? null : { type: "image", src: n, ...l("alt", p(e.alt, m.maxString)) };\n }\n case "audio": {\n let n = K(e.src);\n return n === void 0 ? null : { type: "audio", src: n, ...l("alt", p(e.alt, m.maxString)), ...l("loop", e.loop === true ? true : void 0) };\n }\n case "video": {\n let n = K(e.src);\n return n === void 0 ? null : { type: "video", src: n, ...l("alt", p(e.alt, m.maxString)), ...l("poster", K(e.poster)), ...l("loop", e.loop === true ? true : void 0), ...l("muted", e.muted === true ? true : void 0), ...l("aspectRatio", w(e.aspectRatio, ae)) };\n }\n case "badge": {\n let n = p(e.label, m.maxString) ?? p(e.text, m.maxString) ?? p(e.value, m.maxString);\n return n === void 0 ? null : { type: "badge", label: n, ...l("tone", w(e.tone, ie)), ...l("icon", p(e.icon, 64)) };\n }\n case "hero": {\n let n = p(e.title, m.maxString);\n return n === void 0 ? null : { type: "hero", title: n, ...l("subtitle", p(e.subtitle, m.maxString)), ...l("value", p(e.value, 128)), ...l("label", p(e.label, m.maxString)), ...l("delta", p(e.delta, 64)), ...l("spark", je(e.spark)), ...l("tone", w(e.tone, he)) };\n }\n case "stat": {\n let n = p(e.label, m.maxString), o = p(e.value, 128);\n return n === void 0 || o === void 0 ? null : { type: "stat", label: n, value: o, ...l("delta", p(e.delta, 64)), ...l("spark", je(e.spark)), ...l("size", e.size === "hero" ? "hero" : void 0) };\n }\n case "progress": {\n let n = k(e.value, 0, 100);\n return n === void 0 ? null : { type: "progress", value: n, ...l("label", p(e.label, m.maxString)), ...l("valueLabel", p(e.valueLabel, 64)), ...l("variant", w(e.variant, ye)), ...l("target", k(e.target, 0, 100)) };\n }\n case "divider":\n return { type: "divider" };\n case "spacer":\n return { type: "spacer" };\n case "avatar": {\n let n = p(e.name, 64);\n return n === void 0 ? null : { type: "avatar", name: n, ...l("color", E(e.color)) };\n }\n case "list": {\n let n = Pn(e.items, m.maxListItems, i, r + 1);\n return n === void 0 ? null : { type: "list", items: n, ...l("filter", p(e.filter, 64)) };\n }\n case "table": {\n let n = ke(e);\n if (n === null) return null;\n let { columns: o, rows: a } = n, u = Array.isArray(e.types) ? e.types : void 0, d = u === void 0 ? void 0 : o.map((g, x) => {\n let $ = u[x];\n return typeof $ == "string" && Ee.includes($) ? $ : "text";\n }), c = Array.isArray(e.details) ? e.details : void 0, f = c === void 0 ? void 0 : a.map((g, x) => {\n if (!C({ columns: o, rows: a, types: d }, x)) return null;\n let $ = _(c[x], i, r + 1);\n return $.length === 0 ? null : $;\n });\n return { type: "table", columns: o, rows: a, ...l("types", d), ...l("total", e.total === true ? true : void 0), ...l("export", e.export === true ? true : void 0), ...l("filter", p(e.filter, 64)), ...l("filterColumn", D(e.filterColumn, 0, m.maxTableCols - 1)), ...l("sortField", p(e.sortField, 64)), ...l("details", f !== void 0 && f.some((g) => g !== null) ? f : void 0) };\n }\n case "chart": {\n let n = Te(e.data, m.maxChartPoints), o = Array.isArray(e.series) ? Le(e.series, m.maxPlotSeries, m.maxChartPoints) : void 0;\n return n === void 0 && o === void 0 ? null : { type: "chart", data: n ?? [], ...l("kind", w(e.kind, U)), ...l("series", o), ...l("horizontal", e.horizontal === true ? true : void 0), ...l("stacked", e.stacked === true ? true : void 0), ...l("filter", p(e.filter, 64)), ...l("palette", Fe(e.palette)) };\n }\n case "tabs": {\n let n = vn(e.tabs, i, r);\n return n === void 0 ? null : { type: "tabs", tabs: n };\n }\n case "plot": {\n let n = qn(e.series, m.maxPlotSeries);\n return n === void 0 ? null : { type: "plot", series: n, ...l("xMin", k(e.xMin, -1e6, 1e6)), ...l("xMax", k(e.xMax, -1e6, 1e6)), ...l("yMin", k(e.yMin, -1e9, 1e9)), ...l("yMax", k(e.yMax, -1e9, 1e9)), ...l("title", p(e.title, m.maxString)) };\n }\n case "callout": {\n let n = p(e.content, m.maxString);\n return n === void 0 ? null : { type: "callout", content: n, ...l("tone", w(e.tone, se)), ...l("title", p(e.title, m.maxString)) };\n }\n case "steps": {\n let n = zn(e.steps);\n return n === void 0 ? null : { type: "steps", steps: n, ...l("current", D(e.current, 0, n.length)) };\n }\n case "keyvalue": {\n let n = Fn(e.pairs, m.maxKeyValuePairs);\n return n === void 0 ? null : { type: "keyvalue", pairs: n };\n }\n case "diff": {\n let n = jn(e.diffs);\n return n === void 0 ? null : { type: "diff", diffs: n };\n }\n case "json":\n return "value" in e ? { type: "json", value: e.value } : null;\n case "code": {\n let n = p(e.code, m.maxCode);\n return n === void 0 ? null : { type: "code", code: n, ...l("lang", p(e.lang, 64)), ...l("title", p(e.title, m.maxString)), ...l("wrap", e.wrap === true ? true : void 0) };\n }\n case "radio": {\n let n = Q(e.options, m.maxOptions, m.maxString);\n return n === void 0 ? null : { type: "radio", options: n, ...l("label", p(e.label, m.maxString)), ...l("selected", D(e.selected, 0, n.length - 1)), ...l("action", p(e.action, 200)), ...l("group", p(e.group, 200)), ...l("answer", typeof e.answer == "number" && Number.isFinite(e.answer) && e.answer >= 0 && e.answer < n.length ? Math.trunc(e.answer) : typeof e.answer == "string" ? e.answer.slice(0, 512) : void 0), ...l("explanation", p(e.explanation, m.maxString)) };\n }\n case "submit": {\n let n = p(e.label, m.maxString), o = p(e.action, 200);\n return n === void 0 ? null : { type: "submit", label: n, ...l("action", o), ...l("resetAction", p(e.resetAction, 200)), ...l("groups", Q(e.groups, m.maxOptions, 200)) };\n }\n case "switch": {\n let n = p(e.label, m.maxString);\n return n === void 0 ? null : { type: "switch", label: n, ...l("checked", e.checked === true ? true : void 0), ...l("action", p(e.action, 200)) };\n }\n case "slider": {\n let n = k(e.min, -1e9, 1e9) ?? 0, o = k(e.max, -1e9, 1e9) ?? 100, a = Math.min(n, o), u = Math.max(n, o), d = k(e.step, 1e-9, Math.max(u - a, 1e-9)), c = k(e.value, a, u) ?? a;\n return { type: "slider", min: a, max: u, ...l("step", d), value: c, ...l("label", p(e.label, m.maxString)), ...l("action", p(e.action, 200)), ...l("id", p(e.id, 200)) };\n }\n case "textarea":\n return { type: "textarea", ...l("label", p(e.label, m.maxString)), ...l("placeholder", p(e.placeholder, m.maxString)), ...l("rows", D(e.rows, 1, 30)), ...l("value", p(e.value, m.maxString)), ...l("action", p(e.action, 200)), ...l("id", p(e.id, 200)) };\n case "accordion": {\n let n = Ln(e.items, i, r);\n return n === void 0 ? null : { type: "accordion", items: n };\n }\n case "copy": {\n let n = p(e.text, m.maxCode);\n return n === void 0 ? null : { type: "copy", text: n, ...l("label", p(e.label, 128)) };\n }\n case "svg": {\n let n = p(e.code, m.maxCode);\n return n === void 0 ? null : { type: "svg", code: n, ...l("title", p(e.title, m.maxString)), ...l("height", D(e.height, 100, 800)) };\n }\n case "mermaid": {\n let n = p(e.code, m.maxMermaid);\n return n === void 0 ? null : { type: "mermaid", code: n };\n }\n case "scene3d": {\n let n = Vn(e.meshes);\n return n === void 0 ? null : { type: "scene3d", meshes: n, ...l("title", p(e.title, m.maxString)), ...l("ambient", k(e.ambient, 0, 2)), ...l("background", E(e.background)) };\n }\n case "diagram":\n return Bn(e);\n case "timeline": {\n let n = Yn(e.items, m.maxTimelineItems);\n return n === void 0 ? null : { type: "timeline", items: n };\n }\n case "file-tree": {\n let n = Qn(e.items, m.maxListItems);\n return n === void 0 ? null : { type: "file-tree", items: n };\n }\n case "breadcrumb": {\n let n = Q(e.items, m.maxBreadcrumbItems, m.maxString);\n return n === void 0 ? null : { type: "breadcrumb", items: n };\n }\n case "quiz": {\n let n = p(e.question, m.maxString), o = Zn(e.options, e.answer);\n return n === void 0 || o === void 0 ? null : { type: "quiz", question: n, options: o, ...l("explanation", p(e.explanation, m.maxString)), ...l("id", p(e.id, 200)), ...l("action", p(e.action, 200)) };\n }\n case "echart": {\n let n = e.data !== void 0 ? Te(e.data, m.maxChartPoints) : void 0, o = e.series !== void 0 && Array.isArray(e.series) ? Le(e.series, m.maxPlotSeries, m.maxChartPoints) : void 0, a = Array.isArray(e.links) ? e.links.slice(0, m.maxChartPoints).flatMap((c) => {\n let f = y(c), g = f === void 0 ? void 0 : p(f.from, 64), x = f === void 0 ? void 0 : p(f.to, 64);\n return g === void 0 || x === void 0 ? [] : [{ from: g, to: x, ...l("value", k(f.value, 0, 1e9)) }];\n }) : void 0, u = e.option !== void 0 ? Ce(e.option, 0, { count: m.maxEChartOptionNodes }) : void 0, d = u === void 0 || typeof u != "object" || u === null || Array.isArray(u) ? void 0 : u;\n return d === void 0 && n === void 0 && o === void 0 && (a === void 0 || a.length === 0) ? null : { type: "echart", ...l("title", p(e.title, m.maxString)), ...l("height", D(e.height, 100, 800)), ...l("preset", w(e.preset, ge)), ...l("data", n), ...l("series", o), ...l("links", a !== void 0 && a.length > 0 ? a : void 0), ...l("palette", Fe(e.palette)), ...l("option", d) };\n }\n default:\n return t;\n }\n }\n function Q(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= i) break;\n if (typeof s == "string") e.push(s.slice(0, r));\n else if (s !== null && typeof s == "object") {\n let n = s, o = typeof n.label == "string" ? n.label : typeof n.value == "string" ? n.value : typeof n.title == "string" ? n.title : JSON.stringify(s);\n e.push(o.slice(0, r));\n }\n }\n return e;\n }\n function Pn(t, i, r, e) {\n if (!Array.isArray(t)) return;\n let s = [];\n for (let n of t) {\n if (s.length >= i) break;\n if (typeof n == "string") {\n s.push(n.slice(0, m.maxString));\n continue;\n }\n let o = y(n);\n if (o !== void 0 && typeof o.type == "string") {\n if (r.remaining <= 0) break;\n r.remaining -= 1;\n let u = Je(o, r, e);\n u !== null && s.push(u);\n continue;\n }\n let a = o === void 0 ? void 0 : p(o.title, m.maxString);\n a !== void 0 && s.push({ title: a, ...l("desc", p(o?.desc, m.maxString)) });\n }\n return s;\n }\n function Te(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.label, 128), o = s === void 0 ? void 0 : k(s.value, -1e12, 1e12);\n n === void 0 || o === void 0 || r.push({ label: n, value: o, ...l("color", s === void 0 ? void 0 : E(s.color)) });\n }\n return r;\n }\n function Le(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= i) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.label, 128), a = n === void 0 ? void 0 : Te(n.data, r);\n o === void 0 || a === void 0 || e.push({ label: o, data: a, ...l("color", n === void 0 ? void 0 : E(n.color)) });\n }\n return e;\n }\n function vn(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= m.maxTabs) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.label, 128);\n if (o === void 0 || n === void 0) continue;\n let a = n.items !== void 0 ? n.items : n.content !== void 0 ? Array.isArray(n.content) ? n.content : [n.content] : void 0;\n e.push({ label: o, items: _(a, i, r + 1) });\n }\n return e;\n }\n function qn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.expr, 512);\n if (n === void 0 || s === void 0) continue;\n let o = [];\n if (Array.isArray(s.params)) for (let a of s.params) {\n if (o.length >= m.maxPlotParams) break;\n let u = y(a), d = u === void 0 ? void 0 : p(u.name, 64), c = u === void 0 ? void 0 : k(u.value, -1e9, 1e9);\n d === void 0 || c === void 0 || o.push({ name: d, value: c, ...l("min", u === void 0 ? void 0 : k(u.min, -1e9, 1e9)), ...l("max", u === void 0 ? void 0 : k(u.max, -1e9, 1e9)), ...l("step", u === void 0 ? void 0 : k(u.step, 1e-9, 1e9)), ...l("animateTo", u === void 0 ? void 0 : k(u.animateTo, -1e9, 1e9)), ...l("durationMs", u === void 0 ? void 0 : k(u.durationMs, 1, 12e4)), ...l("loop", u === void 0 ? void 0 : u.loop === true ? true : void 0) });\n }\n r.push({ expr: n, ...l("label", p(s.label, 128)), ...l("color", E(s.color)), ...l("kind", w(s.kind, oe)), ...l("params", o.length > 0 ? o : void 0) });\n }\n return r;\n }\n function zn(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxSteps) break;\n let e = y(r), s = e === void 0 ? void 0 : p(e.title, 256);\n s !== void 0 && i.push({ title: s, ...l("desc", e === void 0 ? void 0 : p(e.desc, m.maxString)) });\n }\n return i;\n }\n function Fn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.key, 256), o = s === void 0 ? void 0 : p(s.value, m.maxString);\n n === void 0 || o === void 0 || r.push({ key: n, value: o });\n }\n return r;\n }\n function jn(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= 24) break;\n let e = y(r), s = e === void 0 ? void 0 : p(e.path, 1024), n = e === void 0 ? void 0 : p(e.newText, 2e4);\n if (s === void 0 || n === void 0) continue;\n let o = e === void 0 ? void 0 : e.oldText;\n i.push({ path: s, newText: n, oldText: o === null || typeof o != "string" ? null : o.slice(0, 2e4) });\n }\n return i;\n }\n function Ln(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= m.maxAccordionItems) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.title, 256);\n o === void 0 || n === void 0 || e.push({ title: o, items: _(n.items, i, r + 1) });\n }\n return e;\n }\n function Vn(t) {\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxMeshes) break;\n let e = y(r), s = e === void 0 ? void 0 : w(e.shape, ue);\n if (s === void 0) continue;\n let n = e === void 0 ? void 0 : k(e.scale, -1e6, 1e6) ?? Z(e.scale), o = e === void 0 ? void 0 : k(e.size, -1e6, 1e6) ?? Z(e.size);\n i.push({ shape: s, ...l("color", e === void 0 ? void 0 : E(e.color)), ...l("position", e === void 0 ? void 0 : Z(e.position)), ...l("rotation", e === void 0 ? void 0 : Z(e.rotation)), ...l("scale", n), ...l("size", o) });\n }\n return i;\n }\n function Z(t) {\n if (!Array.isArray(t) || t.length !== 3) return;\n let [i, r, e] = t;\n if (!(typeof i != "number" || !Number.isFinite(i) || typeof r != "number" || !Number.isFinite(r) || typeof e != "number" || !Number.isFinite(e))) return [Math.min(1e6, Math.max(-1e6, i)), Math.min(1e6, Math.max(-1e6, r)), Math.min(1e6, Math.max(-1e6, e))];\n }\n function P(t, i, r) {\n return Math.min(r, Math.max(i, Math.round(t / 4) * 4));\n }\n function Kn(t) {\n if (!Array.isArray(t)) return;\n let i = [], r = /* @__PURE__ */ new Set();\n for (let e of t) {\n if (i.length >= m.maxDiagramNodes) break;\n let s = y(e);\n if (s === void 0) continue;\n let n = p(s.id, 128), o = p(s.label, m.maxString);\n if (n === void 0 || o === void 0 || r.has(n)) continue;\n r.add(n);\n let a = w(s.type, ce), u = s.x === void 0 ? void 0 : P(k(s.x, -1e6, 1e6) ?? 0, 0, 1e6), d = s.y === void 0 ? void 0 : P(k(s.y, -1e6, 1e6) ?? 0, 0, 1e6), c = s.w === void 0 ? void 0 : P(k(s.w, -1e6, 1e6) ?? 96, 40, 2e3), f = s.h === void 0 ? void 0 : P(k(s.h, -1e6, 1e6) ?? 48, 24, 1200);\n i.push({ id: n, label: o, ...l("sub", p(s.sub, 256)), ...l("type", a), ...l("x", u), ...l("y", d), ...l("w", c), ...l("h", f), ...l("tag", p(s.tag, 32)) });\n }\n return i;\n }\n function Hn(t) {\n if (t === void 0) return [];\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxDiagramEdges) break;\n let e = y(r);\n if (e === void 0) continue;\n let s = p(e.from, 128), n = p(e.to, 128);\n s === void 0 || n === void 0 || i.push({ from: s, to: n, ...l("label", p(e.label, m.maxDiagramLabel)), ...l("kind", w(e.kind, pe)), ...l("route", w(e.route, me)) });\n }\n return i;\n }\n function Jn(t) {\n let i = y(t);\n if (i === void 0) return;\n let r = {};\n for (let e of ["paper", "paper-2", "ink", "muted", "soft", "rule", "accent", "accent-tint", "link"]) {\n let s = E(i[e]);\n s !== void 0 && (r[e] = s);\n }\n return Object.keys(r).length === 0 ? void 0 : r;\n }\n function Un(t) {\n if (t === void 0) return [];\n if (!Array.isArray(t)) return;\n let i = [];\n for (let r of t) {\n if (i.length >= m.maxDiagramZones) break;\n let e = y(r);\n if (e === void 0) continue;\n let s = p(e.label, 64);\n s !== void 0 && i.push({ label: s, ...l("x", e.x === void 0 ? void 0 : P(k(e.x, -1e6, 1e6) ?? 0, 0, 1e6)), ...l("y", e.y === void 0 ? void 0 : P(k(e.y, -1e6, 1e6) ?? 0, 0, 1e6)), ...l("w", e.w === void 0 ? void 0 : P(k(e.w, -1e6, 1e6) ?? 100, 40, 2e3)), ...l("h", e.h === void 0 ? void 0 : P(k(e.h, -1e6, 1e6) ?? 100, 40, 1200)) });\n }\n return i;\n }\n function Bn(t) {\n let i = y(t);\n if (i === void 0) return null;\n let r = w(i.kind, de);\n if (r === void 0) return null;\n let e = Kn(i.nodes);\n if (e === void 0) return null;\n let s = Hn(i.edges);\n if (s === void 0) return null;\n let n = Un(i.zones);\n return n === void 0 ? null : { type: "diagram", kind: r, nodes: e, edges: s, ...l("zones", n.length > 0 ? n : void 0), ...l("variant", w(i.variant, fe)), ...l("title", p(i.title, 256)), ...l("theme", Jn(i.theme)) };\n }\n function Yn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let e of t) {\n if (r.length >= i) break;\n let s = y(e), n = s === void 0 ? void 0 : p(s.title, 256);\n n !== void 0 && r.push({ title: n, ...l("desc", s === void 0 ? void 0 : p(s.desc, m.maxString)), ...l("time", s === void 0 ? void 0 : p(s.time, 128)) });\n }\n return r;\n }\n function Qn(t, i) {\n return Ue(t, i, m.maxTreeDepth);\n }\n function Ue(t, i, r) {\n if (!Array.isArray(t)) return;\n let e = [];\n for (let s of t) {\n if (e.length >= i) break;\n let n = y(s), o = n === void 0 ? void 0 : p(n.name, 256);\n if (o === void 0) continue;\n let a = n !== void 0 && r > 0 && Array.isArray(n.children) ? Ue(n.children, i, r - 1) : void 0;\n e.push({ name: o, ...l("type", n === void 0 ? void 0 : w(n.type, le)), ...l("children", a) });\n }\n return e;\n }\n function Zn(t, i) {\n if (!Array.isArray(t)) return;\n let r = [];\n for (let s of t) {\n if (r.length >= m.maxQuizOptions) break;\n let n = y(s), o = typeof s == "string" ? p(s, 512) : n === void 0 ? void 0 : p(n.label, 512);\n o !== void 0 && r.push({ label: o, ...l("correct", n === void 0 ? void 0 : n.correct === true ? true : void 0), ...l("feedback", n === void 0 ? void 0 : p(n.feedback, m.maxString)) });\n }\n if (r.length === 0) return;\n if (r.some((s) => s.correct === true)) return r;\n let e = typeof i == "number" && Number.isFinite(i) ? Math.trunc(i) : typeof i == "string" ? r.findIndex((s) => s.label === i.slice(0, 512)) : -1;\n return e < 0 || e >= r.length ? r : r.map((s, n) => n === e ? { ...s, correct: true } : s);\n }\n var Wn = /<(?:script|img|svg|iframe|video|audio|object|embed|source)\\b|on[a-z]+\\s*=|javascript:/i;\n function Ce(t, i, r) {\n if (r.count <= 0 || (r.count -= 1, i > m.maxEChartOptionDepth)) return;\n if (typeof t == "string") {\n let n = t.slice(0, m.maxString);\n return n.toLowerCase().includes("url(") || Wn.test(n) ? void 0 : n;\n }\n if (typeof t == "number" && Number.isFinite(t) || typeof t == "boolean") return t;\n if (t === null) return null;\n if (Array.isArray(t)) {\n let n = Math.min(t.length, m.maxEChartArrayLen), o = [];\n for (let a = 0; a < n; a++) {\n let u = Ce(t[a], i + 1, r);\n u !== void 0 && o.push(u);\n }\n return o.length > 0 || t.length === 0 ? o : void 0;\n }\n let e = y(t);\n if (e === void 0) return;\n let s = {};\n for (let [n, o] of Object.entries(e)) {\n let a = Ce(o, i + 1, r);\n a !== void 0 && (n === "tooltip" && typeof a == "object" && a !== null && !Array.isArray(a) && (a.renderMode = "richText"), s[n] = a);\n }\n return Object.keys(s).length > 0 || Object.keys(e).length === 0 ? s : void 0;\n }\n function Be(t) {\n let i = y(t);\n if (i === void 0) return null;\n if (N(t)) {\n let e = z(t);\n return e === null ? null : Be(e);\n }\n if (!Array.isArray(i.items)) return null;\n let r = { remaining: m.maxNodes };\n return { ...l("title", p(i.title, m.maxString)), ...l("gap", k(i.gap, 0, 96)), ...l("panel", i.panel === true ? true : void 0), ...l("append", i.append === true ? true : void 0), items: _(i.items, r, 0) };\n }\n function Xn(t, i = Number.POSITIVE_INFINITY) {\n let r = 0, e = (n) => {\n if (Array.isArray(n)) for (let o of n) {\n if (r >= i) return;\n r += 1;\n let a = y(o);\n if (a !== void 0) {\n if (a.type === "tabs" && Array.isArray(a.tabs)) for (let u of a.tabs) {\n if (r >= i) return;\n let d = y(u);\n d !== void 0 && e(d.items);\n }\n else if (a.type === "accordion" && Array.isArray(a.items)) for (let u of a.items) {\n if (r >= i) return;\n let d = y(u);\n d !== void 0 && e(d.items);\n }\n else if ((a.type === "row" || a.type === "col" || a.type === "grid" || a.type === "card") && Array.isArray(a.items)) e(a.items);\n else if (a.type !== "file-tree") {\n if (a.type === "list" && Array.isArray(a.items)) for (let u of a.items) {\n if (r >= i) return;\n let d = y(u);\n d !== void 0 && typeof d.type == "string" && e([d]);\n }\n else if (a.type === "table" && Array.isArray(a.details)) {\n let u = I(a).length;\n for (let d = 0; d < Math.min(a.details.length, u); d++) {\n if (r >= i) return;\n let c = a.details[d];\n Array.isArray(c) && C(a, d) && e(c);\n }\n }\n }\n }\n }\n }, s = y(t);\n return e(s === void 0 ? [] : s.items), r;\n }\n var et = q;\n function nt(t, i, r) {\n let e = 0, s = (d) => {\n let c = y(d);\n return c !== void 0 && typeof c.type == "string" && et.has(c.type);\n };\n function n(d, c) {\n if (Array.isArray(d)) {\n for (let f = 0; f < d.length; f++) if (o(d[f], `${c}[${f}]`), e >= i) return;\n }\n }\n function o(d, c) {\n if (e >= i || !s(d)) return;\n let f = y(d);\n if (f !== void 0) {\n if (e += 1, r(f, c), f.type === "tabs" && Array.isArray(f.tabs)) for (let g = 0; g < f.tabs.length; g++) a(f.tabs[g], `${c}.tabs[${g}]`);\n else if (f.type === "accordion" && Array.isArray(f.items)) for (let g = 0; g < f.items.length; g++) a(f.items[g], `${c}.items[${g}]`);\n else if ((f.type === "row" || f.type === "col" || f.type === "grid" || f.type === "card") && Array.isArray(f.items)) n(f.items, `${c}.items`);\n else if (f.type === "list" && Array.isArray(f.items)) for (let g = 0; g < f.items.length; g++) o(f.items[g], `${c}.items[${g}]`);\n else if (f.type === "table" && Array.isArray(f.details)) {\n let g = I(f).length;\n for (let x = 0; x < Math.min(f.details.length, g); x++) Array.isArray(f.details[x]) && C(f, x) && n(f.details[x], `${c}.details[${x}]`);\n }\n }\n }\n function a(d, c) {\n let f = y(d);\n if (f === void 0) return;\n let g = f.items !== void 0 ? f.items : f.content;\n Array.isArray(g) ? n(g, `${c}.items`) : o(g, `${c}.items`);\n }\n let u = y(t);\n return u === void 0 || (N(u) && s(t) ? o(t, "spec") : n(u.items, "items")), e;\n }\n function Ye(t, i = Number.POSITIVE_INFINITY) {\n return nt(t, i, () => {\n });\n }\n function tt(t, i = Number.POSITIVE_INFINITY) {\n return Ye(t, i);\n }\n function Qe(t) {\n let i = [], r = y(t);\n if (r === void 0) return { ok: false, errors: ["spec root must be an object"] };\n if (N(t)) {\n let a = z(t);\n return a !== null ? Qe(a) : { ok: false, errors: ["spec.items must be an array"] };\n }\n if (!Array.isArray(r.items)) return { ok: false, errors: ["spec.items must be an array"] };\n Ke(r, "spec", V, i, ["items"]);\n let e = 0, s = false, n = (a, u, d) => {\n if (!s) {\n if (!Array.isArray(a)) {\n i.push(`${d} must be an array`);\n return;\n }\n for (let c = 0; c < a.length; c++) {\n if (s || e >= m.maxNodes) {\n s || (i.push(`spec exceeds ${m.maxNodes} nodes; tail elided`), s = true);\n return;\n }\n e += 1;\n let f = `${d}[${c}]`;\n Xe(a[c], u, f, i, n);\n }\n }\n };\n n(r.items, 0, "items"), i.length === 0 && i.push(...Re(r).diagnostics);\n let o = [...new Set(i)];\n return { ok: o.length === 0, errors: o };\n }\n function Ze(t) {\n let i = Ie(t), r = Be(i.value), e = Qe(i.value), s = Ye(i.value, m.maxNodes + 1), n = r === null ? 0 : tt(r), o = r === null ? 0 : Xn(r), a = e.errors.filter((u) => !u.includes(": unknown type "));\n return r !== null && a.length === 0 && a.push(...Re(r).diagnostics), s > n && a.push(`repair dropped ${s - n} declared native node(s): declared ${s}, rendered ${n}`), { value: i.value, normalized: i.value, repaired: r, spec: r, errors: [...new Set(a)], warnings: [...i.warnings, ...Pe(i.value)], declaredCount: s, renderedCount: o, declaredNativeCount: s, renderedNativeCount: n, renderedTotalCount: o };\n }\n function it(t) {\n return t.errors.length > 0 && t.errors.every((i) => i.startsWith("spec exceeds ") || i.startsWith("repair dropped ")) && t.renderedNativeCount === m.maxNodes && t.declaredNativeCount === m.maxNodes + 1;\n }\n function Ne(t) {\n return t.spec !== null && (t.errors.length === 0 || it(t));\n }\n var rt = /^(items\\[\\d+\\](?:\\.(?:items\\[\\d+\\]|tabs\\[\\d+\\]\\.items\\[\\d+\\]|details\\[\\d+\\](?:\\[\\d+\\])?))*)/;\n function st(t) {\n let i = rt.exec(t);\n return i === null ? null : i[1] ?? null;\n }\n function Ve(t, i) {\n let r = [...i.matchAll(/(?:^|\\.)(items|tabs|details)\\[(\\d+)\\]|\\[(\\d+)\\]/g)];\n if (r.length === 0 || r[r.length - 1][1] === "tabs") return;\n let e = t;\n for (let s = 0; s < r.length; s++) {\n let n = r[s], o = n[1] === void 0 ? e : y(e)?.[n[1]], a = Number(n[2] ?? n[3]);\n if (!Array.isArray(o) || a >= o.length) return;\n if (s === r.length - 1) return { array: o, index: a, preserveIndex: n[1] === "details" };\n if (e = o[a], e === void 0) return;\n }\n }\n function ot(t) {\n try {\n return y(JSON.parse(JSON.stringify(t))) ?? null;\n } catch {\n return null;\n }\n }\n function at(t) {\n if (Ne(t)) return t.spec;\n if (t.spec === null) return null;\n let i = y(t.value);\n if (i === void 0) return null;\n let r = /* @__PURE__ */ new Set(), e = /* @__PURE__ */ new Set();\n for (let d of t.errors) {\n if (d.startsWith("spec exceeds ")) continue;\n let c = st(d);\n c !== null && (d === `${c}.details must not contain more entries than rows` ? e.add(c) : r.add(c));\n }\n if (r.size === 0 && e.size === 0) return null;\n let s = ot(N(i) ? z(i) : i);\n if (s === null) return null;\n let n = [...r].map((d) => Ve(s, d)).filter((d) => d !== void 0), o = [...e].map((d) => Ve(s, d)).filter((d) => d !== void 0);\n for (let { array: d, index: c } of o) {\n let f = y(d[c]);\n f?.type === "table" && Array.isArray(f.details) && (f.details.length = Math.min(f.details.length, I(f).length));\n }\n let a = /* @__PURE__ */ new Map();\n for (let { array: d, index: c, preserveIndex: f } of n) {\n if (f) {\n d[c] = null;\n continue;\n }\n let g = a.get(d);\n g === void 0 ? a.set(d, [c]) : g.push(c);\n }\n for (let [d, c] of a) {\n c.sort((f, g) => g - f);\n for (let f of c) d.splice(f, 1);\n }\n let u = Ze(s);\n return !Ne(u) || u.renderedNativeCount === 0 ? null : u.spec;\n }\n function We(t, i, r) {\n if (Array.isArray(t)) for (let e = 0; e < t.length; e++) {\n let s = y(t[e]), n = `${i}[${e}]`;\n if (s === void 0) {\n r.push(`${n} must be an object`);\n continue;\n }\n typeof s.label != "string" && r.push(`${n}.label must be a string`), (typeof s.value != "number" || !Number.isFinite(s.value)) && r.push(`${n}.value must be a finite number`), s.color !== void 0 && typeof s.color != "string" && r.push(`${n}.color must be a string`);\n }\n }\n function ut(t, i, r) {\n if (Array.isArray(t)) for (let e = 0; e < t.length; e++) {\n let s = y(t[e]), n = `${i}[${e}]`;\n if (s === void 0) {\n r.push(`${n} must be an object`);\n continue;\n }\n typeof s.label != "string" && r.push(`${n}.label must be a string`), s.color !== void 0 && typeof s.color != "string" && r.push(`${n}.color must be a string`), Array.isArray(s.data) || r.push(`${n}.data must be an array`), We(s.data, `${n}.data`, r);\n }\n }\n function lt(t, i, r) {\n !Array.isArray(t.data) && !Array.isArray(t.series) && r.push(`${i}: type \'chart\' requires data or series (array)`), t.variant !== void 0 && r.push(`${i}.variant is unsupported; use kind`), t.data !== void 0 && !Array.isArray(t.data) && r.push(`${i}.data must be an array`), t.series !== void 0 && !Array.isArray(t.series) && r.push(`${i}.series must be an array`), t.kind !== void 0 && (typeof t.kind != "string" || !U.includes(t.kind)) && r.push(`${i}.kind must be bars, line, or donut`);\n let e = t.kind === void 0 ? "bars" : t.kind, s = Array.isArray(t.series) ? t.series : void 0;\n if (Array.isArray(t.data) && t.data.length === 0 && (s === void 0 || s.length === 0) && r.push(`${i}.data must not be empty`), s !== void 0) {\n s.length === 0 && r.push(`${i}.series must not be empty`), e === "donut" && r.push(`${i}.series is only supported for bars and line`);\n for (let n = 0; n < s.length; n++) {\n let o = y(s[n]);\n o !== void 0 && Array.isArray(o.data) && o.data.length === 0 && r.push(`${i}.series[${n}].data must not be empty`);\n }\n }\n e === "donut" && t.data === void 0 && r.push(`${i}.data is required for donut`), e === "line" && t.data === void 0 && (s === void 0 || s.length === 0) && r.push(`${i}.data is required for line (or provide series)`), We(t.data, `${i}.data`, r), ut(t.series, `${i}.series`, r);\n }\n function dt(t, i, r) {\n if (Array.isArray(t)) for (let e = 0; e < t.length; e++) {\n let s = t[e];\n if (y(s) === void 0) {\n if (!Array.isArray(s)) {\n r.push(`${i}[${e}] must be an array or object`);\n continue;\n }\n for (let n = 0; n < s.length; n++) {\n let o = s[n];\n typeof o != "string" && (typeof o != "number" || !Number.isFinite(o)) && r.push(`${i}[${e}][${n}] must be a string or finite number`);\n }\n }\n }\n }\n function Xe(t, i, r, e, s) {\n if (i > m.maxDepth) {\n e.push(`${r}: exceeds max depth ${m.maxDepth}`);\n return;\n }\n let n = y(t);\n if (n === void 0) {\n e.push(`${r}: must be an object`);\n return;\n }\n let o = n.type;\n if (typeof o != "string") {\n e.push(`${r}: missing string \'type\'`);\n return;\n }\n let a = (c) => {\n n[c] !== void 0 && typeof n[c] != "string" && e.push(`${r}: \'${c}\' must be a string`);\n }, u = (c) => {\n n[c] !== void 0 && (typeof n[c] != "number" || !Number.isFinite(n[c])) && e.push(`${r}: \'${c}\' must be a finite number`);\n };\n switch (o) {\n case "text":\n typeof n.content != "string" && typeof n.text != "string" && e.push(`${r}: type \'text\' requires content or text (string)`), a("content"), a("text");\n break;\n case "row":\n case "col":\n case "card":\n case "grid":\n Array.isArray(n.items) || e.push(`${r}: type \'${o}\' requires items (array)`), s(n.items, i + 1, `${r}.items`), o === "grid" && u("cols");\n break;\n case "button":\n case "checkbox":\n case "link":\n case "switch":\n typeof n.label != "string" && e.push(`${r}: type \'${o}\' requires label (string)`), a("label");\n break;\n case "image":\n case "audio":\n case "video":\n typeof n.src != "string" && e.push(`${r}: type \'${o}\' requires src (string)`), a("src"), a("alt"), o === "video" && a("poster");\n break;\n case "slider":\n a("label"), u("min"), u("max"), u("step"), u("value");\n break;\n case "input":\n case "textarea":\n a("label"), a("placeholder"), a("value");\n break;\n case "select":\n case "radio":\n Array.isArray(n.options) || e.push(`${r}: type \'${o}\' requires options (array)`);\n break;\n case "submit":\n typeof n.label != "string" && e.push(`${r}: type \'submit\' requires label (string)`);\n break;\n case "badge":\n typeof n.label != "string" && typeof n.text != "string" && typeof n.value != "string" && e.push(`${r}: type \'badge\' requires label, text, or value (string)`), a("label"), a("text"), a("value");\n break;\n case "hero":\n typeof n.title != "string" && e.push(`${r}: type \'hero\' requires title (string)`), a("subtitle");\n break;\n case "stat":\n typeof n.label != "string" && e.push(`${r}: type \'stat\' requires label (string)`), typeof n.value != "string" && e.push(`${r}: type \'stat\' requires value (string)`), a("delta");\n break;\n case "progress":\n (typeof n.value != "number" || !Number.isFinite(n.value) || n.value < 0 || n.value > 100) && e.push(`${r}: type \'progress\' requires value (number 0..100)`), u("value");\n break;\n case "avatar":\n typeof n.name != "string" && e.push(`${r}: type \'avatar\' requires name (string)`);\n break;\n case "list":\n if (Array.isArray(n.items) || e.push(`${r}: type \'list\' requires items (array)`), Array.isArray(n.items)) for (let c = 0; c < n.items.length; c++) {\n let f = y(n.items[c]);\n f !== void 0 && typeof f.type == "string" && Xe(f, i + 1, `${r}.items[${c}]`, e, s);\n }\n break;\n case "table":\n if (!Array.isArray(n.columns) && !He(n) && e.push(`${r}: type \'table\' requires columns (array)`), Array.isArray(n.rows) || e.push(`${r}: type \'table\' requires rows (array)`), n.types !== void 0 && !Array.isArray(n.types) && e.push(`${r}.types must be an array of column cell types`), n.details !== void 0 && !Array.isArray(n.details) && e.push(`${r}.details must be an array aligned with rows`), Array.isArray(n.details)) {\n let c = { columns: n.columns, rows: n.rows, types: n.types }, f = I(c).length;\n n.details.length > f && e.push(`${r}.details must not contain more entries than rows`);\n for (let g = 0; g < Math.min(n.details.length, f); g++) {\n let x = n.details[g];\n if (!(x === null || !C(c, g))) {\n if (!Array.isArray(x)) {\n e.push(`${r}.details[${g}] must be an array or null`);\n continue;\n }\n s(x, i + 1, `${r}.details[${g}]`);\n }\n }\n }\n dt(n.rows, `${r}.rows`, e);\n break;\n case "chart":\n lt(n, r, e);\n break;\n case "tabs": {\n if (Array.isArray(n.tabs) || e.push(`${r}: type \'tabs\' requires tabs (array)`), Array.isArray(n.tabs)) for (let c = 0; c < n.tabs.length; c++) {\n let f = y(n.tabs[c]);\n if (f === void 0) {\n e.push(`${r}.tabs[${c}] must be an object`);\n continue;\n }\n typeof f.label != "string" && e.push(`${r}.tabs[${c}].label must be a string`), s(f.items, i + 1, `${r}.tabs[${c}].items`);\n }\n break;\n }\n case "plot":\n Array.isArray(n.series) || e.push(`${r}: type \'plot\' requires series (array)`);\n break;\n case "callout":\n typeof n.content != "string" && e.push(`${r}: type \'callout\' requires content (string)`);\n break;\n case "steps":\n Array.isArray(n.steps) || e.push(`${r}: type \'steps\' requires steps (array)`);\n break;\n case "keyvalue":\n Array.isArray(n.pairs) || e.push(`${r}: type \'keyvalue\' requires pairs (array)`);\n break;\n case "diff":\n Array.isArray(n.diffs) || e.push(`${r}: type \'diff\' requires diffs (array)`);\n break;\n case "json":\n "value" in n || e.push(`${r}: type \'json\' requires value`);\n break;\n case "code":\n typeof n.code != "string" && e.push(`${r}: type \'code\' requires code (string)`);\n break;\n case "accordion":\n if (Array.isArray(n.items) || e.push(`${r}: type \'accordion\' requires items (array)`), Array.isArray(n.items)) for (let c = 0; c < n.items.length; c++) {\n let f = y(n.items[c]);\n if (f === void 0) {\n e.push(`${r}.items[${c}] must be an object`);\n continue;\n }\n typeof f.title != "string" && e.push(`${r}.items[${c}].title must be a string`), s(f.items, i + 1, `${r}.items[${c}].items`);\n }\n break;\n case "copy":\n typeof n.text != "string" && e.push(`${r}: type \'copy\' requires text (string)`);\n break;\n case "svg":\n typeof n.code != "string" && e.push(`${r}: type \'svg\' requires code (string)`), u("height");\n break;\n case "mermaid":\n typeof n.code != "string" && e.push(`${r}: type \'mermaid\' requires code (string)`);\n break;\n case "scene3d":\n Array.isArray(n.meshes) || e.push(`${r}: type \'scene3d\' requires meshes (array)`);\n break;\n case "timeline":\n Array.isArray(n.items) || e.push(`${r}: type \'timeline\' requires items (array)`);\n break;\n case "file-tree":\n Array.isArray(n.items) || e.push(`${r}: type \'file-tree\' requires items (array)`);\n break;\n case "breadcrumb":\n Array.isArray(n.items) || e.push(`${r}: type \'breadcrumb\' requires items (array)`);\n break;\n case "quiz":\n typeof n.question != "string" && e.push(`${r}: type \'quiz\' requires question (string)`), Array.isArray(n.options) || e.push(`${r}: type \'quiz\' requires options (array)`);\n break;\n case "diagram":\n typeof n.kind != "string" && e.push(`${r}: type \'diagram\' requires kind (string)`), Array.isArray(n.nodes) || e.push(`${r}: type \'diagram\' requires nodes (array)`), n.edges !== void 0 && !Array.isArray(n.edges) && e.push(`${r}: type \'diagram\' requires edges (array) when present`);\n break;\n case "echart":\n n.option === void 0 && n.data === void 0 && n.series === void 0 && (!Array.isArray(n.links) || n.links.length === 0) && e.push(`${r}: type \'echart\' requires option, data, series, or links`), u("height");\n break;\n default:\n e.push(`${r}: unknown type \'${o}\' (custom renderer?)`);\n }\n let d = T[o];\n d !== void 0 && In(n, r, d, e);\n }\n\n // lib/normalize-visual.js\n function normalizeVisual(value, schemas) {\n const unwrap = (v2) => v2 && typeof v2 === "object" && !Array.isArray(v2) && Object.keys(v2).length === 1 && Array.isArray(v2.item) ? v2.item : v2;\n const scalar2 = (v2, kind) => kind === "number" && typeof v2 === "string" && v2.trim() !== "" && Number.isFinite(Number(v2)) ? Number(v2) : kind === "boolean" && (v2 === "true" || v2 === "false") ? v2 === "true" : v2;\n function record(input, schema, depth = 0) {\n if (!input || typeof input !== "object" || Array.isArray(input) || depth > 32) return input;\n const out2 = { ...input };\n for (const [key, v2] of Object.entries(input)) {\n const target = schema.aliases?.[key] ?? key, kind = schema.fields?.[target];\n if (kind === "array" || kind === "nodes") {\n let array2 = unwrap(v2);\n if (Array.isArray(array2)) array2 = array2.map((x) => kind === "nodes" ? node2(x, depth + 1) : schema.nested?.[target] ? record(x, schema.nested[target], depth + 1) : x);\n out2[key] = array2;\n } else out2[key] = scalar2(v2, kind);\n }\n return out2;\n }\n function node2(v2, depth) {\n if (!v2 || typeof v2 !== "object" || Array.isArray(v2)) return v2;\n if (v2.type === "heading") {\n v2 = { ...v2, type: "text", content: v2.content ?? v2.text ?? v2.title, size: v2.size ?? "h3" };\n delete v2.text;\n delete v2.title;\n }\n if (["card", "row", "col", "grid"].includes(v2.type) && v2.items === void 0 && Array.isArray(unwrap(v2.children))) {\n v2 = { ...v2, items: unwrap(v2.children) };\n delete v2.children;\n }\n const out2 = record(v2, schemas[v2.type] ?? {}, depth);\n if (v2.type === "quiz" && Array.isArray(out2.options)) out2.options = out2.options.map((x) => record(x, { fields: { correct: "boolean" } }));\n if (v2.type === "table") {\n for (const key of ["rows", "data", "items", "details"]) if (Array.isArray(out2[key])) out2[key] = out2[key].map((row) => {\n row = unwrap(row);\n return key === "details" && Array.isArray(row) ? row.map((x) => node2(x, depth + 1)) : row;\n });\n }\n if (v2.type === "echart") {\n for (const key of ["data", "series", "links"]) if (Array.isArray(out2[key])) out2[key] = out2[key].map((x) => record(x, { fields: { value: "number", data: "array" }, nested: { data: { fields: { value: "number" } } } }));\n }\n return out2;\n }\n if (Array.isArray(value)) return { items: value.map((x) => node2(x, 0)) };\n if (!value || typeof value !== "object") return value;\n const out = { ...value }, items = unwrap(value.items);\n if (Array.isArray(items)) out.items = items.map((x) => node2(x, 0));\n return out;\n }\n\n // lib/visual.js\n var VISUAL_TYPES = Object.freeze([...q]);\n function validateVisual(value) {\n const encoded = JSON.stringify(value);\n if (!encoded || new TextEncoder().encode(encoded).length > 131072) throw Error("DSH UI: visual spec exceeds 128 KiB");\n const processed = Ze(normalizeVisual(value, T)), spec = Ne(processed) ? processed.spec : at(processed);\n if (!spec || !processed.renderedNativeCount) throw Error("DSH UI: visual spec: " + (processed.errors.slice(0, 4).join("; ") || "requires registered components"));\n const critical = /* @__PURE__ */ new Set(["quiz", "radio", "submit", "input", "textarea", "select", "slider", "checkbox", "switch"]);\n const inventory = (items, path = "items", result = []) => {\n for (const [n, v2] of (Array.isArray(items) ? items : []).entries()) {\n if (!v2 || typeof v2 !== "object") continue;\n const at2 = path + "[" + n + "]";\n if (critical.has(v2.type)) result.push({ type: v2.type, id: v2.id ?? v2.group ?? v2.question ?? v2.label, path: at2 });\n if (["row", "col", "grid", "card"].includes(v2.type)) inventory(v2.items, at2 + ".items", result);\n if (v2.type === "tabs") for (const [i, t] of (v2.tabs ?? []).entries()) inventory(t.items, at2 + ".tabs[" + i + "].items", result);\n if (v2.type === "accordion") for (const [i, t] of (v2.items ?? []).entries()) inventory(t.items, at2 + ".items[" + i + "].items", result);\n }\n return result;\n };\n const source = normalizeVisual(value, T), before = inventory(source.items), after = inventory(spec.items);\n const available = [...after], missing = before.filter((v2) => {\n const i = available.findIndex((n) => n.type === v2.type && n.id === v2.id);\n if (i < 0) return true;\n available.splice(i, 1);\n return false;\n });\n if (missing.length) throw Error("DSH UI: critical component was rejected at " + missing.map((v2) => v2.path + " (" + v2.type + ")").join(", ") + ". " + processed.errors.slice(0, 4).join("; "));\n const stableIds = /* @__PURE__ */ new Set();\n function walk(items) {\n for (const n of items) {\n if (n.id !== void 0) {\n if (stableIds.has(n.id)) throw Error("DSH UI: duplicate extended component id " + n.id);\n stableIds.add(n.id);\n }\n if (!VISUAL_TYPES.includes(n.type)) throw Error("DSH UI: unsupported visual component " + n.type);\n if (n.type === "input" && n.inputType === "password") throw Error("DSH UI: do not collect passwords or secrets in a UI");\n if (n.type !== "file-tree" && Array.isArray(n.items)) walk(n.items.filter((x) => x && typeof x === "object" && "type" in x));\n for (const t of n.tabs ?? []) walk(t.items ?? []);\n if (n.type === "table") {\n for (const d of n.details ?? []) if (d) walk(d);\n }\n }\n }\n walk(spec.items);\n delete spec.panel;\n delete spec.append;\n return { spec, warnings: processed.errors.slice(0, 12), count: processed.renderedNativeCount };\n }\n function visualDocument(value) {\n if (Array.isArray(value)) value = { items: value };\n const { spec, warnings } = validateVisual(value), title = spec.title || "\\u53EF\\u89C6\\u5316";\n const texts = [];\n function gather(v2) {\n if (!v2 || typeof v2 !== "object") return;\n for (const [k2, x] of Object.entries(v2)) {\n if (["title", "content", "label", "question", "explanation", "alt"].includes(k2) && typeof x === "string") texts.push(x);\n else if (x && typeof x === "object") Array.isArray(x) ? x.forEach(gather) : gather(x);\n }\n }\n gather(spec);\n return { version: 1, title, fallback: texts.join("\\n").slice(0, 8192) || title, nodes: [{ id: "visual", type: "visual", spec, warnings }] };\n }\n\n // lib/normalize-authoring.js\n var object = (v2) => v2 !== null && typeof v2 === "object" && !Array.isArray(v2);\n var own = (v2, k2) => Object.hasOwn(v2, k2);\n var singleItem = (v2) => object(v2) && Object.keys(v2).length === 1 && own(v2, "item");\n var array = (v2) => {\n let candidate = v2;\n for (let i = 0; i < 8 && singleItem(candidate); i++) candidate = candidate.item;\n return Array.isArray(candidate) ? candidate : v2;\n };\n var numericOps = /* @__PURE__ */ new Set(["add", "sub", "mul", "div", "min", "max", "round", "ceil", "floor", "abs", "lt", "lte", "gt", "gte"]);\n function number(v2) {\n if (typeof v2 !== "string" || !/^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:e[+-]?\\d+)?$/i.test(v2.trim())) return v2;\n const n = Number(v2);\n return Number.isFinite(n) && (!Number.isInteger(n) || Number.isSafeInteger(n)) ? n : v2;\n }\n var boolean = (v2) => v2 === "true" ? true : v2 === "false" ? false : v2;\n function expression(e, numeric = false, logical = false) {\n if (!object(e)) return e;\n if (Object.keys(e).length === 1 && own(e, "expr") && typeof e.expr === "number" && Number.isFinite(e.expr)) {\n e.const = e.expr;\n delete e.expr;\n }\n if (own(e, "const")) {\n if (numeric) e.const = number(e.const);\n if (logical) e.const = boolean(e.const);\n }\n if (own(e, "args")) e.args = array(e.args);\n if (Array.isArray(e.args)) e.args.forEach((arg, i) => expression(arg, numericOps.has(e.op) || e.op === "if" && i > 0 && numeric, e.op === "if" && i === 0));\n if (object(e.map?.fields)) Object.values(e.map.fields).forEach((e2) => expression(e2));\n return e;\n }\n function normalizeAuthoring(doc2) {\n if (Array.isArray(doc2)) doc2 = visualDocument(doc2);\n if (object(doc2) && !own(doc2, "nodes") && (own(doc2, "items") || typeof doc2.type === "string")) doc2 = visualDocument(doc2);\n if (!object(doc2)) return doc2;\n if (own(doc2, "version")) doc2.version = number(doc2.version);\n if (object(doc2.presentation) && doc2.presentation.layout === "flow" && (!own(doc2.presentation, "preset") || doc2.presentation.preset === "flow")) {\n doc2.presentation.layout = "guide";\n doc2.presentation.preset = "flow";\n }\n if (object(doc2.state)) for (const k2 of Object.keys(doc2.state)) {\n let s = doc2.state[k2];\n if (typeof s === "string" && s.trim().startsWith("{")) {\n try {\n const parsed = JSON.parse(s);\n if (object(parsed)) s = parsed;\n } catch {\n }\n }\n if (singleItem(s) && object(s.item)) s = s.item;\n doc2.state[k2] = s;\n if (!object(s)) continue;\n if (own(s, "options")) s.options = array(s.options);\n if (s.type === "number") {\n for (const field of ["default", "min", "max", "step"]) if (own(s, field)) s[field] = number(s[field]);\n if (Array.isArray(s.options)) s.options = s.options.map(number);\n } else if (s.type === "boolean") {\n if (own(s, "default")) s.default = boolean(s.default);\n if (Array.isArray(s.options)) s.options = s.options.map(boolean);\n }\n }\n if (object(doc2.derived)) Object.values(doc2.derived).forEach((e) => expression(e));\n if (object(doc2.actions)) {\n for (const action of Object.values(doc2.actions)) if (object(action) && own(action, "stateKeys")) action.stateKeys = array(action.stateKeys);\n }\n function nodes(list) {\n list = array(list);\n if (!Array.isArray(list)) return list;\n for (const node2 of list) {\n if (!object(node2)) continue;\n if (node2.type === "code" && (node2.copyable === true || node2.copyable === "true")) delete node2.copyable;\n if (["slider", "input"].includes(node2.type) && typeof node2.bind === "string" && node2.bind.startsWith("state.")) {\n const spec = doc2.state?.[node2.bind.slice(6)];\n if (spec?.type === "number") {\n for (const field of ["min", "max", "step"]) if (own(node2, field) && number(node2[field]) === spec[field]) delete node2[field];\n }\n }\n if (["text", "heading", "callout"].includes(node2.type) && own(node2, "content")) {\n if (!own(node2, "text")) {\n node2.text = node2.content;\n delete node2.content;\n } else if (node2.text === node2.content) delete node2.content;\n }\n if (["text", "heading", "callout"].includes(node2.type) && typeof node2.text === "string") {\n const spans = array(node2.spans);\n if (Array.isArray(spans) && spans.every((s) => object(s) && typeof s.text === "string") && spans.map((s) => s.text).join("") === node2.text) delete node2.text;\n }\n if (node2.type === "table" && own(node2, "types")) {\n const columns = array(node2.columns), rows = array(node2.rows), types = array(node2.types);\n const allowed = ["id", "type", "label", "columns", "rows", "types"];\n if (Object.keys(node2).every((k2) => allowed.includes(k2)) && Array.isArray(columns) && columns.length && columns.every((c) => object(c) && typeof c.key === "string" && typeof c.label === "string" && Object.keys(c).every((k2) => ["key", "label", "unit"].includes(k2))) && new Set(columns.map((c) => c.key)).size === columns.length && Array.isArray(rows) && rows.every(object) && Array.isArray(types) && types.length === columns.length && types.every((t) => ["text", "num", "delta", "bar", "badge"].includes(t))) {\n const spec = { ...node2.label ? { title: node2.label } : {}, items: [{ type: "table", columns: columns.map((c) => c.label + (c.unit ? ` (${c.unit})` : "")), rows: rows.map((row) => columns.map((c) => row[c.key] ?? null)), types }] }, id = node2.id;\n for (const k2 of Object.keys(node2)) delete node2[k2];\n Object.assign(node2, { ...id !== void 0 ? { id } : {}, type: "visual", spec });\n }\n }\n if (typeof node2.id === "string" && VISUAL_TYPES.includes(node2.type) && !own(COMPONENTS, node2.type)) {\n const spec = { items: [{ ...node2 }] }, id = node2.id;\n for (const k2 of Object.keys(node2)) delete node2[k2];\n Object.assign(node2, { id, type: "visual", spec });\n }\n if (node2.type === "table" && Array.isArray(node2.columns) && node2.columns.length && node2.columns.every((c) => object(c) && typeof c.key === "string") && new Set(node2.columns.map((c) => c.key)).size === node2.columns.length && Array.isArray(node2.rows) && node2.rows.every((row) => Array.isArray(row) && row.length === node2.columns.length)) {\n node2.rows = node2.rows.map((row) => Object.fromEntries(node2.columns.map((c, i) => [c.key, row[i]])));\n }\n if (node2.type === "table" && Array.isArray(node2.columns) && node2.columns.length && Array.isArray(node2.rows) && node2.rows.every(Array.isArray) && node2.columns.every((c) => object(c) && Number.isInteger(c.key) && c.key >= 0) && new Set(node2.columns.map((c) => c.key)).size === node2.columns.length) {\n const columns = node2.columns.map((c) => ({ ...c, key: "col_" + c.key }));\n node2.rows = node2.rows.map((row) => Object.fromEntries(node2.columns.map((c) => ["col_" + c.key, row[c.key] ?? null])));\n node2.columns = columns;\n }\n if (node2.type === "visual" && typeof node2.id === "string") {\n node2.stateKey ??= "visual_" + node2.id;\n doc2.state ??= {};\n if (!own(doc2.state, node2.stateKey)) doc2.state[node2.stateKey] = { type: "json", default: {} };\n }\n if (node2.type === "sandbox") {\n if (!own(node2, "title")) node2.title = doc2.title;\n if (!own(node2, "fallback")) node2.fallback = doc2.fallback;\n }\n for (const field of ["children", "items", "columns", "libraries", "stateKeys", "dataKeys", "derivedKeys"]) if (own(node2, field)) node2[field] = array(node2[field]);\n if (["table", "chart"].includes(node2.type) && own(node2, "rows")) node2.rows = array(node2.rows);\n for (const field of ["decimals", "height"]) if (own(node2, field)) node2[field] = number(node2[field]);\n if (["row", "column"].includes(node2.type)) {\n if (own(node2, "gap")) node2.gap = number(node2.gap);\n if (node2.type === "row" && own(node2, "columns")) node2.columns = number(node2.columns);\n }\n if (["text", "heading", "callout"].includes(node2.type)) {\n for (const field of ["size", "weight", "lineHeight"]) if (own(node2, field)) node2[field] = number(node2[field]);\n if (own(node2, "spans")) node2.spans = array(node2.spans);\n if (Array.isArray(node2.spans)) {\n for (const span of node2.spans) if (object(span)) {\n for (const field of ["size", "weight", "lineHeight"]) if (own(span, field)) span[field] = number(span[field]);\n }\n }\n }\n if (node2.type === "details" && own(node2, "open")) node2.open = boolean(node2.open);\n if (node2.type === "text" && own(node2, "copyable")) node2.copyable = boolean(node2.copyable);\n if (node2.type === "code" && own(node2, "wrap")) node2.wrap = boolean(node2.wrap);\n if (["table", "chart"].includes(node2.type) && Array.isArray(node2.rows)) {\n for (const row of node2.rows) if (object(row)) for (const cell of Object.values(row)) expression(cell);\n }\n for (const field of ["text", "value", "max", "rows"]) if (own(node2, field)) expression(node2[field], node2.type === "progress");\n if (["row", "column", "card", "details"].includes(node2.type) && own(node2, "children")) node2.children = nodes(node2.children);\n }\n return list;\n }\n if (own(doc2, "nodes")) doc2.nodes = nodes(doc2.nodes);\n return doc2;\n }\n\n // lib/typography.js\n var TEXT_PRESETS = Object.freeze(["reading", "brief", "comparison", "list", "callout", "scorecard", "flow", "minimal"]);\n var TYPE_FIELDS = Object.freeze(["size", "weight", "color", "align", "lineHeight"]);\n var TEXT_SIZES = Object.freeze({ sm: 14, md: 16, lg: 20, xl: 26, hero: 36 });\n var TEXT_COLORS = Object.freeze({ default: "var(--du-ink)", muted: "var(--du-muted)", accent: "var(--du-accent)", success: "var(--du-green)", warning: "var(--du-amber)", danger: "var(--du-red)", violet: "var(--du-violet)" });\n function validateTypography(value, at2 = "text") {\n const fail2 = (message) => {\n throw Error(`DSH UI: ${at2}.${message}`);\n };\n if (value.size !== void 0 && !(typeof value.size === "number" && Number.isFinite(value.size) && value.size >= 12 && value.size <= 48) && !Object.hasOwn(TEXT_SIZES, value.size)) fail2("size must be 12..48 px or sm/md/lg/xl/hero");\n if (value.weight !== void 0 && ![400, 500, 600, 700, 800].includes(value.weight)) fail2("weight must be 400/500/600/700/800");\n if (value.color !== void 0 && (typeof value.color !== "string" || !Object.hasOwn(TEXT_COLORS, value.color) && !/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(value.color))) fail2("color must be default/muted/accent/success/warning/danger/violet or #RGB/#RRGGBB");\n if (value.align !== void 0 && !["left", "center", "right"].includes(value.align)) fail2("align must be left/center/right");\n if (value.lineHeight !== void 0 && !(typeof value.lineHeight === "number" && value.lineHeight >= 1.2 && value.lineHeight <= 2.4)) fail2("lineHeight must be 1.2..2.4");\n }\n\n // lib/links.js\n function validateLink(node2) {\n const fail2 = (message) => {\n throw Error("DSH UI: " + message);\n };\n if ([node2.href, node2.path, node2.action].filter((v2) => v2 !== void 0).length !== 1) fail2(`node.${node2.id}: choose exactly one href (http/https), path (file), or action (Agent follow-up)`);\n if (node2.variant !== void 0 && !["primary", "secondary", "text"].includes(node2.variant)) fail2("link/button variant must be primary/secondary/text");\n if (node2.href !== void 0) {\n if (typeof node2.href !== "string" || node2.href.length > 8192 || /[\\u0000-\\u0020\\u007f]/.test(node2.href) || !/^https?:\\/\\//i.test(node2.href)) fail2("href must be an absolute http/https URL; encode spaces");\n let url;\n try {\n url = new URL(node2.href);\n } catch {\n fail2("invalid href URL");\n }\n if (!url.hostname || url.username || url.password) fail2("href must have a host and must not contain credentials");\n }\n if (node2.path !== void 0) {\n if (typeof node2.path !== "string" || !node2.path.trim() || node2.path.length > 8192 || /[\\u0000-\\u001f\\u007f]/.test(node2.path) || /^\\s*(?:[a-z][a-z\\d+.-]*:|[\\\\/]{2})/i.test(node2.path) && !/^\\s*[a-z]:[\\\\/]/i.test(node2.path)) fail2("path must be a local file path, not a URL, network path or command");\n }\n }\n\n // lib/protocol.js\n var LIMITS = Object.freeze({ bytes: 131072, nodes: 160, depth: 12, rows: 500, expressions: 128, steps: 4096 });\n var own2 = (o, k2) => Object.hasOwn(o, k2);\n var fail = (message) => {\n throw new Error(`DSH UI: ${message}`);\n };\n var object2 = (x) => x !== null && typeof x === "object" && !Array.isArray(x);\n var finite = (x) => typeof x === "number" && Number.isFinite(x);\n var scalar = (x) => typeof x === "string" || typeof x === "boolean" || finite(x);\n var text = (x, at2) => {\n if (typeof x !== "string" || x.length > 8192) fail(`${at2} must be a string of at most 8192 characters`);\n };\n function fields(value, allowed, at2) {\n if (!object2(value)) fail(`${at2} must be an object`);\n for (const k2 of Object.keys(value)) if (!allowed.includes(k2)) {\n const hint = at2 === "document" ? " Controls and visual components belong in nodes as registered typed nodes, not extra document fields." : "";\n fail(`unknown field ${at2}.${k2}; allowed fields at ${at2}: ${allowed.join(", ")}.${hint}`);\n }\n }\n function safeJson(value, depth = 0, source = false) {\n if (depth > 48) fail("JSON nesting is too deep");\n if (value === null || typeof value === "boolean") return;\n if (typeof value === "string") {\n if (source) {\n if (value.length > SANDBOX_LIMITS.source) fail("canvas source exceeds 48 Ki characters");\n return;\n }\n return text(value, "value");\n }\n if (typeof value === "number") {\n if (!finite(value)) fail("numbers must be finite");\n return;\n }\n if (typeof value !== "object") fail("only JSON values are accepted");\n if (Array.isArray(value) && value.length > LIMITS.rows) fail("too many array items");\n for (const k2 of Object.keys(value)) {\n if (["__proto__", "prototype", "constructor"].includes(k2)) fail("unsafe property name");\n safeJson(value[k2], depth + 1, value.type === "sandbox" && ["html", "css", "script"].includes(k2));\n }\n }\n function initialState(doc2) {\n return Object.fromEntries(Object.entries(doc2.state).map(([k2, spec]) => [k2, spec.default]));\n }\n function validateState(doc2, state2) {\n if (!object2(state2) || Object.keys(state2).length !== Object.keys(doc2.state).length) fail("state keys do not match the document");\n const result = {};\n for (const [k2, s] of Object.entries(doc2.state)) {\n if (!own2(state2, k2)) fail(`missing state.${k2}`);\n const v2 = state2[k2];\n if (s.type === "number") {\n if (!finite(v2) || v2 < s.min || v2 > s.max) fail(`state.${k2} is outside its numeric range`);\n const offset = (v2 - s.min) / s.step;\n if (Math.abs(offset - Math.round(offset)) > 1e-6) fail(`state.${k2} does not match its step`);\n } else if (s.type === "json") {\n if (!object2(v2) && !Array.isArray(v2)) fail(`state.${k2} must be an array or object for type json`);\n safeJson(v2);\n if (new TextEncoder().encode(JSON.stringify(v2)).length > 16384) fail(`state.${k2} JSON exceeds 16 KiB`);\n } else if (s.type === "string") text(v2, `state.${k2}`);\n else if (typeof v2 !== "boolean") fail(`state.${k2} must be boolean`);\n if (s.options && !s.options.includes(v2)) fail(`invalid option for state.${k2}`);\n result[k2] = v2;\n }\n return result;\n }\n var ARITY = { add: [1, 8], sub: [2, 2], mul: [1, 8], div: [2, 2], min: [1, 8], max: [1, 8], round: [1, 1], ceil: [1, 1], floor: [1, 1], abs: [1, 1], eq: [2, 2], neq: [2, 2], lt: [2, 2], lte: [2, 2], gt: [2, 2], gte: [2, 2], if: [3, 3] };\n function reference(doc2, ref) {\n if (typeof ref !== "string" || !["state", "data", "derived"].includes(ref.split(".")[0]) || ref.split(".").length !== 2 || !validIdentifier(ref.split(".")[1])) fail(`invalid reference ${JSON.stringify(ref)}; use state.key, data.key or derived.key with a letter/underscore identifier`);\n const [group, k2] = ref.split(".");\n if (!own2(doc2[group], k2)) fail(`unknown reference ${ref}`);\n return [group, k2];\n }\n function evaluate(doc2, state2) {\n const derived = {}, active = /* @__PURE__ */ new Set();\n let steps = 0, generatedRows = 0;\n const budget = () => {\n if (++steps > LIMITS.steps) fail("calculation budget exceeded");\n };\n const resolve = (ref) => {\n budget();\n const [group, k2] = reference(doc2, ref);\n if (group !== "derived") return (group === "state" ? state2 : doc2.data)[k2];\n if (own2(derived, k2)) return derived[k2];\n if (active.has(k2)) fail(`cyclic calculation ${k2}`);\n active.add(k2);\n const result2 = expression2(doc2.derived[k2]);\n active.delete(k2);\n derived[k2] = result2;\n return result2;\n };\n const expression2 = (e, item) => {\n budget();\n if (own2(e, "map")) {\n const rows = resolve(e.map.source);\n if ((generatedRows += rows.length) > LIMITS.rows) fail("generated row limit exceeded");\n return rows.map((row) => Object.fromEntries(Object.entries(e.map.fields).map(([k2, value]) => {\n const out2 = expression2(value, row);\n if (!scalar(out2)) fail("generated cells must be scalar");\n return [k2, out2];\n })));\n }\n if (own2(e, "const")) return e.const;\n if (own2(e, "ref")) {\n if (e.ref.startsWith("item.")) {\n const k2 = e.ref.slice(5);\n if (!item || !own2(item, k2) || !scalar(item[k2])) fail("invalid item reference");\n return item[k2];\n }\n return resolve(e.ref);\n }\n if (e.op === "if") {\n const condition = expression2(e.args[0], item);\n if (typeof condition !== "boolean") fail("if condition must be boolean");\n return expression2(e.args[condition ? 1 : 2], item);\n }\n const a = e.args.map((arg) => expression2(arg, item));\n if (e.op === "eq") return a[0] === a[1];\n if (e.op === "neq") return a[0] !== a[1];\n if (!a.every(finite)) fail(`operator ${e.op} requires finite numbers`);\n let out;\n switch (e.op) {\n case "add":\n out = a.reduce((x, y2) => x + y2, 0);\n break;\n case "sub":\n out = a[0] - a[1];\n break;\n case "mul":\n out = a.reduce((x, y2) => x * y2, 1);\n break;\n case "div":\n if (a[1] === 0) fail("division by zero");\n out = a[0] / a[1];\n break;\n case "min":\n out = Math.min(...a);\n break;\n case "max":\n out = Math.max(...a);\n break;\n case "round":\n out = Math.round(a[0]);\n break;\n case "ceil":\n out = Math.ceil(a[0]);\n break;\n case "floor":\n out = Math.floor(a[0]);\n break;\n case "abs":\n out = Math.abs(a[0]);\n break;\n case "lt":\n return a[0] < a[1];\n case "lte":\n return a[0] <= a[1];\n case "gt":\n return a[0] > a[1];\n case "gte":\n return a[0] >= a[1];\n default:\n fail(`unsupported operator ${e.op}`);\n }\n if (!finite(out)) fail("non-finite calculation result");\n return out;\n };\n for (const k2 of Object.keys(doc2.derived)) resolve(`derived.${k2}`);\n if (new TextEncoder().encode(JSON.stringify(derived)).length > LIMITS.bytes) fail("derived output exceeds 128 KiB");\n const resolveCell = (cell) => {\n const out = expression2(cell);\n if (!scalar(out)) fail("inline row formula cells must resolve to a string, boolean or finite number");\n return out;\n };\n const result = { derived, resolveValue: (value) => {\n if (Array.isArray(value)) return value.map((row) => object2(row) ? Object.fromEntries(Object.entries(row).map(([k2, cell]) => [k2, object2(cell) && ["const", "ref", "op"].some((field) => own2(cell, field)) ? resolveCell(cell) : cell])) : row);\n if (!object2(value)) return value;\n return expression2(value);\n } };\n checkViewValues(doc2, result);\n return result;\n }\n function checkViewValues(doc2, evaluated) {\n function walk(list) {\n for (const n of list) {\n if (n.type === "table" || n.type === "chart") {\n const rows = evaluated.resolveValue(n.rows);\n if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object2)) fail("table/chart rows must reference an array of objects");\n if (n.type === "chart") {\n const index = rows.findIndex((r) => !own2(r, n.labelKey) || !scalar(r[n.labelKey]) || !own2(r, n.valueKey) || !finite(r[n.valueKey]));\n if (index >= 0) {\n const row = rows[index], missing = [n.labelKey, n.valueKey].filter((k2) => !own2(row, k2));\n fail("chart requires labels and finite numeric values. node." + n.id + ".rows[" + index + "]: " + (missing.length ? "missing field(s) " + missing.join(", ") : n.valueKey + " must resolve to a finite number") + ". Available keys: " + Object.keys(row).slice(0, 16).join(", ") + ". For live values use inline rows:[{" + n.labelKey + \':"\\u9879\\u76EE",\' + n.valueKey + \':{ref:"derived.amount"}}]; static data labels alone contain no amounts. Keep all nodes/state/derived when correcting the document\');\n }\n }\n if (n.type === "chart" && n.xScale === "linear" && rows.some((r) => !finite(r[n.labelKey]))) fail("linear chart requires numeric x values");\n }\n if (n.type === "metric" && !scalar(evaluated.resolveValue(n.value))) fail(`node.${n.id}.value must resolve to a number, string or boolean; use table for rows or a canvas for structured data`);\n if (n.type === "progress") {\n const v2 = evaluated.resolveValue(n.value), max = evaluated.resolveValue(n.max);\n if (!finite(v2) || !finite(max) || max <= 0 || v2 < 0 || v2 > max) fail("progress requires 0 <= value <= positive max");\n }\n if (n.children) walk(n.children);\n }\n }\n walk(doc2.nodes);\n }\n function validateDocument(input) {\n safeJson(input);\n const json = JSON.stringify(input);\n if (new TextEncoder().encode(json).length > LIMITS.bytes) fail("document exceeds 128 KiB");\n const normalized = normalizeAuthoring(JSON.parse(json));\n safeJson(normalized);\n const doc2 = expandExpressions(normalized);\n fields(doc2, ["version", "title", "fallback", "state", "data", "derived", "nodes", "actions", "presentation"], "document");\n if (doc2.presentation !== void 0) {\n fields(doc2.presentation, ["layout", "accent", "density", "preset"], "presentation");\n if (doc2.presentation.preset !== void 0 && !TEXT_PRESETS.includes(doc2.presentation.preset)) fail("unknown presentation preset; use " + TEXT_PRESETS.join("/"));\n for (const [k2, allowed] of Object.entries({ layout: UI_LAYOUTS, accent: UI_ACCENTS, density: ["comfortable", "compact"] }))\n if (doc2.presentation[k2] !== void 0 && !allowed.includes(doc2.presentation[k2])) fail(`unknown presentation ${k2}`);\n }\n if (doc2.version !== 1) fail(own2(doc2, "version") ? "document.version must be 1" : "document.version is missing. render_ui creates a complete document, not a partial patch: send {version:1,title,fallback,nodes:[...]} for shared controls/formulas, or {title,items:[...]} for extended visuals. Include all content, not only data/derived");\n text(doc2.title, "title");\n text(doc2.fallback, "fallback");\n if (!doc2.title.trim() || !doc2.fallback.trim()) fail("title and fallback cannot be empty");\n for (const group of ["state", "data", "derived", "actions"]) {\n doc2[group] ??= {};\n if (!object2(doc2[group]) || Object.keys(doc2[group]).length > 64) fail(`invalid ${group}`);\n for (const k2 of Object.keys(doc2[group])) if (!validIdentifier(k2)) fail(`invalid key in ${group}: ${JSON.stringify(k2)}; use 1..64 letters, numbers or underscores, starting with a letter/underscore (Chinese letters supported); no spaces, dots or hyphens. Put display labels in label/text`);\n }\n for (const [k2, s] of Object.entries(doc2.state)) {\n fields(s, ["type", "default", "min", "max", "step", "options"], `state.${k2}`);\n if (s.type === "string" && (Array.isArray(s.default) || object2(s.default)) && !own2(s, "options")) s.type = "json";\n if (!["number", "string", "boolean", "json"].includes(s.type)) fail(`unsupported state type ${k2}; use number, string, boolean or json (arrays/objects)`);\n if (s.type === "json" && own2(s, "options")) fail(`state.${k2}: json state does not support select options; use scalar options or a canvas`);\n if (s.type === "number") {\n for (const field of ["default", "min", "max", "step"]) if (!finite(s[field])) fail(`state.${k2}.${field} must be a finite JSON number; received ${s[field] === null ? "null" : typeof s[field]}. Supply {type:"number",default:2,min:1,max:12,step:1}; do not omit limits or include units in numeric fields`);\n if (s.min >= s.max || s.step <= 0) fail(`invalid numeric limits for state.${k2}: require min < max and step > 0; received min=${s.min}, max=${s.max}, step=${s.step}`);\n if ((s.max - s.min) / s.step > 1e9) fail(`numeric step too small for ${k2}`);\n } else if (["min", "max", "step"].some((p2) => own2(s, p2))) fail(`numeric limits on non-number ${k2}`);\n if (s.options !== void 0 && (!Array.isArray(s.options) || !s.options.length || s.options.length > 64 || !s.options.every(scalar))) fail(`state.${k2}.options must be a direct array of 1..64 scalar values, e.g. options:["3","5","7"], not {item:[...]}`);\n }\n const defaults = validateState(doc2, initialState(doc2));\n let expressions = 0;\n const expressionShapes = /* @__PURE__ */ new Set();\n for (const [k2, spec] of Object.entries(doc2.state))\n for (const option of spec.options ?? []) validateState(doc2, { ...defaults, [k2]: option });\n function validateExpression(e, depth = 0, itemRows, at2 = "expression") {\n if (depth > LIMITS.depth) fail(at2 + ": expression nesting exceeds " + LIMITS.depth);\n const shape = JSON.stringify(e);\n if (!expressionShapes.has(shape)) {\n expressionShapes.add(shape);\n if (++expressions > LIMITS.expressions) fail(at2 + ": expression limit exceeded (128 distinct expressions). Reuse derived references instead of expanding long formulas; keep the complete document when retrying");\n }\n if (!object2(e)) fail(`${at2}: expression must be an object`);\n if (own2(e, "map")) {\n if (depth !== 0) fail("map is only allowed at the root of a derived value");\n fields(e, ["map"], "expression");\n fields(e.map, ["source", "fields"], "map");\n if (typeof e.map.source !== "string" || !e.map.source.startsWith("data.")) fail(\'map source must reference static data using a string such as "data.samples"; put object rows in document.data.samples, not inline in map.source\');\n const [, k2] = reference(doc2, e.map.source), rows = doc2.data[k2];\n if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object2)) fail("map source must be object rows");\n if (!object2(e.map.fields) || !Object.keys(e.map.fields).length || Object.keys(e.map.fields).length > 16) fail("map requires 1..16 fields");\n for (const [k3, value2] of Object.entries(e.map.fields)) {\n if (!validIdentifier(k3)) fail(`invalid map field ${JSON.stringify(k3).slice(0, 100)}; use a letter/underscore identifier such as powerW or \\u529F\\u7387, without spaces, dots or hyphens`);\n validateExpression(value2, depth + 1, rows, `${at2}.map.fields.${k3}`);\n }\n return;\n }\n if (own2(e, "const")) {\n fields(e, ["const"], "expression");\n if (!scalar(e.const)) fail("constant must be scalar");\n return;\n }\n if (own2(e, "ref")) {\n fields(e, ["ref"], "expression");\n if (typeof e.ref === "string" && e.ref.startsWith("item.")) {\n const k2 = e.ref.slice(5);\n if (!itemRows || !validIdentifier(k2) || itemRows.some((row) => !own2(row, k2) || !scalar(row[k2]))) fail("invalid or unscoped item reference");\n } else reference(doc2, e.ref);\n return;\n }\n fields(e, ["op", "args"], "expression");\n const arity = ARITY[e.op];\n if (!arity || !Array.isArray(e.args) || e.args.length < arity[0] || e.args.length > arity[1]) fail(`${at2}: invalid operator or argument count for ${JSON.stringify(e.op)}; args must be a direct array${arity ? ` with ${arity[0]}..${arity[1]} expressions` : " and op must be registered"}. Received ${Array.isArray(e.args) ? e.args.length + " arguments" : typeof e.args}. Prefer {expr:"state.people * state.days"} for arithmetic; missing operands cannot be inferred`);\n e.args.forEach((a, i) => validateExpression(a, depth + 1, itemRows, `${at2}.args[${i}]`));\n }\n Object.entries(doc2.derived).forEach(([k2, e]) => validateExpression(e, 0, void 0, `derived.${k2}`));\n const visited = /* @__PURE__ */ new Set(), active = /* @__PURE__ */ new Set();\n function visit(k2) {\n if (active.has(k2)) fail(`cyclic calculation ${k2}`);\n if (visited.has(k2)) return;\n active.add(k2);\n function walk(e) {\n if (e.ref?.startsWith("derived.")) visit(e.ref.split(".")[1]);\n for (const a of e.args ?? []) walk(a);\n for (const value2 of Object.values(e.map?.fields ?? {})) walk(value2);\n }\n walk(doc2.derived[k2]);\n active.delete(k2);\n visited.add(k2);\n }\n Object.keys(doc2.derived).forEach(visit);\n for (const [k2, a] of Object.entries(doc2.actions)) {\n fields(a, ["type", "intent", "stateKeys"], `actions.${k2}`);\n if (a.type !== "agent.followup") fail("only agent.followup actions are supported");\n text(a.intent, "action intent");\n if (!a.intent.trim() || !Array.isArray(a.stateKeys) || a.stateKeys.length > 64 || new Set(a.stateKeys).size !== a.stateKeys.length || a.stateKeys.some((s) => !own2(doc2.state, s))) fail("invalid action stateKeys");\n }\n const ids = /* @__PURE__ */ new Map();\n let count2 = 0;\n const value = (v2, at2) => {\n if (object2(v2)) {\n if (own2(v2, "map")) fail("map belongs in derived");\n validateExpression(v2, 0, void 0, at2);\n } else if (!scalar(v2)) fail(`invalid value at ${at2}`);\n };\n function nodes(list, depth = 0, path = "nodes") {\n if (!Array.isArray(list)) fail(path === "nodes" ? \'document.nodes is missing or is not an array. State/derived define values but do not create visible UI. Include nodes:[{id:"heading",type:"heading",text:"..."},...] and actual controls in the SAME complete document; do not resend state/data/derived alone. Declared state keys: \' + Object.keys(doc2.state).join(", ") : path + " must be an array of child nodes; use children:[{id,type,...}]");\n if (depth > LIMITS.depth) fail(path + " exceeds maximum node depth " + LIMITS.depth);\n for (const [index, n] of list.entries()) {\n const at2 = `${path}[${index}]`;\n if (++count2 > LIMITS.nodes) fail("too many nodes");\n if (!object2(n)) fail(`${at2} must be a node object`);\n if (!own2(n, "id")) fail(`${at2}.id is missing (type=${JSON.stringify(n.type)}). Every node, including sandbox, needs its own id; add e.g. id:"canvas". JSON field order does not matter`);\n if (!validIdentifier(n.id)) fail(`${at2}.id is invalid: ${JSON.stringify(n.id)}. Use 1..64 letters/numbers/underscores starting with a letter/underscore`);\n if (ids.has(n.id)) fail(`${at2}.id duplicates ${JSON.stringify(n.id)} first declared at ${ids.get(n.id)}. Give each node a unique id; state keys and node ids are separate namespaces`);\n ids.set(n.id, `${at2}.id`);\n if (!Object.hasOwn(COMPONENTS, n.type)) fail("unsupported component " + n.type);\n if (["table", "chart"].includes(n.type) && typeof n.rows === "string" && /^(data|derived)\\./.test(n.rows)) n.rows = { ref: n.rows };\n switch (n.type) {\n case "visual": {\n const previous = Array.isArray(n.warnings) ? n.warnings.filter((x) => typeof x === "string").map((x) => x.slice(0, 512)).slice(0, 12) : [];\n const checked = validateVisual(n.spec);\n n.spec = checked.spec;\n n.warnings = [.../* @__PURE__ */ new Set([...previous, ...checked.warnings])].slice(0, 12);\n count2 += checked.count;\n if (count2 > LIMITS.nodes) fail("too many nodes, including visual components");\n if (!validIdentifier(n.stateKey) || doc2.state[n.stateKey]?.type !== "json") fail("visual requires its own json stateKey");\n break;\n }\n case "sandbox": {\n text(n.title, `${at2}.title (canvas title)`);\n text(n.fallback, `${at2}.fallback (canvas fallback)`);\n if (!n.title.trim()) fail(`${at2}.title must not be empty`);\n if (!n.fallback.trim()) fail(`${at2}.fallback must not be empty`);\n if (typeof n.html !== "string" || !n.html.trim()) fail(`${at2}.html must be a non-empty HTML string; script/css/fallback belong beside html on the sandbox node, not inside it`);\n for (const field of ["html", "css", "script"]) if (n[field] !== void 0 && (typeof n[field] !== "string" || n[field].length > SANDBOX_LIMITS.source)) fail("canvas source exceeds 48 Ki characters");\n if (n.libraries !== void 0 && (!Array.isArray(n.libraries) || n.libraries.length > 1 || n.libraries.some((v2) => v2 !== "mechanism"))) fail(\'canvas libraries supports only ["mechanism"] or []\');\n if (n.height !== void 0 && (!Number.isInteger(n.height) || n.height < 160 || n.height > SANDBOX_LIMITS.height)) fail("canvas height must be 160..1000");\n for (const [field, group] of [["stateKeys", "state"], ["dataKeys", "data"], ["derivedKeys", "derived"]]) if (n[field] !== void 0 && (!Array.isArray(n[field]) || n[field].length > 64 || new Set(n[field]).size !== n[field].length || n[field].some((k2) => !own2(doc2[group], k2)))) fail("invalid canvas " + field);\n break;\n }\n case "row":\n case "column":\n if (n.gap !== void 0 && !(typeof n.gap === "number" && Number.isFinite(n.gap) && n.gap >= 0 && n.gap <= 40)) fail("gap must be 0..40 pixels");\n if (n.columns !== void 0 && (!Number.isInteger(n.columns) || n.columns < 1 || n.columns > 4)) fail("columns must be 1..4");\n break;\n case "card":\n if (n.title !== void 0) text(n.title, "card title");\n if (n.surface !== void 0 && !UI_SURFACES.includes(n.surface)) fail("unknown card surface");\n break;\n case "details":\n text(n.title, "details title");\n if (n.open === "true" || n.open === "false") n.open = n.open === "true";\n if (n.open !== void 0 && typeof n.open !== "boolean") fail(`node.${n.id}.open must be boolean true or false`);\n break;\n case "badge":\n value(n.text, "badge text");\n break;\n case "progress":\n text(n.label, "progress label");\n value(n.value, "progress value");\n value(n.max, "progress max");\n if (n.unit !== void 0) text(n.unit, "progress unit");\n break;\n case "steps": {\n if (n.title !== void 0) text(n.title, "steps title");\n const at3 = `node.${n.id}.items`;\n if (!Array.isArray(n.items)) fail(`${at3} must be an array of 1..12 step objects, received ${n.items === null ? "null" : typeof n.items}. Use items:[{"title":"First step","description":"One sentence"}], not items:{item:[...]}. status is optional for a static guide`);\n if (!n.items.length || n.items.length > 12) fail(`${at3} requires 1..12 items; received ${n.items.length}. Split a longer guide into separate steps nodes`);\n for (const [i, item] of n.items.entries()) {\n const stepAt = `${at3}[${i}]`;\n fields(item, ["title", "description", "status"], stepAt);\n text(item.title, `${stepAt}.title`);\n if (item.description !== void 0) text(item.description, `${stepAt}.description`);\n if (item.status !== void 0 && !["pending", "active", "done", "error"].includes(item.status)) fail(`${stepAt}.status must be pending, active, done or error; omit status for a static guide`);\n }\n break;\n }\n case "heading":\n case "text":\n case "callout":\n if (n.type === "text") {\n if (n.title !== void 0) text(n.title, "text block title");\n if (n.copyable !== void 0 && typeof n.copyable !== "boolean") fail("copyable must be boolean");\n }\n validateTypography(n, `node.${n.id}`);\n if (n.spans !== void 0) {\n if (n.text !== void 0) fail(`node.${n.id}: use text or spans, not both`);\n if (!Array.isArray(n.spans) || !n.spans.length || n.spans.length > 80) fail("spans must contain 1..80 text fragments");\n for (const [i, span] of n.spans.entries()) {\n fields(span, ["text", ...TYPE_FIELDS], `node.${n.id}.spans[${i}]`);\n text(span.text, "span text");\n validateTypography(span, `node.${n.id}.spans[${i}]`);\n }\n } else value(n.text, "text");\n break;\n case "metric":\n text(n.label, "metric label");\n value(n.value, "metric value");\n if (n.unit !== void 0) text(n.unit, "unit");\n if (n.decimals !== void 0 && (!Number.isInteger(n.decimals) || n.decimals < 0 || n.decimals > 6)) fail("invalid decimals");\n break;\n case "input":\n case "slider":\n case "select":\n case "toggle": {\n text(n.label, "control label");\n if (typeof n.bind !== "string" || !n.bind.startsWith("state.")) fail("controls must bind state");\n const [, k2] = reference(doc2, n.bind), spec = doc2.state[k2];\n if (n.type === "slider" && spec.type !== "number") fail("slider requires numeric state");\n if (n.type === "toggle" && spec.type !== "boolean") fail("toggle requires boolean state");\n if (["input", "select"].includes(n.type) && spec.type === "json") fail(`node.${n.id}: structured state requires a sandbox with DSHUI.setState; use separate boolean states and toggle nodes for a native checklist`);\n if (n.type === "input" && spec.type === "boolean") fail("use toggle for boolean state");\n if (n.type === "select" && !spec.options) fail("select requires options");\n if (n.type === "select" && n.variant !== void 0 && !["dropdown", "segmented"].includes(n.variant)) fail(`node.${n.id}.variant must be dropdown or segmented`);\n break;\n }\n case "code":\n if (typeof n.code !== "string" || n.code.length > SANDBOX_LIMITS.source) fail("code must be a string of at most 48 Ki characters");\n if (n.lang !== void 0) text(n.lang, "code language");\n if (n.title !== void 0) text(n.title, "code title");\n if (n.wrap !== void 0 && typeof n.wrap !== "boolean") fail("code wrap must be boolean");\n break;\n case "button":\n case "link":\n text(n.text, "button text");\n validateLink(n);\n if (n.action !== void 0 && !own2(doc2.actions, n.action)) fail("unknown action");\n break;\n case "divider":\n if (n.label !== void 0) text(n.label, "divider label");\n break;\n case "table": {\n if (n.label !== void 0) text(n.label, "table label");\n if (!Array.isArray(n.rows)) value(n.rows, "node." + n.id + ".rows");\n if (!Array.isArray(n.columns) || !n.columns.length || n.columns.length > 16) fail("invalid table columns");\n const cols = /* @__PURE__ */ new Set();\n for (const c of n.columns) {\n fields(c, ["key", "label", "unit"], "column");\n if (!validIdentifier(c.key) || cols.has(c.key)) fail("invalid or duplicate column key");\n cols.add(c.key);\n text(c.label, "column label");\n if (c.unit !== void 0) text(c.unit, "column unit");\n }\n break;\n }\n case "chart":\n if (n.rows === void 0) fail("node." + n.id + \'.rows is missing; supply rows:[{label:"\\u9879\\u76EE",value:123}] or a rows binding, plus labelKey/valueKey matching its fields. Do not invent missing amounts\');\n if (!Array.isArray(n.rows)) value(n.rows, "node." + n.id + ".rows");\n if (!["bar", "line"].includes(n.kind) || !validIdentifier(n.labelKey) || !validIdentifier(n.valueKey)) fail("invalid chart");\n text(n.label, "chart label");\n if (n.unit !== void 0) text(n.unit, "chart unit");\n if (n.xScale !== void 0 && (!["category", "linear"].includes(n.xScale) || n.xScale === "linear" && n.kind !== "line")) fail("invalid xScale");\n break;\n default:\n fail(`unsupported component ${n.type}`);\n }\n if (["heading", "text", "callout", "card", "metric", "button", "link", "badge", "progress", "details"].includes(n.type)) {\n if (n.icon !== void 0 && !UI_ICONS.includes(n.icon)) fail("unknown UI icon");\n if (!["button", "link"].includes(n.type)) {\n if (n.tone !== void 0 && !UI_TONES.includes(n.tone)) fail("unknown UI tone");\n }\n }\n if (["table", "chart"].includes(n.type) && Array.isArray(n.rows)) {\n for (const [i, row] of n.rows.entries()) if (object2(row)) {\n for (const [k2, cell] of Object.entries(row)) if (object2(cell) && ["const", "ref", "op"].some((field) => own2(cell, field))) value(cell, at2 + ".rows[" + i + "]." + k2);\n }\n }\n fields(n, componentFields(n.type), `node.${n.id}`);\n if (["row", "column", "card", "details"].includes(n.type)) nodes(n.children, depth + 1, `${at2}.children`);\n }\n }\n nodes(doc2.nodes);\n if (!count2) fail("at least one node is required");\n evaluate(doc2, defaults);\n return doc2;\n }\n\n // src/export-runtime.js\n var payload = JSON.parse(document.getElementById("dsh-ui-export").textContent);\n var doc = validateDocument(payload.document);\n var node = doc.nodes.flatMap(function flatten(n) {\n return [n, ...(n.children ?? []).flatMap(flatten)];\n }).find((n) => n.id === payload.nodeId && n.type === "sandbox");\n if (!node) throw Error("\\u5BFC\\u51FA\\u7684\\u753B\\u5E03\\u4E0D\\u5B58\\u5728");\n var state = validateState(doc, payload.state);\n var connected = false;\n var start = Date.now();\n var count = 0;\n var token = () => Array.from(crypto.getRandomValues(new Uint8Array(16)), (b2) => b2.toString(16).padStart(2, "0")).join("");\n var channel = token();\n var nonce = payload.nonce;\n var frame = document.createElement("iframe");\n frame.title = node.title;\n frame.sandbox = "allow-scripts";\n frame.referrerPolicy = "no-referrer";\n frame.style.cssText = "display:block;width:100%;height:" + (node.height ?? 420) + "px;border:0";\n var status = document.getElementById("status");\n var publish = () => {\n try {\n frame.contentWindow.postMessage({ dshCanvas: 1, channel, type: "snapshot", payload: { ...canvasSnapshot(node, state, doc.data, evaluate(doc, state).derived, false, payload.theme), visible: !document.hidden } }, "*");\n } catch (e) {\n status.textContent = "\\u8BA1\\u7B97\\u5931\\u8D25\\uFF1A" + e.message;\n }\n };\n addEventListener("message", (event) => {\n const m2 = event.data;\n if (event.source !== frame.contentWindow || m2?.channel !== channel || m2.dshCanvas !== 1) return;\n if (Date.now() - start > 1e3) {\n start = Date.now();\n count = 0;\n }\n if (++count > SANDBOX_LIMITS.rate) return;\n if (m2.type === "ready") {\n connected = true;\n publish();\n } else if (m2.type === "patch" && connected) {\n try {\n const next = validateState(doc, { ...state, ...canvasPatch(m2.payload, node) });\n evaluate(doc, next);\n state = next;\n status.textContent = "\\u672C\\u5730\\u53C2\\u6570\\u5DF2\\u66F4\\u65B0\\uFF1B\\u5237\\u65B0\\u6587\\u4EF6\\u4F1A\\u56DE\\u5230\\u5BFC\\u51FA\\u65F6\\u7684\\u53C2\\u6570\\u3002";\n } catch (e) {\n status.textContent = "\\u53C2\\u6570\\u65E0\\u6548\\uFF1A" + e.message;\n }\n publish();\n } else if (m2.type === "height" && Number.isFinite(m2.payload) && m2.payload >= 0) frame.style.height = Math.max(32, Math.min(1e3, Math.ceil(m2.payload))) + "px";\n else if (m2.type === "error") status.textContent = "\\u753B\\u5E03\\u8FD0\\u884C\\u5F02\\u5E38\\uFF1A" + String(m2.payload).slice(0, 1e3);\n });\n document.addEventListener("visibilitychange", () => {\n if (connected) publish();\n });\n document.getElementById("surface").append(frame);\n frame.srcdoc = sandboxDocument(node, channel, nonce);\n})();\n';
|
|
3502
3573
|
|
|
3503
3574
|
// lib/canvas-export.js
|
|
3504
|
-
function standaloneCanvas(document2, node,
|
|
3505
|
-
validateState(document2,
|
|
3575
|
+
function standaloneCanvas(document2, node, state2, theme = {}) {
|
|
3576
|
+
validateState(document2, state2);
|
|
3506
3577
|
const token = Array.from(crypto.getRandomValues(new Uint8Array(16)), (b2) => b2.toString(16).padStart(2, "0")).join("");
|
|
3507
|
-
const json = JSON.stringify({ document: document2, nodeId: node.id, state, theme, nonce: token }).replace(/</g, "\\u003c");
|
|
3578
|
+
const json = JSON.stringify({ document: document2, nodeId: node.id, state: state2, theme, nonce: token }).replace(/</g, "\\u003c");
|
|
3508
3579
|
const escape = (s) => String(s).replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
3509
3580
|
return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta http-equiv="Content-Security-Policy" content="default-src 'none';script-src 'nonce-${token}';style-src 'unsafe-inline';frame-src 'self';base-uri 'none';form-action 'none'"><title>${escape(node.title)}</title><style>body{margin:0;padding:24px;background:${theme.scheme === "dark" ? "#161b23" : "#f4f6fa"};color:${theme.scheme === "dark" ? "#e6edf6" : "#182537"};font:14px/1.6 system-ui,sans-serif}main{max-width:1100px;margin:auto}h1{font-size:22px}p{overflow-wrap:anywhere}#surface{background:${theme.scheme === "dark" ? "#161b23" : "#fff"};border-radius:12px;overflow:hidden}#status{min-height:1.6em}</style></head><body><main><h1>${escape(node.title)}</h1><p>DSH Motion UI \xB7 \u72EC\u7ACB\u526F\u672C\u3002\u5305\u542B\u5BFC\u51FA\u65F6\u53C2\u6570\uFF0C\u672C\u5730\u4EA4\u4E92\u4E0D\u4F1A\u4FDD\u5B58\u5230 DSH\uFF0C\u4E5F\u4E0D\u4F1A\u8C03\u7528 Agent\u3002</p><div id="surface"></div><p id="status" role="status"></p><details><summary>\u6587\u5B57\u8BF4\u660E</summary><p>${escape(node.fallback)}</p></details></main><script type="application/json" id="dsh-ui-export">${json}<\/script><script nonce="${token}">${EXPORT_RUNTIME.replace(/<\/script/gi, "<\\/script")}<\/script></body></html>`;
|
|
3510
3581
|
}
|
|
@@ -3529,11 +3600,11 @@ function grammarPrompt(id2) {
|
|
|
3529
3600
|
\u8868\u9762\u4E0E\u8FB9\u754C\uFF1A${g.surfaces}
|
|
3530
3601
|
\u63A7\u4EF6\u4E0E\u53CD\u9988\uFF1A${g.controls}
|
|
3531
3602
|
\u907F\u514D\uFF1A${g.avoid}
|
|
3532
|
-
\u540C\u4E00\u4EFB\u52A1\
|
|
3603
|
+
\u540C\u4E00\u4EFB\u52A1\u5E94\u6709\u53EF\u8FA8\u8BC6\u7684\u6784\u56FE\u4E0E\u5C42\u7EA7\uFF0C\u4E0D\u80FD\u53EA\u6362\u5F3A\u8C03\u8272\u3002\u4FDD\u6301\u5185\u5BB9\u548CDOM\u9605\u8BFB\u987A\u5E8F\u3002\u539F\u751F\u4EA4\u4E92\u5171\u7528\uFF0C\u8282\u594F\u968F\u98CE\u683C\u53D8\u5316\uFF1B\u7981\u6B62\u73BB\u7483\u3002\u793A\u4F8B\u5C55\u793A\u8BED\u8A00\uFF0C\u4E0D\u8981\u6C42\u6BCF\u6B21\u4F7F\u7528\u5168\u90E8\u6A21\u5757\u3002`;
|
|
3533
3604
|
}
|
|
3534
3605
|
function grammarExample(id2) {
|
|
3535
3606
|
const heading = { type: "heading", text: "\u5148\u4EA4\u4ED8\u4E00\u4E2A\u53EF\u7528\u7248\u672C" }, body = { type: "text", text: "\u628A\u76EE\u6807\u7F29\u5C0F\uFF0C\u628A\u5173\u952E\u4F53\u9A8C\u505A\u597D\u3002" }, note = { type: "text", text: "\u5148\u9A8C\u8BC1\uFF0C\u518D\u9010\u6B65\u5B8C\u5584\u3002", color: "muted" };
|
|
3536
|
-
const choice = (title,
|
|
3607
|
+
const choice = (title, text3) => ({ type: "card", title, children: [{ type: "text", text: text3 }] });
|
|
3537
3608
|
const choices = [choice("\u5148\u505A\u5C0F\u7248\u672C", "\u9A8C\u8BC1\u91CD\u70B9"), choice("\u5148\u94FA\u5168\u529F\u80FD", "\u8986\u76D6\u9700\u6C42")];
|
|
3538
3609
|
const metrics = [{ type: "metric", label: "\u63A8\u8FDB\u9636\u6BB5", value: 3, unit: "\u6B65" }, { type: "metric", label: "\u6838\u5FC3\u76EE\u6807", value: 1, unit: "\u4E2A" }];
|
|
3539
3610
|
const flow = { type: "steps", items: [{ title: "\u660E\u786E\u76EE\u6807", description: "\u5148\u6293\u4F4F\u91CD\u70B9\u3002" }, { title: "\u89E3\u91CA\u5173\u7CFB", description: "\u7528\u56FE\u5F62\u8BF4\u660E\u3002" }, { title: "\u7ED9\u51FA\u884C\u52A8", description: "\u6536\u6210\u4E0B\u4E00\u6B65\u3002" }] };
|
|
@@ -3745,7 +3816,7 @@ function ActionMenu({ label, children }) {
|
|
|
3745
3816
|
// src/sandbox.js
|
|
3746
3817
|
var h6 = import_react8.default.createElement;
|
|
3747
3818
|
var randomToken = () => Array.from(crypto.getRandomValues(new Uint8Array(16)), (b2) => b2.toString(16).padStart(2, "0")).join("");
|
|
3748
|
-
function Sandbox({ node, document: doc, state, data, derived, disabled, preview, update, onAudit }) {
|
|
3819
|
+
function Sandbox({ node, document: doc, state: state2, data, derived, disabled, preview, update, onAudit }) {
|
|
3749
3820
|
const showDetails = useViewDetails();
|
|
3750
3821
|
const frame2 = (0, import_react8.useRef)(null), latest = (0, import_react8.useRef)(null), connected = (0, import_react8.useRef)(false), loads = (0, import_react8.useRef)(0), visible = (0, import_react8.useRef)(true), errorKind = (0, import_react8.useRef)("");
|
|
3751
3822
|
const [error, setError] = (0, import_react8.useState)(""), [stopped, setStopped] = (0, import_react8.useState)(false), [generation, setGeneration] = (0, import_react8.useState)(0);
|
|
@@ -3755,7 +3826,7 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
|
|
|
3755
3826
|
const sourceKey = JSON.stringify(node);
|
|
3756
3827
|
const config = (0, import_react8.useMemo)(() => ({ channel: randomToken(), nonce: randomToken() }), [sourceKey, generation]);
|
|
3757
3828
|
const srcDoc = (0, import_react8.useMemo)(() => sandboxDocument(node, config.channel, config.nonce), [sourceKey, config]);
|
|
3758
|
-
latest.current = { node, state, data, derived, disabled, update, onAudit };
|
|
3829
|
+
latest.current = { node, state: state2, data, derived, disabled, update, onAudit };
|
|
3759
3830
|
const publish2 = () => {
|
|
3760
3831
|
const el = frame2.current, current2 = latest.current;
|
|
3761
3832
|
if (!el || !connected.current) return;
|
|
@@ -3841,7 +3912,7 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
|
|
|
3841
3912
|
}, [config, preview, stopped]);
|
|
3842
3913
|
(0, import_react8.useEffect)(() => {
|
|
3843
3914
|
publish2();
|
|
3844
|
-
}, [
|
|
3915
|
+
}, [state2, data, derived, disabled, config, token]);
|
|
3845
3916
|
const inactive = preview || stopped;
|
|
3846
3917
|
const restart = () => {
|
|
3847
3918
|
setStopped(false);
|
|
@@ -3853,7 +3924,7 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
|
|
|
3853
3924
|
const theme = Object.fromEntries(["bg", "ink", "muted", "accent", "line", "soft"].map((k2) => [k2, css.getPropertyValue("--du-" + k2).trim()]));
|
|
3854
3925
|
theme.visualStyle = el.closest(".dgui-root")?.dataset.visualStyle ?? "";
|
|
3855
3926
|
theme.scheme = document.body.hasAttribute("data-ds-dark-theme") || el.closest("[data-preview-theme=dark]") ? "dark" : "light";
|
|
3856
|
-
const url = URL.createObjectURL(new Blob([standaloneCanvas(doc, node,
|
|
3927
|
+
const url = URL.createObjectURL(new Blob([standaloneCanvas(doc, node, state2, theme)], { type: "text/html;charset=utf-8" }));
|
|
3857
3928
|
const link = document.createElement("a");
|
|
3858
3929
|
link.href = url;
|
|
3859
3930
|
link.download = (node.title.replace(/[<>:"/\\|?*\x00-\x1f]/g, "_").slice(0, 80) || "dsh-ui") + ".html";
|
|
@@ -3898,10 +3969,10 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
|
|
|
3898
3969
|
}
|
|
3899
3970
|
|
|
3900
3971
|
// lib/build-info.js
|
|
3901
|
-
var BUILD_INFO = Object.freeze({ "version": "0.7.
|
|
3972
|
+
var BUILD_INFO = Object.freeze({ "version": "0.7.1", "id": "0.7.1+d92c9bf2bf64", "sourceHash": "d92c9bf2bf6407506977357f099a9c7935c744d97606dc631267a62be10735eb" });
|
|
3902
3973
|
|
|
3903
3974
|
// lib/refinement.js
|
|
3904
|
-
var AUDIT_MESSAGES = Object.freeze({ overflow: "\u5185\u5BB9\u8D85\u51FA\u89C6\u53E3\u5BBD\u5EA6", smallText: "\u6587\u5B57\u5B9E\u9645\u663E\u793A\u5C3A\u5BF8\u5C0F\u4E8E 12px", contrast: "\u6587\u5B57\u4E0E\u80CC\u666F\u5BF9\u6BD4\u5EA6\u504F\u4F4E", missingLabel: "\u4EA4\u4E92\u63A7\u4EF6\u7F3A\u5C11\u53EF\u8BBF\u95EE\u540D\u79F0", runtimeError: "\u753B\u5E03\u62A5\u544A\u8FD0\u884C\u5F02\u5E38" });
|
|
3975
|
+
var AUDIT_MESSAGES = Object.freeze({ overflow: "\u5185\u5BB9\u8D85\u51FA\u89C6\u53E3\u5BBD\u5EA6", smallText: "\u6587\u5B57\u5B9E\u9645\u663E\u793A\u5C3A\u5BF8\u5C0F\u4E8E 12px", contrast: "\u6587\u5B57\u4E0E\u80CC\u666F\u5BF9\u6BD4\u5EA6\u504F\u4F4E", missingLabel: "\u4EA4\u4E92\u63A7\u4EF6\u7F3A\u5C11\u53EF\u8BBF\u95EE\u540D\u79F0", runtimeError: "\u753B\u5E03\u62A5\u544A\u8FD0\u884C\u5F02\u5E38", clippedText: "\u6587\u5B57\u53EF\u80FD\u88AB\u9690\u85CF\u6216\u88C1\u5207", bottomWhitespace: "\u5185\u5BB9\u4E0B\u65B9\u5B58\u5728\u660E\u663E\u7A7A\u767D" });
|
|
3905
3976
|
|
|
3906
3977
|
// src/current-document.js
|
|
3907
3978
|
var import_react9 = require("react");
|
|
@@ -4243,6 +4314,104 @@ function focusUi(id2, sessionId) {
|
|
|
4243
4314
|
notifyUi();
|
|
4244
4315
|
}
|
|
4245
4316
|
|
|
4317
|
+
// lib/scene-entry.js
|
|
4318
|
+
var object3 = (v2) => v2 !== null && typeof v2 === "object" && !Array.isArray(v2);
|
|
4319
|
+
var fail2 = (at2, message) => {
|
|
4320
|
+
throw Error("DSH UI: " + at2 + " " + message);
|
|
4321
|
+
};
|
|
4322
|
+
var fields2 = (v2, allowed, at2) => {
|
|
4323
|
+
if (!object3(v2)) fail2(at2, "must be an object");
|
|
4324
|
+
for (const k2 of Object.keys(v2)) if (!allowed.includes(k2)) fail2(at2 + "." + k2, "is not supported; use " + allowed.join(", "));
|
|
4325
|
+
};
|
|
4326
|
+
var text2 = (v2, at2) => {
|
|
4327
|
+
if (typeof v2 !== "string" || !v2.trim() || v2.length > 8192) fail2(at2, "must be non-empty text of at most8192 characters");
|
|
4328
|
+
return v2;
|
|
4329
|
+
};
|
|
4330
|
+
var num = (v2, at2, min, max, integer = false) => {
|
|
4331
|
+
if (typeof v2 !== "number" || !Number.isFinite(v2) || v2 < min || v2 > max || integer && !Number.isInteger(v2)) fail2(at2, `must be ${integer ? "an integer" : "a number"} in ${min}..${max}; supply actual or explicitly assumed values`);
|
|
4332
|
+
return v2;
|
|
4333
|
+
};
|
|
4334
|
+
var metric = (id2, label, ref, unit2 = "", decimals = 0) => ({ id: id2, type: "metric", label, value: { ref: "derived." + ref }, unit: unit2, decimals });
|
|
4335
|
+
var state = (value, max, step = 1) => ({ type: "number", default: value, min: 0, max, step });
|
|
4336
|
+
var SCENE_IDS = Object.freeze(["flow", "comparison", "allocation", "budget"]);
|
|
4337
|
+
function sceneDocument(args = {}) {
|
|
4338
|
+
if (new TextEncoder().encode(JSON.stringify(args)).length > LIMITS.bytes) fail2("render_scene", "exceeds128KiB");
|
|
4339
|
+
fields2(args, ["scene", "title", "items", "total", "unit", "values"], "render_scene");
|
|
4340
|
+
if (!SCENE_IDS.includes(args.scene)) fail2("scene", "must be " + SCENE_IDS.join("/"));
|
|
4341
|
+
const used = { flow: ["items"], comparison: ["items"], allocation: ["items", "total", "unit"], budget: ["values"] }[args.scene];
|
|
4342
|
+
for (const k2 of Object.keys(args)) if (!["scene", "title", ...used].includes(k2)) fail2(k2, "does not apply to " + args.scene);
|
|
4343
|
+
const doc = { version: 1, title: args.title ?? { flow: "\u6B65\u9AA4\u6307\u5F15", comparison: "\u65B9\u6848\u5BF9\u6BD4", allocation: "\u65F6\u95F4\u4E0E\u6570\u91CF\u5206\u914D", budget: "\u65C5\u884C\u9884\u7B97\u4F30\u7B97" }[args.scene], fallback: "", nodes: [] };
|
|
4344
|
+
text2(doc.title, "title");
|
|
4345
|
+
if (args.scene === "flow" || args.scene === "comparison" || args.scene === "allocation") {
|
|
4346
|
+
const [min, max] = args.scene === "flow" ? [1, 12] : args.scene === "comparison" ? [2, 4] : [2, 8];
|
|
4347
|
+
if (!Array.isArray(args.items) || args.items.length < min || args.items.length > max) fail2("items", `requires a direct array of ${min}..${max} complete objects`);
|
|
4348
|
+
args.items.forEach((v2, i) => {
|
|
4349
|
+
fields2(v2, args.scene === "flow" ? ["title", "description"] : args.scene === "comparison" ? ["title", "description", "value", "unit", "points"] : ["label", "percent"], "items[" + i + "]");
|
|
4350
|
+
text2(v2[args.scene === "allocation" ? "label" : "title"], "items[" + i + "]." + (args.scene === "allocation" ? "label" : "title"));
|
|
4351
|
+
if (v2.description !== void 0) text2(v2.description, "items[" + i + "].description");
|
|
4352
|
+
});
|
|
4353
|
+
}
|
|
4354
|
+
if (args.scene === "flow") {
|
|
4355
|
+
doc.presentation = { layout: "guide", preset: "flow" };
|
|
4356
|
+
doc.nodes = [{ id: "steps", type: "steps", items: structuredClone(args.items) }];
|
|
4357
|
+
doc.fallback = args.items.map((v2, i) => i + 1 + ". " + v2.title + (v2.description ? "\uFF1A" + v2.description : "")).join("\n");
|
|
4358
|
+
} else if (args.scene === "comparison") {
|
|
4359
|
+
doc.presentation = { layout: "comparison", preset: "comparison" };
|
|
4360
|
+
doc.nodes = [{ id: "options", type: "row", columns: args.items.length, children: args.items.map((v2, i) => {
|
|
4361
|
+
const children = [];
|
|
4362
|
+
if (v2.description) children.push({ id: "description_" + i, type: "text", text: v2.description });
|
|
4363
|
+
if (v2.value !== void 0) {
|
|
4364
|
+
if (!["number", "string", "boolean"].includes(typeof v2.value)) fail2("items[" + i + "].value", "must be scalar");
|
|
4365
|
+
if (v2.unit !== void 0) text2(v2.unit, "items[" + i + "].unit");
|
|
4366
|
+
children.push({ id: "value_" + i, type: "metric", label: v2.title, value: v2.value, ...v2.unit ? { unit: v2.unit } : {} });
|
|
4367
|
+
} else if (v2.unit !== void 0) fail2("items[" + i + "].unit", "requires a value");
|
|
4368
|
+
if (v2.points !== void 0) {
|
|
4369
|
+
if (!Array.isArray(v2.points) || v2.points.length > 8) fail2("items[" + i + "].points", "requires up to8 texts");
|
|
4370
|
+
v2.points.forEach((t, j2) => children.push({ id: "point_" + i + "_" + j2, type: "text", text: text2(t, "items[" + i + "].points[" + j2 + "]") }));
|
|
4371
|
+
}
|
|
4372
|
+
if (!children.length) fail2("items[" + i + "]", "needs description, value or points, not only a title");
|
|
4373
|
+
return { id: "option_" + i, type: "card", title: v2.title, children };
|
|
4374
|
+
}) }];
|
|
4375
|
+
doc.fallback = args.items.map((v2) => [v2.title, v2.description, v2.value === void 0 ? "" : String(v2.value) + (v2.unit ?? ""), ...v2.points ?? []].filter(Boolean).join("\uFF1B")).join("\n");
|
|
4376
|
+
} else if (args.scene === "allocation") {
|
|
4377
|
+
const total = num(args.total, "total", 1e-3, 1e5);
|
|
4378
|
+
if (Math.abs(total * 1e3 - Math.round(total * 1e3)) > 1e-7) fail2("total", "supports up to3 decimals");
|
|
4379
|
+
const unit2 = args.unit ?? "\u5206\u949F";
|
|
4380
|
+
text2(unit2, "unit");
|
|
4381
|
+
let sum = 0;
|
|
4382
|
+
args.items.forEach((v2, i) => sum += num(v2.percent, "items[" + i + "].percent", 0, 100));
|
|
4383
|
+
if (Math.abs(sum - 100) > 1e-6) fail2("items.percent", "must sum to100; received " + sum);
|
|
4384
|
+
doc.presentation = { layout: "workbench" };
|
|
4385
|
+
doc.state = { total: state(total, Math.max(total * 3, 100), Number.isInteger(total) ? 1 : 1e-3) };
|
|
4386
|
+
doc.derived = Object.fromEntries(args.items.map((v2, i) => ["part_" + i, { expr: "state.total * " + v2.percent + " / 100" }]));
|
|
4387
|
+
doc.nodes = [{ id: "total", type: "slider", label: "\u603B\u91CF\uFF08" + unit2 + "\uFF09", bind: "state.total" }, { id: "allocation", type: "row", columns: Math.min(args.items.length, 4), children: args.items.map((v2, i) => metric("part_" + i, v2.label, "part_" + i, unit2, 2)) }, { id: "distribution", type: "chart", kind: "bar", label: "\u5206\u914D\u7ED3\u679C", unit: unit2, labelKey: "label", valueKey: "value", rows: args.items.map((v2, i) => ({ label: v2.label, value: { ref: "derived.part_" + i } })) }];
|
|
4388
|
+
doc.fallback = "\u521D\u59CB\u603B\u91CF " + total + unit2 + "\uFF1B" + args.items.map((v2) => v2.label + " " + v2.percent + "%").join("\uFF0C") + "\u3002\u8C03\u8282\u603B\u91CF\u540E\u6309\u76F8\u540C\u6BD4\u4F8B\u5206\u914D\u3002";
|
|
4389
|
+
} else {
|
|
4390
|
+
fields2(args.values, ["people", "nights", "roomRate", "transportPerPerson"], "values");
|
|
4391
|
+
const v2 = args.values;
|
|
4392
|
+
num(v2.people, "values.people", 1, 100, true);
|
|
4393
|
+
num(v2.nights, "values.nights", 1, 365, true);
|
|
4394
|
+
for (const k2 of ["roomRate", "transportPerPerson"]) {
|
|
4395
|
+
num(v2[k2], "values." + k2, 0, 1e5);
|
|
4396
|
+
if (Math.abs(v2[k2] * 100 - Math.round(v2[k2] * 100)) > 1e-6) fail2("values." + k2, "supports up to2 decimal places");
|
|
4397
|
+
}
|
|
4398
|
+
doc.presentation = { layout: "workbench" };
|
|
4399
|
+
doc.state = { people: { ...state(v2.people, 100), min: 1 }, nights: { ...state(v2.nights, 365), min: 1 }, roomRate: state(v2.roomRate, 1e5, 0.01), transportPerPerson: state(v2.transportPerPerson, 1e5, 0.01) };
|
|
4400
|
+
doc.derived = { rooms: { expr: "ceil(state.people / 2)" }, lodging: { expr: "derived.rooms * state.nights * state.roomRate" }, transport: { expr: "state.people * state.transportPerPerson" }, total: { expr: "derived.lodging + derived.transport" }, lodgingShare: { expr: "derived.total > 0 ? round(derived.lodging / derived.total * 1000) / 10 : 0" }, transportShare: { expr: "derived.total > 0 ? round(derived.transport / derived.total * 1000) / 10 : 0" } };
|
|
4401
|
+
doc.nodes = [{ id: "parameters", type: "card", title: "\u8C03\u6574\u53C2\u6570", children: Object.entries({ people: "\u4EBA\u6570\uFF08\u4EBA\uFF09", nights: "\u5165\u4F4F\u665A\u6570\uFF08\u665A\uFF09", roomRate: "\u6BCF\u623F\u6BCF\u665A\uFF08\u5143\uFF09", transportPerPerson: "\u6BCF\u4EBA\u4EA4\u901A\uFF08\u5143\uFF09" }).map(([k2, label]) => ({ id: k2, type: k2 === "people" || k2 === "nights" ? "slider" : "input", label, bind: "state." + k2 })) }, { id: "totals", type: "row", columns: 3, children: [metric("rooms", "\u623F\u95F4\u6570", "rooms", "\u95F4"), metric("lodging", "\u4F4F\u5BBF", "lodging", "\u5143", 2), metric("total", "\u603B\u8BA1", "total", "\u5143", 2)] }, { id: "costs", type: "table", columns: [{ key: "label", label: "\u9879\u76EE" }, { key: "value", label: "\u91D1\u989D", unit: "\u5143" }, { key: "share", label: "\u5360\u6BD4", unit: "%" }], rows: [{ label: "\u4F4F\u5BBF", value: { ref: "derived.lodging" }, share: { ref: "derived.lodgingShare" } }, { label: "\u4EA4\u901A", value: { ref: "derived.transport" }, share: { ref: "derived.transportShare" } }] }, { id: "distribution", type: "chart", kind: "bar", label: "\u4F4F\u5BBF\u4E0E\u4EA4\u901A", unit: "\u5143", labelKey: "label", valueKey: "value", rows: [{ label: "\u4F4F\u5BBF", value: { ref: "derived.lodging" } }, { label: "\u4EA4\u901A", value: { ref: "derived.transport" } }] }, { id: "basis", type: "text", text: "\u4E24\u4F4D\u6210\u4EBA\u4E00\u95F4\u623F\uFF0C\u623F\u95F4\u6570\u5411\u4E0A\u53D6\u6574\uFF1B\u4F4F\u5BBF = \u623F\u95F4\u6570 \xD7 \u5165\u4F4F\u665A\u6570 \xD7 \u6BCF\u623F\u6BCF\u665A\uFF0C\u4EA4\u901A\u6309\u4EBA\u6570\u8BA1\u7B97\u3002\u53EA\u8BA1\u7B97\u8F93\u5165\u7684\u4F4F\u5BBF\u4E0E\u4EA4\u901A\uFF0C\u672A\u542B\u5176\u4ED6\u8D39\u7528\uFF1B\u8F93\u5165\u4EF7\u683C\u7531\u7528\u6237\u6216\u56DE\u7B54\u63D0\u4F9B\u3002" }];
|
|
4402
|
+
doc.fallback = "\u6309\u8F93\u5165\u4EF7\u683C\u4F30\u7B97\u4F4F\u5BBF\u4E0E\u4EA4\u901A\uFF1A" + v2.people + "\u4EBA\uFF0C" + v2.nights + "\u665A\uFF0C\u623F\u4EF7" + v2.roomRate + "\u5143\uFF0C\u6BCF\u4EBA\u4EA4\u901A" + v2.transportPerPerson + "\u5143\u3002\u4E24\u4F4D\u6210\u4EBA\u4E00\u95F4\u623F\uFF0C\u623F\u95F4\u6570\u5411\u4E0A\u53D6\u6574\uFF1B\u4E0D\u662F\u5B9E\u65F6\u4EF7\u683C\u6216\u62A5\u4EF7\u3002";
|
|
4403
|
+
}
|
|
4404
|
+
return validateDocument(doc);
|
|
4405
|
+
}
|
|
4406
|
+
function previewScene(raw) {
|
|
4407
|
+
try {
|
|
4408
|
+
if (typeof raw !== "string" || raw.length > LIMITS.bytes) return null;
|
|
4409
|
+
return sceneDocument(JSON.parse(raw));
|
|
4410
|
+
} catch {
|
|
4411
|
+
return null;
|
|
4412
|
+
}
|
|
4413
|
+
}
|
|
4414
|
+
|
|
4246
4415
|
// lib/third-party/anatomy-iso.mjs
|
|
4247
4416
|
var AZIMUTH = 45;
|
|
4248
4417
|
var ELEVATION = 30;
|
|
@@ -4307,16 +4476,16 @@ function fitProjection(points, width, height, { pad = 24, headroom = 0, azimuth
|
|
|
4307
4476
|
// lib/mechanism-geometry.js
|
|
4308
4477
|
var MECHANISM_LIMITS = Object.freeze({ parts: 96, teeth: 64, faces: 8192 });
|
|
4309
4478
|
var finite2 = (v2) => typeof v2 === "number" && Number.isFinite(v2);
|
|
4310
|
-
var
|
|
4479
|
+
var fail3 = (s) => {
|
|
4311
4480
|
throw Error("Motion mechanism: " + s);
|
|
4312
4481
|
};
|
|
4313
|
-
var
|
|
4314
|
-
if (!finite2(v2) || v2 < min || v2 > max)
|
|
4482
|
+
var num2 = (v2, label, min = -1e4, max = 1e4) => {
|
|
4483
|
+
if (!finite2(v2) || v2 < min || v2 > max) fail3(label + " must be a finite number in " + min + ".." + max);
|
|
4315
4484
|
return v2;
|
|
4316
4485
|
};
|
|
4317
4486
|
var vector = (v2, label) => {
|
|
4318
|
-
if (!Array.isArray(v2) || v2.length !== 3)
|
|
4319
|
-
return v2.map((x, i) =>
|
|
4487
|
+
if (!Array.isArray(v2) || v2.length !== 3) fail3(label + " must be [x,y,z]");
|
|
4488
|
+
return v2.map((x, i) => num2(x, label + "[" + i + "]"));
|
|
4320
4489
|
};
|
|
4321
4490
|
var id = (v2) => typeof v2 === "string" && /^[\p{L}_][\p{L}\p{M}\p{N}_]{0,63}$/u.test(v2) && !["constructor", "prototype", "__proto__"].includes(v2);
|
|
4322
4491
|
var kinds = ["box", "cylinder", "gear", "rod", "spring"];
|
|
@@ -4327,74 +4496,74 @@ var dot = (a, b2) => a.reduce((s, v2, i) => s + v2 * b2[i], 0);
|
|
|
4327
4496
|
var cross = (a, b2) => [a[1] * b2[2] - a[2] * b2[1], a[2] * b2[0] - a[0] * b2[2], a[0] * b2[1] - a[1] * b2[0]];
|
|
4328
4497
|
var unit = (a) => {
|
|
4329
4498
|
const len = Math.hypot(...a);
|
|
4330
|
-
if (len < 1e-6)
|
|
4499
|
+
if (len < 1e-6) fail3("zero-length axis");
|
|
4331
4500
|
return mul(a, 1 / len);
|
|
4332
4501
|
};
|
|
4333
4502
|
function validateScene(spec) {
|
|
4334
|
-
if (!spec || typeof spec !== "object" || Array.isArray(spec))
|
|
4335
|
-
if (!Array.isArray(spec.parts) || !spec.parts.length || spec.parts.length > MECHANISM_LIMITS.parts)
|
|
4503
|
+
if (!spec || typeof spec !== "object" || Array.isArray(spec)) fail3("scene must be an object");
|
|
4504
|
+
if (!Array.isArray(spec.parts) || !spec.parts.length || spec.parts.length > MECHANISM_LIMITS.parts) fail3("parts requires 1..96 objects");
|
|
4336
4505
|
const seen = /* @__PURE__ */ new Set(), groups = /* @__PURE__ */ new Set();
|
|
4337
4506
|
for (const [i, p2] of spec.parts.entries()) {
|
|
4338
4507
|
const at2 = "parts[" + i + "]";
|
|
4339
|
-
if (!p2 || typeof p2 !== "object" || !id(p2.id) || seen.has(p2.id))
|
|
4508
|
+
if (!p2 || typeof p2 !== "object" || !id(p2.id) || seen.has(p2.id)) fail3(at2 + ".id must be a unique identifier");
|
|
4340
4509
|
seen.add(p2.id);
|
|
4341
|
-
if (!kinds.includes(p2.type))
|
|
4510
|
+
if (!kinds.includes(p2.type)) fail3(at2 + ".type must be " + kinds.join("/"));
|
|
4342
4511
|
if (p2.group !== void 0) {
|
|
4343
|
-
if (!id(p2.group))
|
|
4512
|
+
if (!id(p2.group)) fail3(at2 + ".group must be an identifier");
|
|
4344
4513
|
groups.add(p2.group);
|
|
4345
4514
|
}
|
|
4346
|
-
for (const k2 of ["label", "description"]) if (p2[k2] !== void 0 && (typeof p2[k2] !== "string" || p2[k2].length > 1024))
|
|
4347
|
-
if (p2.cover !== void 0 && typeof p2.cover !== "boolean")
|
|
4348
|
-
if (p2.material !== void 0 && !["metal", "dark", "accent", "warm", "cool"].includes(p2.material))
|
|
4515
|
+
for (const k2 of ["label", "description"]) if (p2[k2] !== void 0 && (typeof p2[k2] !== "string" || p2[k2].length > 1024)) fail3(at2 + "." + k2 + " must be short text");
|
|
4516
|
+
if (p2.cover !== void 0 && typeof p2.cover !== "boolean") fail3(at2 + ".cover must be boolean");
|
|
4517
|
+
if (p2.material !== void 0 && !["metal", "dark", "accent", "warm", "cool"].includes(p2.material)) fail3(at2 + ".material must be metal/dark/accent/warm/cool");
|
|
4349
4518
|
if (p2.at !== void 0) vector(p2.at, at2 + ".at");
|
|
4350
4519
|
if (p2.explode !== void 0) vector(p2.explode, at2 + ".explode");
|
|
4351
|
-
if (p2.rotation !== void 0)
|
|
4352
|
-
if (p2.axis !== void 0 && !["x", "y", "z"].includes(p2.axis))
|
|
4520
|
+
if (p2.rotation !== void 0) num2(p2.rotation, at2 + ".rotation", -1e9, 1e9);
|
|
4521
|
+
if (p2.axis !== void 0 && !["x", "y", "z"].includes(p2.axis)) fail3(at2 + ".axis must be x/y/z");
|
|
4353
4522
|
if (p2.type === "box") {
|
|
4354
4523
|
const size = vector(p2.size, at2 + ".size");
|
|
4355
|
-
if (size.some((v2) => v2 <= 0 || v2 > 2e3))
|
|
4356
|
-
if (p2.round !== void 0)
|
|
4524
|
+
if (size.some((v2) => v2 <= 0 || v2 > 2e3)) fail3(at2 + ".size must be positive and <=2000");
|
|
4525
|
+
if (p2.round !== void 0) num2(p2.round, at2 + ".round", 0, Math.min(size[0], size[1]) / 2);
|
|
4357
4526
|
}
|
|
4358
4527
|
if (["cylinder", "gear"].includes(p2.type)) {
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
if (p2.inner !== void 0)
|
|
4528
|
+
num2(p2.radius, at2 + ".radius", 0.1, 1e3);
|
|
4529
|
+
num2(p2.height ?? 8, at2 + ".height", 0.1, 1e3);
|
|
4530
|
+
if (p2.inner !== void 0) num2(p2.inner, at2 + ".inner", 0, p2.radius - 0.01);
|
|
4362
4531
|
}
|
|
4363
4532
|
if (p2.type === "gear") {
|
|
4364
|
-
const teeth =
|
|
4365
|
-
if (!Number.isInteger(teeth))
|
|
4366
|
-
if (p2.module !== void 0)
|
|
4533
|
+
const teeth = num2(p2.teeth, at2 + ".teeth", 6, 64);
|
|
4534
|
+
if (!Number.isInteger(teeth)) fail3(at2 + ".teeth must be an integer");
|
|
4535
|
+
if (p2.module !== void 0) num2(p2.module, at2 + ".module", 0.1, p2.radius / 3);
|
|
4367
4536
|
}
|
|
4368
4537
|
if (["rod", "spring"].includes(p2.type)) {
|
|
4369
4538
|
vector(p2.from, at2 + ".from");
|
|
4370
4539
|
vector(p2.to, at2 + ".to");
|
|
4371
|
-
if (Math.hypot(...sub(p2.to, p2.from)) < 0.1)
|
|
4372
|
-
|
|
4540
|
+
if (Math.hypot(...sub(p2.to, p2.from)) < 0.1) fail3(at2 + " endpoints must differ");
|
|
4541
|
+
num2(p2.radius ?? 2, at2 + ".radius", 0.1, 200);
|
|
4373
4542
|
}
|
|
4374
4543
|
if (p2.type === "spring") {
|
|
4375
|
-
const turns =
|
|
4376
|
-
if (!Number.isInteger(turns))
|
|
4544
|
+
const turns = num2(p2.turns ?? 8, at2 + ".turns", 2, 24);
|
|
4545
|
+
if (!Number.isInteger(turns)) fail3(at2 + ".turns must be integer");
|
|
4377
4546
|
}
|
|
4378
4547
|
}
|
|
4379
4548
|
if (spec.groups !== void 0) {
|
|
4380
|
-
if (!Array.isArray(spec.groups) || spec.groups.length > 12)
|
|
4549
|
+
if (!Array.isArray(spec.groups) || spec.groups.length > 12) fail3("groups must be an array of <=12 labels");
|
|
4381
4550
|
const ids = /* @__PURE__ */ new Set();
|
|
4382
4551
|
for (const g of spec.groups) {
|
|
4383
|
-
if (!g || !id(g.id) || ids.has(g.id) || !groups.has(g.id) || typeof g.label !== "string" || g.label.length > 128)
|
|
4552
|
+
if (!g || !id(g.id) || ids.has(g.id) || !groups.has(g.id) || typeof g.label !== "string" || g.label.length > 128) fail3("groups must name unique existing part groups");
|
|
4384
4553
|
ids.add(g.id);
|
|
4385
4554
|
}
|
|
4386
4555
|
}
|
|
4387
4556
|
if (spec.bounds !== void 0) {
|
|
4388
|
-
if (!Array.isArray(spec.bounds) || spec.bounds.length !== 2)
|
|
4557
|
+
if (!Array.isArray(spec.bounds) || spec.bounds.length !== 2) fail3("bounds must be [minXYZ,maxXYZ]");
|
|
4389
4558
|
const [a, b2] = spec.bounds.map((v2, i) => vector(v2, "bounds[" + i + "]"));
|
|
4390
|
-
if (a.some((v2, i) => v2 >= b2[i]))
|
|
4559
|
+
if (a.some((v2, i) => v2 >= b2[i])) fail3("bounds min must be below max on every axis");
|
|
4391
4560
|
}
|
|
4392
|
-
if (spec.azimuth !== void 0)
|
|
4393
|
-
if (spec.elevation !== void 0)
|
|
4394
|
-
if (spec.title !== void 0 && (typeof spec.title !== "string" || spec.title.length > 256))
|
|
4561
|
+
if (spec.azimuth !== void 0) num2(spec.azimuth, "azimuth", 10, 80);
|
|
4562
|
+
if (spec.elevation !== void 0) num2(spec.elevation, "elevation", 15, 70);
|
|
4563
|
+
if (spec.title !== void 0 && (typeof spec.title !== "string" || spec.title.length > 256)) fail3("title must be short text");
|
|
4395
4564
|
if (spec.bind !== void 0) {
|
|
4396
|
-
if (!spec.bind || typeof spec.bind !== "object" || Array.isArray(spec.bind))
|
|
4397
|
-
for (const [k2, v2] of Object.entries(spec.bind)) if (!["explode", "selected", "cutaway"].includes(k2) || !id(v2))
|
|
4565
|
+
if (!spec.bind || typeof spec.bind !== "object" || Array.isArray(spec.bind)) fail3("bind must be an object");
|
|
4566
|
+
for (const [k2, v2] of Object.entries(spec.bind)) if (!["explode", "selected", "cutaway"].includes(k2) || !id(v2)) fail3("bind only accepts declared state keys for explode/selected/cutaway");
|
|
4398
4567
|
}
|
|
4399
4568
|
return spec;
|
|
4400
4569
|
}
|
|
@@ -4471,18 +4640,18 @@ function sceneBounds(spec) {
|
|
|
4471
4640
|
});
|
|
4472
4641
|
}
|
|
4473
4642
|
function gearPair({ driverTeeth = 16, drivenTeeth = 32, rpm = 30, angle = 0, module: module2 = 2 } = {}) {
|
|
4474
|
-
for (const [k2, v2] of Object.entries({ driverTeeth, drivenTeeth })) if (!Number.isInteger(v2) || v2 < 6 || v2 > 64)
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4643
|
+
for (const [k2, v2] of Object.entries({ driverTeeth, drivenTeeth })) if (!Number.isInteger(v2) || v2 < 6 || v2 > 64) fail3(k2 + " must be integer 6..64");
|
|
4644
|
+
num2(rpm, "rpm", -600, 600);
|
|
4645
|
+
num2(angle, "angle", -1e9, 1e9);
|
|
4646
|
+
num2(module2, "module", 0.1, 10);
|
|
4478
4647
|
return { driverRadius: driverTeeth * module2 / 2, drivenRadius: drivenTeeth * module2 / 2, centerDistance: (driverTeeth + drivenTeeth) * module2 / 2, driverAngle: angle, drivenAngle: -angle * driverTeeth / drivenTeeth + Math.PI - Math.PI / drivenTeeth, driverRpm: rpm, drivenRpm: -rpm * driverTeeth / drivenTeeth, ratio: drivenTeeth / driverTeeth };
|
|
4479
4648
|
}
|
|
4480
4649
|
function sliderCrank({ angle = 0, radius = 20, rod = 70, z: z2 = 20 } = {}) {
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
if (rod <= radius)
|
|
4650
|
+
num2(angle, "angle", -1e9, 1e9);
|
|
4651
|
+
num2(radius, "radius", 0.1, 200);
|
|
4652
|
+
num2(rod, "rod", 0.1, 1e3);
|
|
4653
|
+
num2(z2, "z");
|
|
4654
|
+
if (rod <= radius) fail3("connecting rod length must exceed crank radius");
|
|
4486
4655
|
const crank = [radius * Math.cos(angle), radius * Math.sin(angle), z2], x = crank[0] + Math.sqrt(rod * rod - crank[1] * crank[1]);
|
|
4487
4656
|
return { crank, piston: [x, 0, z2], position: x, stroke: radius * 2, angle };
|
|
4488
4657
|
}
|
|
@@ -4609,27 +4778,27 @@ var n = (value, min, max, step = 1) => ({ type: "number", default: value, min, m
|
|
|
4609
4778
|
function mechanismExample(name) {
|
|
4610
4779
|
if (!MECHANISM_SCENES.some((s) => s.id === name)) throw Error("Motion mechanism: scene must be assembly/gears/crank");
|
|
4611
4780
|
const scene = { assembly: assemblyScene, gears: gearsScene, crank: crankScene }[name]();
|
|
4612
|
-
const
|
|
4781
|
+
const state2 = { explode: n(name === "assembly" ? 0.45 : 0, 0, 1, 0.01), selected: { type: "string", default: "all" }, cutaway: { type: "boolean", default: name === "gears" } };
|
|
4613
4782
|
const bind = { explode: "explode", selected: "selected", cutaway: "cutaway" }, nodes = [];
|
|
4614
4783
|
if (name !== "assembly") {
|
|
4615
|
-
Object.assign(
|
|
4784
|
+
Object.assign(state2, { rpm: n(20, 0, 90), running: { type: "boolean", default: false }, angle: n(0, 0, 360) });
|
|
4616
4785
|
Object.assign(bind, { rpm: "rpm", running: "running", angle: "angle" });
|
|
4617
4786
|
nodes.push({ id: "rpm", type: "slider", label: "\u8F93\u5165\u8F6C\u901F\uFF08rpm\uFF09", bind: "state.rpm" }, { id: "angle", type: "slider", label: "\u624B\u52A8\u89D2\u5EA6\uFF08\xB0\uFF0C\u6682\u505C\u65F6\u8C03\u8282\uFF09", bind: "state.angle" }, { id: "running", type: "toggle", label: "\u8FD0\u884C\u673A\u68B0\u793A\u610F", bind: "state.running" });
|
|
4618
4787
|
}
|
|
4619
4788
|
if (name === "gears") {
|
|
4620
|
-
|
|
4789
|
+
state2.teeth = n(32, 16, 48);
|
|
4621
4790
|
bind.teeth = "teeth";
|
|
4622
4791
|
nodes.unshift({ id: "teeth", type: "slider", label: "\u4ECE\u52A8\u8F6E\u9F7F\u6570\uFF08\u4E3B\u52A8\u8F6E16\u9F7F\uFF09", bind: "state.teeth" });
|
|
4623
4792
|
}
|
|
4624
4793
|
if (name === "crank") {
|
|
4625
|
-
|
|
4794
|
+
state2.radius = n(20, 10, 28);
|
|
4626
4795
|
bind.radius = "radius";
|
|
4627
4796
|
nodes.unshift({ id: "radius", type: "slider", label: "\u66F2\u67C4\u534A\u5F84\uFF08\u793A\u610F\u957F\u5EA6\u5355\u4F4D\uFF09", bind: "state.radius" });
|
|
4628
4797
|
}
|
|
4629
4798
|
const fallback = name === "assembly" ? "\u5E95\u5EA7\u652F\u6491\u529F\u80FD\u677F\uFF0C\u5904\u7406\u6A21\u5757\u4E0A\u65B9\u4E3A\u6563\u70ED\u5C42\uFF0C\u5916\u58F3\u4FDD\u62A4\u5185\u90E8\u3002\u62C6\u89E3\u8868\u793A\u88C5\u914D\u5173\u7CFB\uFF0C\u4E0D\u8868\u793A\u53D7\u529B\u8FD0\u52A8\u3002" : name === "gears" ? "\u5916\u556E\u5408\u9F7F\u8F6E\u53CD\u5411\u8F6C\u52A8\u3002\u4E3B\u52A8\u8F6E16\u9F7F\u300120 rpm\uFF0C\u4ECE\u52A8\u8F6E\u9ED8\u8BA432\u9F7F\u3001-10 rpm\uFF0C\u4E2D\u5FC3\u8DDD\u7531\u6A21\u6570\u548C\u9F7F\u6570\u786E\u5B9A\u3002\u9F7F\u5F62\u4E3A\u7B80\u5316\u793A\u610F\uFF0C\u4E0D\u7528\u4E8E\u52A0\u5DE5\u3002" : "\u65CB\u8F6C\u66F2\u67C4\u5E26\u52A8\u5B9A\u957F\u8FDE\u6746\uFF0C\u6ED1\u5757\u6CBF\u5BFC\u8F68\u5F80\u590D\u3002\u9ED8\u8BA4\u534A\u5F8420\u3001\u6746\u957F70\uFF0C\u5B8C\u6574\u884C\u7A0B40\uFF0C\u4F4D\u7F6E\u7531\u51E0\u4F55\u7EA6\u675F\u8BA1\u7B97\u3002\u975E\u52A8\u529B\u5B66\u4EFF\u771F\u3002";
|
|
4630
|
-
nodes.unshift({ id: "mechanism", type: "sandbox", title: scene.title, fallback, height: 560, libraries: ["mechanism"], stateKeys: Object.keys(
|
|
4799
|
+
nodes.unshift({ id: "mechanism", type: "sandbox", title: scene.title, fallback, height: 560, libraries: ["mechanism"], stateKeys: Object.keys(state2), html: '<div id="diagram"><section class="mui-mechanism">' + sceneSvg(scene, { explode: state2.explode.default, cutaway: state2.cutaway.default, preview: true }) + "<p>" + fallback + "</p></section></div>", css: MECHANISM_CSS, script: 'const diagram=DSHUI.mechanism.mountDemo("#diagram",' + JSON.stringify(name) + ',{title:"",bind:' + JSON.stringify(bind) + '});addEventListener("pagehide",()=>diagram.destroy(),{once:true});' });
|
|
4631
4800
|
nodes.push({ id: "accuracy", type: "text", text: fallback });
|
|
4632
|
-
return validateDocument({ version: 1, title: scene.title, fallback, state, nodes });
|
|
4801
|
+
return validateDocument({ version: 1, title: scene.title, fallback, state: state2, nodes });
|
|
4633
4802
|
}
|
|
4634
4803
|
|
|
4635
4804
|
// lib/mechanism-entry.js
|
|
@@ -4688,7 +4857,7 @@ function dispose(entry) {
|
|
|
4688
4857
|
function publish(entry, calls, invalidated = []) {
|
|
4689
4858
|
for (const key2 of invalidated) entry.previews.delete(key2);
|
|
4690
4859
|
for (const call of calls) {
|
|
4691
|
-
const doc = call.name === "render_mechanism" ? previewMechanism(call.raw) : call.name === "render_text" ? previewText(call.raw) : previewDocument(call.raw);
|
|
4860
|
+
const doc = call.name === "render_scene" ? previewScene(call.raw) : call.name === "render_mechanism" ? previewMechanism(call.raw) : call.name === "render_text" ? previewText(call.raw) : previewDocument(call.raw);
|
|
4692
4861
|
const canvas = call.name === "render_canvas" ? previewCanvas(call.raw) : null;
|
|
4693
4862
|
if (doc || canvas) entry.previews.set(call.callId, { call, doc, canvas });
|
|
4694
4863
|
}
|
|
@@ -4752,21 +4921,21 @@ var import_react15 = __toESM(require("react"), 1);
|
|
|
4752
4921
|
var JSX = __toESM(require("react/jsx-runtime"), 1);
|
|
4753
4922
|
|
|
4754
4923
|
// src/visual-state.js
|
|
4755
|
-
function visualStateSignature(
|
|
4924
|
+
function visualStateSignature(state2 = {}, defaults = {}) {
|
|
4756
4925
|
const sorted = (value) => Object.fromEntries(Object.entries(value ?? {}).sort(([a], [b2]) => a.localeCompare(b2)));
|
|
4757
|
-
return JSON.stringify({ answers: sorted(
|
|
4926
|
+
return JSON.stringify({ answers: sorted(state2.answers), multiAnswers: sorted(state2.multiAnswers), fields: sorted({ ...defaults, ...state2.fields }), locked: state2.locked === true });
|
|
4758
4927
|
}
|
|
4759
4928
|
|
|
4760
4929
|
// lib/visual-defaults.js
|
|
4761
4930
|
function visualDefaults(spec) {
|
|
4762
|
-
const
|
|
4931
|
+
const fields3 = {};
|
|
4763
4932
|
const walk = (items) => {
|
|
4764
4933
|
for (const n2 of items ?? []) {
|
|
4765
4934
|
if (!n2 || typeof n2 !== "object") continue;
|
|
4766
4935
|
if (n2.id) {
|
|
4767
|
-
if (["input", "textarea"].includes(n2.type) && typeof n2.value === "string")
|
|
4768
|
-
if (n2.type === "slider")
|
|
4769
|
-
if (n2.type === "select" && Number.isInteger(n2.selected) && typeof n2.options?.[n2.selected] === "string")
|
|
4936
|
+
if (["input", "textarea"].includes(n2.type) && typeof n2.value === "string") fields3[n2.id] = n2.value;
|
|
4937
|
+
if (n2.type === "slider") fields3[n2.id] = String(n2.value ?? n2.min ?? 0);
|
|
4938
|
+
if (n2.type === "select" && Number.isInteger(n2.selected) && typeof n2.options?.[n2.selected] === "string") fields3[n2.id] = n2.options[n2.selected];
|
|
4770
4939
|
}
|
|
4771
4940
|
if (["card", "row", "col", "grid"].includes(n2.type)) walk(n2.items);
|
|
4772
4941
|
if (n2.type === "tabs") for (const t of n2.tabs ?? []) walk(t.items);
|
|
@@ -4774,7 +4943,7 @@ function visualDefaults(spec) {
|
|
|
4774
4943
|
}
|
|
4775
4944
|
};
|
|
4776
4945
|
walk(spec.items);
|
|
4777
|
-
return
|
|
4946
|
+
return fields3;
|
|
4778
4947
|
}
|
|
4779
4948
|
|
|
4780
4949
|
// src/visual-view.js
|
|
@@ -4817,15 +4986,15 @@ function loadVisual() {
|
|
|
4817
4986
|
});
|
|
4818
4987
|
return pending;
|
|
4819
4988
|
}
|
|
4820
|
-
function VisualView({ node, state, update, disabled, preview, sendPrompt, openFile, provenance, documentTitle }) {
|
|
4989
|
+
function VisualView({ node, state: state2, update, disabled, preview, sendPrompt, openFile, provenance, documentTitle }) {
|
|
4821
4990
|
const defaults = visualDefaults(node.spec), stateSignature = (v2) => visualStateSignature(v2, defaults);
|
|
4822
4991
|
const showDetails = useViewDetails();
|
|
4823
4992
|
const [core, setCore] = (0, import_react15.useState)(), [error, setError] = (0, import_react15.useState)(""), [epoch, setEpoch] = (0, import_react15.useState)(0), [busy, setBusy] = (0, import_react15.useState)(false), [feedback, setFeedback] = (0, import_react15.useState)("");
|
|
4824
|
-
const last = (0, import_react15.useRef)(stateSignature(
|
|
4825
|
-
latest.current =
|
|
4993
|
+
const last = (0, import_react15.useRef)(stateSignature(state2)), latest = (0, import_react15.useRef)(state2), sending = (0, import_react15.useRef)(false), source = (0, import_react15.useRef)(node.spec);
|
|
4994
|
+
latest.current = state2;
|
|
4826
4995
|
if (source.current !== node.spec) {
|
|
4827
4996
|
source.current = node.spec;
|
|
4828
|
-
last.current = stateSignature(
|
|
4997
|
+
last.current = stateSignature(state2);
|
|
4829
4998
|
}
|
|
4830
4999
|
(0, import_react15.useEffect)(() => {
|
|
4831
5000
|
let live = true;
|
|
@@ -4839,12 +5008,12 @@ function VisualView({ node, state, update, disabled, preview, sendPrompt, openFi
|
|
|
4839
5008
|
};
|
|
4840
5009
|
}, []);
|
|
4841
5010
|
(0, import_react15.useEffect)(() => {
|
|
4842
|
-
const serialized = stateSignature(
|
|
5011
|
+
const serialized = stateSignature(state2);
|
|
4843
5012
|
if (serialized !== last.current) {
|
|
4844
5013
|
last.current = serialized;
|
|
4845
5014
|
setEpoch((e) => e + 1);
|
|
4846
5015
|
}
|
|
4847
|
-
}, [
|
|
5016
|
+
}, [state2]);
|
|
4848
5017
|
const changed = (next) => {
|
|
4849
5018
|
if (disabled || preview) return;
|
|
4850
5019
|
const serialized = stateSignature(next);
|
|
@@ -4887,7 +5056,7 @@ function VisualView({ node, state, update, disabled, preview, sendPrompt, openFi
|
|
|
4887
5056
|
setError("\u5BFC\u51FA\u5931\u8D25\uFF1A" + e.message);
|
|
4888
5057
|
}
|
|
4889
5058
|
};
|
|
4890
|
-
const content = h10(core.ErrorBoundary, { label: "Motion UI" }, h10(core.GenuiBlock, { key: epoch, spec, initialState:
|
|
5059
|
+
const content = h10(core.ErrorBoundary, { label: "Motion UI" }, h10(core.GenuiBlock, { key: epoch, spec, initialState: state2, animateEntrance: !preview, onStateChange: preview ? () => {
|
|
4891
5060
|
} : changed }));
|
|
4892
5061
|
return h10("section", { "data-ui-node": node.id, "data-motion-visual": true }, h10("div", { inert: disabled || preview || busy ? "" : void 0, "aria-busy": busy }, h10(core.GenuiActionContext.Provider, { value: action }, h10(core.FileLinkOpenContext.Provider, { value: disabled || preview ? void 0 : openFile }, content))), showDetails && !preview && h10("div", { className: "dgui-row" }, h10("button", { type: "button", disabled, onClick: () => exportAs("html") }, "\u5BFC\u51FA HTML"), h10("button", { type: "button", disabled, onClick: () => exportAs("json") }, "\u5BFC\u51FA JSON")), error && h10("p", { role: "alert" }, error), feedback && h10("p", { role: "status" }, feedback));
|
|
4893
5062
|
}
|
|
@@ -4909,7 +5078,7 @@ function diagnoseDelivery(input) {
|
|
|
4909
5078
|
const document2 = validateDocument(input), diagnostics = deliveryDiagnostics(document2);
|
|
4910
5079
|
return { valid: true, complete: diagnostics.length === 0, document: document2, diagnostics };
|
|
4911
5080
|
} catch (e) {
|
|
4912
|
-
return { valid: false, complete: false, diagnostics: [{ severity: "error", path: "document", message: e.message }] };
|
|
5081
|
+
return { valid: false, complete: false, diagnostics: [{ severity: "error", path: e.path ?? e.message.match(/(?:^DSH UI: |unknown field )((?:node|nodes|derived|state|document|presentation)(?:\.[\p{L}\p{N}_]+|\[\d+\])+)/u)?.[1] ?? "document", message: e.message }] };
|
|
4913
5082
|
}
|
|
4914
5083
|
}
|
|
4915
5084
|
function resolveSourceFence(raw, { svg = false } = {}) {
|
|
@@ -4932,17 +5101,17 @@ function resolveSourceFence(raw, { svg = false } = {}) {
|
|
|
4932
5101
|
// src/copy-block.js
|
|
4933
5102
|
var import_react16 = __toESM(require("react"), 1);
|
|
4934
5103
|
var h11 = import_react16.default.createElement;
|
|
4935
|
-
async function copyContent(
|
|
5104
|
+
async function copyContent(text3) {
|
|
4936
5105
|
try {
|
|
4937
5106
|
if (typeof navigator.clipboard?.writeText === "function") {
|
|
4938
|
-
await navigator.clipboard.writeText(
|
|
5107
|
+
await navigator.clipboard.writeText(text3);
|
|
4939
5108
|
return true;
|
|
4940
5109
|
}
|
|
4941
5110
|
} catch {
|
|
4942
5111
|
}
|
|
4943
5112
|
const active = document.activeElement, selection = window.getSelection(), ranges = selection ? Array.from({ length: selection.rangeCount }, (_2, i) => selection.getRangeAt(i).cloneRange()) : [];
|
|
4944
5113
|
const field = document.createElement("textarea");
|
|
4945
|
-
field.value =
|
|
5114
|
+
field.value = text3;
|
|
4946
5115
|
field.readOnly = true;
|
|
4947
5116
|
field.style.cssText = "position:fixed;left:-10000px;top:0;opacity:0";
|
|
4948
5117
|
document.body.append(field);
|
|
@@ -4974,18 +5143,18 @@ var COPY_BLOCK_CSS = `
|
|
|
4974
5143
|
@media(prefers-reduced-motion:reduce){.motion-copy-button .dgui-icon,.motion-copy-button path{animation:none!important;transition:none!important}}
|
|
4975
5144
|
@media(max-width:600px){.motion-copy-block{padding:14px 16px;border-radius:20px}}
|
|
4976
5145
|
`;
|
|
4977
|
-
function CopyBlock({ text:
|
|
5146
|
+
function CopyBlock({ text: text3, children, title, lang, code = false, wrap = false, disabled = false, style, nodeId, copyLabel, copiedLabel }) {
|
|
4978
5147
|
const [status, setStatus] = (0, import_react16.useState)("idle"), timer = (0, import_react16.useRef)();
|
|
4979
5148
|
(0, import_react16.useEffect)(() => () => clearTimeout(timer.current), []);
|
|
4980
5149
|
const label = status === "done" ? copiedLabel ?? "\u5DF2\u590D\u5236" : status === "error" ? "\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u9009\u62E9\u5185\u5BB9" : copyLabel ?? (code ? "\u590D\u5236\u4EE3\u7801" : "\u590D\u5236\u6587\u672C");
|
|
4981
5150
|
async function copy2() {
|
|
4982
5151
|
clearTimeout(timer.current);
|
|
4983
5152
|
setStatus("copying");
|
|
4984
|
-
const ok = await copyContent(
|
|
5153
|
+
const ok = await copyContent(text3);
|
|
4985
5154
|
setStatus(ok ? "done" : "error");
|
|
4986
5155
|
timer.current = setTimeout(() => setStatus("idle"), 2e3);
|
|
4987
5156
|
}
|
|
4988
|
-
return h11("section", { className: "motion-copy-block", "data-copy-status": status, "data-code": code || void 0, "data-ui-node": nodeId, style }, h11("style", null, COPY_BLOCK_CSS), h11("div", { className: "motion-copy-bar" }, code && h11("span", { "aria-hidden": true }, "\u3008/\u3009"), h11("span", { className: "motion-copy-title" }, title ?? (code ? lang || "\u4EE3\u7801" : "\u6587\u672C")), h11("button", { className: "motion-copy-button", type: "button", title: label, "aria-label": label, "data-status": status, disabled: disabled || status === "copying", onClick: copy2 }, h11(Icon, { name: status === "done" ? "check" : status === "error" ? "warning" : "copy" })), h11("span", { className: "motion-copy-sr", role: "status", "aria-live": "polite" }, status === "done" ? "\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F" : status === "error" ? label : "")), code ? h11("pre", { className: "motion-copy-code", "data-wrap": wrap || void 0 }, h11("code", { "data-language": lang },
|
|
5157
|
+
return h11("section", { className: "motion-copy-block", "data-copy-status": status, "data-code": code || void 0, "data-ui-node": nodeId, style }, h11("style", null, COPY_BLOCK_CSS), h11("div", { className: "motion-copy-bar" }, code && h11("span", { "aria-hidden": true }, "\u3008/\u3009"), h11("span", { className: "motion-copy-title" }, title ?? (code ? lang || "\u4EE3\u7801" : "\u6587\u672C")), h11("button", { className: "motion-copy-button", type: "button", title: label, "aria-label": label, "data-status": status, disabled: disabled || status === "copying", onClick: copy2 }, h11(Icon, { name: status === "done" ? "check" : status === "error" ? "warning" : "copy" })), h11("span", { className: "motion-copy-sr", role: "status", "aria-live": "polite" }, status === "done" ? "\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F" : status === "error" ? label : "")), code ? h11("pre", { className: "motion-copy-code", "data-wrap": wrap || void 0 }, h11("code", { "data-language": lang }, text3)) : h11("div", { className: "motion-copy-body" }, children ?? text3));
|
|
4989
5158
|
}
|
|
4990
5159
|
|
|
4991
5160
|
// src/view.js
|
|
@@ -5008,9 +5177,9 @@ function NumericInput({ id: id2, spec, value, onChange, invalidChanged, disabled
|
|
|
5008
5177
|
disabled,
|
|
5009
5178
|
"aria-invalid": invalid,
|
|
5010
5179
|
onChange(e) {
|
|
5011
|
-
const
|
|
5012
|
-
setDraft(
|
|
5013
|
-
const n2 = Number(
|
|
5180
|
+
const text3 = e.target.value;
|
|
5181
|
+
setDraft(text3);
|
|
5182
|
+
const n2 = Number(text3), bad = text3.trim() === "" || !Number.isFinite(n2) || n2 < spec.min || n2 > spec.max || Math.abs((n2 - spec.min) / spec.step - Math.round((n2 - spec.min) / spec.step)) > 1e-6;
|
|
5014
5183
|
setInvalid(bad);
|
|
5015
5184
|
invalidChanged(id2, bad);
|
|
5016
5185
|
if (!bad) onChange(n2);
|
|
@@ -5093,7 +5262,7 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
|
|
|
5093
5262
|
canvasAudits.current.set(id2, { coverage: coverage ? { ...coverage, nodeId: id2 } : void 0, issues: issues.filter((i) => Object.hasOwn(AUDIT_MESSAGES, i.code)).slice(0, 40).map((i) => ({ ...i, nodeId: id2 })) });
|
|
5094
5263
|
collectAudit();
|
|
5095
5264
|
};
|
|
5096
|
-
const { state, setState, ready, status, issue, epoch, retry, useRemote, keepLocal } = useSavedState(record, sessionId, preview);
|
|
5265
|
+
const { state: state2, setState, ready, status, issue, epoch, retry, useRemote, keepLocal } = useSavedState(record, sessionId, preview);
|
|
5097
5266
|
const [error, setError] = (0, import_react17.useState)(""), [actionStatus, setActionStatus] = (0, import_react17.useState)("");
|
|
5098
5267
|
const [busy, setBusy] = (0, import_react17.useState)(false), [invalidFields, setInvalidFields] = (0, import_react17.useState)({});
|
|
5099
5268
|
const pending2 = (0, import_react17.useRef)(false);
|
|
@@ -5103,15 +5272,15 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
|
|
|
5103
5272
|
const invalidChanged = import_react17.default.useCallback((id2, invalid) => setInvalidFields((previous) => previous[id2] === invalid ? previous : { ...previous, [id2]: invalid }), []);
|
|
5104
5273
|
let computed;
|
|
5105
5274
|
try {
|
|
5106
|
-
computed = evaluate(doc,
|
|
5275
|
+
computed = evaluate(doc, state2);
|
|
5107
5276
|
} catch (e) {
|
|
5108
5277
|
computed = { error: e.message };
|
|
5109
5278
|
}
|
|
5110
|
-
const currentState = (0, import_react17.useRef)(
|
|
5111
|
-
currentState.current =
|
|
5279
|
+
const currentState = (0, import_react17.useRef)(state2);
|
|
5280
|
+
currentState.current = state2;
|
|
5112
5281
|
(0, import_react17.useEffect)(() => {
|
|
5113
5282
|
collectAudit();
|
|
5114
|
-
}, [
|
|
5283
|
+
}, [state2, ready, collectAudit]);
|
|
5115
5284
|
const updatePatch = (patch) => {
|
|
5116
5285
|
const next = validateState(doc, { ...currentState.current, ...patch });
|
|
5117
5286
|
currentState.current = next;
|
|
@@ -5134,7 +5303,7 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
|
|
|
5134
5303
|
setActionStatus("\u6B63\u5728\u53D1\u9001\u2026");
|
|
5135
5304
|
setError("");
|
|
5136
5305
|
try {
|
|
5137
|
-
const prompt = followupPrompt(doc,
|
|
5306
|
+
const prompt = followupPrompt(doc, state2, actionKey, { documentId: record.documentId, sourceCallId: record.callId, sourceSessionId: record.sessionId, viewedSessionId: sessionId });
|
|
5138
5307
|
await sendPrompt(prompt);
|
|
5139
5308
|
setActionStatus("\u5DF2\u52A0\u5165\u5F53\u524D\u4F1A\u8BDD\u961F\u5217");
|
|
5140
5309
|
} catch (e) {
|
|
@@ -5151,11 +5320,11 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
|
|
|
5151
5320
|
const copy2 = () => n2.spans ? n2.spans.map((span, i) => h12("span", { key: i, style: typographyStyle(span) }, span.text)) : display(resolve(n2.text));
|
|
5152
5321
|
switch (n2.type) {
|
|
5153
5322
|
case "visual":
|
|
5154
|
-
return h12(VisualView, { key: n2.id, node: n2, state:
|
|
5323
|
+
return h12(VisualView, { key: n2.id, node: n2, state: state2[n2.stateKey], update: (value) => updatePatch({ [n2.stateKey]: value }), disabled, preview, sendPrompt, openFile, documentTitle: doc.title, provenance: { documentId: record.documentId, sourceSessionId: record.sessionId, viewedSessionId: sessionId } });
|
|
5155
5324
|
case "code":
|
|
5156
5325
|
return h12(CopyBlock, { key: n2.id, nodeId: n2.id, text: n2.code, lang: n2.lang, title: n2.title, wrap: n2.wrap, code: true, disabled: preview });
|
|
5157
5326
|
case "sandbox":
|
|
5158
|
-
return h12(Sandbox, { key: n2.id, node: n2, document: doc, state, data: doc.data, derived: computed.derived ?? {}, disabled, preview: preview || !ready, update: updatePatch, onAudit });
|
|
5327
|
+
return h12(Sandbox, { key: n2.id, node: n2, document: doc, state: state2, data: doc.data, derived: computed.derived ?? {}, disabled, preview: preview || !ready, update: updatePatch, onAudit });
|
|
5159
5328
|
case "heading":
|
|
5160
5329
|
return h12("h4", { ...props, className: "dgui-section-title" }, n2.icon && h12(Icon, { name: n2.icon }), h12("span", null, copy2()));
|
|
5161
5330
|
case "text":
|
|
@@ -5184,7 +5353,7 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
|
|
|
5184
5353
|
case "slider":
|
|
5185
5354
|
case "select":
|
|
5186
5355
|
case "toggle": {
|
|
5187
|
-
const k2 = n2.bind.split(".")[1], spec = doc.state[k2], v2 =
|
|
5356
|
+
const k2 = n2.bind.split(".")[1], spec = doc.state[k2], v2 = state2[k2], id2 = `dgui-${record.documentId}-${n2.id}-${viewId}`;
|
|
5188
5357
|
let control;
|
|
5189
5358
|
if (n2.type === "select" && n2.variant === "segmented" && spec.options.length >= 2 && spec.options.length <= 8) control = h12(SegmentedControl, { id: id2, label: n2.label, options: spec.options, value: v2, disabled: !ready, onChange: (value) => update(k2, value) });
|
|
5190
5359
|
else if (n2.type === "select") control = h12("select", { id: id2, value: spec.options.indexOf(v2), disabled: !ready, onChange: (e) => update(k2, spec.options[Number(e.target.value)]) }, spec.options.map((o, i) => h12("option", { key: i, value: i }, display(o))));
|
|
@@ -5333,7 +5502,7 @@ var turnUiDefinition = {
|
|
|
5333
5502
|
};
|
|
5334
5503
|
|
|
5335
5504
|
// src/stream-history.js
|
|
5336
|
-
var names = /* @__PURE__ */ new Set(["render_ui", "render_canvas", "render_text", "render_mechanism"]);
|
|
5505
|
+
var names = /* @__PURE__ */ new Set(["render_ui", "render_canvas", "render_text", "render_mechanism", "render_scene"]);
|
|
5337
5506
|
var streamUiDefinition = {
|
|
5338
5507
|
kind: "dshUiStream",
|
|
5339
5508
|
target: "chat",
|
|
@@ -5345,37 +5514,37 @@ var streamUiDefinition = {
|
|
|
5345
5514
|
start(_context, { event }) {
|
|
5346
5515
|
return { turn: event.data.turn, calls: [], invalidated: [], settled: false };
|
|
5347
5516
|
},
|
|
5348
|
-
update({ state }, { event }) {
|
|
5349
|
-
if (event.type === "turn/end") return { ...
|
|
5350
|
-
if (
|
|
5517
|
+
update({ state: state2 }, { event }) {
|
|
5518
|
+
if (event.type === "turn/end") return { ...state2, calls: [], settled: true };
|
|
5519
|
+
if (state2.settled) return state2;
|
|
5351
5520
|
if (event.type === "tool/call") {
|
|
5352
5521
|
const call2 = { key: `${event.data.step}:durable:${event.data.callId}`, callId: event.data.callId, name: event.data.name, raw: event.data.arguments ?? event.data.argsRaw ?? "" };
|
|
5353
|
-
if (typeof call2.raw !== "string" || call2.raw.length > LIMITS.bytes) return
|
|
5354
|
-
return { ...
|
|
5522
|
+
if (typeof call2.raw !== "string" || call2.raw.length > LIMITS.bytes) return state2;
|
|
5523
|
+
return { ...state2, anchorSeq: state2.anchorSeq ?? event.seq, calls: [...state2.calls.filter((c) => c.callId !== call2.callId), call2].slice(-24) };
|
|
5355
5524
|
}
|
|
5356
|
-
if (event.type === "llm/retry") return { ...
|
|
5525
|
+
if (event.type === "llm/retry") return { ...state2, invalidated: [...state2.invalidated, ...state2.calls.filter((c) => c.key.startsWith(`${event.data.step}:`)).map((c) => c.callId)].slice(-48), calls: state2.calls.filter((c) => !c.key.startsWith(`${event.data.step}:`)) };
|
|
5357
5526
|
if (event.type === "tool/result") {
|
|
5358
|
-
if (!event.data.message.isError) return
|
|
5359
|
-
return { ...
|
|
5527
|
+
if (!event.data.message.isError) return state2;
|
|
5528
|
+
return { ...state2, invalidated: [...state2.invalidated, event.data.callId].slice(-48), calls: state2.calls.filter((c) => c.callId !== event.data.callId) };
|
|
5360
5529
|
}
|
|
5361
|
-
const chunk = event.type === "chunkrow/tool-call-chunks" ? { ...event.data, argumentsDelta: event.data.args.join("") } : event.data.chunk, key2 = `${event.data.step}:${chunk.index}`, previous =
|
|
5530
|
+
const chunk = event.type === "chunkrow/tool-call-chunks" ? { ...event.data, argumentsDelta: event.data.args.join("") } : event.data.chunk, key2 = `${event.data.step}:${chunk.index}`, previous = state2.calls.find((c) => c.key === key2);
|
|
5362
5531
|
const name = chunk.name ?? previous?.name;
|
|
5363
|
-
if (!names.has(name)) return
|
|
5532
|
+
if (!names.has(name)) return state2;
|
|
5364
5533
|
const raw = (previous?.raw ?? "") + (chunk.argumentsDelta ?? "");
|
|
5365
|
-
if (raw.length > LIMITS.bytes) return { ...
|
|
5534
|
+
if (raw.length > LIMITS.bytes) return { ...state2, calls: state2.calls.filter((c) => c.key !== key2) };
|
|
5366
5535
|
const call = { key: key2, name, callId: previous?.callId ?? String(chunk.id), raw };
|
|
5367
|
-
return { ...
|
|
5536
|
+
return { ...state2, anchorSeq: state2.anchorSeq ?? event.seq, calls: [...state2.calls.filter((c) => c.key !== key2), call].slice(-24) };
|
|
5368
5537
|
},
|
|
5369
5538
|
publication: () => "immediate",
|
|
5370
|
-
buildLocationData({ state }, scope2, previous) {
|
|
5371
|
-
if (scope2 !== "turn" || !
|
|
5372
|
-
if (previous?.value ===
|
|
5373
|
-
return { kind: "turn", turn:
|
|
5539
|
+
buildLocationData({ state: state2 }, scope2, previous) {
|
|
5540
|
+
if (scope2 !== "turn" || !state2) return null;
|
|
5541
|
+
if (previous?.value === state2) return previous;
|
|
5542
|
+
return { kind: "turn", turn: state2.turn, key: "dshUiStream", value: state2 };
|
|
5374
5543
|
},
|
|
5375
5544
|
buildViewNode(context) {
|
|
5376
|
-
const
|
|
5377
|
-
if (!
|
|
5378
|
-
return { key: context.key, id: context.id, kind: "dshUiStream", target: "chat", anchorSeq:
|
|
5545
|
+
const state2 = context.state;
|
|
5546
|
+
if (!state2) return null;
|
|
5547
|
+
return { key: context.key, id: context.id, kind: "dshUiStream", target: "chat", anchorSeq: state2.anchorSeq ?? context.start?.event.seq ?? 0, location: context.start?.location ?? context.matches[0]?.location ?? { kind: "unresolved" }, visibility: state2.settled || state2.anchorSeq === void 0 ? "hidden" : "visible", data: state2 };
|
|
5379
5548
|
}
|
|
5380
5549
|
};
|
|
5381
5550
|
|
|
@@ -5501,10 +5670,10 @@ ${root} .dgui-steps li[data-step-status=active]{border-color:var(--du-accent)}${
|
|
|
5501
5670
|
var import_react18 = __toESM(require("react"), 1);
|
|
5502
5671
|
var h13 = import_react18.default.createElement;
|
|
5503
5672
|
var PREVIEW_LAYOUTS = [["text", "\u6587\u5B57\u8BF4\u660E"], ["comparison", "\u53CC\u5217\u5BF9\u6BD4"], ["list", "\u5206\u9694\u5217\u8868"], ["summary", "\u6570\u636E\u6458\u8981"], ["controls", "\u63A7\u4EF6\u8868\u5355"], ["flow", "\u6D41\u7A0B\u56FE\u89E3"]];
|
|
5504
|
-
var header = (
|
|
5505
|
-
var copy = (
|
|
5506
|
-
var card = (title,
|
|
5507
|
-
var
|
|
5673
|
+
var header = (text3) => h13("div", { className: "dgui-header" }, h13("strong", { className: "dgui-header-title" }, text3));
|
|
5674
|
+
var copy = (text3) => h13("p", { className: "dgui-copy" }, text3);
|
|
5675
|
+
var card = (title, text3) => h13("div", { key: title, className: "dgui-card" }, h13("strong", { className: "dgui-section-title" }, title), copy(text3));
|
|
5676
|
+
var metric2 = (number2, label) => h13("div", { key: label, className: "dgui-metric" }, h13("span", { className: "dgui-metric-label" }, label), h13("strong", null, number2));
|
|
5508
5677
|
function StyleSample({ styleId, layout = "text" }) {
|
|
5509
5678
|
let body, title;
|
|
5510
5679
|
if (layout === "text") {
|
|
@@ -5517,13 +5686,13 @@ function StyleSample({ styleId, layout = "text" }) {
|
|
|
5517
5686
|
body = h13("div", { className: "dgui-row" }, card("\u5148\u505A\u5C0F\u7248\u672C", "\u9A8C\u8BC1\u91CD\u70B9"), card("\u5148\u94FA\u5168\u529F\u80FD", "\u8986\u76D6\u9700\u6C42"));
|
|
5518
5687
|
} else if (layout === "summary") {
|
|
5519
5688
|
title = "\u8BA9\u91CD\u70B9\u4E00\u773C\u53EF\u89C1";
|
|
5520
|
-
body = h13("div", { className: "dgui-row" },
|
|
5689
|
+
body = h13("div", { className: "dgui-row" }, metric2("3", "\u63A8\u8FDB\u9636\u6BB5"), metric2("1", "\u6838\u5FC3\u76EE\u6807"));
|
|
5521
5690
|
} else if (layout === "controls") {
|
|
5522
5691
|
title = "\u8BA9\u53C2\u6570\u76F4\u63A5\u8BF4\u8BDD";
|
|
5523
5692
|
body = h13("div", { className: "dgui-column" }, h13("div", { className: "dgui-control" }, h13("span", { className: "dgui-control-label" }, "\u6BCF\u5468\u6295\u5165"), h13("output", null, "12 \u5C0F\u65F6"), h13("span", { className: "dgui-sample-track" }, h13("i"))), h13("div", { className: "dgui-sample-options" }, ["\u8F7B\u91CF", "\u5747\u8861", "\u6DF1\u5165"].map((t, i) => h13("span", { key: t, "data-selected": i === 1 || void 0 }, t))));
|
|
5524
5693
|
} else {
|
|
5525
5694
|
title = "\u628A\u590D\u6742\u95EE\u9898\u8BB2\u6E05\u695A";
|
|
5526
|
-
body = h13("ol", { className: "dgui-steps", "data-sample-layout": layout }, ["\u660E\u786E\u76EE\u6807", "\u89E3\u91CA\u5173\u7CFB", "\u7ED9\u51FA\u884C\u52A8"].map((
|
|
5695
|
+
body = h13("ol", { className: "dgui-steps", "data-sample-layout": layout }, ["\u660E\u786E\u76EE\u6807", "\u89E3\u91CA\u5173\u7CFB", "\u7ED9\u51FA\u884C\u52A8"].map((text3, i) => h13("li", { key: text3 }, h13("span", { className: "dgui-step-dot" }, layout === "list" ? "\u2713" : String(i + 1).padStart(2, "0")), h13("div", null, h13("strong", null, text3), layout === "list" && h13("p", null, ["\u5148\u6293\u4F4F\u91CD\u70B9", "\u7528\u56FE\u5F62\u8BF4\u660E", "\u6536\u6210\u4E0B\u4E00\u6B65"][i])))));
|
|
5527
5696
|
}
|
|
5528
5697
|
return h13("div", { className: "dgui-root dgui-style-preview", "data-preset": "brief", "data-visual-style": styleId, "data-layout": layout, "aria-hidden": true }, header(title), h13("div", { className: "dgui-content" }, body));
|
|
5529
5698
|
}
|
|
@@ -5683,7 +5852,7 @@ var READING_CSS = `
|
|
|
5683
5852
|
`;
|
|
5684
5853
|
|
|
5685
5854
|
// src/styles.js
|
|
5686
|
-
var
|
|
5855
|
+
var CSS2 = `
|
|
5687
5856
|
.dgui-chart-data-button{margin-left:auto;border:0;background:transparent;color:var(--du-muted);font:inherit;cursor:pointer;padding:4px 8px}.dgui-chart-data-button:hover{color:var(--du-accent)}.dgui-sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip-path:inset(50%)!important;white-space:nowrap!important;border:0!important}.dgui-canvas{position:relative}.dgui-action-menu{position:absolute;top:6px;right:6px;z-index:2}.dgui-menu-trigger{width:32px;height:32px;border:1px solid var(--du-line);border-radius:8px;background:var(--du-bg);color:var(--du-muted);font-size:24px;line-height:1;cursor:pointer}.dgui-menu-content{position:absolute;top:38px;right:0;display:grid;min-width:156px;padding:5px;border:1px solid var(--du-line);border-radius:10px;background:var(--du-bg);box-shadow:0 6px 20px #0002}.dgui-menu-content button{border:0;border-radius:6px;background:transparent;color:var(--du-ink);padding:9px 12px;text-align:left;font:inherit;white-space:nowrap;cursor:pointer}.dgui-menu-content button:hover{background:var(--du-soft)}.dgui-menu-content button:disabled{opacity:.45;cursor:default}.dgui-action-menu button:focus-visible{outline:2px solid var(--du-accent);outline-offset:2px}
|
|
5688
5857
|
.dgui-root.dgui-settings{border:0;border-radius:0;box-shadow:none;background:transparent;padding:0;margin:0;max-width:720px;display:flex;flex-direction:column;gap:14px;font-size:13px;line-height:1.65}
|
|
5689
5858
|
.dgui-settings h3{font-size:14px;font-weight:600;margin:0}.dgui-settings label{font-weight:500}.dgui-settings p{color:var(--du-muted)}
|
|
@@ -5865,18 +6034,18 @@ var fenceUiDefinition = {
|
|
|
5865
6034
|
start(_c, { event }) {
|
|
5866
6035
|
return { turn: event.data.turn, blocks: [], settled: false };
|
|
5867
6036
|
},
|
|
5868
|
-
update({ state }, { event }) {
|
|
5869
|
-
if (event.type === "turn/end") return { ...
|
|
5870
|
-
if (
|
|
6037
|
+
update({ state: state2 }, { event }) {
|
|
6038
|
+
if (event.type === "turn/end") return { ...state2, settled: true };
|
|
6039
|
+
if (state2.settled) return state2;
|
|
5871
6040
|
const step = event.data.step;
|
|
5872
|
-
if (event.type === "llm/retry") return { ...
|
|
6041
|
+
if (event.type === "llm/retry") return { ...state2, invalidated: [...state2.invalidated ?? [], step].slice(-48), blocks: state2.blocks.filter((b2) => b2.step !== step) };
|
|
5873
6042
|
if (event.type === "assistant/message") {
|
|
5874
6043
|
const blocks = (event.data.message?.content ?? []).flatMap((b2, index) => b2.type === "text" ? [{ step, index, text: b2.text }] : []);
|
|
5875
|
-
return { ...
|
|
6044
|
+
return { ...state2, everUi: state2.everUi || blocks.some((b2) => /(?:```|~~~)(?:dsh-ui|motion-ui|svg)/i.test(b2.text)), anchorSeq: state2.anchorSeq ?? event.seq, blocks: [...state2.blocks.filter((b2) => b2.step !== step), ...blocks].slice(-48) };
|
|
5876
6045
|
}
|
|
5877
|
-
const chunk = event.type === "chunkrow/text-chunks" ? { index: event.data.index, text: event.data.texts.join("") } : event.data.chunk, previous =
|
|
5878
|
-
if (
|
|
5879
|
-
return { ...
|
|
6046
|
+
const chunk = event.type === "chunkrow/text-chunks" ? { index: event.data.index, text: event.data.texts.join("") } : event.data.chunk, previous = state2.blocks.find((b2) => b2.step === step && b2.index === chunk.index), text3 = (previous?.text ?? "") + (chunk.text ?? chunk.delta ?? "");
|
|
6047
|
+
if (text3.length > 262144) return state2;
|
|
6048
|
+
return { ...state2, everUi: state2.everUi || /(?:```|~~~)(?:dsh-ui|motion-ui|svg)/i.test(text3), anchorSeq: state2.anchorSeq ?? event.seq, blocks: [...state2.blocks.filter((b2) => b2 !== previous), { step, index: chunk.index, text: text3 }].slice(-48) };
|
|
5880
6049
|
},
|
|
5881
6050
|
publication: () => "immediate",
|
|
5882
6051
|
buildViewNode(c) {
|
|
@@ -5890,9 +6059,9 @@ var import_react23 = __toESM(require("react"), 1);
|
|
|
5890
6059
|
var import_client2 = require("react-dom/client");
|
|
5891
6060
|
|
|
5892
6061
|
// lib/fences.js
|
|
5893
|
-
function extractUiFences(
|
|
5894
|
-
if (typeof
|
|
5895
|
-
const lines =
|
|
6062
|
+
function extractUiFences(text3) {
|
|
6063
|
+
if (typeof text3 !== "string" || new TextEncoder().encode(text3).length > 262144) return [];
|
|
6064
|
+
const lines = text3.split("\n"), out = [];
|
|
5896
6065
|
let fence = null;
|
|
5897
6066
|
for (const line of lines) {
|
|
5898
6067
|
if (!fence) {
|
|
@@ -5934,28 +6103,28 @@ function FenceContent({ document: document2, sessionId, source, settled, sendPro
|
|
|
5934
6103
|
}, [document2, sessionId, source, settled]);
|
|
5935
6104
|
return h18(UiBoundary, { fallback: document2.fallback }, h18(UiView, { record: record ?? { document: document2, documentId: "fence-preview-" + source }, sessionId, sendPrompt, preview: !record }), error && h18("p", { role: "alert" }, error));
|
|
5936
6105
|
}
|
|
5937
|
-
function candidates(
|
|
6106
|
+
function candidates(state2) {
|
|
5938
6107
|
const steps = /* @__PURE__ */ new Map();
|
|
5939
|
-
for (const b2 of
|
|
6108
|
+
for (const b2 of state2.blocks) {
|
|
5940
6109
|
if (!steps.has(b2.step)) steps.set(b2.step, []);
|
|
5941
6110
|
steps.get(b2.step).push(b2);
|
|
5942
6111
|
}
|
|
5943
6112
|
const all = [];
|
|
5944
6113
|
for (const [step, blocks] of steps) {
|
|
5945
|
-
const
|
|
5946
|
-
for (const [fence, index] of extractUiFences(
|
|
6114
|
+
const text3 = blocks.sort((a, b2) => a.index - b2.index).map((b2) => b2.text).join("\n");
|
|
6115
|
+
for (const [fence, index] of extractUiFences(text3).map((f, i) => [f, i])) {
|
|
5947
6116
|
let spec;
|
|
5948
6117
|
try {
|
|
5949
|
-
if (
|
|
6118
|
+
if (state2.settled) {
|
|
5950
6119
|
const result = resolveSourceFence(fence.raw, { svg: fence.language === "svg" });
|
|
5951
6120
|
if (result.marker) continue;
|
|
5952
|
-
all.push({ key: `${
|
|
6121
|
+
all.push({ key: `${state2.turn}:${step}:${index}`, raw: fence.raw, document: result.document, error: result.valid ? void 0 : result.diagnostics.map((d) => d.message).join("; ") });
|
|
5953
6122
|
continue;
|
|
5954
6123
|
}
|
|
5955
6124
|
spec = fence.language === "svg" ? fence.complete ? { items: [{ type: "svg", title: "SVG", code: fence.raw }] } : null : pt(fence.raw);
|
|
5956
6125
|
if (!spec) continue;
|
|
5957
6126
|
const document2 = validateDocument(spec);
|
|
5958
|
-
all.push({ key: `${
|
|
6127
|
+
all.push({ key: `${state2.turn}:${step}:${index}`, raw: fence.raw, document: document2 });
|
|
5959
6128
|
} catch {
|
|
5960
6129
|
}
|
|
5961
6130
|
}
|
|
@@ -5976,7 +6145,7 @@ function dispose2(e) {
|
|
|
5976
6145
|
e.entries.delete(e.key);
|
|
5977
6146
|
}
|
|
5978
6147
|
function FenceNodeView({ node, sessionId, sendPrompt }) {
|
|
5979
|
-
const anchor = (0, import_react23.useRef)(null),
|
|
6148
|
+
const anchor = (0, import_react23.useRef)(null), state2 = node.data;
|
|
5980
6149
|
(0, import_react23.useLayoutEffect)(() => {
|
|
5981
6150
|
const scroll = anchor.current?.closest("[data-conversation-scroll]");
|
|
5982
6151
|
if (!scroll) return;
|
|
@@ -5986,7 +6155,7 @@ function FenceNodeView({ node, sessionId, sendPrompt }) {
|
|
|
5986
6155
|
roots3.set(scroll, entries);
|
|
5987
6156
|
}
|
|
5988
6157
|
for (const e2 of entries.values()) if (e2.sessionId !== sessionId) dispose2(e2);
|
|
5989
|
-
const key2 = sessionId + ":" +
|
|
6158
|
+
const key2 = sessionId + ":" + state2.turn;
|
|
5990
6159
|
let e = entries.get(key2);
|
|
5991
6160
|
if (!e) {
|
|
5992
6161
|
e = { key: key2, entries, sessionId, url: location.href, views: /* @__PURE__ */ new Map(), scroll, seat: anchor.current.closest("[data-chat-turn]") ?? anchor.current };
|
|
@@ -6039,10 +6208,10 @@ function FenceNodeView({ node, sessionId, sendPrompt }) {
|
|
|
6039
6208
|
e.observer = new MutationObserver(e.queue);
|
|
6040
6209
|
e.observer.observe(document.body, { subtree: true, childList: true, characterData: true });
|
|
6041
6210
|
}
|
|
6042
|
-
e.state =
|
|
6211
|
+
e.state = state2;
|
|
6043
6212
|
e.sendPrompt = sendPrompt;
|
|
6044
6213
|
e.queue();
|
|
6045
|
-
}, [
|
|
6214
|
+
}, [state2, sessionId, sendPrompt]);
|
|
6046
6215
|
return h18("span", { ref: anchor, hidden: true });
|
|
6047
6216
|
}
|
|
6048
6217
|
|
|
@@ -6076,11 +6245,11 @@ function apply(ctx) {
|
|
|
6076
6245
|
ctx.effect(() => {
|
|
6077
6246
|
const style = document.createElement("style");
|
|
6078
6247
|
style.dataset.plugin = "dsh-generative-ui";
|
|
6079
|
-
style.textContent =
|
|
6248
|
+
style.textContent = CSS2 + VISUAL_CSS;
|
|
6080
6249
|
document.head.append(style);
|
|
6081
6250
|
return () => style.remove();
|
|
6082
6251
|
});
|
|
6083
|
-
for (const name of ["render_ui", "render_canvas", "render_text", "render_mechanism"]) ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
|
|
6252
|
+
for (const name of ["render_ui", "render_canvas", "render_text", "render_mechanism", "render_scene"]) ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
|
|
6084
6253
|
name: "tool.call.toolview",
|
|
6085
6254
|
key: name,
|
|
6086
6255
|
inject: (sessionId) => ({ sendPrompt: (prompt) => ctx.sessions.scope(sessionId).get("conversation").send(prompt) })
|