@stacksjs/stx 0.2.82 → 0.2.84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/app-shell.js +21 -11
  2. package/dist/build-assets.js +19 -9
  3. package/dist/build-mode-detector.js +22 -12
  4. package/dist/build-views.js +22 -12
  5. package/dist/build.js +21 -11
  6. package/dist/caching.js +19 -9
  7. package/dist/cli.js +22 -12
  8. package/dist/component-processing.js +21 -11
  9. package/dist/component-renderer.js +21 -11
  10. package/dist/components.js +22 -12
  11. package/dist/conditionals.js +1 -1
  12. package/dist/custom-directives.js +1 -1
  13. package/dist/dev-server/index.js +22 -12
  14. package/dist/dev-server/serve-app.js +21 -11
  15. package/dist/dev-server/serve-file.js +21 -11
  16. package/dist/dev-server/serve-markdown.js +22 -12
  17. package/dist/dev-server/serve-multi.js +21 -11
  18. package/dist/dev-server.js +21 -11
  19. package/dist/docs.js +22 -12
  20. package/dist/dynamic-components.js +21 -11
  21. package/dist/error-handling.js +1 -1
  22. package/dist/errors/formatter.js +1 -1
  23. package/dist/errors/index.js +1 -1
  24. package/dist/i18n.js +1 -1
  25. package/dist/includes.js +21 -11
  26. package/dist/index.js +21 -11
  27. package/dist/interactive.js +22 -12
  28. package/dist/lazy-loader.js +98 -88
  29. package/dist/misc-directives.js +1 -1
  30. package/dist/plugin.js +21 -11
  31. package/dist/process.js +21 -11
  32. package/dist/production-builder.js +21 -11
  33. package/dist/production-server.js +21 -11
  34. package/dist/pwa/index.js +22 -12
  35. package/dist/pwa/offline.js +22 -12
  36. package/dist/pwa.js +21 -11
  37. package/dist/reactive.js +1 -1
  38. package/dist/render.js +22 -12
  39. package/dist/runtime-injection.js +19 -9
  40. package/dist/seo.js +1 -1
  41. package/dist/serve.js +22 -12
  42. package/dist/signal-processing.js +41 -31
  43. package/dist/signals.js +19 -9
  44. package/dist/site-builder/build.js +22 -12
  45. package/dist/site-builder/index.js +22 -12
  46. package/dist/ssg.js +21 -11
  47. package/dist/ssr.js +22 -12
  48. package/dist/store-loader.js +18 -18
  49. package/dist/story/cli.js +22 -12
  50. package/dist/story/commands/dev.js +22 -12
  51. package/dist/story/commands/index.js +22 -12
  52. package/dist/story/index.js +22 -12
  53. package/dist/story/renderer.js +22 -12
  54. package/dist/story/server.js +22 -12
  55. package/dist/story/visual-testing.js +22 -12
  56. package/dist/streaming.js +21 -11
  57. package/dist/template-compiler.js +22 -12
  58. package/dist/template-hydrator.js +22 -12
  59. package/dist/testing.js +147 -137
  60. package/dist/utils.js +21 -11
  61. package/dist/web-components.js +22 -12
  62. package/package.json +5 -5
@@ -58,7 +58,7 @@ ${H}`)}if(q.suggestion)B.push(`
58
58
  ${"\x1B[31m"}\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${"\x1B[0m"}`),B.join("")}function nq(q,J,Z){let $=q.split(`
59
59
  `),X=Math.max(0,J-Z-1),W=Math.min($.length-1,J+Z-1),V=[];for(let Y=X;Y<=W;Y++){let U=(Y+1).toString().padStart(4),B=Y===J-1?">":" ";V.push(`${B}${U} | ${$[Y]}`)}return V.join(`
60
60
  `)}function aq(q,J,Z){let $=q.split(`
