dsh-motion-ui 0.8.0 → 0.8.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 +25 -0
- package/README.md +4 -0
- package/VERIFICATION.md +7 -0
- package/client.js +254 -95
- package/lib/build-info.js +1 -1
- package/lib/canvas-source.js +27 -0
- package/lib/export-runtime-bundle.js +1 -1
- package/lib/sandbox.js +2 -1
- package/package.json +1 -1
package/client.js
CHANGED
|
@@ -36,7 +36,7 @@ __export(client_exports, {
|
|
|
36
36
|
inject: () => inject
|
|
37
37
|
});
|
|
38
38
|
module.exports = __toCommonJS(client_exports);
|
|
39
|
-
var
|
|
39
|
+
var import_react28 = __toESM(require("react"), 1);
|
|
40
40
|
|
|
41
41
|
// src/expressive-controls.js
|
|
42
42
|
var import_react2 = __toESM(require("react"), 1);
|
|
@@ -218,7 +218,7 @@ var MOTION_CSS = `
|
|
|
218
218
|
`;
|
|
219
219
|
|
|
220
220
|
// src/view.js
|
|
221
|
-
var
|
|
221
|
+
var import_react18 = __toESM(require("react"), 1);
|
|
222
222
|
|
|
223
223
|
// lib/presentation.js
|
|
224
224
|
var UI_ICONS = Object.freeze(["sparkles", "sliders", "layers", "chart", "gauge", "cpu", "database", "info", "check", "warning", "arrow", "target", "external", "file", "globe"]);
|
|
@@ -227,6 +227,63 @@ var UI_LAYOUTS = Object.freeze(["dashboard", "workbench", "comparison", "guide",
|
|
|
227
227
|
var UI_ACCENTS = Object.freeze(["blue", "teal", "violet", "amber", "rose"]);
|
|
228
228
|
var UI_SURFACES = Object.freeze(["outline", "soft", "featured"]);
|
|
229
229
|
|
|
230
|
+
// lib/canvas-source.js
|
|
231
|
+
function normalizeCanvasHtml(html) {
|
|
232
|
+
let protectedDepth = 0;
|
|
233
|
+
return html.replace(/<!--[\s\S]*?-->|<(?:"[^"]*"|'[^']*'|[^'">])*>|[^<]+|</g, (token) => {
|
|
234
|
+
if (token.startsWith("<")) {
|
|
235
|
+
const tag = token.match(/^<(\/)?(pre|code|textarea|script|style)\b/i);
|
|
236
|
+
if (tag) protectedDepth = Math.max(0, protectedDepth + (tag[1] ? -1 : 1));
|
|
237
|
+
return token;
|
|
238
|
+
}
|
|
239
|
+
return !protectedDepth && /^(?:\s|\\[rn])+$/.test(token) ? token.replace(/\\[rn]/g, "\n") : token;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
function normalizeCanvasCss(css) {
|
|
243
|
+
let out = "", quote = "", comment = false, last = "";
|
|
244
|
+
for (let i = 0; i < css.length; i++) {
|
|
245
|
+
const c = css[i], next = css[i + 1];
|
|
246
|
+
if (comment) {
|
|
247
|
+
out += c;
|
|
248
|
+
if (c === "*" && next === "/") {
|
|
249
|
+
out += next;
|
|
250
|
+
i++;
|
|
251
|
+
comment = false;
|
|
252
|
+
}
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (quote) {
|
|
256
|
+
out += c;
|
|
257
|
+
if (c === "\\" && next !== void 0) {
|
|
258
|
+
out += next;
|
|
259
|
+
i++;
|
|
260
|
+
} else if (c === quote) quote = "";
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
if (c === "/" && next === "*") {
|
|
264
|
+
out += "/*";
|
|
265
|
+
i++;
|
|
266
|
+
comment = true;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (c === '"' || c === "'") {
|
|
270
|
+
quote = c;
|
|
271
|
+
out += c;
|
|
272
|
+
last = c;
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (c === "\\" && /[rn]/.test(next ?? "") && /[{};]/.test(last)) {
|
|
276
|
+
out += "\n";
|
|
277
|
+
i++;
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
out += c;
|
|
281
|
+
if (!/\s/.test(c)) last = c;
|
|
282
|
+
}
|
|
283
|
+
return out;
|
|
284
|
+
}
|
|
285
|
+
var canvasSource = (node) => ({ html: normalizeCanvasHtml(node.html), css: normalizeCanvasCss(node.css ?? ""), script: node.script ?? "" });
|
|
286
|
+
|
|
230
287
|
// lib/mechanism-runtime-bundle.js
|
|
231
288
|
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';
|
|
232
289
|
|
|
@@ -376,12 +433,12 @@ function createTimelineAPI(animate, capture = false, notify = () => {
|
|
|
376
433
|
if (!Number.isFinite(duration) || duration <= 0 || duration > 86400 || typeof draw !== "function") throw Error("Timeline requires positive duration and draw(time, info)");
|
|
377
434
|
if (!Array.isArray(chapters) || chapters.length > 100 || chapters.some((c) => !c || typeof c.label !== "string" || !Number.isFinite(c.time) || c.time < 0 || c.time >= duration)) throw Error("Invalid timeline chapters");
|
|
378
435
|
let time = 0, playing = !!autoplay && !capture, disposed = false, reduced = false, visible = true;
|
|
379
|
-
const
|
|
436
|
+
const listeners5 = /* @__PURE__ */ new Set();
|
|
380
437
|
const state2 = () => ({ id: id2, time, duration, playing, loop: !!loop, reducedMotion: reduced, visible, chapters: chapters.map((c) => ({ time: c.time, label: c.label })) });
|
|
381
438
|
const render = () => {
|
|
382
439
|
draw(time, state2());
|
|
383
440
|
notify(state2());
|
|
384
|
-
for (const fn2 of
|
|
441
|
+
for (const fn2 of listeners5) fn2(state2());
|
|
385
442
|
};
|
|
386
443
|
const seek = (value) => {
|
|
387
444
|
if (disposed) throw Error("Timeline disposed");
|
|
@@ -406,14 +463,14 @@ function createTimelineAPI(animate, capture = false, notify = () => {
|
|
|
406
463
|
return seek(chapters[index].time);
|
|
407
464
|
}, subscribe(fn2) {
|
|
408
465
|
if (typeof fn2 !== "function") throw Error("Timeline listener required");
|
|
409
|
-
|
|
466
|
+
listeners5.add(fn2);
|
|
410
467
|
fn2(state2());
|
|
411
|
-
return () =>
|
|
468
|
+
return () => listeners5.delete(fn2);
|
|
412
469
|
}, dispose() {
|
|
413
470
|
if (disposed) return;
|
|
414
471
|
disposed = true;
|
|
415
472
|
stop();
|
|
416
|
-
|
|
473
|
+
listeners5.clear();
|
|
417
474
|
timelines.delete(id2);
|
|
418
475
|
} });
|
|
419
476
|
timelines.set(id2, api);
|
|
@@ -454,7 +511,7 @@ function canvasPatch(message, node) {
|
|
|
454
511
|
function sandboxDocument(node, channel, nonce) {
|
|
455
512
|
const json = (value) => JSON.stringify(value).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
456
513
|
return `<!doctype html><html><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'nonce-${nonce}'; 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="${nonce}">(()=>{
|
|
457
|
-
const channel=${json(channel)}, source=${json(
|
|
514
|
+
const channel=${json(channel)}, source=${json(canvasSource(node))};
|
|
458
515
|
let snapshot={state:{},data:{},derived:{},disabled:true,theme:{}}, started=false;
|
|
459
516
|
const listeners=new Set(), send=(type,payload)=>parent.postMessage({dshCanvas:1,channel,type,payload},'*');
|
|
460
517
|
const report=e=>send('error',String(e?.message??e).slice(0,1000));
|
|
@@ -3293,10 +3350,10 @@ function useSavedState(record, sessionId, preview = false) {
|
|
|
3293
3350
|
const timer = setTimeout(async () => {
|
|
3294
3351
|
r.saving = true;
|
|
3295
3352
|
if (r.alive) setStatus("\u6B63\u5728\u4FDD\u5B58\u53C2\u6570\u2026");
|
|
3296
|
-
const
|
|
3353
|
+
const revision3 = r.revision;
|
|
3297
3354
|
try {
|
|
3298
|
-
const saved = checked(await request(STATE_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ documentId: record.documentId, sessionId, revision:
|
|
3299
|
-
if (saved.revision !==
|
|
3355
|
+
const saved = checked(await request(STATE_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ documentId: record.documentId, sessionId, revision: revision3, state: state2 }) }));
|
|
3356
|
+
if (saved.revision !== revision3 + 1 || JSON.stringify(saved.state) !== signature) throw new Error("Unexpected save response");
|
|
3300
3357
|
r.revision = saved.revision;
|
|
3301
3358
|
r.saved = signature;
|
|
3302
3359
|
broadcastState(record.documentId, sessionId, saved, receive.current);
|
|
@@ -3624,7 +3681,7 @@ function CanvasPreview({ node }) {
|
|
|
3624
3681
|
const css = getComputedStyle(el.closest(".dgui-root") ?? el.parentElement);
|
|
3625
3682
|
const theme = Object.fromEntries(["bg", "soft", "ink", "muted", "line", "accent"].map((k2) => [k2, css.getPropertyValue("--du-" + k2).trim()]));
|
|
3626
3683
|
theme.scheme = document.body.hasAttribute("data-ds-dark-theme") || el.closest("[data-preview-theme=dark]") ? "dark" : "light";
|
|
3627
|
-
el.contentWindow?.postMessage({ channel: config.channel, html: latest.current.html, css: latest.current.css
|
|
3684
|
+
el.contentWindow?.postMessage({ channel: config.channel, html: canvasSource(latest.current).html, css: canvasSource(latest.current).css, theme }, "*");
|
|
3628
3685
|
};
|
|
3629
3686
|
(0, import_react5.useEffect)(() => {
|
|
3630
3687
|
const timer = setTimeout(publish2, 120);
|
|
@@ -3650,7 +3707,7 @@ function CanvasPreview({ node }) {
|
|
|
3650
3707
|
var import_react8 = __toESM(require("react"), 1);
|
|
3651
3708
|
|
|
3652
3709
|
// lib/export-runtime-bundle.js
|
|
3653
|
-
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/timeline.js\n function createTimelineAPI(animate, capture = false, notify = () => {\n }) {\n const timelines = /* @__PURE__ */ new Map();\n function timeline(options) {\n const { id = "main", duration, draw, loop = false, autoplay = true, chapters = [] } = options ?? {};\n if (typeof id !== "string" || !/^[A-Za-z_][\\w-]{0,63}$/.test(id) || timelines.has(id)) throw Error("Timeline id must be unique");\n if (!Number.isFinite(duration) || duration <= 0 || duration > 86400 || typeof draw !== "function") throw Error("Timeline requires positive duration and draw(time, info)");\n if (!Array.isArray(chapters) || chapters.length > 100 || chapters.some((c) => !c || typeof c.label !== "string" || !Number.isFinite(c.time) || c.time < 0 || c.time >= duration)) throw Error("Invalid timeline chapters");\n let time = 0, playing = !!autoplay && !capture, disposed = false, reduced = false, visible = true;\n const listeners = /* @__PURE__ */ new Set();\n const state2 = () => ({ id, time, duration, playing, loop: !!loop, reducedMotion: reduced, visible, chapters: chapters.map((c) => ({ time: c.time, label: c.label })) });\n const render = () => {\n draw(time, state2());\n notify(state2());\n for (const fn2 of listeners) fn2(state2());\n };\n const seek = (value) => {\n if (disposed) throw Error("Timeline disposed");\n if (!Number.isFinite(value)) throw Error("Timeline seek requires finite seconds");\n time = Math.max(0, Math.min(duration, value));\n render();\n return state2();\n };\n const api = Object.freeze({ state: state2, seek, play() {\n if (disposed) throw Error("Timeline disposed");\n playing = true;\n render();\n }, pause() {\n playing = false;\n render();\n }, replay() {\n playing = !capture;\n seek(0);\n }, chapter(index) {\n if (!Number.isInteger(index) || !chapters[index]) throw Error("Invalid chapter");\n playing = false;\n return seek(chapters[index].time);\n }, subscribe(fn2) {\n if (typeof fn2 !== "function") throw Error("Timeline listener required");\n listeners.add(fn2);\n fn2(state2());\n return () => listeners.delete(fn2);\n }, dispose() {\n if (disposed) return;\n disposed = true;\n stop();\n listeners.clear();\n timelines.delete(id);\n } });\n timelines.set(id, api);\n const stop = animate((info) => {\n reduced = !!info.reducedMotion;\n visible = info.visible !== false;\n if (!capture && playing && !reduced && visible) {\n const next = time + info.delta;\n time = loop ? next % duration : Math.min(duration, next);\n if (!loop && time === duration) playing = false;\n }\n render();\n });\n return api;\n }\n return { timeline, capture: Object.freeze({ list: () => [...timelines.values()].map((t) => t.state()), seek: (id, time) => {\n const t = timelines.get(id);\n if (!t) throw Error("Timeline not found: " + id);\n t.seek(time);\n t.pause();\n return t.state();\n } }) };\n }\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&&!window.__DSHMotionRender;\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 let soundTick=0,soundPlaying,soundTime,soundVisible;const timelineAPI=(${createTimelineAPI.toString()})(api.animate,!!window.__DSHMotionRender,s=>{if(snapshot.motionSound){const now=performance.now();if(now-soundTick>=100||s.playing!==soundPlaying||s.visible!==soundVisible||(!s.playing&&s.time!==soundTime)){soundTick=now;soundPlaying=s.playing;soundTime=s.time;soundVisible=s.visible;send(\'timeline\',s)}}});api.timeline=timelineAPI.timeline;\n Object.defineProperty(window,\'__DSHMotionCapture\',{value:timelineAPI.capture,writable:false});\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 sound = payload.soundtrack;\n var audio;\n var unlocked = false;\n var soundState;\n var caption;\n if (payload.captions?.length && !window.__DSHMotionRender) {\n caption = document.createElement("div");\n caption.setAttribute("aria-live", "off");\n caption.style.cssText = "position:absolute;bottom:5%;left:10%;right:10%;text-align:center;white-space:pre-line;pointer-events:none;font:600 clamp(14px,2.1vw,28px)/1.4 system-ui;color:white;text-shadow:0 1px 4px black";\n const surface = document.getElementById("surface");\n surface.style.position = "relative";\n surface.append(caption);\n }\n var soundAllowed = () => unlocked && soundState?.playing && !soundState.reducedMotion && soundState.visible && !document.hidden;\n if (sound && !window.__DSHMotionRender && /^[\\w-]+\\.(wav|mp3|m4a|aac|ogg|flac)$/.test(sound.file)) {\n audio = document.createElement("audio");\n audio.src = sound.file;\n audio.preload = "auto";\n audio.volume = Math.max(0, Math.min(1, sound.volume ?? 0.3));\n const button = document.createElement("button");\n button.textContent = "\\u5F00\\u542F\\u914D\\u4E50";\n button.type = "button";\n button.addEventListener("click", () => {\n unlocked = !unlocked;\n button.textContent = unlocked ? "\\u5173\\u95ED\\u914D\\u4E50" : "\\u5F00\\u542F\\u914D\\u4E50";\n if (!soundAllowed()) audio.pause();\n else audio.play().then(() => {\n if (!soundAllowed()) audio.pause();\n }).catch(() => {\n unlocked = false;\n button.textContent = "\\u70B9\\u51FB\\u91CD\\u8BD5\\u914D\\u4E50";\n });\n });\n status.before(button);\n status.before(audio);\n }\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, motionSound: !!audio || !!caption } }, "*");\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 else if (m2.type === "timeline" && m2.payload.id === "main") {\n soundState = m2.payload;\n if (caption) caption.textContent = payload.captions.find((c) => m2.payload.time >= c.start && m2.payload.time < c.end)?.text ?? "";\n if (!audio) return;\n const t = m2.payload.time;\n if (Number.isFinite(t) && Math.abs(audio.currentTime - t) > 0.2) audio.currentTime = t;\n if (!soundAllowed()) audio.pause();\n else if (audio.paused) audio.play().then(() => {\n if (!soundAllowed()) audio.pause();\n }).catch(() => {\n unlocked = false;\n status.textContent = "\\u8BF7\\u70B9\\u51FB\\u5F00\\u542F\\u914D\\u4E50\\u4EE5\\u5141\\u8BB8\\u64AD\\u653E\\u58F0\\u97F3\\u3002";\n });\n }\n });\n document.addEventListener("visibilitychange", () => {\n if (document.hidden) audio?.pause();\n if (connected) publish();\n });\n addEventListener("pagehide", () => audio?.pause());\n document.getElementById("surface").append(frame);\n frame.srcdoc = sandboxDocument(node, channel, nonce);\n})();\n';
|
|
3710
|
+
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/canvas-source.js\n function normalizeCanvasHtml(html) {\n let protectedDepth = 0;\n return html.replace(/<!--[\\s\\S]*?-->|<(?:"[^"]*"|\'[^\']*\'|[^\'">])*>|[^<]+|</g, (token2) => {\n if (token2.startsWith("<")) {\n const tag = token2.match(/^<(\\/)?(pre|code|textarea|script|style)\\b/i);\n if (tag) protectedDepth = Math.max(0, protectedDepth + (tag[1] ? -1 : 1));\n return token2;\n }\n return !protectedDepth && /^(?:\\s|\\\\[rn])+$/.test(token2) ? token2.replace(/\\\\[rn]/g, "\\n") : token2;\n });\n }\n function normalizeCanvasCss(css) {\n let out = "", quote = "", comment = false, last = "";\n for (let i = 0; i < css.length; i++) {\n const c = css[i], next = css[i + 1];\n if (comment) {\n out += c;\n if (c === "*" && next === "/") {\n out += next;\n i++;\n comment = false;\n }\n continue;\n }\n if (quote) {\n out += c;\n if (c === "\\\\" && next !== void 0) {\n out += next;\n i++;\n } else if (c === quote) quote = "";\n continue;\n }\n if (c === "/" && next === "*") {\n out += "/*";\n i++;\n comment = true;\n continue;\n }\n if (c === \'"\' || c === "\'") {\n quote = c;\n out += c;\n last = c;\n continue;\n }\n if (c === "\\\\" && /[rn]/.test(next ?? "") && /[{};]/.test(last)) {\n out += "\\n";\n i++;\n continue;\n }\n out += c;\n if (!/\\s/.test(c)) last = c;\n }\n return out;\n }\n var canvasSource = (node2) => ({ html: normalizeCanvasHtml(node2.html), css: normalizeCanvasCss(node2.css ?? ""), script: node2.script ?? "" });\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/timeline.js\n function createTimelineAPI(animate, capture = false, notify = () => {\n }) {\n const timelines = /* @__PURE__ */ new Map();\n function timeline(options) {\n const { id = "main", duration, draw, loop = false, autoplay = true, chapters = [] } = options ?? {};\n if (typeof id !== "string" || !/^[A-Za-z_][\\w-]{0,63}$/.test(id) || timelines.has(id)) throw Error("Timeline id must be unique");\n if (!Number.isFinite(duration) || duration <= 0 || duration > 86400 || typeof draw !== "function") throw Error("Timeline requires positive duration and draw(time, info)");\n if (!Array.isArray(chapters) || chapters.length > 100 || chapters.some((c) => !c || typeof c.label !== "string" || !Number.isFinite(c.time) || c.time < 0 || c.time >= duration)) throw Error("Invalid timeline chapters");\n let time = 0, playing = !!autoplay && !capture, disposed = false, reduced = false, visible = true;\n const listeners = /* @__PURE__ */ new Set();\n const state2 = () => ({ id, time, duration, playing, loop: !!loop, reducedMotion: reduced, visible, chapters: chapters.map((c) => ({ time: c.time, label: c.label })) });\n const render = () => {\n draw(time, state2());\n notify(state2());\n for (const fn2 of listeners) fn2(state2());\n };\n const seek = (value) => {\n if (disposed) throw Error("Timeline disposed");\n if (!Number.isFinite(value)) throw Error("Timeline seek requires finite seconds");\n time = Math.max(0, Math.min(duration, value));\n render();\n return state2();\n };\n const api = Object.freeze({ state: state2, seek, play() {\n if (disposed) throw Error("Timeline disposed");\n playing = true;\n render();\n }, pause() {\n playing = false;\n render();\n }, replay() {\n playing = !capture;\n seek(0);\n }, chapter(index) {\n if (!Number.isInteger(index) || !chapters[index]) throw Error("Invalid chapter");\n playing = false;\n return seek(chapters[index].time);\n }, subscribe(fn2) {\n if (typeof fn2 !== "function") throw Error("Timeline listener required");\n listeners.add(fn2);\n fn2(state2());\n return () => listeners.delete(fn2);\n }, dispose() {\n if (disposed) return;\n disposed = true;\n stop();\n listeners.clear();\n timelines.delete(id);\n } });\n timelines.set(id, api);\n const stop = animate((info) => {\n reduced = !!info.reducedMotion;\n visible = info.visible !== false;\n if (!capture && playing && !reduced && visible) {\n const next = time + info.delta;\n time = loop ? next % duration : Math.min(duration, next);\n if (!loop && time === duration) playing = false;\n }\n render();\n });\n return api;\n }\n return { timeline, capture: Object.freeze({ list: () => [...timelines.values()].map((t) => t.state()), seek: (id, time) => {\n const t = timelines.get(id);\n if (!t) throw Error("Timeline not found: " + id);\n t.seek(time);\n t.pause();\n return t.state();\n } }) };\n }\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(canvasSource(node2))};\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&&!window.__DSHMotionRender;\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 let soundTick=0,soundPlaying,soundTime,soundVisible;const timelineAPI=(${createTimelineAPI.toString()})(api.animate,!!window.__DSHMotionRender,s=>{if(snapshot.motionSound){const now=performance.now();if(now-soundTick>=100||s.playing!==soundPlaying||s.visible!==soundVisible||(!s.playing&&s.time!==soundTime)){soundTick=now;soundPlaying=s.playing;soundTime=s.time;soundVisible=s.visible;send(\'timeline\',s)}}});api.timeline=timelineAPI.timeline;\n Object.defineProperty(window,\'__DSHMotionCapture\',{value:timelineAPI.capture,writable:false});\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 sound = payload.soundtrack;\n var audio;\n var unlocked = false;\n var soundState;\n var caption;\n if (payload.captions?.length && !window.__DSHMotionRender) {\n caption = document.createElement("div");\n caption.setAttribute("aria-live", "off");\n caption.style.cssText = "position:absolute;bottom:5%;left:10%;right:10%;text-align:center;white-space:pre-line;pointer-events:none;font:600 clamp(14px,2.1vw,28px)/1.4 system-ui;color:white;text-shadow:0 1px 4px black";\n const surface = document.getElementById("surface");\n surface.style.position = "relative";\n surface.append(caption);\n }\n var soundAllowed = () => unlocked && soundState?.playing && !soundState.reducedMotion && soundState.visible && !document.hidden;\n if (sound && !window.__DSHMotionRender && /^[\\w-]+\\.(wav|mp3|m4a|aac|ogg|flac)$/.test(sound.file)) {\n audio = document.createElement("audio");\n audio.src = sound.file;\n audio.preload = "auto";\n audio.volume = Math.max(0, Math.min(1, sound.volume ?? 0.3));\n const button = document.createElement("button");\n button.textContent = "\\u5F00\\u542F\\u914D\\u4E50";\n button.type = "button";\n button.addEventListener("click", () => {\n unlocked = !unlocked;\n button.textContent = unlocked ? "\\u5173\\u95ED\\u914D\\u4E50" : "\\u5F00\\u542F\\u914D\\u4E50";\n if (!soundAllowed()) audio.pause();\n else audio.play().then(() => {\n if (!soundAllowed()) audio.pause();\n }).catch(() => {\n unlocked = false;\n button.textContent = "\\u70B9\\u51FB\\u91CD\\u8BD5\\u914D\\u4E50";\n });\n });\n status.before(button);\n status.before(audio);\n }\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, motionSound: !!audio || !!caption } }, "*");\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 else if (m2.type === "timeline" && m2.payload.id === "main") {\n soundState = m2.payload;\n if (caption) caption.textContent = payload.captions.find((c) => m2.payload.time >= c.start && m2.payload.time < c.end)?.text ?? "";\n if (!audio) return;\n const t = m2.payload.time;\n if (Number.isFinite(t) && Math.abs(audio.currentTime - t) > 0.2) audio.currentTime = t;\n if (!soundAllowed()) audio.pause();\n else if (audio.paused) audio.play().then(() => {\n if (!soundAllowed()) audio.pause();\n }).catch(() => {\n unlocked = false;\n status.textContent = "\\u8BF7\\u70B9\\u51FB\\u5F00\\u542F\\u914D\\u4E50\\u4EE5\\u5141\\u8BB8\\u64AD\\u653E\\u58F0\\u97F3\\u3002";\n });\n }\n });\n document.addEventListener("visibilitychange", () => {\n if (document.hidden) audio?.pause();\n if (connected) publish();\n });\n addEventListener("pagehide", () => audio?.pause());\n document.getElementById("surface").append(frame);\n frame.srcdoc = sandboxDocument(node, channel, nonce);\n})();\n';
|
|
3654
3711
|
|
|
3655
3712
|
// lib/canvas-export.js
|
|
3656
3713
|
function standaloneCanvas(document2, node, state2, theme = {}, soundtrack, captions) {
|
|
@@ -4050,7 +4107,7 @@ function Sandbox({ node, document: doc, state: state2, data, derived, disabled,
|
|
|
4050
4107
|
}
|
|
4051
4108
|
|
|
4052
4109
|
// lib/build-info.js
|
|
4053
|
-
var BUILD_INFO = Object.freeze({ "version": "0.8.
|
|
4110
|
+
var BUILD_INFO = Object.freeze({ "version": "0.8.1", "id": "0.8.1+7d966f2ef4ce", "sourceHash": "7d966f2ef4cea9bdaa32c1ea1ff74f2b51eb223f21e34b949c1e77f1459fd811" });
|
|
4054
4111
|
|
|
4055
4112
|
// lib/refinement.js
|
|
4056
4113
|
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" });
|
|
@@ -4116,11 +4173,11 @@ function HistoryView({ record, sessionId }) {
|
|
|
4116
4173
|
setBusy(false);
|
|
4117
4174
|
}
|
|
4118
4175
|
}
|
|
4119
|
-
async function restore(
|
|
4176
|
+
async function restore(revision3) {
|
|
4120
4177
|
setBusy(true);
|
|
4121
4178
|
setError("");
|
|
4122
4179
|
try {
|
|
4123
|
-
const next = await request2({ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ documentRevision: record.documentRevision ?? 0, targetRevision:
|
|
4180
|
+
const next = await request2({ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ documentRevision: record.documentRevision ?? 0, targetRevision: revision3 }) });
|
|
4124
4181
|
publishDocument(next);
|
|
4125
4182
|
setPreview(null);
|
|
4126
4183
|
setVersions(await request2());
|
|
@@ -4130,11 +4187,11 @@ function HistoryView({ record, sessionId }) {
|
|
|
4130
4187
|
setBusy(false);
|
|
4131
4188
|
}
|
|
4132
4189
|
}
|
|
4133
|
-
async function inspect(
|
|
4190
|
+
async function inspect(revision3) {
|
|
4134
4191
|
setBusy(true);
|
|
4135
4192
|
setError("");
|
|
4136
4193
|
try {
|
|
4137
|
-
const r = await fetch(url + "&revision=" +
|
|
4194
|
+
const r = await fetch(url + "&revision=" + revision3, { credentials: "same-origin" }), v2 = await r.json();
|
|
4138
4195
|
if (!r.ok) throw new Error(v2.error ?? "\u5386\u53F2\u8BFB\u53D6\u5931\u8D25");
|
|
4139
4196
|
setPreview({ ...v2, document: validateDocument(v2.document) });
|
|
4140
4197
|
} catch (e) {
|
|
@@ -4368,7 +4425,7 @@ function PresentationView({ raw, sessionId, sendPrompt, openFile, scope: scope2
|
|
|
4368
4425
|
block.style.display = previous;
|
|
4369
4426
|
};
|
|
4370
4427
|
}, [host, owner]);
|
|
4371
|
-
const content = h8(ValidatedView, { raw, fallback: raw.document.fallback, sessionId, sendPrompt, openFile });
|
|
4428
|
+
const content = h8(ValidatedView, { raw, fallback: raw.document.fallback, sessionId, sendPrompt, openFile, replaceExportedCanvases: true });
|
|
4372
4429
|
return h8(
|
|
4373
4430
|
"div",
|
|
4374
4431
|
{ ref: anchor, "data-dgui-presentation": raw.documentId },
|
|
@@ -5238,12 +5295,43 @@ function CopyBlock({ text: text3, children, title, lang, code = false, wrap = fa
|
|
|
5238
5295
|
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));
|
|
5239
5296
|
}
|
|
5240
5297
|
|
|
5298
|
+
// src/media-presentation.js
|
|
5299
|
+
var import_react17 = require("react");
|
|
5300
|
+
var owners = /* @__PURE__ */ new Map();
|
|
5301
|
+
var listeners4 = /* @__PURE__ */ new Set();
|
|
5302
|
+
var revision2 = 0;
|
|
5303
|
+
var emit2 = () => {
|
|
5304
|
+
revision2++;
|
|
5305
|
+
for (const fn2 of listeners4) fn2();
|
|
5306
|
+
};
|
|
5307
|
+
function presentMedia(owner, sessionId, records2) {
|
|
5308
|
+
owners.set(owner, { sessionId, records: records2 });
|
|
5309
|
+
emit2();
|
|
5310
|
+
return () => {
|
|
5311
|
+
if (owners.delete(owner)) emit2();
|
|
5312
|
+
};
|
|
5313
|
+
}
|
|
5314
|
+
function useExportedCanvases(record, sessionId, enabled) {
|
|
5315
|
+
(0, import_react17.useSyncExternalStore)((fn2) => {
|
|
5316
|
+
listeners4.add(fn2);
|
|
5317
|
+
return () => listeners4.delete(fn2);
|
|
5318
|
+
}, () => revision2, () => 0);
|
|
5319
|
+
const ids = /* @__PURE__ */ new Set();
|
|
5320
|
+
if (!enabled) return ids;
|
|
5321
|
+
for (const value of owners.values()) if (value.sessionId === sessionId) for (const media of value.records) {
|
|
5322
|
+
if (media.kind !== "render" || media.sessionId !== sessionId || media.documentId !== record.documentId) continue;
|
|
5323
|
+
if ((media.documentRevision ?? 0) !== (record.documentRevision ?? 0)) continue;
|
|
5324
|
+
if (media.nodeId) ids.add(media.nodeId);
|
|
5325
|
+
}
|
|
5326
|
+
return ids;
|
|
5327
|
+
}
|
|
5328
|
+
|
|
5241
5329
|
// src/view.js
|
|
5242
|
-
var h12 =
|
|
5330
|
+
var h12 = import_react18.default.createElement;
|
|
5243
5331
|
var display = (value) => value === void 0 || value === null ? "\u2014" : typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
5244
5332
|
function NumericInput({ id: id2, spec, value, onChange, invalidChanged, disabled }) {
|
|
5245
|
-
const [draft, setDraft] = (0,
|
|
5246
|
-
(0,
|
|
5333
|
+
const [draft, setDraft] = (0, import_react18.useState)(String(value)), [invalid, setInvalid] = (0, import_react18.useState)(false);
|
|
5334
|
+
(0, import_react18.useEffect)(() => {
|
|
5247
5335
|
setDraft(String(value));
|
|
5248
5336
|
setInvalid(false);
|
|
5249
5337
|
invalidChanged(id2, false);
|
|
@@ -5277,7 +5365,7 @@ function Table({ rows, columns, id: id2, label }) {
|
|
|
5277
5365
|
));
|
|
5278
5366
|
}
|
|
5279
5367
|
function Chart({ node, rows }) {
|
|
5280
|
-
const [showData, setShowData] = (0,
|
|
5368
|
+
const [showData, setShowData] = (0, import_react18.useState)(false);
|
|
5281
5369
|
const data = rows.slice(0, 40), values = data.map((r) => r[node.valueKey]);
|
|
5282
5370
|
const low = node.kind === "line" && values.length ? Math.min(...values) : Math.min(0, ...values);
|
|
5283
5371
|
const high = node.kind === "line" && values.length ? Math.max(...values) : Math.max(0, ...values), range = high - low || 1;
|
|
@@ -5308,13 +5396,14 @@ function Chart({ node, rows }) {
|
|
|
5308
5396
|
h12("div", { hidden: !showData }, h12(Table, { rows, columns: [{ key: node.labelKey, label: "\u9879\u76EE" }, { key: node.valueKey, label: node.label, unit: node.unit }], id: `${node.id}-data` }))
|
|
5309
5397
|
);
|
|
5310
5398
|
}
|
|
5311
|
-
function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
|
|
5399
|
+
function UiView({ record, sessionId, sendPrompt, openFile, preview = false, replaceExportedCanvases = false }) {
|
|
5400
|
+
const exportedCanvases = useExportedCanvases(record, sessionId, replaceExportedCanvases);
|
|
5312
5401
|
const showDetails = useViewDetails();
|
|
5313
5402
|
const nativeStyle = useNativeStyle();
|
|
5314
5403
|
const doc = record.document;
|
|
5315
|
-
const viewId =
|
|
5316
|
-
const root2 = (0,
|
|
5317
|
-
const collectAudit =
|
|
5404
|
+
const viewId = import_react18.default.useId();
|
|
5405
|
+
const root2 = (0, import_react18.useRef)(null), canvasAudits = (0, import_react18.useRef)(/* @__PURE__ */ new Map()), [audit, setAudit] = (0, import_react18.useState)(null), auditPending = (0, import_react18.useRef)(0);
|
|
5406
|
+
const collectAudit = import_react18.default.useCallback(() => {
|
|
5318
5407
|
clearTimeout(auditPending.current);
|
|
5319
5408
|
auditPending.current = setTimeout(() => {
|
|
5320
5409
|
if (!root2.current || preview) return;
|
|
@@ -5326,7 +5415,7 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
|
|
|
5326
5415
|
});
|
|
5327
5416
|
}, 250);
|
|
5328
5417
|
}, [record.documentId, record.documentRevision, sessionId, preview]);
|
|
5329
|
-
(0,
|
|
5418
|
+
(0, import_react18.useEffect)(() => {
|
|
5330
5419
|
canvasAudits.current.clear();
|
|
5331
5420
|
collectAudit();
|
|
5332
5421
|
window.addEventListener("resize", collectAudit);
|
|
@@ -5344,22 +5433,22 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
|
|
|
5344
5433
|
collectAudit();
|
|
5345
5434
|
};
|
|
5346
5435
|
const { state: state2, setState, ready, status, issue, epoch, retry, useRemote, keepLocal } = useSavedState(record, sessionId, preview);
|
|
5347
|
-
const [error, setError] = (0,
|
|
5348
|
-
const [busy, setBusy] = (0,
|
|
5349
|
-
const pending2 = (0,
|
|
5350
|
-
(0,
|
|
5436
|
+
const [error, setError] = (0, import_react18.useState)(""), [actionStatus, setActionStatus] = (0, import_react18.useState)("");
|
|
5437
|
+
const [busy, setBusy] = (0, import_react18.useState)(false), [invalidFields, setInvalidFields] = (0, import_react18.useState)({});
|
|
5438
|
+
const pending2 = (0, import_react18.useRef)(false);
|
|
5439
|
+
(0, import_react18.useEffect)(() => {
|
|
5351
5440
|
setInvalidFields({});
|
|
5352
5441
|
}, [epoch]);
|
|
5353
|
-
const invalidChanged =
|
|
5442
|
+
const invalidChanged = import_react18.default.useCallback((id2, invalid) => setInvalidFields((previous) => previous[id2] === invalid ? previous : { ...previous, [id2]: invalid }), []);
|
|
5354
5443
|
let computed;
|
|
5355
5444
|
try {
|
|
5356
5445
|
computed = evaluate(doc, state2);
|
|
5357
5446
|
} catch (e) {
|
|
5358
5447
|
computed = { error: e.message };
|
|
5359
5448
|
}
|
|
5360
|
-
const currentState = (0,
|
|
5449
|
+
const currentState = (0, import_react18.useRef)(state2);
|
|
5361
5450
|
currentState.current = state2;
|
|
5362
|
-
(0,
|
|
5451
|
+
(0, import_react18.useEffect)(() => {
|
|
5363
5452
|
collectAudit();
|
|
5364
5453
|
}, [state2, ready, collectAudit]);
|
|
5365
5454
|
const updatePatch = (patch) => {
|
|
@@ -5397,6 +5486,7 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
|
|
|
5397
5486
|
}
|
|
5398
5487
|
const resolve = (value) => computed.error ? "\u2014" : computed.resolveValue(value);
|
|
5399
5488
|
function renderNode(n2) {
|
|
5489
|
+
if (n2.type === "sandbox" && exportedCanvases.has(n2.id)) return null;
|
|
5400
5490
|
const props = { key: n2.id, "data-ui-node": n2.id, "data-tone": n2.tone, style: ["text", "heading", "callout"].includes(n2.type) ? typographyStyle(n2) : ["row", "column"].includes(n2.type) ? { gap: n2.gap, ...n2.columns ? { "--du-columns": n2.columns } : {} } : void 0 };
|
|
5401
5491
|
const copy2 = () => n2.spans ? n2.spans.map((span, i) => h12("span", { key: i, style: typographyStyle(span) }, span.text)) : display(resolve(n2.text));
|
|
5402
5492
|
switch (n2.type) {
|
|
@@ -5440,7 +5530,7 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
|
|
|
5440
5530
|
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))));
|
|
5441
5531
|
else if (n2.type === "toggle") control = h12(ElasticToggle, { id: id2, checked: v2, disabled: !ready, onChange: (value) => update(k2, value) });
|
|
5442
5532
|
else if (n2.type === "toggle") control = h12("input", { id: id2, className: "dgui-toggle", type: "checkbox", checked: v2, disabled: !ready, onChange: (e) => update(k2, e.target.checked) });
|
|
5443
|
-
else if (n2.type === "slider") control = h12(
|
|
5533
|
+
else if (n2.type === "slider") control = h12(import_react18.default.Fragment, null, h12("input", { id: id2, style: { "--du-range": (spec.max > spec.min ? (v2 - spec.min) / (spec.max - spec.min) * 100 : 0) + "%" }, type: "range", min: spec.min, max: spec.max, step: spec.step, value: v2, disabled: !ready, onChange: (e) => update(k2, Number(e.target.value)) }), h12("output", { htmlFor: id2 }, display(v2)));
|
|
5444
5534
|
else if (spec.type === "number") control = h12(NumericInput, { id: id2, spec, value: v2, disabled: !ready, invalidChanged, onChange: (value) => update(k2, value) });
|
|
5445
5535
|
else control = h12("input", { id: id2, type: "text", value: v2, maxLength: 8192, disabled: !ready, onChange: (e) => update(k2, e.target.value) });
|
|
5446
5536
|
if (n2.type === "input" && spec.type === "number") control = h12(Stepper, { value: v2, spec, label: n2.label, disabled: !ready, onChange: (value) => update(k2, value) }, control);
|
|
@@ -5470,6 +5560,7 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
|
|
|
5470
5560
|
return null;
|
|
5471
5561
|
}
|
|
5472
5562
|
}
|
|
5563
|
+
if (doc.nodes.every((n2) => n2.type === "sandbox" && exportedCanvases.has(n2.id))) return null;
|
|
5473
5564
|
return h12(
|
|
5474
5565
|
"section",
|
|
5475
5566
|
{ ref: root2, className: "dgui-root", "data-document-revision": record.documentRevision ?? 0, "data-dgui-build": BUILD_INFO.id, "data-dsh-generative-ui": record.documentId, "data-preset": doc.presentation?.preset ?? ({ comparison: "comparison", guide: "list", report: "reading" }[doc.presentation?.layout] ?? "brief"), "data-visual-style": nativeStyle, "data-layout": doc.presentation?.layout, "data-accent": doc.presentation?.accent, "data-density": doc.presentation?.density, "data-preview": preview || void 0, "aria-label": doc.title, "aria-busy": preview || void 0 },
|
|
@@ -5481,7 +5572,7 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
|
|
|
5481
5572
|
"div",
|
|
5482
5573
|
{ className: "dgui-recovery" },
|
|
5483
5574
|
issue.kind === "conflict" ? h12(
|
|
5484
|
-
|
|
5575
|
+
import_react18.default.Fragment,
|
|
5485
5576
|
null,
|
|
5486
5577
|
h12("button", { type: "button", className: "dgui-secondary", disabled: status === "\u6B63\u5728\u6062\u590D\u53C2\u6570\u2026", onClick: useRemote }, "\u4F7F\u7528\u5DF2\u4FDD\u5B58\u53C2\u6570"),
|
|
5487
5578
|
h12("button", { type: "button", className: "dgui-secondary", disabled: status === "\u6B63\u5728\u6062\u590D\u53C2\u6570\u2026", onClick: keepLocal }, "\u4FDD\u7559\u672C\u9875\u53C2\u6570\u5E76\u91CD\u8BD5")
|
|
@@ -5494,7 +5585,7 @@ function UiView({ record, sessionId, sendPrompt, openFile, preview = false }) {
|
|
|
5494
5585
|
showDetails && h12("details", { className: "dgui-fallback" }, h12("summary", null, Object.keys(doc.state).length ? "\u539F\u59CB\u6587\u5B57\u8BF4\u660E\u4E0E\u521D\u59CB\u53C2\u6570" : "\u539F\u59CB\u6587\u5B57\u8BF4\u660E"), h12("p", null, doc.fallback), Object.keys(doc.state).length > 0 && h12("pre", null, JSON.stringify(initialState(doc), null, 2)))
|
|
5495
5586
|
);
|
|
5496
5587
|
}
|
|
5497
|
-
var UiBoundary = class extends
|
|
5588
|
+
var UiBoundary = class extends import_react18.default.Component {
|
|
5498
5589
|
state = { failed: false };
|
|
5499
5590
|
static getDerivedStateFromError() {
|
|
5500
5591
|
return { failed: true };
|
|
@@ -5519,10 +5610,10 @@ function ToolView(props) {
|
|
|
5519
5610
|
}
|
|
5520
5611
|
function TurnUiView(props) {
|
|
5521
5612
|
const stream = props.turn.data.get("dshUiStream");
|
|
5522
|
-
return h12(
|
|
5613
|
+
return h12(import_react18.default.Fragment, null, stream && typeof stream === "object" && !Array.isArray(stream) && h12(StreamSurface, { stream, sessionId: props.sessionId, committedIds: (props.turn.data.get("dshGenerativeUi") ?? []).filter((r) => r.displayReady && !r.isPatch).map((r) => r.raw.documentId) }), (props.turn.data.get("dshGenerativeUi") ?? []).filter((r) => r.displayReady === true).map((r) => r.isPatch ? h12(PatchNotice, { key: `patch-${r.seq}`, raw: r.raw }) : h12(PresentationView, { key: r.raw.documentId, ...r, sessionId: props.sessionId, sendPrompt: props.sendPrompt, openFile: props.openFile, scope: props.presentationScope })));
|
|
5523
5614
|
}
|
|
5524
5615
|
function PatchNotice({ raw }) {
|
|
5525
|
-
(0,
|
|
5616
|
+
(0, import_react18.useEffect)(() => {
|
|
5526
5617
|
try {
|
|
5527
5618
|
if (raw) publishDocument(raw);
|
|
5528
5619
|
} catch {
|
|
@@ -5530,9 +5621,9 @@ function PatchNotice({ raw }) {
|
|
|
5530
5621
|
}, [raw]);
|
|
5531
5622
|
return h12("p", { className: "dgui-copy" }, "\u754C\u9762\u4FEE\u6539\u5DF2\u4FDD\u5B58\uFF1B\u539F\u754C\u9762\u5DF2\u66F4\u65B0\u3002");
|
|
5532
5623
|
}
|
|
5533
|
-
function ValidatedView({ raw, fallback, sessionId, sendPrompt, openFile }) {
|
|
5624
|
+
function ValidatedView({ raw, fallback, sessionId, sendPrompt, openFile, replaceExportedCanvases = false }) {
|
|
5534
5625
|
const { record: current2, status, retry } = useCurrentDocument(raw ?? {}, sessionId);
|
|
5535
|
-
const result = (0,
|
|
5626
|
+
const result = (0, import_react18.useMemo)(() => {
|
|
5536
5627
|
try {
|
|
5537
5628
|
if (!current2 || current2.version !== 1 || typeof current2.documentId !== "string" || typeof current2.callId !== "string") return null;
|
|
5538
5629
|
return { ...current2, document: validateDocument(current2.document) };
|
|
@@ -5542,11 +5633,11 @@ function ValidatedView({ raw, fallback, sessionId, sendPrompt, openFile }) {
|
|
|
5542
5633
|
}, [current2]);
|
|
5543
5634
|
if (!result) return h12("div", { className: "dgui-root" }, h12("p", null, "\u6587\u5B57\u7ED3\u679C\uFF08\u672A\u63D0\u4F9B\u517C\u5BB9\u7684\u754C\u9762\u6570\u636E\uFF09"), h12("pre", null, fallback));
|
|
5544
5635
|
return h12(
|
|
5545
|
-
|
|
5636
|
+
import_react18.default.Fragment,
|
|
5546
5637
|
null,
|
|
5547
5638
|
status === "error" && h12("div", { className: "dgui-root dgui-document-warning", role: "status" }, h12("p", null, "\u672A\u80FD\u786E\u8BA4\u6700\u65B0\u754C\u9762\u7248\u672C\uFF0C\u5F53\u524D\u663E\u793A\u5DF2\u77E5\u7248\u672C\u3002"), h12("button", { type: "button", className: "dgui-secondary", onClick: retry }, "\u91CD\u65B0\u8BFB\u53D6\u6700\u65B0\u754C\u9762")),
|
|
5548
5639
|
status === "loading" && h12("p", { className: "dgui-copy", role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u6700\u65B0\u754C\u9762\u7248\u672C\u2026"),
|
|
5549
|
-
h12(UiBoundary, { key: `${result.documentId}:${sessionId}`, fallback: fallback ?? result.document.fallback }, h12(UiView, { key: `${result.documentId}:${sessionId}`, record: result, sessionId, sendPrompt, openFile }))
|
|
5640
|
+
h12(UiBoundary, { key: `${result.documentId}:${sessionId}`, fallback: fallback ?? result.document.fallback }, h12(UiView, { key: `${result.documentId}:${sessionId}`, record: result, sessionId, sendPrompt, openFile, replaceExportedCanvases }))
|
|
5550
5641
|
);
|
|
5551
5642
|
}
|
|
5552
5643
|
|
|
@@ -5748,8 +5839,8 @@ ${root} .dgui-steps li[data-step-status=active]{border-color:var(--du-accent)}${
|
|
|
5748
5839
|
`;
|
|
5749
5840
|
|
|
5750
5841
|
// src/style-previews.js
|
|
5751
|
-
var
|
|
5752
|
-
var h13 =
|
|
5842
|
+
var import_react19 = __toESM(require("react"), 1);
|
|
5843
|
+
var h13 = import_react19.default.createElement;
|
|
5753
5844
|
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"]];
|
|
5754
5845
|
var header = (text3) => h13("div", { className: "dgui-header" }, h13("strong", { className: "dgui-header-title" }, text3));
|
|
5755
5846
|
var copy = (text3) => h13("p", { className: "dgui-copy" }, text3);
|
|
@@ -5761,7 +5852,7 @@ function StyleSample({ styleId, layout = "text" }) {
|
|
|
5761
5852
|
title = "\u5148\u4EA4\u4ED8\u4E00\u4E2A\u53EF\u7528\u7248\u672C";
|
|
5762
5853
|
const content = h13("div", { className: "dgui-column" }, copy("\u628A\u76EE\u6807\u7F29\u5C0F\uFF0C\u628A\u5173\u952E\u4F53\u9A8C\u505A\u597D\u3002"), h13("p", { className: "dgui-copy dgui-sample-note" }, "\u5148\u9A8C\u8BC1\uFF0C\u518D\u9010\u6B65\u5B8C\u5584\u3002"));
|
|
5763
5854
|
body = styleId === "soft" ? card("\u4ECA\u5929\u7684\u91CD\u70B9", "\u628A\u76EE\u6807\u7F29\u5C0F\uFF0C\u628A\u5173\u952E\u4F53\u9A8C\u505A\u597D\u3002") : content;
|
|
5764
|
-
if (styleId === "soft") body = h13(
|
|
5855
|
+
if (styleId === "soft") body = h13(import_react19.default.Fragment, null, body, h13("p", { className: "dgui-copy dgui-sample-note" }, "\u5148\u9A8C\u8BC1\uFF0C\u518D\u9010\u6B65\u5B8C\u5584\u3002"));
|
|
5765
5856
|
} else if (layout === "comparison") {
|
|
5766
5857
|
title = "\u4E24\u79CD\u63A8\u8FDB\u65B9\u5F0F";
|
|
5767
5858
|
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"));
|
|
@@ -5778,7 +5869,7 @@ function StyleSample({ styleId, layout = "text" }) {
|
|
|
5778
5869
|
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));
|
|
5779
5870
|
}
|
|
5780
5871
|
function StyleOptions({ value, disabled, onChange }) {
|
|
5781
|
-
const [layout, setLayout] = (0,
|
|
5872
|
+
const [layout, setLayout] = (0, import_react19.useState)("text"), id2 = (0, import_react19.useId)();
|
|
5782
5873
|
return h13(
|
|
5783
5874
|
"div",
|
|
5784
5875
|
null,
|
|
@@ -5960,10 +6051,10 @@ body[data-ds-dark-theme] .dgui-root,.dgui-root[data-preview-theme=dark]{--du-acc
|
|
|
5960
6051
|
` + SOFT_CSS + READING_CSS + NATIVE_STYLE_CSS + MOTION_CSS + EXPRESSIVE_CSS + STYLE_SETTINGS_CSS;
|
|
5961
6052
|
|
|
5962
6053
|
// src/motion-library.js
|
|
5963
|
-
var
|
|
5964
|
-
var h14 =
|
|
6054
|
+
var import_react20 = __toESM(require("react"), 1);
|
|
6055
|
+
var h14 = import_react20.default.createElement;
|
|
5965
6056
|
function MotionLibrary() {
|
|
5966
|
-
const [open, setOpen] = (0,
|
|
6057
|
+
const [open, setOpen] = (0, import_react20.useState)(false), [months, setMonths] = (0, import_react20.useState)(1), [seats, setSeats] = (0, import_react20.useState)(2), [checks, setChecks] = (0, import_react20.useState)([false, false, false]), style = useNativeStyle();
|
|
5967
6058
|
const total = 29 * months * seats, done = checks.filter(Boolean).length;
|
|
5968
6059
|
return h14("section", { "aria-label": "\u52A8\u6001\u4EA4\u4E92\u6848\u4F8B" }, h14("h4", null, "\u52A8\u6001\u4EA4\u4E92\u6848\u4F8B"), h14("p", null, "\u53EF\u76F4\u63A5\u64CD\u4F5C\u7684\u672C\u5730\u6F14\u793A\u3002\u793A\u4F8B\u4EF7\u683C\u4E0D\u662F\u62A5\u4EF7\uFF0C\u52FE\u9009\u4E0D\u4EE3\u8868\u5DF2\u6267\u884C\u68C0\u67E5\uFF1B\u64CD\u4F5C\u4E0D\u4F1A\u8C03\u7528\u6A21\u578B\u6216\u6539\u52A8\u8BBE\u7F6E\u3002"), h14("button", { className: "dgui-secondary", type: "button", "aria-expanded": open, onClick: () => setOpen(!open) }, open ? "\u6536\u8D77\u4EA4\u4E92\u6F14\u793A" : "\u4F53\u9A8C\u4EA4\u4E92\u6F14\u793A"), open && h14(
|
|
5969
6060
|
"section",
|
|
@@ -5989,10 +6080,10 @@ function MotionLibrary() {
|
|
|
5989
6080
|
}
|
|
5990
6081
|
|
|
5991
6082
|
// src/video-capabilities.js
|
|
5992
|
-
var
|
|
5993
|
-
var h15 =
|
|
6083
|
+
var import_react21 = __toESM(require("react"), 1);
|
|
6084
|
+
var h15 = import_react21.default.createElement;
|
|
5994
6085
|
function VideoCapabilities() {
|
|
5995
|
-
const [report, setReport] = (0,
|
|
6086
|
+
const [report, setReport] = (0, import_react21.useState)(), [error, setError] = (0, import_react21.useState)(""), [busy, setBusy] = (0, import_react21.useState)(false);
|
|
5996
6087
|
const check = async () => {
|
|
5997
6088
|
setBusy(true);
|
|
5998
6089
|
setError("");
|
|
@@ -6006,21 +6097,21 @@ function VideoCapabilities() {
|
|
|
6006
6097
|
setBusy(false);
|
|
6007
6098
|
}
|
|
6008
6099
|
};
|
|
6009
|
-
return h15("section", { "aria-label": "\u89C6\u9891\u5236\u4F5C\u73AF\u5883" }, h15("h4", null, "\u89C6\u9891\u5236\u4F5C"), h15("p", null, "\u53EF\u4EE5\u8BA9\u6A21\u578B\u5236\u4F5C\u53EF\u7F16\u8F91\u52A8\u6548\u5E76\u5BFC\u51FA MP4\uFF0C\u4E5F\u80FD\u68C0\u67E5\u3001\u622A\u53D6\u548C\u62FC\u63A5\u672C\u5730\u89C6\u9891\uFF0C\u6DFB\u52A0\u914D\u97F3\u3001\u591A\u8F68\u914D\u4E50\u4E0E\u5B9A\u65F6\u5B57\u5E55\u3002\u666E\u901A UI \u4E0D\u4F1A\u81EA\u52A8\u5BFC\u51FA\u89C6\u9891\u3002"), h15("button", { type: "button", className: "dgui-secondary", disabled: busy, onClick: check }, busy ? "\u6B63\u5728\u68C0\u67E5\u2026" : "\u68C0\u67E5\u89C6\u9891\u73AF\u5883"), report && h15(
|
|
6100
|
+
return h15("section", { "aria-label": "\u89C6\u9891\u5236\u4F5C\u73AF\u5883" }, h15("h4", null, "\u89C6\u9891\u5236\u4F5C"), h15("p", null, "\u53EF\u4EE5\u8BA9\u6A21\u578B\u5236\u4F5C\u53EF\u7F16\u8F91\u52A8\u6548\u5E76\u5BFC\u51FA MP4\uFF0C\u4E5F\u80FD\u68C0\u67E5\u3001\u622A\u53D6\u548C\u62FC\u63A5\u672C\u5730\u89C6\u9891\uFF0C\u6DFB\u52A0\u914D\u97F3\u3001\u591A\u8F68\u914D\u4E50\u4E0E\u5B9A\u65F6\u5B57\u5E55\u3002\u666E\u901A UI \u4E0D\u4F1A\u81EA\u52A8\u5BFC\u51FA\u89C6\u9891\u3002"), h15("button", { type: "button", className: "dgui-secondary", disabled: busy, onClick: check }, busy ? "\u6B63\u5728\u68C0\u67E5\u2026" : "\u68C0\u67E5\u89C6\u9891\u73AF\u5883"), report && h15(import_react21.default.Fragment, null, h15("p", { role: "status" }, "\u6D4F\u89C8\u5668\uFF1A" + (report.browser ? "\u53EF\u7528" : "\u7F3A\u5931") + " \xB7 FFmpeg\uFF1A" + (report.ffmpeg ? "\u53EF\u7528" : "\u7F3A\u5931") + " \xB7 FFprobe\uFF1A" + (report.ffprobe ? "\u53EF\u7528" : "\u7F3A\u5931")), h15("p", null, "\u914D\u97F3\uFF1A" + (report.voice?.configured ? "MiniMax \u5DF2\u914D\u7F6E" : "\u672A\u914D\u7F6E") + "\u3002\u914D\u97F3\u4F1A\u8C03\u7528\u4ED8\u8D39 API\uFF1B\u4F7F\u7528\u5B98\u65B9 mmx \u8BA4\u8BC1\u6216 MINIMAX_API_KEY\uFF0C\u4E0D\u590D\u5236 DSH \u6A21\u578B\u5BC6\u94A5\u3002"), (!report.browser || !report.ffmpeg || !report.ffprobe) && h15("p", null, "\u9700\u8981\u672C\u673A Chrome/Edge \u6216 Chromium\uFF0C\u4EE5\u53CA FFmpeg/FFprobe\u3002\u53EF\u7528 DSH_MOTION_BROWSER\u3001DSH_MOTION_FFMPEG\u3001DSH_MOTION_FFPROBE \u914D\u7F6E\u8DEF\u5F84\uFF1B\u4E0D\u4F1A\u81EA\u52A8\u4E0B\u8F7D\u5927\u578B\u8FD0\u884C\u65F6\u3002")), error && h15("p", { role: "alert" }, error));
|
|
6010
6101
|
}
|
|
6011
6102
|
|
|
6012
6103
|
// src/settings.js
|
|
6013
|
-
var
|
|
6104
|
+
var import_react24 = __toESM(require("react"), 1);
|
|
6014
6105
|
|
|
6015
6106
|
// src/runtime-diagnostics.js
|
|
6016
|
-
var
|
|
6017
|
-
var h16 =
|
|
6107
|
+
var import_react22 = __toESM(require("react"), 1);
|
|
6108
|
+
var h16 = import_react22.default.createElement;
|
|
6018
6109
|
var activation = { active: false, channel: "\u672A\u6FC0\u6D3B", sidebar: false };
|
|
6019
6110
|
function setRuntimeActivation(patch) {
|
|
6020
6111
|
activation = { ...activation, ...patch };
|
|
6021
6112
|
}
|
|
6022
6113
|
function RuntimeDiagnostics() {
|
|
6023
|
-
const [report, setReport] = (0,
|
|
6114
|
+
const [report, setReport] = (0, import_react22.useState)(), [error, setError] = (0, import_react22.useState)(""), [busy, setBusy] = (0, import_react22.useState)(false);
|
|
6024
6115
|
const check = async () => {
|
|
6025
6116
|
setBusy(true);
|
|
6026
6117
|
setError("");
|
|
@@ -6037,11 +6128,11 @@ function RuntimeDiagnostics() {
|
|
|
6037
6128
|
setBusy(false);
|
|
6038
6129
|
}
|
|
6039
6130
|
};
|
|
6040
|
-
return h16("section", { "aria-label": "\u8FD0\u884C\u72B6\u6001" }, h16("h4", null, "\u8FD0\u884C\u72B6\u6001"), h16("p", null, "\u5BA2\u6237\u7AEF\uFF1A" + (activation.active ? "\u5DF2\u6FC0\u6D3B" : "\u6B63\u5728\u6FC0\u6D3B") + " \xB7 " + activation.channel), h16("button", { className: "dgui-secondary", type: "button", disabled: busy, onClick: check }, busy ? "\u6B63\u5728\u68C0\u67E5\u2026" : "\u68C0\u67E5\u8FD0\u884C\u72B6\u6001"), report && h16(
|
|
6131
|
+
return h16("section", { "aria-label": "\u8FD0\u884C\u72B6\u6001" }, h16("h4", null, "\u8FD0\u884C\u72B6\u6001"), h16("p", null, "\u5BA2\u6237\u7AEF\uFF1A" + (activation.active ? "\u5DF2\u6FC0\u6D3B" : "\u6B63\u5728\u6FC0\u6D3B") + " \xB7 " + activation.channel), h16("button", { className: "dgui-secondary", type: "button", disabled: busy, onClick: check }, busy ? "\u6B63\u5728\u68C0\u67E5\u2026" : "\u68C0\u67E5\u8FD0\u884C\u72B6\u6001"), report && h16(import_react22.default.Fragment, null, h16("p", null, "\u6784\u5EFA\uFF1A" + report.build.id + (report.build.id === BUILD_INFO.id ? " \xB7 \u524D\u540E\u7AEF\u4E00\u81F4" : " \xB7 \u524D\u540E\u7AEF\u4E0D\u540C\uFF0C\u8BF7\u91CD\u542F\u5BBF\u4E3B\u5E76\u5237\u65B0")), h16("p", null, "\u672C\u5730\u8D44\u6E90\uFF1A" + (report.assets.every((a) => a.available) && report.assetRouteOK ? "\u6B63\u5E38" : "\u6709\u7F3A\u5931\u6216\u8DEF\u7531\u4E0D\u53EF\u7528")), h16("p", null, "\u540C\u8F6E\u4FEE\u590D\u63A5\u53E3\uFF1A" + (report.feedbackHookRegistered ? "\u5DF2\u6CE8\u518C" : "\u5F53\u524D\u5BBF\u4E3B\u4E0D\u53EF\u7528") + " \xB7 \u539F\u751F\u4FA7\u680F\uFF1A" + (activation.sidebar ? "\u5DF2\u63A5\u5165" : "\u5F53\u524D\u5BBF\u4E3B\u672A\u63D0\u4F9B")), h16("p", null, "\u63A7\u4EF6\u4E0E\u6A21\u578B\u811A\u672C\u5728\u6574\u8F6E\u7ED3\u675F\u540E\u542F\u7528\uFF1B\u4E0D\u6539\u53D8\u5BBF\u4E3B\u6743\u9650\u3002")), error && h16("p", { role: "alert" }, error));
|
|
6041
6132
|
}
|
|
6042
6133
|
|
|
6043
6134
|
// src/scene-library.js
|
|
6044
|
-
var
|
|
6135
|
+
var import_react23 = __toESM(require("react"), 1);
|
|
6045
6136
|
|
|
6046
6137
|
// lib/scene-library.js
|
|
6047
6138
|
var SCENES = Object.freeze([
|
|
@@ -6056,11 +6147,11 @@ var SCENES = Object.freeze([
|
|
|
6056
6147
|
]);
|
|
6057
6148
|
|
|
6058
6149
|
// src/scene-library.js
|
|
6059
|
-
var h17 =
|
|
6150
|
+
var h17 = import_react23.default.createElement;
|
|
6060
6151
|
function SceneLibrary() {
|
|
6061
|
-
const [open, setOpen] = (0,
|
|
6152
|
+
const [open, setOpen] = (0, import_react23.useState)(false), [selected, select] = (0, import_react23.useState)("brief"), [status, setStatus] = (0, import_react23.useState)("");
|
|
6062
6153
|
const scene = SCENES.find((s) => s.id === selected);
|
|
6063
|
-
return h17("section", { "aria-label": "\u573A\u666F\u6848\u4F8B\u5E93" }, h17("h4", null, "\u573A\u666F\u6848\u4F8B\u5E93"), h17("p", null, "\u6309\u7528\u9014\u9884\u89C8\u77ED\u6848\u4F8B\u3002\u6848\u4F8B\u5C55\u793A\u7ED3\u6784\uFF0C\u751F\u6210\u65F6\u4F1A\u9002\u914D\u5F53\u524D\u5F15\u5BFC\u98CE\u683C\uFF1B\u63A7\u4EF6\u5728\u6B64\u5904\u53EA\u4F5C\u9884\u89C8\u3002"), h17("button", { className: "dgui-secondary", type: "button", "aria-expanded": open, onClick: () => setOpen(!open) }, open ? "\u6536\u8D77\u6848\u4F8B" : "\u6D4F\u89C8\u6848\u4F8B"), open && h17(
|
|
6154
|
+
return h17("section", { "aria-label": "\u573A\u666F\u6848\u4F8B\u5E93" }, h17("h4", null, "\u573A\u666F\u6848\u4F8B\u5E93"), h17("p", null, "\u6309\u7528\u9014\u9884\u89C8\u77ED\u6848\u4F8B\u3002\u6848\u4F8B\u5C55\u793A\u7ED3\u6784\uFF0C\u751F\u6210\u65F6\u4F1A\u9002\u914D\u5F53\u524D\u5F15\u5BFC\u98CE\u683C\uFF1B\u63A7\u4EF6\u5728\u6B64\u5904\u53EA\u4F5C\u9884\u89C8\u3002"), h17("button", { className: "dgui-secondary", type: "button", "aria-expanded": open, onClick: () => setOpen(!open) }, open ? "\u6536\u8D77\u6848\u4F8B" : "\u6D4F\u89C8\u6848\u4F8B"), open && h17(import_react23.default.Fragment, null, h17("div", { className: "dgui-row dgui-scene-choices", role: "group", "aria-label": "\u9009\u62E9\u6848\u4F8B" }, SCENES.map((s) => h17("button", { className: "dgui-secondary", key: s.id, type: "button", "aria-pressed": s.id === selected, onClick: () => {
|
|
6064
6155
|
select(s.id);
|
|
6065
6156
|
setStatus("");
|
|
6066
6157
|
} }, s.name))), h17(UiView, { key: selected, record: { documentId: "scene-" + selected, document: validateDocument(scene.spec) }, sessionId: "scene-preview", preview: true }), h17("button", { className: "dgui-secondary", type: "button", onClick: async () => {
|
|
@@ -6074,10 +6165,10 @@ function SceneLibrary() {
|
|
|
6074
6165
|
}
|
|
6075
6166
|
|
|
6076
6167
|
// src/settings.js
|
|
6077
|
-
var h18 =
|
|
6168
|
+
var h18 = import_react24.default.createElement;
|
|
6078
6169
|
function ModeSettings({ scope: scope2 }) {
|
|
6079
|
-
const [snapshot2, setSnapshot] = (0,
|
|
6080
|
-
(0,
|
|
6170
|
+
const [snapshot2, setSnapshot] = (0, import_react24.useState)(() => scope2.getSnapshot()), [busy, setBusy] = (0, import_react24.useState)(false), [message, setMessage] = (0, import_react24.useState)(""), pending2 = (0, import_react24.useRef)(false);
|
|
6171
|
+
(0, import_react24.useEffect)(() => scope2.subscribe(() => setSnapshot(scope2.getSnapshot())), [scope2]);
|
|
6081
6172
|
const ready = snapshot2.status === "ready" && snapshot2.value !== void 0;
|
|
6082
6173
|
async function change(mode, key2 = "designMode") {
|
|
6083
6174
|
if (pending2.current || !ready) return;
|
|
@@ -6158,7 +6249,7 @@ var fenceUiDefinition = {
|
|
|
6158
6249
|
};
|
|
6159
6250
|
|
|
6160
6251
|
// src/fence-view.js
|
|
6161
|
-
var
|
|
6252
|
+
var import_react25 = __toESM(require("react"), 1);
|
|
6162
6253
|
var import_client2 = require("react-dom/client");
|
|
6163
6254
|
|
|
6164
6255
|
// lib/fences.js
|
|
@@ -6183,11 +6274,11 @@ function extractUiFences(text3) {
|
|
|
6183
6274
|
}
|
|
6184
6275
|
|
|
6185
6276
|
// src/fence-view.js
|
|
6186
|
-
var h19 =
|
|
6277
|
+
var h19 = import_react25.default.createElement;
|
|
6187
6278
|
var roots3 = /* @__PURE__ */ new WeakMap();
|
|
6188
6279
|
function FenceContent({ document: document2, sessionId, source, settled, sendPrompt }) {
|
|
6189
|
-
const [record, setRecord] = (0,
|
|
6190
|
-
(0,
|
|
6280
|
+
const [record, setRecord] = (0, import_react25.useState)(), [error, setError] = (0, import_react25.useState)("");
|
|
6281
|
+
(0, import_react25.useEffect)(() => {
|
|
6191
6282
|
if (!settled) return;
|
|
6192
6283
|
let active = true;
|
|
6193
6284
|
fetch("/api/plugins/dsh-generative-ui/fence", { method: "POST", credentials: "same-origin", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ document: document2, sessionId, source }) }).then(async (r) => {
|
|
@@ -6204,7 +6295,7 @@ function FenceContent({ document: document2, sessionId, source, settled, sendPro
|
|
|
6204
6295
|
active = false;
|
|
6205
6296
|
};
|
|
6206
6297
|
}, [document2, sessionId, source, settled]);
|
|
6207
|
-
return h19(UiBoundary, { fallback: document2.fallback }, h19(UiView, { record: record ?? { document: document2, documentId: "fence-preview-" + source }, sessionId, sendPrompt, preview: !record }), error && h19("p", { role: "alert" }, error));
|
|
6298
|
+
return h19(UiBoundary, { fallback: document2.fallback }, h19(UiView, { record: record ?? { document: document2, documentId: "fence-preview-" + source }, sessionId, sendPrompt, preview: !record, replaceExportedCanvases: true }), error && h19("p", { role: "alert" }, error));
|
|
6208
6299
|
}
|
|
6209
6300
|
function candidates(state2) {
|
|
6210
6301
|
const steps = /* @__PURE__ */ new Map();
|
|
@@ -6248,8 +6339,8 @@ function dispose2(e) {
|
|
|
6248
6339
|
e.entries.delete(e.key);
|
|
6249
6340
|
}
|
|
6250
6341
|
function FenceNodeView({ node, sessionId, sendPrompt }) {
|
|
6251
|
-
const anchor = (0,
|
|
6252
|
-
(0,
|
|
6342
|
+
const anchor = (0, import_react25.useRef)(null), state2 = node.data;
|
|
6343
|
+
(0, import_react25.useLayoutEffect)(() => {
|
|
6253
6344
|
const scroll = anchor.current?.closest("[data-conversation-scroll]");
|
|
6254
6345
|
if (!scroll) return;
|
|
6255
6346
|
let entries = roots3.get(scroll);
|
|
@@ -6340,7 +6431,7 @@ function mediaRecord(message) {
|
|
|
6340
6431
|
const files = (value.files ?? []).map((f) => typeof f === "string" ? f : f?.name).filter((f) => allowedFiles.has(f));
|
|
6341
6432
|
if (!files.includes("video.mp4")) continue;
|
|
6342
6433
|
const output = value.output ?? {}, positive = (n2) => typeof n2 === "number" && Number.isFinite(n2) && n2 > 0 ? n2 : null;
|
|
6343
|
-
return { id: value.id, sessionId: value.sessionId, kind: value.kind, files: [...new Set(files)], documentId: uuid.test(value.documentId) ? value.documentId : null, nodeId: typeof value.nodeId === "string" ? value.nodeId : null, duration: positive(output.duration), width: positive(output.width), height: positive(output.height), hasAudio: Array.isArray(output.audio) ? output.audio.length > 0 : null };
|
|
6434
|
+
return { id: value.id, sessionId: value.sessionId, kind: value.kind, files: [...new Set(files)], documentId: uuid.test(value.documentId) ? value.documentId : null, documentRevision: Number.isSafeInteger(value.documentRevision) && value.documentRevision >= 0 ? value.documentRevision : null, nodeId: typeof value.nodeId === "string" ? value.nodeId : null, duration: positive(output.duration), width: positive(output.width), height: positive(output.height), hasAudio: Array.isArray(output.audio) ? output.audio.length > 0 : null };
|
|
6344
6435
|
} catch {
|
|
6345
6436
|
}
|
|
6346
6437
|
}
|
|
@@ -6379,10 +6470,44 @@ var mediaHistoryDefinition = {
|
|
|
6379
6470
|
}
|
|
6380
6471
|
};
|
|
6381
6472
|
|
|
6473
|
+
// src/media-source.js
|
|
6474
|
+
var import_react26 = require("react");
|
|
6475
|
+
function useMediaSource(url) {
|
|
6476
|
+
const native = typeof location !== "undefined" && location.protocol === "dsh-app:";
|
|
6477
|
+
const [attempt, setAttempt] = (0, import_react26.useState)(0), [state2, setState] = (0, import_react26.useState)({ src: native ? null : url, loading: native, error: "" });
|
|
6478
|
+
(0, import_react26.useEffect)(() => {
|
|
6479
|
+
if (!native) {
|
|
6480
|
+
setState({ src: url, loading: false, error: "" });
|
|
6481
|
+
return;
|
|
6482
|
+
}
|
|
6483
|
+
const controller = new AbortController();
|
|
6484
|
+
let active = true, objectUrl;
|
|
6485
|
+
setState({ src: null, loading: true, error: "" });
|
|
6486
|
+
(async () => {
|
|
6487
|
+
try {
|
|
6488
|
+
const response = await fetch(url, { credentials: "same-origin", signal: controller.signal });
|
|
6489
|
+
if (!response.ok) throw Error("HTTP " + response.status);
|
|
6490
|
+
const blob = await response.blob();
|
|
6491
|
+
if (!active) return;
|
|
6492
|
+
objectUrl = URL.createObjectURL(blob);
|
|
6493
|
+
setState({ src: objectUrl, loading: false, error: "" });
|
|
6494
|
+
} catch (e) {
|
|
6495
|
+
if (active && e.name !== "AbortError") setState({ src: null, loading: false, error: "\u89C6\u9891\u672A\u80FD\u8F7D\u5165\uFF0C\u8BF7\u91CD\u8BD5\u3002" });
|
|
6496
|
+
}
|
|
6497
|
+
})();
|
|
6498
|
+
return () => {
|
|
6499
|
+
active = false;
|
|
6500
|
+
controller.abort();
|
|
6501
|
+
if (objectUrl) URL.revokeObjectURL(objectUrl);
|
|
6502
|
+
};
|
|
6503
|
+
}, [url, native, attempt]);
|
|
6504
|
+
return { ...state2, retry: () => setAttempt((n2) => n2 + 1), native };
|
|
6505
|
+
}
|
|
6506
|
+
|
|
6382
6507
|
// src/media-player.js
|
|
6383
|
-
var
|
|
6508
|
+
var import_react27 = __toESM(require("react"), 1);
|
|
6384
6509
|
var import_client3 = require("react-dom/client");
|
|
6385
|
-
var h20 =
|
|
6510
|
+
var h20 = import_react27.default.createElement;
|
|
6386
6511
|
var players = /* @__PURE__ */ new Set();
|
|
6387
6512
|
var preferenceKey = "dsh-motion-ui:video-playback";
|
|
6388
6513
|
function formatMediaTime(seconds) {
|
|
@@ -6404,10 +6529,33 @@ function remember(v2) {
|
|
|
6404
6529
|
}
|
|
6405
6530
|
}
|
|
6406
6531
|
function VideoPlayer({ record }) {
|
|
6407
|
-
const video = (0,
|
|
6408
|
-
const
|
|
6409
|
-
const lastVolume = (0,
|
|
6410
|
-
(0,
|
|
6532
|
+
const video = (0, import_react27.useRef)(null), root2 = (0, import_react27.useRef)(null), [prefs] = (0, import_react27.useState)(preferences), [playing, setPlaying] = (0, import_react27.useState)(false), [time, setTime] = (0, import_react27.useState)(0), [duration, setDuration] = (0, import_react27.useState)(record.duration ?? 0), [ready, setReady] = (0, import_react27.useState)(false), [volume, setVolume] = (0, import_react27.useState)(prefs.volume), [muted, setMuted] = (0, import_react27.useState)(prefs.muted), [rate, setRate] = (0, import_react27.useState)(prefs.rate), [fullscreen, setFullscreen] = (0, import_react27.useState)(false), [error, setError] = (0, import_react27.useState)(""), [notice, setNotice] = (0, import_react27.useState)("");
|
|
6533
|
+
const mediaUrl = mediaAssetUrl(record, "video.mp4"), transport = useMediaSource(mediaUrl), src = transport.src, poster = mediaAssetUrl(record, "poster.jpg"), playbackError = error || transport.error;
|
|
6534
|
+
const lastVolume = (0, import_react27.useRef)(prefs.volume || 0.8);
|
|
6535
|
+
const drag = (0, import_react27.useRef)(null), pendingSeek = (0, import_react27.useRef)(null);
|
|
6536
|
+
function beginSeek(e) {
|
|
6537
|
+
const v2 = video.current;
|
|
6538
|
+
if (!v2 || !ready) return;
|
|
6539
|
+
drag.current = { resume: !v2.paused, value: Number(e.currentTarget.value) };
|
|
6540
|
+
v2.pause();
|
|
6541
|
+
e.currentTarget.setPointerCapture?.(e.pointerId);
|
|
6542
|
+
}
|
|
6543
|
+
function changeSeek(value) {
|
|
6544
|
+
if (drag.current) {
|
|
6545
|
+
drag.current.value = Number(value);
|
|
6546
|
+
setTime(Number(value));
|
|
6547
|
+
} else seek(value);
|
|
6548
|
+
}
|
|
6549
|
+
function endSeek(cancel = false) {
|
|
6550
|
+
const active = drag.current;
|
|
6551
|
+
if (!active) return;
|
|
6552
|
+
drag.current = null;
|
|
6553
|
+
if (cancel) setTime(video.current.currentTime);
|
|
6554
|
+
else seek(active.value);
|
|
6555
|
+
if (active.resume) video.current.play().catch(() => {
|
|
6556
|
+
});
|
|
6557
|
+
}
|
|
6558
|
+
(0, import_react27.useEffect)(() => {
|
|
6411
6559
|
const v2 = video.current, container = root2.current;
|
|
6412
6560
|
if (!v2) return;
|
|
6413
6561
|
players.add(v2);
|
|
@@ -6446,8 +6594,10 @@ function VideoPlayer({ record }) {
|
|
|
6446
6594
|
function seek(value) {
|
|
6447
6595
|
const v2 = video.current;
|
|
6448
6596
|
if (!v2 || !ready || !Number.isFinite(duration) || duration <= 0) return;
|
|
6449
|
-
|
|
6450
|
-
|
|
6597
|
+
const target = Math.max(0, Math.min(duration, Number(value)));
|
|
6598
|
+
pendingSeek.current = target;
|
|
6599
|
+
v2.currentTime = target;
|
|
6600
|
+
setTime(target);
|
|
6451
6601
|
}
|
|
6452
6602
|
function mute() {
|
|
6453
6603
|
const v2 = video.current;
|
|
@@ -6484,7 +6634,7 @@ function VideoPlayer({ record }) {
|
|
|
6484
6634
|
{ ref: root2, className: "motion-video-player", "data-motion-video": record.id, "aria-label": "\u89C6\u9891\u64AD\u653E\u5668", onKeyDown: key2 },
|
|
6485
6635
|
h20("video", {
|
|
6486
6636
|
ref: video,
|
|
6487
|
-
src,
|
|
6637
|
+
src: src ?? void 0,
|
|
6488
6638
|
poster: poster ?? void 0,
|
|
6489
6639
|
preload: "metadata",
|
|
6490
6640
|
playsInline: true,
|
|
@@ -6497,7 +6647,13 @@ function VideoPlayer({ record }) {
|
|
|
6497
6647
|
setError("");
|
|
6498
6648
|
if (Number.isFinite(v2.duration)) setDuration(v2.duration);
|
|
6499
6649
|
},
|
|
6500
|
-
onTimeUpdate: (e) =>
|
|
6650
|
+
onTimeUpdate: (e) => {
|
|
6651
|
+
if (!drag.current && pendingSeek.current === null) setTime(e.currentTarget.currentTime);
|
|
6652
|
+
},
|
|
6653
|
+
onSeeked: (e) => {
|
|
6654
|
+
pendingSeek.current = null;
|
|
6655
|
+
if (!drag.current) setTime(e.currentTarget.currentTime);
|
|
6656
|
+
},
|
|
6501
6657
|
onDurationChange: (e) => {
|
|
6502
6658
|
if (Number.isFinite(e.currentTarget.duration)) setDuration(e.currentTarget.duration);
|
|
6503
6659
|
},
|
|
@@ -6529,8 +6685,8 @@ function VideoPlayer({ record }) {
|
|
|
6529
6685
|
h20(
|
|
6530
6686
|
"div",
|
|
6531
6687
|
{ className: "motion-video-controls" },
|
|
6532
|
-
h20("input", { className: "motion-video-seek", type: "range", min: 0, max: duration || 1, step: 0.05, value: Math.min(time, duration || 1), disabled: !ready, "aria-label": "\u64AD\u653E\u8FDB\u5EA6\uFF08\u79D2\uFF09", "aria-valuetext": formatMediaTime(time) + " / " + formatMediaTime(duration), onChange: (e) =>
|
|
6533
|
-
button(playing ? "\u6682\u505C\u89C6\u9891" : "\u64AD\u653E\u89C6\u9891", playing ? "pause" : "play", toggle, { disabled: !!
|
|
6688
|
+
h20("input", { className: "motion-video-seek", type: "range", min: 0, max: duration || 1, step: 0.05, value: Math.min(time, duration || 1), disabled: !ready, "aria-label": "\u64AD\u653E\u8FDB\u5EA6\uFF08\u79D2\uFF09", "aria-valuetext": formatMediaTime(time) + " / " + formatMediaTime(duration), onPointerDown: beginSeek, onPointerUp: () => endSeek(), onPointerCancel: () => endSeek(true), onLostPointerCapture: () => endSeek(true), onChange: (e) => changeSeek(e.currentTarget.value) }),
|
|
6689
|
+
button(playing ? "\u6682\u505C\u89C6\u9891" : "\u64AD\u653E\u89C6\u9891", playing ? "pause" : "play", toggle, { disabled: !!playbackError || !src }),
|
|
6534
6690
|
h20("output", { className: "motion-video-time", "aria-label": "\u64AD\u653E\u65F6\u95F4" }, formatMediaTime(time) + " / " + formatMediaTime(duration)),
|
|
6535
6691
|
h20("div", { className: "motion-video-volume" }, button(muted || volume === 0 ? "\u53D6\u6D88\u9759\u97F3" : "\u9759\u97F3\u89C6\u9891", muted || volume === 0 ? "volumeOff" : "volume", mute, { "aria-pressed": muted || volume === 0 }), h20("input", { type: "range", min: 0, max: 1, step: 0.05, value: muted ? 0 : volume, "aria-label": "\u89C6\u9891\u97F3\u91CF", "aria-valuetext": Math.round((muted ? 0 : volume) * 100) + "%", onChange: (e) => {
|
|
6536
6692
|
const v2 = video.current;
|
|
@@ -6541,19 +6697,22 @@ function VideoPlayer({ record }) {
|
|
|
6541
6697
|
video.current.playbackRate = Number(e.currentTarget.value);
|
|
6542
6698
|
} }, [0.5, 1, 1.25, 1.5, 2].map((v2) => h20("option", { key: v2, value: v2 }, v2 + "\xD7"))),
|
|
6543
6699
|
button(fullscreen ? "\u9000\u51FA\u5168\u5C4F" : "\u5168\u5C4F\u64AD\u653E", fullscreen ? "minimize" : "fullscreen", full),
|
|
6544
|
-
h20("a", { href:
|
|
6700
|
+
h20("a", { href: mediaUrl, download: "video.mp4", "aria-label": "\u4E0B\u8F7D\u89C6\u9891", title: "\u4E0B\u8F7D\u89C6\u9891" }, h20(Icon, { name: "download" })),
|
|
6545
6701
|
record.files.includes("source.html") && h20("a", { className: "motion-video-source", href: mediaAssetUrl(record, "source.html"), download: "source.html" }, "\u6E90\u7801"),
|
|
6546
6702
|
record.files.includes("project.zip") && h20("a", { className: "motion-video-source", href: mediaAssetUrl(record, "project.zip"), download: "project.zip" }, "\u5DE5\u7A0B")
|
|
6547
6703
|
),
|
|
6548
|
-
|
|
6704
|
+
transport.loading && h20("p", { className: "motion-video-message", role: "status" }, "\u6B63\u5728\u8F7D\u5165\u89C6\u9891\uFF0C\u5B8C\u6210\u540E\u53EF\u62D6\u52A8\u5B9A\u4F4D\u2026"),
|
|
6705
|
+
playbackError && h20("div", { className: "motion-video-message", role: "alert" }, h20("span", null, playbackError), h20("button", { type: "button", onClick: () => {
|
|
6549
6706
|
setError("");
|
|
6550
|
-
video.current.load();
|
|
6707
|
+
transport.native ? transport.retry() : video.current.load();
|
|
6551
6708
|
} }, "\u91CD\u65B0\u52A0\u8F7D")),
|
|
6552
6709
|
notice && h20("p", { className: "motion-video-message", role: "status" }, notice)
|
|
6553
6710
|
);
|
|
6554
6711
|
}
|
|
6555
6712
|
function MediaRecords({ records: records2, sessionId }) {
|
|
6556
|
-
|
|
6713
|
+
const owner = (0, import_react27.useRef)({});
|
|
6714
|
+
(0, import_react27.useLayoutEffect)(() => presentMedia(owner.current, sessionId, records2), [records2, sessionId]);
|
|
6715
|
+
return h20(import_react27.default.Fragment, null, records2.filter((r) => r.sessionId === sessionId).map((record) => h20(VideoPlayer, { key: record.id, record })));
|
|
6557
6716
|
}
|
|
6558
6717
|
var mediaRoots = /* @__PURE__ */ new WeakMap();
|
|
6559
6718
|
var allMediaRoots = /* @__PURE__ */ new Set();
|
|
@@ -6594,8 +6753,8 @@ function placeOutsideFold(entry) {
|
|
|
6594
6753
|
});
|
|
6595
6754
|
}
|
|
6596
6755
|
function MediaNodeView({ node, sessionId }) {
|
|
6597
|
-
const anchor = (0,
|
|
6598
|
-
(0,
|
|
6756
|
+
const anchor = (0, import_react27.useRef)(null), [inline, setInline] = (0, import_react27.useState)(false), state2 = node.data;
|
|
6757
|
+
(0, import_react27.useLayoutEffect)(() => {
|
|
6599
6758
|
const scroll = anchor.current?.closest("[data-conversation-scroll]");
|
|
6600
6759
|
if (!scroll) {
|
|
6601
6760
|
setInline(true);
|
|
@@ -6638,7 +6797,7 @@ function MediaNodeView({ node, sessionId }) {
|
|
|
6638
6797
|
entry.root.render(h20(MediaRecords, { records: state2.records ?? [], sessionId }));
|
|
6639
6798
|
}
|
|
6640
6799
|
}, [state2, sessionId]);
|
|
6641
|
-
return h20(
|
|
6800
|
+
return h20(import_react27.default.Fragment, null, h20("span", { ref: anchor, hidden: true }), inline && h20(MediaRecords, { records: state2.records ?? [], sessionId }));
|
|
6642
6801
|
}
|
|
6643
6802
|
function MediaToolView({ block, phase }) {
|
|
6644
6803
|
if (block?.isError) return h20("p", { className: "dgui-tool-error", role: "alert" }, (block.content ?? []).filter((c) => c.type === "text").map((c) => c.text).join("\n"));
|
|
@@ -6662,7 +6821,7 @@ function apply(ctx) {
|
|
|
6662
6821
|
console.info("[motion-ui] client active; channel=conversation-events/fence-dom");
|
|
6663
6822
|
const scope2 = ctx.configForms.get("motion-ui");
|
|
6664
6823
|
configureViewSettings(scope2);
|
|
6665
|
-
ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({ name: "plugins.bundle.config", key: "dsh-motion-ui" }, (props) =>
|
|
6824
|
+
ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({ name: "plugins.bundle.config", key: "dsh-motion-ui" }, (props) => import_react28.default.createElement(ModeSettings, { ...props, scope: scope2 })));
|
|
6666
6825
|
ctx.uiConversation.events.register(turnUiDefinition);
|
|
6667
6826
|
ctx.uiConversation.events.register(streamUiDefinition);
|
|
6668
6827
|
ctx.uiConversation.events.register(fenceUiDefinition);
|