61
- `),X=Math.max(0,J-Z-1),W=Math.min($.length-1,J+Z-1),V="\x1B[90m",Y="\x1B[31m",U="\x1B[0m",B=[];for(let G=X;G<=W;G++){let H=(G+1).toString().padStart(4),Q=G===J-1,F=Q?"\x1B[31m>\x1B[0m":" ",M=Q?`\x1B[31m${$[G]}\x1B[0m`:`\x1B[90m${$[G]}`;B.push(`${F}${H}\x1B[0m | ${M}`)}return B.join(`
61
+ `),X=Math.max(0,J-Z-1),W=Math.min($.length-1,J+Z-1),V="\x1B[90m",Y="\x1B[31m",U="\x1B[0m",B=[];for(let G=X;G<=W;G++){let H=(G+1).toString().padStart(4),Q=G===J-1,F=Q?"\x1B[31m>\x1B[0m":" ",M=Q?`\x1B[31m${$[G]}\x1B[0m`:`\x1B[90m${$[G]}\x1B[0m`;B.push(`${F}\x1B[90m${H}\x1B[0m | ${M}`)}return B.join(`
62
62
  `)}function Fq(q){return q.replace(/--/g,"- -").replace(/>/g,"&gt;")}function Qq(q,J){let $=q.substring(0,J).split(`
63
63
  `);return{line:$.length,column:$[$.length-1].length}}function tq(q,J,Z){return p({type:q,message:J,code:Z,format:"html"}).formatted}function eq(q,J,Z,$,X){return p({type:q,message:J,code:X,filePath:Z,line:$,format:"console"}).formatted}function qJ(q,J,Z){let $=Z.template.split(`
64
64
  `),X=Qq(Z.template,Z.offset),W=`[${q} Error at line ${X.line} in ${Z.filePath}]: ${J}
package/dist/plugin.js CHANGED
@@ -2664,7 +2664,7 @@ window.__stx_reactive = (function() {
2664
2664
 
2665
2665
  return { initScope: initScope, reactive: reactive };
2666
2666
  })();
2667
- `}function ZY($,Z){let X=$.replace(/\{!!([\s\S]*?)!!\}/g,(Y,Q)=>{try{let J=f0(Q,Z,!0);if(J===void 0)return Y;return String(J)}catch{return Y}});return X=X.replace(/\{\{([\s\S]*?)\}\}/g,(Y,Q)=>{try{let J=f0(Q,Z,!0);if(J===void 0)return Y;return JSON.stringify(J)}catch{return Y}}),X}function xU($,Z){if($.length===0)return"";let X=$.map((Y)=>{let Q=JSON.stringify(Object.fromEntries(Y.refs)),J=ZY(Y.stateExpr,Z),G=Y.initExpr?ZY(Y.initExpr,Z):null,K=JSON.stringify(J),W=G?JSON.stringify(G):"null";return`
2667
+ `}function ZY($,Z){let X=$.replace(/\{!!([\s\S]*?)!!\}/g,(Y,Q)=>{try{let J=f0(Q,Z,!0);if(J===void 0)return Y;return String(J)}catch{return Y}});return X=X.replace(/\{\{([\s\S]*?)\}\}/g,(Y,Q)=>{try{let J=f0(Q,Z,!0);if(J===void 0)return Y;if(typeof J==="string"){let G=J.trim();if(G.startsWith("{")&&G.endsWith("}")||G.startsWith("[")&&G.endsWith("]"))try{return JSON.parse(G),G}catch{}}return JSON.stringify(J)}catch{return Y}}),X}function xU($,Z){if($.length===0)return"";let X=$.map((Y)=>{let Q=JSON.stringify(Object.fromEntries(Y.refs)),J=ZY(Y.stateExpr,Z),G=Y.initExpr?ZY(Y.initExpr,Z):null,K=JSON.stringify(J),W=G?JSON.stringify(G):"null";return`
2668
2668
  (function() {
2669
2669
  var scopeEl = document.querySelector('${Y.selector}');
2670
2670
  if (!scopeEl) return;
@@ -4735,6 +4735,13 @@ catch (e2) {
4735
4735
 
4736
4736
  // Known directive names to exclude from generic :attr binding
4737
4737
  var DIRECTIVE_NAMES = {class:1, style:1, text:1, html:1, show:1, model:1, 'if':1, 'for':1, ref:1};
4738
+ // SVG attributes are case-sensitive, but the HTML parser lowercases
4739
+ // prefixed attribute names \u2014 ':viewBox' arrives as ':viewbox' because
4740
+ // the spec's "adjust SVG attributes" step only covers unprefixed names.
4741
+ // Without restoring the canonical casing, setAttribute('viewbox') creates
4742
+ // a dead duplicate attribute and the real viewBox never updates.
4743
+ var SVG_ATTR_CASE = {attributename:'attributeName', attributetype:'attributeType', basefrequency:'baseFrequency', baseprofile:'baseProfile', calcmode:'calcMode', clippathunits:'clipPathUnits', diffuseconstant:'diffuseConstant', edgemode:'edgeMode', filterunits:'filterUnits', glyphref:'glyphRef', gradienttransform:'gradientTransform', gradientunits:'gradientUnits', kernelmatrix:'kernelMatrix', kernelunitlength:'kernelUnitLength', keypoints:'keyPoints', keysplines:'keySplines', keytimes:'keyTimes', lengthadjust:'lengthAdjust', limitingconeangle:'limitingConeAngle', markerheight:'markerHeight', markerunits:'markerUnits', markerwidth:'markerWidth', maskcontentunits:'maskContentUnits', maskunits:'maskUnits', numoctaves:'numOctaves', pathlength:'pathLength', patterncontentunits:'patternContentUnits', patterntransform:'patternTransform', patternunits:'patternUnits', pointsatx:'pointsAtX', pointsaty:'pointsAtY', pointsatz:'pointsAtZ', preservealpha:'preserveAlpha', preserveaspectratio:'preserveAspectRatio', primitiveunits:'primitiveUnits', refx:'refX', refy:'refY', repeatcount:'repeatCount', repeatdur:'repeatDur', requiredextensions:'requiredExtensions', requiredfeatures:'requiredFeatures', specularconstant:'specularConstant', specularexponent:'specularExponent', spreadmethod:'spreadMethod', startoffset:'startOffset', stddeviation:'stdDeviation', stitchtiles:'stitchTiles', surfacescale:'surfaceScale', systemlanguage:'systemLanguage', tablevalues:'tableValues', targetx:'targetX', targety:'targetY', textlength:'textLength', viewbox:'viewBox', viewtarget:'viewTarget', xchannelselector:'xChannelSelector', ychannelselector:'yChannelSelector', zoomandpan:'zoomAndPan'};
4744
+ var SVG_NS = 'http://www.w3.org/2000/svg';
4738
4745
  var EVENT_RE = /^(click|dblclick|mousedown|mouseup|mousemove|mouseenter|mouseleave|keydown|keyup|keypress|input|change|submit|focus|blur|scroll|resize|touchstart|touchend|touchmove|contextmenu|wheel|pointerdown|pointerup|pointermove)/;
4739
4746
  var KEY_MAP = {enter:'Enter', tab:'Tab', escape:'Escape', space:' ', up:'ArrowUp', down:'ArrowDown', left:'ArrowLeft', right:'ArrowRight', 'delete':'Delete', backspace:'Backspace'};
4740
4747
 
@@ -4759,7 +4766,8 @@ catch (e2) {
4759
4766
  if (name.startsWith('@bind:') || name.startsWith('x-bind:')
4760
4767
  || (name.startsWith(':') && !name.startsWith('::') && !DIRECTIVE_NAMES[name.slice(1).split('.')[0]] && !EVENT_RE.test(name.slice(1)))
4761
4768
  || (name.startsWith('x-') && !X_HANDLED[name.split('.')[0]] && !X_HANDLED[name])) {
4762
- const attrName = name.startsWith('@bind:') ? name.slice(6) : name.startsWith('x-bind:') ? name.slice(7) : name.startsWith('x-') ? name.slice(2) : name.slice(1);
4769
+ let attrName = name.startsWith('@bind:') ? name.slice(6) : name.startsWith('x-bind:') ? name.slice(7) : name.startsWith('x-') ? name.slice(2) : name.slice(1);
4770
+ if (el.namespaceURI === SVG_NS && SVG_ATTR_CASE[attrName]) attrName = SVG_ATTR_CASE[attrName];
4763
4771
  effect(() => {
4764
4772
  const v = evalAttrExpr(value);
4765
4773
  if (v === false || v === null || v === undefined) {
@@ -5138,10 +5146,12 @@ else {
5138
5146
  });
5139
5147
  }
5140
5148
  else if (Array.isArray(value)) {
5141
- el.className = originalClasses + ' ' + value.filter(Boolean).join(' ');
5149
+ var _clsArr = originalClasses + ' ' + value.filter(Boolean).join(' ');
5150
+ if (typeof el.className === 'string') el.className = _clsArr; else el.setAttribute('class', _clsArr);
5142
5151
  }
5143
5152
  else {
5144
- el.className = originalClasses + (value ? ' ' + value : '');
5153
+ var _clsStr = originalClasses + (value ? ' ' + value : '');
5154
+ if (typeof el.className === 'string') el.className = _clsStr; else el.setAttribute('class', _clsStr);
5145
5155
  }
5146
5156
  });
5147
5157
  }
@@ -7465,10 +7475,10 @@ else {
7465
7475
  var root = scriptEl ? scriptEl.nextElementSibling : null;
7466
7476
  if (!root && scriptEl) root = scriptEl.previousElementSibling || scriptEl.parentElement;
7467
7477
 
7468
- // SPA fallback: during router navigation, script is appended to <body>
7478
+ // SPA fallback: during router navigation, script is appended to body>
7469
7479
  // (not inside the content container), so nextElementSibling won't find the page content.
7470
7480
  // Only use fallback when we genuinely couldn't find a suitable root element.
7471
- // Do NOT fallback just because the script is in <body> \u2014 layout scripts in <body>
7481
+ // Do NOT fallback just because the script is in body> \u2014 layout scripts in body>
7472
7482
  // with valid siblings (e.g. sidebar <aside>) should use those siblings as root.
7473
7483
  var needsFallback = !root || root === document.body
7474
7484
  || (root && root.tagName === 'SCRIPT');
@@ -7787,7 +7797,7 @@ else {
7787
7797
  mountCallbacks.forEach(fn => fn());
7788
7798
  });
7789
7799
 
7790
- // Multi-root fragment fix: a no-<body> setup page tags only the FIRST
7800
+ // Multi-root fragment fix: a no-body> setup page tags only the FIRST
7791
7801
  // top-level element with data-stx (signal-processing.ts marks one element),
7792
7802
  // so sibling root elements were orphaned \u2014 their :if / :for / {{ }} / x-text
7793
7803
  // never hydrated, which read as "{{ }} doesn't work under :if/:for". The
@@ -7884,7 +7894,7 @@ else {
7884
7894
  el.querySelectorAll('[x-cloak]').forEach(function(c) { c.removeAttribute('x-cloak'); });
7885
7895
  });
7886
7896
 
7887
- // Process <head> elements (title, meta) that may contain {{ }} expressions
7897
+ // Process head> elements (title, meta) that may contain {{ }} expressions
7888
7898
  // Use componentScope which now contains variables from processed components
7889
7899
  const headElements = document.querySelectorAll('head title, head meta[content]');
7890
7900
  headElements.forEach(el => {
@@ -8080,7 +8090,7 @@ catch (e) { console.warn('[stx] destroy callback error:', e); }
8080
8090
 
8081
8091
  // Apply new page's SFC setup function. During SPA navigation, re-executed page
8082
8092
  // scripts set window.stx._latestSetup to the new setup function. This takes priority
8083
- // over the stale data-stx attribute on <body> (which has the PREVIOUS page's function name).
8093
+ // over the stale data-stx attribute on body> (which has the PREVIOUS page's function name).
8084
8094
  var usedLatestSetup = false;
8085
8095
  if (window.stx._latestSetup && typeof window.stx._latestSetup === 'function') {
8086
8096
  try {
@@ -8164,7 +8174,7 @@ catch (e) { console.warn('[stx] destroy callback error:', e); }
8164
8174
 
8165
8175
  // Process the container content \u2014 bind {{ }}, :attr, @event directives.
8166
8176
  // Run synchronously (not in setTimeout) so componentScope is captured correctly.
8167
- // The DOMContentLoaded path processes <body> synchronously \u2014 the SPA path must match.
8177
+ // The DOMContentLoaded path processes body> synchronously \u2014 the SPA path must match.
8168
8178
  console.log('[stx:load] container:', container.tagName, '__stx_scope:', !!container.__stx_scope, 'scope keys:', Object.keys(componentScope).slice(0, 10));
8169
8179
  if (!container.__stx_scope) {
8170
8180
  // Dispose previous effects on the container (from prior navigation)
@@ -8274,7 +8284,7 @@ ${z}${U}
8274
8284
  return { ${_} };
8275
8285
  }
8276
8286
  if(window.stx)window.stx._latestSetup=${G};
8277
- </script>`,j=$;for(let H of J)j=j.split(H.fullMatch).join("");if(j.includes("<body"))j=j.replace(/<body([^>]*)>/,`<body$1 data-stx="${G}">`);else{let H=["script","style","html","head","meta","link","title","!doctype"];j=j.replace(/<([a-zA-Z][a-zA-Z0-9-]*)\b([^>]*)>/i,(L,F,O)=>{if(H.includes(F.toLowerCase()))return L;return`<${F}${O} data-stx="${G}">`})}return{output:j,setupCode:q}}function Y2($){let Z=$,X=[],Y=new Set,Q=0,J=0,G=Z.length,K="",W=()=>{J++;let j=!1;while(J<G){let H=Z[J];if(H==="\\"){J+=2;continue}if(H==="["&&!j){j=!0,J++;continue}if(H==="]"&&j){j=!1,J++;continue}if(H==="/"&&!j){J++;while(J<G&&/[gimsuyd]/.test(Z[J]))J++;return}if(H===`
8287
+ </script>`,j=$;for(let H of J)j=j.split(H.fullMatch).join("");if(j.includes("<body"))j=j.replace(/<body([^>]*)>/,`<body$1 data-stx="${G}">`);else{let H=["script","style","html","head","meta","link","title","!doctype"],L=!1;j=j.replace(/<([a-zA-Z][a-zA-Z0-9-]*)\b([^>]*)>/gi,(F,O,V)=>{if(L||H.includes(O.toLowerCase()))return F;return L=!0,`<${O}${V} data-stx="${G}">`})}return{output:j,setupCode:q}}function Y2($){let Z=$,X=[],Y=new Set,Q=0,J=0,G=Z.length,K="",W=()=>{J++;let j=!1;while(J<G){let H=Z[J];if(H==="\\"){J+=2;continue}if(H==="["&&!j){j=!0,J++;continue}if(H==="]"&&j){j=!1,J++;continue}if(H==="/"&&!j){J++;while(J<G&&/[gimsuyd]/.test(Z[J]))J++;return}if(H===`
8278
8288
  `)return;J++}},B=()=>{if(!K)return!0;if(/[\w)\]]/.test(K))return!1;return!0},U=(j)=>{J++;while(J<G){if(Z[J]==="\\"){J+=2;continue}if(Z[J]===j){J++;return}J++}},_=()=>{J++;while(J<G){if(Z[J]==="\\"){J+=2;continue}if(Z[J]==="`"){J++;return}if(Z[J]==="$"&&Z[J+1]==="{"){J+=2;let j=1;while(J<G&&j>0)if(Z[J]==="{")j++,J++;else if(Z[J]==="}")j--,J++;else if(Z[J]==="'"||Z[J]==='"')U(Z[J]);else if(Z[J]==="`")_();else J++;continue}J++}},z=()=>{if(Z[J]==="/"&&Z[J+1]==="/"){while(J<G&&Z[J]!==`
8279
8289
  `)J++;return!0}if(Z[J]==="/"&&Z[J+1]==="*"){J+=2;while(J<G-1&&!(Z[J]==="*"&&Z[J+1]==="/"))J++;return J+=2,!0}return!1},q=()=>{if(Q!==0)return;let j=Z.slice(J).match(/^(const|let|var)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=/);if(j){let V=j[2];if(!Y.has(V))X.push(V),Y.add(V);return}let H=Z.slice(J).match(/^(?:const|let|var)\s+\{([^}]+)\}\s*=/);if(H){H[1].split(",").forEach((V)=>{let N=V.trim();if(!N)return;let A=N.indexOf(":"),R=(A>=0?N.slice(A+1).trim():N).split(/[\s=]/)[0];if(R&&!Y.has(R))X.push(R),Y.add(R)});return}let L=Z.slice(J).match(/^(?:const|let|var)\s+\[([^\]]+)\]\s*=/);if(L){L[1].split(",").forEach((V)=>{let N=V.trim().replace(/^\.\.\./,"");if(!N)return;let A=N.split(/[\s=]/)[0];if(A&&!Y.has(A))X.push(A),Y.add(A)});return}let F=Z.slice(J).match(/^function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/);if(F){let V=F[1];if(!Y.has(V))X.push(V),Y.add(V);return}let O=Z.slice(J).match(/^async\s+function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/);if(O){let V=O[1];if(!Y.has(V))X.push(V),Y.add(V)}};while(J<G){if(z())continue;if(Z[J]==="'"||Z[J]==='"'){U(Z[J]),K=Z[J-1];continue}if(Z[J]==="`"){_(),K="`";continue}if(Z[J]==="/"&&Z[J+1]!=="/"&&Z[J+1]!=="*"&&B()){W(),K="/";continue}if(Z[J]==="{"){Q++,K="{",J++;continue}if(Z[J]==="}"){Q--,K="}",J++;continue}if(Q===0&&/[a-z]/i.test(Z[J])&&(J===0||/\s|[;{}()]/.test(Z[J-1])))q();if(!/\s/.test(Z[J]))K=Z[J];J++}return X.join(", ")}async function K8($,Z,X,Y){if(!J4($))return $;let Q=$;if(Z.skipSignalsRuntime)return Q;let{output:J,setupCode:G}=await X2(Q,X,Y);if(Q=J,Q=await sJ(Q,Z),Q=rJ(Q),G)if(Q.includes("</head>"))Q=Q.replace("</head>",`${G}
8280
8290
  </head>`);else if(Q.includes("<body"))Q=Q.replace(/<body([^>]*)>/,`<body$1>
package/dist/process.js CHANGED
@@ -2498,7 +2498,7 @@ window.__stx_reactive = (function() {
2498
2498
 
2499
2499
  return { initScope: initScope, reactive: reactive };
2500
2500
  })();
2501
- `}function m8($,Z){let Y=$.replace(/\{!!([\s\S]*?)!!\}/g,(X,Q)=>{try{let J=x0(Q,Z,!0);if(J===void 0)return X;return String(J)}catch{return X}});return Y=Y.replace(/\{\{([\s\S]*?)\}\}/g,(X,Q)=>{try{let J=x0(Q,Z,!0);if(J===void 0)return X;return JSON.stringify(J)}catch{return X}}),Y}function zK($,Z){if($.length===0)return"";let Y=$.map((X)=>{let Q=JSON.stringify(Object.fromEntries(X.refs)),J=m8(X.stateExpr,Z),G=X.initExpr?m8(X.initExpr,Z):null,K=JSON.stringify(J),q=G?JSON.stringify(G):"null";return`
2501
+ `}function m8($,Z){let Y=$.replace(/\{!!([\s\S]*?)!!\}/g,(X,Q)=>{try{let J=x0(Q,Z,!0);if(J===void 0)return X;return String(J)}catch{return X}});return Y=Y.replace(/\{\{([\s\S]*?)\}\}/g,(X,Q)=>{try{let J=x0(Q,Z,!0);if(J===void 0)return X;if(typeof J==="string"){let G=J.trim();if(G.startsWith("{")&&G.endsWith("}")||G.startsWith("[")&&G.endsWith("]"))try{return JSON.parse(G),G}catch{}}return JSON.stringify(J)}catch{return X}}),Y}function zK($,Z){if($.length===0)return"";let Y=$.map((X)=>{let Q=JSON.stringify(Object.fromEntries(X.refs)),J=m8(X.stateExpr,Z),G=X.initExpr?m8(X.initExpr,Z):null,K=JSON.stringify(J),q=G?JSON.stringify(G):"null";return`
2502
2502
  (function() {
2503
2503
  var scopeEl = document.querySelector('${X.selector}');
2504
2504
  if (!scopeEl) return;
@@ -4543,6 +4543,13 @@ catch (e2) {
4543
4543
 
4544
4544
  // Known directive names to exclude from generic :attr binding
4545
4545
  var DIRECTIVE_NAMES = {class:1, style:1, text:1, html:1, show:1, model:1, 'if':1, 'for':1, ref:1};
4546
+ // SVG attributes are case-sensitive, but the HTML parser lowercases
4547
+ // prefixed attribute names \u2014 ':viewBox' arrives as ':viewbox' because
4548
+ // the spec's "adjust SVG attributes" step only covers unprefixed names.
4549
+ // Without restoring the canonical casing, setAttribute('viewbox') creates
4550
+ // a dead duplicate attribute and the real viewBox never updates.
4551
+ var SVG_ATTR_CASE = {attributename:'attributeName', attributetype:'attributeType', basefrequency:'baseFrequency', baseprofile:'baseProfile', calcmode:'calcMode', clippathunits:'clipPathUnits', diffuseconstant:'diffuseConstant', edgemode:'edgeMode', filterunits:'filterUnits', glyphref:'glyphRef', gradienttransform:'gradientTransform', gradientunits:'gradientUnits', kernelmatrix:'kernelMatrix', kernelunitlength:'kernelUnitLength', keypoints:'keyPoints', keysplines:'keySplines', keytimes:'keyTimes', lengthadjust:'lengthAdjust', limitingconeangle:'limitingConeAngle', markerheight:'markerHeight', markerunits:'markerUnits', markerwidth:'markerWidth', maskcontentunits:'maskContentUnits', maskunits:'maskUnits', numoctaves:'numOctaves', pathlength:'pathLength', patterncontentunits:'patternContentUnits', patterntransform:'patternTransform', patternunits:'patternUnits', pointsatx:'pointsAtX', pointsaty:'pointsAtY', pointsatz:'pointsAtZ', preservealpha:'preserveAlpha', preserveaspectratio:'preserveAspectRatio', primitiveunits:'primitiveUnits', refx:'refX', refy:'refY', repeatcount:'repeatCount', repeatdur:'repeatDur', requiredextensions:'requiredExtensions', requiredfeatures:'requiredFeatures', specularconstant:'specularConstant', specularexponent:'specularExponent', spreadmethod:'spreadMethod', startoffset:'startOffset', stddeviation:'stdDeviation', stitchtiles:'stitchTiles', surfacescale:'surfaceScale', systemlanguage:'systemLanguage', tablevalues:'tableValues', targetx:'targetX', targety:'targetY', textlength:'textLength', viewbox:'viewBox', viewtarget:'viewTarget', xchannelselector:'xChannelSelector', ychannelselector:'yChannelSelector', zoomandpan:'zoomAndPan'};
4552
+ var SVG_NS = 'http://www.w3.org/2000/svg';
4546
4553
  var EVENT_RE = /^(click|dblclick|mousedown|mouseup|mousemove|mouseenter|mouseleave|keydown|keyup|keypress|input|change|submit|focus|blur|scroll|resize|touchstart|touchend|touchmove|contextmenu|wheel|pointerdown|pointerup|pointermove)/;
4547
4554
  var KEY_MAP = {enter:'Enter', tab:'Tab', escape:'Escape', space:' ', up:'ArrowUp', down:'ArrowDown', left:'ArrowLeft', right:'ArrowRight', 'delete':'Delete', backspace:'Backspace'};
4548
4555
 
@@ -4567,7 +4574,8 @@ catch (e2) {
4567
4574
  if (name.startsWith('@bind:') || name.startsWith('x-bind:')
4568
4575
  || (name.startsWith(':') && !name.startsWith('::') && !DIRECTIVE_NAMES[name.slice(1).split('.')[0]] && !EVENT_RE.test(name.slice(1)))
4569
4576
  || (name.startsWith('x-') && !X_HANDLED[name.split('.')[0]] && !X_HANDLED[name])) {
4570
- const attrName = name.startsWith('@bind:') ? name.slice(6) : name.startsWith('x-bind:') ? name.slice(7) : name.startsWith('x-') ? name.slice(2) : name.slice(1);
4577
+ let attrName = name.startsWith('@bind:') ? name.slice(6) : name.startsWith('x-bind:') ? name.slice(7) : name.startsWith('x-') ? name.slice(2) : name.slice(1);
4578
+ if (el.namespaceURI === SVG_NS && SVG_ATTR_CASE[attrName]) attrName = SVG_ATTR_CASE[attrName];
4571
4579
  effect(() => {
4572
4580
  const v = evalAttrExpr(value);
4573
4581
  if (v === false || v === null || v === undefined) {
@@ -4946,10 +4954,12 @@ else {
4946
4954
  });
4947
4955
  }
4948
4956
  else if (Array.isArray(value)) {
4949
- el.className = originalClasses + ' ' + value.filter(Boolean).join(' ');
4957
+ var _clsArr = originalClasses + ' ' + value.filter(Boolean).join(' ');
4958
+ if (typeof el.className === 'string') el.className = _clsArr; else el.setAttribute('class', _clsArr);
4950
4959
  }
4951
4960
  else {
4952
- el.className = originalClasses + (value ? ' ' + value : '');
4961
+ var _clsStr = originalClasses + (value ? ' ' + value : '');
4962
+ if (typeof el.className === 'string') el.className = _clsStr; else el.setAttribute('class', _clsStr);
4953
4963
  }
4954
4964
  });
4955
4965
  }
@@ -7273,10 +7283,10 @@ else {
7273
7283
  var root = scriptEl ? scriptEl.nextElementSibling : null;
7274
7284
  if (!root && scriptEl) root = scriptEl.previousElementSibling || scriptEl.parentElement;
7275
7285
 
7276
- // SPA fallback: during router navigation, script is appended to <body>
7286
+ // SPA fallback: during router navigation, script is appended to body>
7277
7287
  // (not inside the content container), so nextElementSibling won't find the page content.
7278
7288
  // Only use fallback when we genuinely couldn't find a suitable root element.
7279
- // Do NOT fallback just because the script is in <body> \u2014 layout scripts in <body>
7289
+ // Do NOT fallback just because the script is in body> \u2014 layout scripts in body>
7280
7290
  // with valid siblings (e.g. sidebar <aside>) should use those siblings as root.
7281
7291
  var needsFallback = !root || root === document.body
7282
7292
  || (root && root.tagName === 'SCRIPT');
@@ -7595,7 +7605,7 @@ else {
7595
7605
  mountCallbacks.forEach(fn => fn());
7596
7606
  });
7597
7607
 
7598
- // Multi-root fragment fix: a no-<body> setup page tags only the FIRST
7608
+ // Multi-root fragment fix: a no-body> setup page tags only the FIRST
7599
7609
  // top-level element with data-stx (signal-processing.ts marks one element),
7600
7610
  // so sibling root elements were orphaned \u2014 their :if / :for / {{ }} / x-text
7601
7611
  // never hydrated, which read as "{{ }} doesn't work under :if/:for". The
@@ -7692,7 +7702,7 @@ else {
7692
7702
  el.querySelectorAll('[x-cloak]').forEach(function(c) { c.removeAttribute('x-cloak'); });
7693
7703
  });
7694
7704
 
7695
- // Process <head> elements (title, meta) that may contain {{ }} expressions
7705
+ // Process head> elements (title, meta) that may contain {{ }} expressions
7696
7706
  // Use componentScope which now contains variables from processed components
7697
7707
  const headElements = document.querySelectorAll('head title, head meta[content]');
7698
7708
  headElements.forEach(el => {
@@ -7888,7 +7898,7 @@ catch (e) { console.warn('[stx] destroy callback error:', e); }
7888
7898
 
7889
7899
  // Apply new page's SFC setup function. During SPA navigation, re-executed page
7890
7900
  // scripts set window.stx._latestSetup to the new setup function. This takes priority
7891
- // over the stale data-stx attribute on <body> (which has the PREVIOUS page's function name).
7901
+ // over the stale data-stx attribute on body> (which has the PREVIOUS page's function name).
7892
7902
  var usedLatestSetup = false;
7893
7903
  if (window.stx._latestSetup && typeof window.stx._latestSetup === 'function') {
7894
7904
  try {
@@ -7972,7 +7982,7 @@ catch (e) { console.warn('[stx] destroy callback error:', e); }
7972
7982
 
7973
7983
  // Process the container content \u2014 bind {{ }}, :attr, @event directives.
7974
7984
  // Run synchronously (not in setTimeout) so componentScope is captured correctly.
7975
- // The DOMContentLoaded path processes <body> synchronously \u2014 the SPA path must match.
7985
+ // The DOMContentLoaded path processes body> synchronously \u2014 the SPA path must match.
7976
7986
  console.log('[stx:load] container:', container.tagName, '__stx_scope:', !!container.__stx_scope, 'scope keys:', Object.keys(componentScope).slice(0, 10));
7977
7987
  if (!container.__stx_scope) {
7978
7988
  // Dispose previous effects on the container (from prior navigation)
@@ -8082,7 +8092,7 @@ ${_}${z}
8082
8092
  return { ${U} };
8083
8093
  }
8084
8094
  if(window.stx)window.stx._latestSetup=${G};
8085
- </script>`,j=$;for(let H of J)j=j.split(H.fullMatch).join("");if(j.includes("<body"))j=j.replace(/<body([^>]*)>/,`<body$1 data-stx="${G}">`);else{let H=["script","style","html","head","meta","link","title","!doctype"];j=j.replace(/<([a-zA-Z][a-zA-Z0-9-]*)\b([^>]*)>/i,(L,F,O)=>{if(H.includes(F.toLowerCase()))return L;return`<${F}${O} data-stx="${G}">`})}return{output:j,setupCode:B}}function l2($){let Z=$,Y=[],X=new Set,Q=0,J=0,G=Z.length,K="",q=()=>{J++;let j=!1;while(J<G){let H=Z[J];if(H==="\\"){J+=2;continue}if(H==="["&&!j){j=!0,J++;continue}if(H==="]"&&j){j=!1,J++;continue}if(H==="/"&&!j){J++;while(J<G&&/[gimsuyd]/.test(Z[J]))J++;return}if(H===`
8095
+ </script>`,j=$;for(let H of J)j=j.split(H.fullMatch).join("");if(j.includes("<body"))j=j.replace(/<body([^>]*)>/,`<body$1 data-stx="${G}">`);else{let H=["script","style","html","head","meta","link","title","!doctype"],L=!1;j=j.replace(/<([a-zA-Z][a-zA-Z0-9-]*)\b([^>]*)>/gi,(F,O,V)=>{if(L||H.includes(O.toLowerCase()))return F;return L=!0,`<${O}${V} data-stx="${G}">`})}return{output:j,setupCode:B}}function l2($){let Z=$,Y=[],X=new Set,Q=0,J=0,G=Z.length,K="",q=()=>{J++;let j=!1;while(J<G){let H=Z[J];if(H==="\\"){J+=2;continue}if(H==="["&&!j){j=!0,J++;continue}if(H==="]"&&j){j=!1,J++;continue}if(H==="/"&&!j){J++;while(J<G&&/[gimsuyd]/.test(Z[J]))J++;return}if(H===`
8086
8096
  `)return;J++}},W=()=>{if(!K)return!0;if(/[\w)\]]/.test(K))return!1;return!0},z=(j)=>{J++;while(J<G){if(Z[J]==="\\"){J+=2;continue}if(Z[J]===j){J++;return}J++}},U=()=>{J++;while(J<G){if(Z[J]==="\\"){J+=2;continue}if(Z[J]==="`"){J++;return}if(Z[J]==="$"&&Z[J+1]==="{"){J+=2;let j=1;while(J<G&&j>0)if(Z[J]==="{")j++,J++;else if(Z[J]==="}")j--,J++;else if(Z[J]==="'"||Z[J]==='"')z(Z[J]);else if(Z[J]==="`")U();else J++;continue}J++}},_=()=>{if(Z[J]==="/"&&Z[J+1]==="/"){while(J<G&&Z[J]!==`
8087
8097
  `)J++;return!0}if(Z[J]==="/"&&Z[J+1]==="*"){J+=2;while(J<G-1&&!(Z[J]==="*"&&Z[J+1]==="/"))J++;return J+=2,!0}return!1},B=()=>{if(Q!==0)return;let j=Z.slice(J).match(/^(const|let|var)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=/);if(j){let V=j[2];if(!X.has(V))Y.push(V),X.add(V);return}let H=Z.slice(J).match(/^(?:const|let|var)\s+\{([^}]+)\}\s*=/);if(H){H[1].split(",").forEach((V)=>{let w=V.trim();if(!w)return;let A=w.indexOf(":"),N=(A>=0?w.slice(A+1).trim():w).split(/[\s=]/)[0];if(N&&!X.has(N))Y.push(N),X.add(N)});return}let L=Z.slice(J).match(/^(?:const|let|var)\s+\[([^\]]+)\]\s*=/);if(L){L[1].split(",").forEach((V)=>{let w=V.trim().replace(/^\.\.\./,"");if(!w)return;let A=w.split(/[\s=]/)[0];if(A&&!X.has(A))Y.push(A),X.add(A)});return}let F=Z.slice(J).match(/^function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/);if(F){let V=F[1];if(!X.has(V))Y.push(V),X.add(V);return}let O=Z.slice(J).match(/^async\s+function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/);if(O){let V=O[1];if(!X.has(V))Y.push(V),X.add(V)}};while(J<G){if(_())continue;if(Z[J]==="'"||Z[J]==='"'){z(Z[J]),K=Z[J-1];continue}if(Z[J]==="`"){U(),K="`";continue}if(Z[J]==="/"&&Z[J+1]!=="/"&&Z[J+1]!=="*"&&W()){q(),K="/";continue}if(Z[J]==="{"){Q++,K="{",J++;continue}if(Z[J]==="}"){Q--,K="}",J++;continue}if(Q===0&&/[a-z]/i.test(Z[J])&&(J===0||/\s|[;{}()]/.test(Z[J-1])))B();if(!/\s/.test(Z[J]))K=Z[J];J++}return Y.join(", ")}async function b3($,Z,Y,X){if(!J4($))return $;let Q=$;if(Z.skipSignalsRuntime)return Q;let{output:J,setupCode:G}=await p2(Q,Y,X);if(Q=J,Q=await x2(Q,Z),Q=v2(Q),G)if(Q.includes("</head>"))Q=Q.replace("</head>",`${G}
8088
8098
  </head>`);else if(Q.includes("<body"))Q=Q.replace(/<body([^>]*)>/,`<body$1>
@@ -1703,6 +1703,13 @@ catch (e2) {
1703
1703
 
1704
1704
  // Known directive names to exclude from generic :attr binding
1705
1705
  var DIRECTIVE_NAMES = {class:1, style:1, text:1, html:1, show:1, model:1, 'if':1, 'for':1, ref:1};
1706
+ // SVG attributes are case-sensitive, but the HTML parser lowercases
1707
+ // prefixed attribute names \u2014 ':viewBox' arrives as ':viewbox' because
1708
+ // the spec's "adjust SVG attributes" step only covers unprefixed names.
1709
+ // Without restoring the canonical casing, setAttribute('viewbox') creates
1710
+ // a dead duplicate attribute and the real viewBox never updates.
1711
+ var SVG_ATTR_CASE = {attributename:'attributeName', attributetype:'attributeType', basefrequency:'baseFrequency', baseprofile:'baseProfile', calcmode:'calcMode', clippathunits:'clipPathUnits', diffuseconstant:'diffuseConstant', edgemode:'edgeMode', filterunits:'filterUnits', glyphref:'glyphRef', gradienttransform:'gradientTransform', gradientunits:'gradientUnits', kernelmatrix:'kernelMatrix', kernelunitlength:'kernelUnitLength', keypoints:'keyPoints', keysplines:'keySplines', keytimes:'keyTimes', lengthadjust:'lengthAdjust', limitingconeangle:'limitingConeAngle', markerheight:'markerHeight', markerunits:'markerUnits', markerwidth:'markerWidth', maskcontentunits:'maskContentUnits', maskunits:'maskUnits', numoctaves:'numOctaves', pathlength:'pathLength', patterncontentunits:'patternContentUnits', patterntransform:'patternTransform', patternunits:'patternUnits', pointsatx:'pointsAtX', pointsaty:'pointsAtY', pointsatz:'pointsAtZ', preservealpha:'preserveAlpha', preserveaspectratio:'preserveAspectRatio', primitiveunits:'primitiveUnits', refx:'refX', refy:'refY', repeatcount:'repeatCount', repeatdur:'repeatDur', requiredextensions:'requiredExtensions', requiredfeatures:'requiredFeatures', specularconstant:'specularConstant', specularexponent:'specularExponent', spreadmethod:'spreadMethod', startoffset:'startOffset', stddeviation:'stdDeviation', stitchtiles:'stitchTiles', surfacescale:'surfaceScale', systemlanguage:'systemLanguage', tablevalues:'tableValues', targetx:'targetX', targety:'targetY', textlength:'textLength', viewbox:'viewBox', viewtarget:'viewTarget', xchannelselector:'xChannelSelector', ychannelselector:'yChannelSelector', zoomandpan:'zoomAndPan'};
1712
+ var SVG_NS = 'http://www.w3.org/2000/svg';
1706
1713
  var EVENT_RE = /^(click|dblclick|mousedown|mouseup|mousemove|mouseenter|mouseleave|keydown|keyup|keypress|input|change|submit|focus|blur|scroll|resize|touchstart|touchend|touchmove|contextmenu|wheel|pointerdown|pointerup|pointermove)/;
1707
1714
  var KEY_MAP = {enter:'Enter', tab:'Tab', escape:'Escape', space:' ', up:'ArrowUp', down:'ArrowDown', left:'ArrowLeft', right:'ArrowRight', 'delete':'Delete', backspace:'Backspace'};
1708
1715
 
@@ -1727,7 +1734,8 @@ catch (e2) {
1727
1734
  if (name.startsWith('@bind:') || name.startsWith('x-bind:')
1728
1735
  || (name.startsWith(':') && !name.startsWith('::') && !DIRECTIVE_NAMES[name.slice(1).split('.')[0]] && !EVENT_RE.test(name.slice(1)))
1729
1736
  || (name.startsWith('x-') && !X_HANDLED[name.split('.')[0]] && !X_HANDLED[name])) {
1730
- const attrName = name.startsWith('@bind:') ? name.slice(6) : name.startsWith('x-bind:') ? name.slice(7) : name.startsWith('x-') ? name.slice(2) : name.slice(1);
1737
+ let attrName = name.startsWith('@bind:') ? name.slice(6) : name.startsWith('x-bind:') ? name.slice(7) : name.startsWith('x-') ? name.slice(2) : name.slice(1);
1738
+ if (el.namespaceURI === SVG_NS && SVG_ATTR_CASE[attrName]) attrName = SVG_ATTR_CASE[attrName];
1731
1739
  effect(() => {
1732
1740
  const v = evalAttrExpr(value);
1733
1741
  if (v === false || v === null || v === undefined) {
@@ -2106,10 +2114,12 @@ else {
2106
2114
  });
2107
2115
  }
2108
2116
  else if (Array.isArray(value)) {
2109
- el.className = originalClasses + ' ' + value.filter(Boolean).join(' ');
2117
+ var _clsArr = originalClasses + ' ' + value.filter(Boolean).join(' ');
2118
+ if (typeof el.className === 'string') el.className = _clsArr; else el.setAttribute('class', _clsArr);
2110
2119
  }
2111
2120
  else {
2112
- el.className = originalClasses + (value ? ' ' + value : '');
2121
+ var _clsStr = originalClasses + (value ? ' ' + value : '');
2122
+ if (typeof el.className === 'string') el.className = _clsStr; else el.setAttribute('class', _clsStr);
2113
2123
  }
2114
2124
  });
2115
2125
  }
@@ -4433,10 +4443,10 @@ else {
4433
4443
  var root = scriptEl ? scriptEl.nextElementSibling : null;
4434
4444
  if (!root && scriptEl) root = scriptEl.previousElementSibling || scriptEl.parentElement;
4435
4445
 
4436
- // SPA fallback: during router navigation, script is appended to <body>
4446
+ // SPA fallback: during router navigation, script is appended to body>
4437
4447
  // (not inside the content container), so nextElementSibling won't find the page content.
4438
4448
  // Only use fallback when we genuinely couldn't find a suitable root element.
4439
- // Do NOT fallback just because the script is in <body> \u2014 layout scripts in <body>
4449
+ // Do NOT fallback just because the script is in body> \u2014 layout scripts in body>
4440
4450
  // with valid siblings (e.g. sidebar <aside>) should use those siblings as root.
4441
4451
  var needsFallback = !root || root === document.body
4442
4452
  || (root && root.tagName === 'SCRIPT');
@@ -4755,7 +4765,7 @@ else {
4755
4765
  mountCallbacks.forEach(fn => fn());
4756
4766
  });
4757
4767
 
4758
- // Multi-root fragment fix: a no-<body> setup page tags only the FIRST
4768
+ // Multi-root fragment fix: a no-body> setup page tags only the FIRST
4759
4769
  // top-level element with data-stx (signal-processing.ts marks one element),
4760
4770
  // so sibling root elements were orphaned \u2014 their :if / :for / {{ }} / x-text
4761
4771
  // never hydrated, which read as "{{ }} doesn't work under :if/:for". The
@@ -4852,7 +4862,7 @@ else {
4852
4862
  el.querySelectorAll('[x-cloak]').forEach(function(c) { c.removeAttribute('x-cloak'); });
4853
4863
  });
4854
4864
 
4855
- // Process <head> elements (title, meta) that may contain {{ }} expressions
4865
+ // Process head> elements (title, meta) that may contain {{ }} expressions
4856
4866
  // Use componentScope which now contains variables from processed components
4857
4867
  const headElements = document.querySelectorAll('head title, head meta[content]');
4858
4868
  headElements.forEach(el => {
@@ -5048,7 +5058,7 @@ catch (e) { console.warn('[stx] destroy callback error:', e); }
5048
5058
 
5049
5059
  // Apply new page's SFC setup function. During SPA navigation, re-executed page
5050
5060
  // scripts set window.stx._latestSetup to the new setup function. This takes priority
5051
- // over the stale data-stx attribute on <body> (which has the PREVIOUS page's function name).
5061
+ // over the stale data-stx attribute on body> (which has the PREVIOUS page's function name).
5052
5062
  var usedLatestSetup = false;
5053
5063
  if (window.stx._latestSetup && typeof window.stx._latestSetup === 'function') {
5054
5064
  try {
@@ -5132,7 +5142,7 @@ catch (e) { console.warn('[stx] destroy callback error:', e); }
5132
5142
 
5133
5143
  // Process the container content \u2014 bind {{ }}, :attr, @event directives.
5134
5144
  // Run synchronously (not in setTimeout) so componentScope is captured correctly.
5135
- // The DOMContentLoaded path processes <body> synchronously \u2014 the SPA path must match.
5145
+ // The DOMContentLoaded path processes body> synchronously \u2014 the SPA path must match.
5136
5146
  console.log('[stx:load] container:', container.tagName, '__stx_scope:', !!container.__stx_scope, 'scope keys:', Object.keys(componentScope).slice(0, 10));
5137
5147
  if (!container.__stx_scope) {
5138
5148
  // Dispose previous effects on the container (from prior navigation)
@@ -7709,7 +7719,7 @@ window.__stx_reactive = (function() {
7709
7719
 
7710
7720
  return { initScope: initScope, reactive: reactive };
7711
7721
  })();
7712
- `}function XZ($,Z){let Y=$.replace(/\{!!([\s\S]*?)!!\}/g,(X,Q)=>{try{let J=f0(Q,Z,!0);if(J===void 0)return X;return String(J)}catch{return X}});return Y=Y.replace(/\{\{([\s\S]*?)\}\}/g,(X,Q)=>{try{let J=f0(Q,Z,!0);if(J===void 0)return X;return JSON.stringify(J)}catch{return X}}),Y}function fK($,Z){if($.length===0)return"";let Y=$.map((X)=>{let Q=JSON.stringify(Object.fromEntries(X.refs)),J=XZ(X.stateExpr,Z),G=X.initExpr?XZ(X.initExpr,Z):null,K=JSON.stringify(J),q=G?JSON.stringify(G):"null";return`
7722
+ `}function XZ($,Z){let Y=$.replace(/\{!!([\s\S]*?)!!\}/g,(X,Q)=>{try{let J=f0(Q,Z,!0);if(J===void 0)return X;return String(J)}catch{return X}});return Y=Y.replace(/\{\{([\s\S]*?)\}\}/g,(X,Q)=>{try{let J=f0(Q,Z,!0);if(J===void 0)return X;if(typeof J==="string"){let G=J.trim();if(G.startsWith("{")&&G.endsWith("}")||G.startsWith("[")&&G.endsWith("]"))try{return JSON.parse(G),G}catch{}}return JSON.stringify(J)}catch{return X}}),Y}function fK($,Z){if($.length===0)return"";let Y=$.map((X)=>{let Q=JSON.stringify(Object.fromEntries(X.refs)),J=XZ(X.stateExpr,Z),G=X.initExpr?XZ(X.initExpr,Z):null,K=JSON.stringify(J),q=G?JSON.stringify(G):"null";return`
7713
7723
  (function() {
7714
7724
  var scopeEl = document.querySelector('${X.selector}');
7715
7725
  if (!scopeEl) return;
@@ -8080,7 +8090,7 @@ ${B}${z}
8080
8090
  return { ${U} };
8081
8091
  }
8082
8092
  if(window.stx)window.stx._latestSetup=${G};
8083
- </script>`,j=$;for(let H of J)j=j.split(H.fullMatch).join("");if(j.includes("<body"))j=j.replace(/<body([^>]*)>/,`<body$1 data-stx="${G}">`);else{let H=["script","style","html","head","meta","link","title","!doctype"];j=j.replace(/<([a-zA-Z][a-zA-Z0-9-]*)\b([^>]*)>/i,(F,L,O)=>{if(H.includes(L.toLowerCase()))return F;return`<${L}${O} data-stx="${G}">`})}return{output:j,setupCode:_}}function JY($){let Z=$,Y=[],X=new Set,Q=0,J=0,G=Z.length,K="",q=()=>{J++;let j=!1;while(J<G){let H=Z[J];if(H==="\\"){J+=2;continue}if(H==="["&&!j){j=!0,J++;continue}if(H==="]"&&j){j=!1,J++;continue}if(H==="/"&&!j){J++;while(J<G&&/[gimsuyd]/.test(Z[J]))J++;return}if(H===`
8093
+ </script>`,j=$;for(let H of J)j=j.split(H.fullMatch).join("");if(j.includes("<body"))j=j.replace(/<body([^>]*)>/,`<body$1 data-stx="${G}">`);else{let H=["script","style","html","head","meta","link","title","!doctype"],F=!1;j=j.replace(/<([a-zA-Z][a-zA-Z0-9-]*)\b([^>]*)>/gi,(L,O,V)=>{if(F||H.includes(O.toLowerCase()))return L;return F=!0,`<${O}${V} data-stx="${G}">`})}return{output:j,setupCode:_}}function JY($){let Z=$,Y=[],X=new Set,Q=0,J=0,G=Z.length,K="",q=()=>{J++;let j=!1;while(J<G){let H=Z[J];if(H==="\\"){J+=2;continue}if(H==="["&&!j){j=!0,J++;continue}if(H==="]"&&j){j=!1,J++;continue}if(H==="/"&&!j){J++;while(J<G&&/[gimsuyd]/.test(Z[J]))J++;return}if(H===`
8084
8094
  `)return;J++}},W=()=>{if(!K)return!0;if(/[\w)\]]/.test(K))return!1;return!0},z=(j)=>{J++;while(J<G){if(Z[J]==="\\"){J+=2;continue}if(Z[J]===j){J++;return}J++}},U=()=>{J++;while(J<G){if(Z[J]==="\\"){J+=2;continue}if(Z[J]==="`"){J++;return}if(Z[J]==="$"&&Z[J+1]==="{"){J+=2;let j=1;while(J<G&&j>0)if(Z[J]==="{")j++,J++;else if(Z[J]==="}")j--,J++;else if(Z[J]==="'"||Z[J]==='"')z(Z[J]);else if(Z[J]==="`")U();else J++;continue}J++}},B=()=>{if(Z[J]==="/"&&Z[J+1]==="/"){while(J<G&&Z[J]!==`
8085
8095
  `)J++;return!0}if(Z[J]==="/"&&Z[J+1]==="*"){J+=2;while(J<G-1&&!(Z[J]==="*"&&Z[J+1]==="/"))J++;return J+=2,!0}return!1},_=()=>{if(Q!==0)return;let j=Z.slice(J).match(/^(const|let|var)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=/);if(j){let V=j[2];if(!X.has(V))Y.push(V),X.add(V);return}let H=Z.slice(J).match(/^(?:const|let|var)\s+\{([^}]+)\}\s*=/);if(H){H[1].split(",").forEach((V)=>{let w=V.trim();if(!w)return;let N=w.indexOf(":"),R=(N>=0?w.slice(N+1).trim():w).split(/[\s=]/)[0];if(R&&!X.has(R))Y.push(R),X.add(R)});return}let F=Z.slice(J).match(/^(?:const|let|var)\s+\[([^\]]+)\]\s*=/);if(F){F[1].split(",").forEach((V)=>{let w=V.trim().replace(/^\.\.\./,"");if(!w)return;let N=w.split(/[\s=]/)[0];if(N&&!X.has(N))Y.push(N),X.add(N)});return}let L=Z.slice(J).match(/^function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/);if(L){let V=L[1];if(!X.has(V))Y.push(V),X.add(V);return}let O=Z.slice(J).match(/^async\s+function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/);if(O){let V=O[1];if(!X.has(V))Y.push(V),X.add(V)}};while(J<G){if(B())continue;if(Z[J]==="'"||Z[J]==='"'){z(Z[J]),K=Z[J-1];continue}if(Z[J]==="`"){U(),K="`";continue}if(Z[J]==="/"&&Z[J+1]!=="/"&&Z[J+1]!=="*"&&W()){q(),K="/";continue}if(Z[J]==="{"){Q++,K="{",J++;continue}if(Z[J]==="}"){Q--,K="}",J++;continue}if(Q===0&&/[a-z]/i.test(Z[J])&&(J===0||/\s|[;{}()]/.test(Z[J-1])))_();if(!/\s/.test(Z[J]))K=Z[J];J++}return Y.join(", ")}async function h3($,Z,Y,X){if(!W4($))return $;let Q=$;if(Z.skipSignalsRuntime)return Q;let{output:J,setupCode:G}=await XY(Q,Y,X);if(Q=J,Q=await r2(Q,Z),Q=s2(Q),G)if(Q.includes("</head>"))Q=Q.replace("</head>",`${G}
8086
8096
  </head>`);else if(Q.includes("<body"))Q=Q.replace(/<body([^>]*)>/,`<body$1>
@@ -2444,7 +2444,7 @@ window.__stx_reactive = (function() {
2444
2444
 
2445
2445
  return { initScope: initScope, reactive: reactive };
2446
2446
  })();
2447
- `}function I8($,Z){let Y=$.replace(/\{!!([\s\S]*?)!!\}/g,(X,Q)=>{try{let J=E0(Q,Z,!0);if(J===void 0)return X;return String(J)}catch{return X}});return Y=Y.replace(/\{\{([\s\S]*?)\}\}/g,(X,Q)=>{try{let J=E0(Q,Z,!0);if(J===void 0)return X;return JSON.stringify(J)}catch{return X}}),Y}function aG($,Z){if($.length===0)return"";let Y=$.map((X)=>{let Q=JSON.stringify(Object.fromEntries(X.refs)),J=I8(X.stateExpr,Z),G=X.initExpr?I8(X.initExpr,Z):null,K=JSON.stringify(J),z=G?JSON.stringify(G):"null";return`
2447
+ `}function I8($,Z){let Y=$.replace(/\{!!([\s\S]*?)!!\}/g,(X,Q)=>{try{let J=E0(Q,Z,!0);if(J===void 0)return X;return String(J)}catch{return X}});return Y=Y.replace(/\{\{([\s\S]*?)\}\}/g,(X,Q)=>{try{let J=E0(Q,Z,!0);if(J===void 0)return X;if(typeof J==="string"){let G=J.trim();if(G.startsWith("{")&&G.endsWith("}")||G.startsWith("[")&&G.endsWith("]"))try{return JSON.parse(G),G}catch{}}return JSON.stringify(J)}catch{return X}}),Y}function aG($,Z){if($.length===0)return"";let Y=$.map((X)=>{let Q=JSON.stringify(Object.fromEntries(X.refs)),J=I8(X.stateExpr,Z),G=X.initExpr?I8(X.initExpr,Z):null,K=JSON.stringify(J),z=G?JSON.stringify(G):"null";return`
2448
2448
  (function() {
2449
2449
  var scopeEl = document.querySelector('${X.selector}');
2450
2450
  if (!scopeEl) return;
@@ -4495,6 +4495,13 @@ catch (e2) {
4495
4495
 
4496
4496
  // Known directive names to exclude from generic :attr binding
4497
4497
  var DIRECTIVE_NAMES = {class:1, style:1, text:1, html:1, show:1, model:1, 'if':1, 'for':1, ref:1};
4498
+ // SVG attributes are case-sensitive, but the HTML parser lowercases
4499
+ // prefixed attribute names \u2014 ':viewBox' arrives as ':viewbox' because
4500
+ // the spec's "adjust SVG attributes" step only covers unprefixed names.
4501
+ // Without restoring the canonical casing, setAttribute('viewbox') creates
4502
+ // a dead duplicate attribute and the real viewBox never updates.
4503
+ var SVG_ATTR_CASE = {attributename:'attributeName', attributetype:'attributeType', basefrequency:'baseFrequency', baseprofile:'baseProfile', calcmode:'calcMode', clippathunits:'clipPathUnits', diffuseconstant:'diffuseConstant', edgemode:'edgeMode', filterunits:'filterUnits', glyphref:'glyphRef', gradienttransform:'gradientTransform', gradientunits:'gradientUnits', kernelmatrix:'kernelMatrix', kernelunitlength:'kernelUnitLength', keypoints:'keyPoints', keysplines:'keySplines', keytimes:'keyTimes', lengthadjust:'lengthAdjust', limitingconeangle:'limitingConeAngle', markerheight:'markerHeight', markerunits:'markerUnits', markerwidth:'markerWidth', maskcontentunits:'maskContentUnits', maskunits:'maskUnits', numoctaves:'numOctaves', pathlength:'pathLength', patterncontentunits:'patternContentUnits', patterntransform:'patternTransform', patternunits:'patternUnits', pointsatx:'pointsAtX', pointsaty:'pointsAtY', pointsatz:'pointsAtZ', preservealpha:'preserveAlpha', preserveaspectratio:'preserveAspectRatio', primitiveunits:'primitiveUnits', refx:'refX', refy:'refY', repeatcount:'repeatCount', repeatdur:'repeatDur', requiredextensions:'requiredExtensions', requiredfeatures:'requiredFeatures', specularconstant:'specularConstant', specularexponent:'specularExponent', spreadmethod:'spreadMethod', startoffset:'startOffset', stddeviation:'stdDeviation', stitchtiles:'stitchTiles', surfacescale:'surfaceScale', systemlanguage:'systemLanguage', tablevalues:'tableValues', targetx:'targetX', targety:'targetY', textlength:'textLength', viewbox:'viewBox', viewtarget:'viewTarget', xchannelselector:'xChannelSelector', ychannelselector:'yChannelSelector', zoomandpan:'zoomAndPan'};
4504
+ var SVG_NS = 'http://www.w3.org/2000/svg';
4498
4505
  var EVENT_RE = /^(click|dblclick|mousedown|mouseup|mousemove|mouseenter|mouseleave|keydown|keyup|keypress|input|change|submit|focus|blur|scroll|resize|touchstart|touchend|touchmove|contextmenu|wheel|pointerdown|pointerup|pointermove)/;
4499
4506
  var KEY_MAP = {enter:'Enter', tab:'Tab', escape:'Escape', space:' ', up:'ArrowUp', down:'ArrowDown', left:'ArrowLeft', right:'ArrowRight', 'delete':'Delete', backspace:'Backspace'};
4500
4507
 
@@ -4519,7 +4526,8 @@ catch (e2) {
4519
4526
  if (name.startsWith('@bind:') || name.startsWith('x-bind:')
4520
4527
  || (name.startsWith(':') && !name.startsWith('::') && !DIRECTIVE_NAMES[name.slice(1).split('.')[0]] && !EVENT_RE.test(name.slice(1)))
4521
4528
  || (name.startsWith('x-') && !X_HANDLED[name.split('.')[0]] && !X_HANDLED[name])) {
4522
- const attrName = name.startsWith('@bind:') ? name.slice(6) : name.startsWith('x-bind:') ? name.slice(7) : name.startsWith('x-') ? name.slice(2) : name.slice(1);
4529
+ let attrName = name.startsWith('@bind:') ? name.slice(6) : name.startsWith('x-bind:') ? name.slice(7) : name.startsWith('x-') ? name.slice(2) : name.slice(1);
4530
+ if (el.namespaceURI === SVG_NS && SVG_ATTR_CASE[attrName]) attrName = SVG_ATTR_CASE[attrName];
4523
4531
  effect(() => {
4524
4532
  const v = evalAttrExpr(value);
4525
4533
  if (v === false || v === null || v === undefined) {
@@ -4898,10 +4906,12 @@ else {
4898
4906
  });
4899
4907
  }
4900
4908
  else if (Array.isArray(value)) {
4901
- el.className = originalClasses + ' ' + value.filter(Boolean).join(' ');
4909
+ var _clsArr = originalClasses + ' ' + value.filter(Boolean).join(' ');
4910
+ if (typeof el.className === 'string') el.className = _clsArr; else el.setAttribute('class', _clsArr);
4902
4911
  }
4903
4912
  else {
4904
- el.className = originalClasses + (value ? ' ' + value : '');
4913
+ var _clsStr = originalClasses + (value ? ' ' + value : '');
4914
+ if (typeof el.className === 'string') el.className = _clsStr; else el.setAttribute('class', _clsStr);
4905
4915
  }
4906
4916
  });
4907
4917
  }
@@ -7225,10 +7235,10 @@ else {
7225
7235
  var root = scriptEl ? scriptEl.nextElementSibling : null;
7226
7236
  if (!root && scriptEl) root = scriptEl.previousElementSibling || scriptEl.parentElement;
7227
7237
 
7228
- // SPA fallback: during router navigation, script is appended to <body>
7238
+ // SPA fallback: during router navigation, script is appended to body>
7229
7239
  // (not inside the content container), so nextElementSibling won't find the page content.
7230
7240
  // Only use fallback when we genuinely couldn't find a suitable root element.
7231
- // Do NOT fallback just because the script is in <body> \u2014 layout scripts in <body>
7241
+ // Do NOT fallback just because the script is in body> \u2014 layout scripts in body>
7232
7242
  // with valid siblings (e.g. sidebar <aside>) should use those siblings as root.
7233
7243
  var needsFallback = !root || root === document.body
7234
7244
  || (root && root.tagName === 'SCRIPT');
@@ -7547,7 +7557,7 @@ else {
7547
7557
  mountCallbacks.forEach(fn => fn());
7548
7558
  });
7549
7559
 
7550
- // Multi-root fragment fix: a no-<body> setup page tags only the FIRST
7560
+ // Multi-root fragment fix: a no-body> setup page tags only the FIRST
7551
7561
  // top-level element with data-stx (signal-processing.ts marks one element),
7552
7562
  // so sibling root elements were orphaned \u2014 their :if / :for / {{ }} / x-text
7553
7563
  // never hydrated, which read as "{{ }} doesn't work under :if/:for". The
@@ -7644,7 +7654,7 @@ else {
7644
7654
  el.querySelectorAll('[x-cloak]').forEach(function(c) { c.removeAttribute('x-cloak'); });
7645
7655
  });
7646
7656
 
7647
- // Process <head> elements (title, meta) that may contain {{ }} expressions
7657
+ // Process head> elements (title, meta) that may contain {{ }} expressions
7648
7658
  // Use componentScope which now contains variables from processed components
7649
7659
  const headElements = document.querySelectorAll('head title, head meta[content]');
7650
7660
  headElements.forEach(el => {
@@ -7840,7 +7850,7 @@ catch (e) { console.warn('[stx] destroy callback error:', e); }
7840
7850
 
7841
7851
  // Apply new page's SFC setup function. During SPA navigation, re-executed page
7842
7852
  // scripts set window.stx._latestSetup to the new setup function. This takes priority
7843
- // over the stale data-stx attribute on <body> (which has the PREVIOUS page's function name).
7853
+ // over the stale data-stx attribute on body> (which has the PREVIOUS page's function name).
7844
7854
  var usedLatestSetup = false;
7845
7855
  if (window.stx._latestSetup && typeof window.stx._latestSetup === 'function') {
7846
7856
  try {
@@ -7924,7 +7934,7 @@ catch (e) { console.warn('[stx] destroy callback error:', e); }
7924
7934
 
7925
7935
  // Process the container content \u2014 bind {{ }}, :attr, @event directives.
7926
7936
  // Run synchronously (not in setTimeout) so componentScope is captured correctly.
7927
- // The DOMContentLoaded path processes <body> synchronously \u2014 the SPA path must match.
7937
+ // The DOMContentLoaded path processes body> synchronously \u2014 the SPA path must match.
7928
7938
  console.log('[stx:load] container:', container.tagName, '__stx_scope:', !!container.__stx_scope, 'scope keys:', Object.keys(componentScope).slice(0, 10));
7929
7939
  if (!container.__stx_scope) {
7930
7940
  // Dispose previous effects on the container (from prior navigation)
@@ -8034,7 +8044,7 @@ ${B}${W}
8034
8044
  return { ${U} };
8035
8045
  }
8036
8046
  if(window.stx)window.stx._latestSetup=${G};
8037
- </script>`,j=$;for(let H of J)j=j.split(H.fullMatch).join("");if(j.includes("<body"))j=j.replace(/<body([^>]*)>/,`<body$1 data-stx="${G}">`);else{let H=["script","style","html","head","meta","link","title","!doctype"];j=j.replace(/<([a-zA-Z][a-zA-Z0-9-]*)\b([^>]*)>/i,(F,L,O)=>{if(H.includes(L.toLowerCase()))return F;return`<${L}${O} data-stx="${G}">`})}return{output:j,setupCode:_}}function P2($){let Z=$,Y=[],X=new Set,Q=0,J=0,G=Z.length,K="",z=()=>{J++;let j=!1;while(J<G){let H=Z[J];if(H==="\\"){J+=2;continue}if(H==="["&&!j){j=!0,J++;continue}if(H==="]"&&j){j=!1,J++;continue}if(H==="/"&&!j){J++;while(J<G&&/[gimsuyd]/.test(Z[J]))J++;return}if(H===`
8047
+ </script>`,j=$;for(let H of J)j=j.split(H.fullMatch).join("");if(j.includes("<body"))j=j.replace(/<body([^>]*)>/,`<body$1 data-stx="${G}">`);else{let H=["script","style","html","head","meta","link","title","!doctype"],F=!1;j=j.replace(/<([a-zA-Z][a-zA-Z0-9-]*)\b([^>]*)>/gi,(L,O,V)=>{if(F||H.includes(O.toLowerCase()))return L;return F=!0,`<${O}${V} data-stx="${G}">`})}return{output:j,setupCode:_}}function P2($){let Z=$,Y=[],X=new Set,Q=0,J=0,G=Z.length,K="",z=()=>{J++;let j=!1;while(J<G){let H=Z[J];if(H==="\\"){J+=2;continue}if(H==="["&&!j){j=!0,J++;continue}if(H==="]"&&j){j=!1,J++;continue}if(H==="/"&&!j){J++;while(J<G&&/[gimsuyd]/.test(Z[J]))J++;return}if(H===`
8038
8048
  `)return;J++}},q=()=>{if(!K)return!0;if(/[\w)\]]/.test(K))return!1;return!0},W=(j)=>{J++;while(J<G){if(Z[J]==="\\"){J+=2;continue}if(Z[J]===j){J++;return}J++}},U=()=>{J++;while(J<G){if(Z[J]==="\\"){J+=2;continue}if(Z[J]==="`"){J++;return}if(Z[J]==="$"&&Z[J+1]==="{"){J+=2;let j=1;while(J<G&&j>0)if(Z[J]==="{")j++,J++;else if(Z[J]==="}")j--,J++;else if(Z[J]==="'"||Z[J]==='"')W(Z[J]);else if(Z[J]==="`")U();else J++;continue}J++}},B=()=>{if(Z[J]==="/"&&Z[J+1]==="/"){while(J<G&&Z[J]!==`
8039
8049
  `)J++;return!0}if(Z[J]==="/"&&Z[J+1]==="*"){J+=2;while(J<G-1&&!(Z[J]==="*"&&Z[J+1]==="/"))J++;return J+=2,!0}return!1},_=()=>{if(Q!==0)return;let j=Z.slice(J).match(/^(const|let|var)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=/);if(j){let V=j[2];if(!X.has(V))Y.push(V),X.add(V);return}let H=Z.slice(J).match(/^(?:const|let|var)\s+\{([^}]+)\}\s*=/);if(H){H[1].split(",").forEach((V)=>{let w=V.trim();if(!w)return;let A=w.indexOf(":"),R=(A>=0?w.slice(A+1).trim():w).split(/[\s=]/)[0];if(R&&!X.has(R))Y.push(R),X.add(R)});return}let F=Z.slice(J).match(/^(?:const|let|var)\s+\[([^\]]+)\]\s*=/);if(F){F[1].split(",").forEach((V)=>{let w=V.trim().replace(/^\.\.\./,"");if(!w)return;let A=w.split(/[\s=]/)[0];if(A&&!X.has(A))Y.push(A),X.add(A)});return}let L=Z.slice(J).match(/^function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/);if(L){let V=L[1];if(!X.has(V))Y.push(V),X.add(V);return}let O=Z.slice(J).match(/^async\s+function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*\(/);if(O){let V=O[1];if(!X.has(V))Y.push(V),X.add(V)}};while(J<G){if(B())continue;if(Z[J]==="'"||Z[J]==='"'){W(Z[J]),K=Z[J-1];continue}if(Z[J]==="`"){U(),K="`";continue}if(Z[J]==="/"&&Z[J+1]!=="/"&&Z[J+1]!=="*"&&q()){z(),K="/";continue}if(Z[J]==="{"){Q++,K="{",J++;continue}if(Z[J]==="}"){Q--,K="}",J++;continue}if(Q===0&&/[a-z]/i.test(Z[J])&&(J===0||/\s|[;{}()]/.test(Z[J-1])))_();if(!/\s/.test(Z[J]))K=Z[J];J++}return Y.join(", ")}async function C3($,Z,Y,X){if(!K4($))return $;let Q=$;if(Z.skipSignalsRuntime)return Q;let{output:J,setupCode:G}=await C2(Q,Y,X);if(Q=J,Q=await M2(Q,Z),Q=T2(Q),G)if(Q.includes("</head>"))Q=Q.replace("</head>",`${G}
8040
8050
  </head>`);else if(Q.includes("<body"))Q=Q.replace(/<body([^>]*)>/,`<body$1>