sibujs 4.7.0 → 4.8.0

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 (81) hide show
  1. package/dist/browser.cjs +45 -4
  2. package/dist/browser.d.cts +23 -0
  3. package/dist/browser.d.ts +23 -0
  4. package/dist/browser.js +6 -5
  5. package/dist/build.cjs +513 -78
  6. package/dist/build.d.cts +22 -8
  7. package/dist/build.d.ts +22 -8
  8. package/dist/build.js +68 -21
  9. package/dist/cdn.dev.global.js +15 -13
  10. package/dist/cdn.full.dev.global.js +15 -13
  11. package/dist/cdn.full.global.js +14 -12
  12. package/dist/cdn.global.js +14 -12
  13. package/dist/chunk-3ACAAQIN.js +224 -0
  14. package/dist/{chunk-DKXRACVN.js → chunk-44MTL7ED.js} +6 -6
  15. package/dist/{chunk-3QWBSL5R.js → chunk-4WMSTZ7J.js} +8 -5
  16. package/dist/{chunk-H3SRKIYX.js → chunk-62BDYGAG.js} +8 -0
  17. package/dist/{chunk-BSY63EM6.js → chunk-C5PEWEGH.js} +20 -5
  18. package/dist/{chunk-BC2SECJD.js → chunk-C7AA2CZX.js} +1 -1
  19. package/dist/{chunk-SLM3IA34.js → chunk-CZPRSWSS.js} +1 -1
  20. package/dist/{chunk-FQRUXCEE.js → chunk-DSID757X.js} +1 -1
  21. package/dist/{chunk-ZVL7TY4K.js → chunk-EGUQLBHE.js} +22 -8
  22. package/dist/{chunk-2INLLLMZ.js → chunk-EXXSN3BW.js} +202 -26
  23. package/dist/{chunk-HURREPU2.js → chunk-FC6KCJSA.js} +87 -150
  24. package/dist/{chunk-Z3OHK6QT.js → chunk-GSGNX35Q.js} +5 -5
  25. package/dist/{chunk-XYV3EDB7.js → chunk-J3YQ457H.js} +37 -20
  26. package/dist/{chunk-VZSG24LS.js → chunk-JUTFX2RM.js} +18 -10
  27. package/dist/{chunk-RUSSKG6G.js → chunk-KJ3UKABJ.js} +1 -1
  28. package/dist/{chunk-UNWRJRKC.js → chunk-LI4W3U6C.js} +1 -1
  29. package/dist/{chunk-FNJXNGYZ.js → chunk-O6TRVMJI.js} +58 -6
  30. package/dist/{chunk-7LUJQAOJ.js → chunk-Q5J2LVKH.js} +1 -1
  31. package/dist/{chunk-4AWA2PVD.js → chunk-QGMSESDD.js} +10 -5
  32. package/dist/{chunk-XZR4PXRE.js → chunk-RGLPEBDE.js} +13 -10
  33. package/dist/{chunk-JWKYU5GV.js → chunk-TQQUN4WR.js} +1 -1
  34. package/dist/{chunk-WOLJZUFQ.js → chunk-UCNP3HVM.js} +12 -8
  35. package/dist/{chunk-WEQ3DMVL.js → chunk-V3LHZSU5.js} +1 -1
  36. package/dist/{chunk-UOL2ECCS.js → chunk-VWT3VXPL.js} +18 -12
  37. package/dist/{chunk-2BPG2XDA.js → chunk-ZVLHNEEL.js} +17 -35
  38. package/dist/{customElement-MmInOW1U.d.ts → customElement-pYDKUzWl.d.cts} +11 -3
  39. package/dist/{customElement-MmInOW1U.d.cts → customElement-pYDKUzWl.d.ts} +11 -3
  40. package/dist/data.cjs +9 -2
  41. package/dist/data.js +6 -6
  42. package/dist/devtools.cjs +1 -1
  43. package/dist/devtools.js +5 -5
  44. package/dist/ecosystem.cjs +400 -37
  45. package/dist/ecosystem.js +9 -8
  46. package/dist/extras.cjs +621 -252
  47. package/dist/extras.d.cts +2 -2
  48. package/dist/extras.d.ts +2 -2
  49. package/dist/extras.js +24 -23
  50. package/dist/index.cjs +464 -70
  51. package/dist/index.d.cts +28 -2
  52. package/dist/index.d.ts +28 -2
  53. package/dist/index.js +16 -12
  54. package/dist/motion.cjs +1 -1
  55. package/dist/motion.js +3 -3
  56. package/dist/patterns.cjs +10 -7
  57. package/dist/patterns.js +6 -6
  58. package/dist/performance.cjs +31 -2
  59. package/dist/performance.d.cts +12 -2
  60. package/dist/performance.d.ts +12 -2
  61. package/dist/performance.js +8 -6
  62. package/dist/plugins.cjs +558 -231
  63. package/dist/plugins.d.cts +8 -3
  64. package/dist/plugins.d.ts +8 -3
  65. package/dist/plugins.js +22 -28
  66. package/dist/{ssr-XOTUASDO.js → ssr-5OWAH3U2.js} +4 -2
  67. package/dist/{ssr-Bli9XRW5.d.ts → ssr-C8hgIAw7.d.cts} +6 -0
  68. package/dist/{ssr-Bli9XRW5.d.cts → ssr-C8hgIAw7.d.ts} +6 -0
  69. package/dist/ssr.cjs +457 -131
  70. package/dist/ssr.d.cts +55 -5
  71. package/dist/ssr.d.ts +55 -5
  72. package/dist/ssr.js +11 -9
  73. package/dist/testing.cjs +3 -3
  74. package/dist/testing.js +4 -4
  75. package/dist/ui.cjs +608 -240
  76. package/dist/ui.d.cts +1 -1
  77. package/dist/ui.d.ts +1 -1
  78. package/dist/ui.js +9 -8
  79. package/dist/widgets.cjs +1 -1
  80. package/dist/widgets.js +7 -7
  81. package/package.json +5 -4
package/dist/index.cjs CHANGED
@@ -28,8 +28,9 @@ __export(index_exports, {
28
28
  Loading: () => Loading,
29
29
  MAX_DRAIN_TEARDOWNS: () => MAX_DRAIN_TEARDOWNS,
30
30
  Portal: () => Portal,
31
- SVG_NS: () => SVG_NS2,
31
+ SVG_NS: () => SVG_NS3,
32
32
  Suspense: () => Suspense,
33
+ __renderParsedTemplate: () => __renderParsedTemplate,
33
34
  __resetIdCounter: () => __resetIdCounter,
34
35
  a: () => a,
35
36
  abbr: () => abbr,
@@ -533,6 +534,11 @@ function checkLeaks(warnThreshold = 0) {
533
534
  function stripControlChars(value) {
534
535
  return value.replace(/[\x00-\x20\x7f-\x9f]+/g, "");
535
536
  }
537
+ var ASCII_UPPER = /[A-Z]/;
538
+ var ASCII_UPPER_G = /[A-Z]/g;
539
+ function canonicalAttrName(name) {
540
+ return ASCII_UPPER.test(name) ? name.replace(ASCII_UPPER_G, (ch) => String.fromCharCode(ch.charCodeAt(0) + 32)) : name;
541
+ }
536
542
  function isEventHandlerAttr(name) {
537
543
  if (name.length < 3) return false;
538
544
  const lower = name.toLowerCase();
@@ -544,6 +550,9 @@ function sanitizeUrl(url) {
544
550
  const probe = stripControlChars(url).trim();
545
551
  if (!probe) return "";
546
552
  const output2 = url.replace(OUTER_TRIM, "");
553
+ if (probe.length >= 2 && (probe[0] === "\\" || probe[0] === "/") && (probe[1] === "\\" || probe[1] === "/") && (probe[0] === "\\" || probe[1] === "\\")) {
554
+ return "";
555
+ }
547
556
  const lower = probe.toLowerCase();
548
557
  let schemeEnd = -1;
549
558
  for (let i2 = 0; i2 < lower.length; i2++) {
@@ -560,19 +569,58 @@ function sanitizeUrl(url) {
560
569
  if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
561
570
  return output2;
562
571
  }
563
- var SRCSET_DESCRIPTOR = /^\s+\d+(\.\d+)?[wx]$/;
572
+ var SRCSET_DESCRIPTOR = /^\d+(\.\d+)?[wx]$/;
573
+ function isSrcsetWhitespace(ch) {
574
+ return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
575
+ }
564
576
  function sanitizeSrcset(value) {
565
- const parts = value.split(",");
577
+ const input2 = String(value);
566
578
  const out = [];
567
- for (let i2 = 0; i2 < parts.length; i2++) {
568
- const part = parts[i2].trim();
569
- if (!part) continue;
570
- const m = part.match(/^(\S+)(\s+.+)?$/);
571
- if (!m) continue;
572
- if (m[2] !== void 0 && !SRCSET_DESCRIPTOR.test(m[2])) continue;
573
- const safe = sanitizeUrl(m[1]);
579
+ let i2 = 0;
580
+ const n = input2.length;
581
+ while (i2 < n) {
582
+ while (i2 < n && (isSrcsetWhitespace(input2[i2]) || input2[i2] === ",")) i2++;
583
+ if (i2 >= n) break;
584
+ const urlStart = i2;
585
+ while (i2 < n && !isSrcsetWhitespace(input2[i2])) i2++;
586
+ let url = input2.slice(urlStart, i2);
587
+ const descriptors = [];
588
+ if (url.endsWith(",")) {
589
+ url = url.replace(/,+$/, "");
590
+ } else {
591
+ let current = "";
592
+ let inParens = false;
593
+ while (i2 < n) {
594
+ const ch = input2[i2];
595
+ if (inParens) {
596
+ current += ch;
597
+ if (ch === ")") inParens = false;
598
+ i2++;
599
+ continue;
600
+ }
601
+ if (isSrcsetWhitespace(ch)) {
602
+ if (current) descriptors.push(current);
603
+ current = "";
604
+ i2++;
605
+ continue;
606
+ }
607
+ if (ch === ",") {
608
+ i2++;
609
+ break;
610
+ }
611
+ if (ch === "(") inParens = true;
612
+ current += ch;
613
+ i2++;
614
+ }
615
+ if (current) descriptors.push(current);
616
+ }
617
+ if (url === "") continue;
618
+ if (descriptors.length > 1) continue;
619
+ if (descriptors.length === 1 && !SRCSET_DESCRIPTOR.test(descriptors[0])) continue;
620
+ const safe = sanitizeUrl(url);
574
621
  if (!safe) continue;
575
- out.push(m[2] ? `${safe}${m[2]}` : safe);
622
+ if (safe.startsWith(",") || safe.endsWith(",")) continue;
623
+ out.push(descriptors.length === 1 ? `${safe} ${descriptors[0]}` : safe);
576
624
  }
577
625
  return out.join(", ");
578
626
  }
@@ -631,8 +679,16 @@ var BLOCKED_CSS_NEEDLES = [
631
679
  "behavior:",
632
680
  "@import",
633
681
  "image-set(",
634
- "filter:progid"
682
+ "filter:progid",
683
+ // CSS Images 4 `image("…")` and CSS Values 5 `src("…")` take a URL as a
684
+ // plain STRING, so they fetch without ever spelling `url(`. Support is thin
685
+ // today, which is exactly when a blocklist should get ahead of it.
686
+ "image(",
687
+ "src("
635
688
  ];
689
+ var CSS_REASON_MOZ_BINDING = 4;
690
+ var CSS_REASON_BEHAVIOR = 5;
691
+ var CSS_REASON_PROGID = 8;
636
692
  function describeElement(el) {
637
693
  if (!el) return "an element";
638
694
  let out = el.tagName.toLowerCase();
@@ -656,7 +712,9 @@ function warnDroppedDeclaration(value, reason, ctx) {
656
712
  "behavior: loads and runs a remote HTC script",
657
713
  "@import pulls in a remote stylesheet",
658
714
  "image-set() fetches remote images, the same exfiltration channel as url()",
659
- "filter:progid activates legacy scriptable filters"
715
+ "filter:progid activates legacy scriptable filters",
716
+ "image() fetches its string argument as a URL, the same exfiltration channel as url()",
717
+ "src() fetches its string argument as a URL, the same exfiltration channel as url()"
660
718
  ];
661
719
  const declaration = ctx?.property ? `${ctx.property}: ${value}` : value;
662
720
  const where = describeElement(ctx?.element);
@@ -671,27 +729,110 @@ function warnDroppedDeclaration(value, reason, ctx) {
671
729
  return `style declaration "${declaration}" was dropped by the style sanitizer on ${where} \u2014 ${reasons[reason]}. The element renders without it, which usually looks like a missing image rather than an error. Sanctioned alternatives: for a content image use an <img> element (or a <picture>); for decoration, put the rule in a stylesheet and set a class instead \u2014 stylesheet CSS is not sanitized, only inline style attributes are. If this declaration is not yours, it came from untrusted data and the drop just prevented an exfiltration.`;
672
730
  });
673
731
  }
732
+ function normalizeCssForScan(value) {
733
+ const normalized = value.includes("\\") ? decodeCssEscapes(value) : value;
734
+ return normalized.toLowerCase().replace(/\s+/g, "");
735
+ }
674
736
  function blockedCssReason(value) {
675
737
  if (!CSS_DANGER_GATE.test(value)) return -1;
676
- const normalized = value.includes("\\") ? decodeCssEscapes(value) : value;
677
- const lower = normalized.toLowerCase().replace(/\s+/g, "");
738
+ const lower = normalizeCssForScan(value);
678
739
  for (let i2 = 0; i2 < BLOCKED_CSS_NEEDLES.length; i2++) {
679
740
  if (lower.includes(BLOCKED_CSS_NEEDLES[i2])) return i2;
680
741
  }
681
742
  return -1;
682
743
  }
683
- function sanitizeCSSValue(value, context2) {
684
- const reason = blockedCssReason(value);
744
+ function sanitizeCSSDeclaration(property, value, context2) {
745
+ const reason = blockedDeclarationReason(property, value);
685
746
  if (reason === -1) return value;
686
- warnDroppedDeclaration(value, reason, context2);
747
+ warnDroppedDeclaration(value, reason, { property, element: context2?.element });
687
748
  return "";
688
749
  }
750
+ function blockedDeclarationReason(property, value) {
751
+ const reason = blockedCssReason(value);
752
+ if (reason !== -1) return reason;
753
+ const name = canonicalAttrName(property);
754
+ if (name === "behavior") return CSS_REASON_BEHAVIOR;
755
+ if (name === "-moz-binding") return CSS_REASON_MOZ_BINDING;
756
+ if ((name === "filter" || name === "-ms-filter") && normalizeCssForScan(value).includes("progid:")) {
757
+ return CSS_REASON_PROGID;
758
+ }
759
+ return -1;
760
+ }
761
+ function parseStyleDeclarations(css) {
762
+ const chunks = [];
763
+ let buf = "";
764
+ let depth = 0;
765
+ let quote2 = "";
766
+ for (let i2 = 0; i2 < css.length; i2++) {
767
+ const ch = css[i2];
768
+ if (quote2) {
769
+ buf += ch;
770
+ if (ch === "\\" && i2 + 1 < css.length) buf += css[++i2];
771
+ else if (ch === quote2) quote2 = "";
772
+ continue;
773
+ }
774
+ if (ch === "\\") {
775
+ buf += ch;
776
+ if (i2 + 1 < css.length) buf += css[++i2];
777
+ continue;
778
+ }
779
+ if (ch === "/" && css[i2 + 1] === "*") {
780
+ const end = css.indexOf("*/", i2 + 2);
781
+ if (end === -1) return null;
782
+ i2 = end + 1;
783
+ continue;
784
+ }
785
+ if (ch === '"' || ch === "'") quote2 = ch;
786
+ else if (ch === "(" || ch === "[") depth++;
787
+ else if (ch === ")" || ch === "]") {
788
+ if (--depth < 0) return null;
789
+ } else if (ch === "{" || ch === "}") return null;
790
+ else if (ch === ";" && depth === 0) {
791
+ chunks.push(buf);
792
+ buf = "";
793
+ continue;
794
+ }
795
+ buf += ch;
796
+ }
797
+ if (quote2 || depth !== 0) return null;
798
+ chunks.push(buf);
799
+ const out = [];
800
+ for (const chunk of chunks) {
801
+ const colon = chunk.indexOf(":");
802
+ if (colon === -1) continue;
803
+ const rawName = chunk.slice(0, colon).trim();
804
+ if (!/^(--[\w-]+|-?[a-zA-Z_][\w-]*)$/.test(rawName)) continue;
805
+ let value = chunk.slice(colon + 1).trim();
806
+ const bang = /!\s*important\s*$/i.exec(value);
807
+ if (bang) value = value.slice(0, bang.index).trim();
808
+ if (value === "") continue;
809
+ const property = rawName.startsWith("--") ? rawName : canonicalAttrName(rawName);
810
+ out.push([property, value, bang !== null]);
811
+ }
812
+ return out;
813
+ }
814
+ function sanitizeStyleDeclarationList(cssText, context2) {
815
+ const input2 = String(cssText);
816
+ const declarations = parseStyleDeclarations(input2);
817
+ if (declarations === null) {
818
+ if (blockedCssReason(input2) !== -1) warnDroppedDeclaration(input2, blockedCssReason(input2), context2);
819
+ return "";
820
+ }
821
+ const kept = [];
822
+ for (const [property, value, important] of declarations) {
823
+ const reason = blockedDeclarationReason(property, value);
824
+ if (reason !== -1) {
825
+ warnDroppedDeclaration(value, reason, { property, element: context2?.element });
826
+ continue;
827
+ }
828
+ kept.push(`${property}: ${value}${important ? " !important" : ""}`);
829
+ }
830
+ return kept.join("; ");
831
+ }
689
832
  function sanitizeStyleAttribute(cssText, context2) {
690
833
  const input2 = String(cssText);
691
834
  if (input2.trim() === "") return "";
692
- if (typeof document === "undefined") {
693
- return sanitizeCSSValue(input2, context2) === "" ? "" : input2;
694
- }
835
+ if (typeof document === "undefined") return sanitizeStyleDeclarationList(input2, context2);
695
836
  const probe = document.createElement("div");
696
837
  try {
697
838
  probe.style.cssText = input2;
@@ -702,8 +843,7 @@ function sanitizeStyleAttribute(cssText, context2) {
702
843
  for (let i2 = 0; i2 < probe.style.length; i2++) {
703
844
  const property = probe.style[i2];
704
845
  const value = probe.style.getPropertyValue(property);
705
- let reason = blockedCssReason(value);
706
- if (reason === -1) reason = blockedCssReason(`${property}:${value}`);
846
+ const reason = blockedDeclarationReason(property, value);
707
847
  if (reason !== -1) {
708
848
  warnDroppedDeclaration(value, reason, { property, element: context2?.element });
709
849
  continue;
@@ -735,6 +875,13 @@ var HTML_CONTENT_ATTRIBUTES = /* @__PURE__ */ new Set(["srcdoc"]);
735
875
  function isHtmlContentAttribute(name) {
736
876
  return HTML_CONTENT_ATTRIBUTES.has(name.toLowerCase());
737
877
  }
878
+ function isUrlAttribute(attr) {
879
+ return URL_ATTRIBUTES.has(attr.toLowerCase());
880
+ }
881
+ function isPolicyAttribute(name) {
882
+ const lower = name.toLowerCase();
883
+ return lower === "style" || URL_ATTRIBUTES.has(lower);
884
+ }
738
885
  function sanitizeAttributeString(attr, value, context2) {
739
886
  const lower = attr.toLowerCase();
740
887
  if (lower === "srcset") return sanitizeSrcset(value);
@@ -742,27 +889,233 @@ function sanitizeAttributeString(attr, value, context2) {
742
889
  if (lower === "style") return sanitizeStyleAttribute(value, context2);
743
890
  return value;
744
891
  }
892
+ function resolveAttributeValue(attr, value, context2) {
893
+ if (!isPolicyAttribute(attr)) return value;
894
+ const safe = sanitizeAttributeString(attr, value, context2);
895
+ return safe === "" ? null : safe;
896
+ }
745
897
 
746
- // src/utils/setSafeAttribute.ts
898
+ // src/utils/metaRefresh.ts
899
+ function isAsciiWhitespace(ch) {
900
+ return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f";
901
+ }
902
+ function trimAsciiWhitespace(value) {
903
+ let start = 0;
904
+ let end = value.length;
905
+ while (start < end && isAsciiWhitespace(value[start])) start++;
906
+ while (end > start && isAsciiWhitespace(value[end - 1])) end--;
907
+ return value.slice(start, end);
908
+ }
909
+ var forbidden = (reason) => ({ kind: "forbidden", reason });
910
+ function parseMetaRefreshContent(content) {
911
+ const raw = trimAsciiWhitespace(stripControlChars(content));
912
+ if (raw === "") return forbidden(DEV ? "empty content" : "");
913
+ let i2 = 0;
914
+ while (i2 < raw.length && raw[i2] >= "0" && raw[i2] <= "9") i2++;
915
+ if (i2 === 0) return forbidden(DEV ? "missing or non-numeric delay" : "");
916
+ const delay = Number.parseInt(raw.slice(0, i2), 10);
917
+ if (!Number.isFinite(delay)) return forbidden(DEV ? "unparseable delay" : "");
918
+ while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
919
+ if (i2 === raw.length) return { kind: "delay-only", delay };
920
+ if (raw[i2] !== ";" && raw[i2] !== ",") return forbidden(DEV ? "unexpected text after delay" : "");
921
+ i2++;
922
+ while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
923
+ const keyStart = i2;
924
+ while (i2 < raw.length && !isAsciiWhitespace(raw[i2]) && raw[i2] !== "=") i2++;
925
+ const key = raw.slice(keyStart, i2).toLowerCase();
926
+ if (key !== "url") return forbidden(DEV ? `unsupported refresh key ${JSON.stringify(key)}` : "");
927
+ while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
928
+ if (raw[i2] !== "=") return forbidden(DEV ? "missing '=' after url" : "");
929
+ i2++;
930
+ while (i2 < raw.length && isAsciiWhitespace(raw[i2])) i2++;
931
+ let destination;
932
+ const quote2 = raw[i2];
933
+ if (quote2 === '"' || quote2 === "'") {
934
+ const close = raw.indexOf(quote2, i2 + 1);
935
+ if (close === -1) return forbidden(DEV ? "unterminated quoted destination" : "");
936
+ destination = raw.slice(i2 + 1, close);
937
+ const rest = trimAsciiWhitespace(raw.slice(close + 1));
938
+ if (rest !== "") return forbidden(DEV ? "trailing text after quoted destination" : "");
939
+ } else {
940
+ destination = trimAsciiWhitespace(raw.slice(i2));
941
+ if (/[;,]/.test(destination)) return forbidden(DEV ? "multiple refresh assignments" : "");
942
+ }
943
+ if (destination === "") return forbidden(DEV ? "empty destination" : "");
944
+ const sanitizedDestination = sanitizeUrl(destination);
945
+ if (sanitizedDestination === "") return forbidden(DEV ? "destination uses a disallowed protocol" : "");
946
+ return { kind: "allowed", delay, destination, sanitizedDestination };
947
+ }
948
+ function resolveMetaRefreshPolicy(attributes) {
949
+ let httpEquiv;
950
+ let content;
951
+ let duplicateName;
952
+ const seen = /* @__PURE__ */ new Set();
953
+ for (const [key, value] of attributes) {
954
+ const canonical = canonicalAttrName(key);
955
+ if (seen.has(canonical)) duplicateName = canonical;
956
+ seen.add(canonical);
957
+ if (canonical === "http-equiv") httpEquiv = value;
958
+ else if (canonical === "content") content = value;
959
+ }
960
+ if (duplicateName !== void 0) {
961
+ return forbidden(DEV ? `duplicate case-insensitive attribute ${JSON.stringify(duplicateName)}` : "");
962
+ }
963
+ if (typeof httpEquiv !== "string") return { kind: "not-refresh" };
964
+ if (trimAsciiWhitespace(stripControlChars(httpEquiv)).toLowerCase() !== "refresh") {
965
+ return { kind: "not-refresh" };
966
+ }
967
+ if (typeof content !== "string") return { kind: "not-refresh" };
968
+ return parseMetaRefreshContent(content);
969
+ }
970
+
971
+ // src/utils/elementPolicy.ts
747
972
  var HTML_NS = "http://www.w3.org/1999/xhtml";
748
973
  var SVG_NS = "http://www.w3.org/2000/svg";
974
+ var BLOCKED_ELEMENTS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
975
+ function canonicalTagName(tag) {
976
+ return canonicalAttrName(tag);
977
+ }
978
+ function isBlockedElement(tag) {
979
+ return BLOCKED_ELEMENTS.has(canonicalTagName(tag));
980
+ }
981
+ var CODE_TEXT_ELEMENTS = /* @__PURE__ */ new Set(["script", "style"]);
982
+ function isCodeTextElement(tag) {
983
+ return CODE_TEXT_ELEMENTS.has(canonicalTagName(tag));
984
+ }
985
+ var ContextualRefusal = {
986
+ None: 0,
987
+ /** The element would carry a refresh directive the shared policy forbids. */
988
+ MetaRefreshForbidden: 1,
989
+ /** A `<meta>` with a reactive binding may not carry any refresh directive. */
990
+ MetaRefreshReactive: 2,
991
+ /** A runtime value may not choose which program a `<script>` runs. */
992
+ ScriptSource: 3,
993
+ /** An SVG animation may not target a URL, handler or document attribute. */
994
+ AnimationTarget: 4,
995
+ /** A runtime-written `href` may not become an applied stylesheet. */
996
+ StylesheetSource: 5
997
+ };
998
+ var SCRIPT_SOURCE_ATTRIBUTES = /* @__PURE__ */ new Set(["src", "href", "xlink:href", "type", "language"]);
999
+ var SVG_ANIMATION_ELEMENTS = /* @__PURE__ */ new Set(["animate", "set", "animateMotion", "animateTransform", "animateColor"]);
1000
+ var reactiveMetaElements = /* @__PURE__ */ new WeakSet();
1001
+ function isHtmlNamespace(el) {
1002
+ return el.namespaceURI === HTML_NS || el.namespaceURI === null;
1003
+ }
1004
+ function metaSnapshot(el, canonical, value) {
1005
+ const snapshot = /* @__PURE__ */ new Map();
1006
+ const attrs = el.attributes;
1007
+ for (let i2 = 0; i2 < attrs.length; i2++) {
1008
+ const attr = attrs[i2];
1009
+ if (attr.name === canonical) continue;
1010
+ snapshot.set(attr.name, attr.value);
1011
+ }
1012
+ if (canonical !== null && value !== null) snapshot.set(canonical, value);
1013
+ return snapshot;
1014
+ }
1015
+ function claimReactiveMeta(el) {
1016
+ if (reactiveMetaElements.has(el)) return;
1017
+ reactiveMetaElements.add(el);
1018
+ if (el.getAttribute("content") === null) return;
1019
+ if (resolveMetaRefreshPolicy(metaSnapshot(el, null, null)).kind !== "not-refresh") {
1020
+ el.removeAttribute("content");
1021
+ }
1022
+ }
1023
+ function metaRefusal(el, name, value, origin) {
1024
+ if (!isHtmlNamespace(el)) return ContextualRefusal.None;
1025
+ const canonical = canonicalAttrName(name);
1026
+ if (canonical !== "http-equiv" && canonical !== "content") return ContextualRefusal.None;
1027
+ if (origin === "reactive") claimReactiveMeta(el);
1028
+ if (value === null) return ContextualRefusal.None;
1029
+ if (canonical === "content" && !el.hasAttribute("http-equiv")) return ContextualRefusal.None;
1030
+ const decision = resolveMetaRefreshPolicy(metaSnapshot(el, canonical, value));
1031
+ if (decision.kind === "forbidden") return ContextualRefusal.MetaRefreshForbidden;
1032
+ if (decision.kind !== "not-refresh" && reactiveMetaElements.has(el)) return ContextualRefusal.MetaRefreshReactive;
1033
+ return ContextualRefusal.None;
1034
+ }
1035
+ function animationRefusal(name, value) {
1036
+ if (value === null || canonicalAttrName(name) !== "attributename") return ContextualRefusal.None;
1037
+ const target = stripControlChars(value);
1038
+ return isUrlAttribute(target) || isEventHandlerAttr(target) || isHtmlContentAttribute(target) ? ContextualRefusal.AnimationTarget : ContextualRefusal.None;
1039
+ }
1040
+ var runtimeHrefLinks = /* @__PURE__ */ new WeakSet();
1041
+ function relHasStylesheet(rel) {
1042
+ if (rel === null) return false;
1043
+ const lower = canonicalAttrName(rel);
1044
+ if (!lower.includes("stylesheet")) return false;
1045
+ const tokens = lower.split(/[\t\n\f\r ]+/);
1046
+ for (let i2 = 0; i2 < tokens.length; i2++) if (tokens[i2] === "stylesheet") return true;
1047
+ return false;
1048
+ }
1049
+ function stylesheetRefusal(el, name, value, origin) {
1050
+ if (!isHtmlNamespace(el)) return ContextualRefusal.None;
1051
+ const canonical = canonicalAttrName(name);
1052
+ if (canonical === "href") {
1053
+ if (origin === "static" || value === null) return ContextualRefusal.None;
1054
+ if (relHasStylesheet(el.getAttribute("rel"))) return ContextualRefusal.StylesheetSource;
1055
+ runtimeHrefLinks.add(el);
1056
+ return ContextualRefusal.None;
1057
+ }
1058
+ if (canonical === "rel") {
1059
+ if (!relHasStylesheet(value)) return ContextualRefusal.None;
1060
+ return runtimeHrefLinks.has(el) && el.hasAttribute("href") ? ContextualRefusal.StylesheetSource : ContextualRefusal.None;
1061
+ }
1062
+ return ContextualRefusal.None;
1063
+ }
1064
+ function contextualAttributeRefusal(el, name, value, origin) {
1065
+ const local = el.localName;
1066
+ if (local === "meta") return metaRefusal(el, name, value, origin);
1067
+ if (local === "link") return stylesheetRefusal(el, name, value, origin);
1068
+ if (local === "script") {
1069
+ if (origin === "static" || value === null) return ContextualRefusal.None;
1070
+ return SCRIPT_SOURCE_ATTRIBUTES.has(canonicalAttrName(name)) ? ContextualRefusal.ScriptSource : ContextualRefusal.None;
1071
+ }
1072
+ if (SVG_ANIMATION_ELEMENTS.has(local) && el.namespaceURI === SVG_NS) return animationRefusal(name, value);
1073
+ return ContextualRefusal.None;
1074
+ }
1075
+ function settleAttributeProvenance(el, name, origin) {
1076
+ if (el.localName !== "link" || canonicalAttrName(name) !== "href") return;
1077
+ if (origin !== "static" && el.hasAttribute("href")) runtimeHrefLinks.add(el);
1078
+ else runtimeHrefLinks.delete(el);
1079
+ }
1080
+
1081
+ // src/utils/setSafeAttribute.ts
1082
+ var HTML_NS2 = "http://www.w3.org/1999/xhtml";
1083
+ var SVG_NS2 = "http://www.w3.org/2000/svg";
749
1084
  var XLINK_NS = "http://www.w3.org/1999/xlink";
750
1085
  var XML_NS = "http://www.w3.org/XML/1998/namespace";
751
1086
  var BOOLEAN_IDL_ATTRS = /* @__PURE__ */ new Set(["checked", "disabled", "selected"]);
752
1087
  function isHtmlElement(el) {
753
- return el.namespaceURI === null || el.namespaceURI === HTML_NS;
1088
+ return el.namespaceURI === null || el.namespaceURI === HTML_NS2;
1089
+ }
1090
+ function warnContextualRefusal(label2, name, refusal) {
1091
+ devWarnLazy(() => {
1092
+ const reasons = [
1093
+ "",
1094
+ 'the element would become a <meta http-equiv="refresh"> directive the shared refresh policy forbids (a destination outside the URL allowlist, or a directive too malformed to read unambiguously)',
1095
+ "a <meta> whose http-equiv or content is reactive may never carry a refresh directive: a browser schedules the navigation as soon as the directive is valid, and nothing can withdraw it when the state changes back",
1096
+ "a runtime value may not choose the program a <script> runs; name the script in static template source, or load it through Head({ script }) as an explicit trust decision",
1097
+ "an SVG animation may not target a URL, event-handler or nested-document attribute; its to / values would be written into that attribute without passing the URL policy",
1098
+ 'a runtime-chosen href may not become an applied <link rel="stylesheet">: a well-formed URL is not a trusted stylesheet. Name the stylesheet in static template source, or load a runtime-chosen one through Head({ link }) as an explicit trust decision'
1099
+ ];
1100
+ return `${label2}: refusing "${name}" in this element's context \u2014 ${reasons[refusal]}. The write was not performed.`;
1101
+ });
754
1102
  }
755
1103
  function setProp(el, key, val) {
756
1104
  el[key] = val;
757
1105
  }
758
1106
  function namespaceFor(el, name) {
759
- if (el.namespaceURI !== SVG_NS) return null;
1107
+ if (el.namespaceURI !== SVG_NS2) return null;
760
1108
  const lower = name.toLowerCase();
761
1109
  if (lower.startsWith("xlink:")) return XLINK_NS;
762
1110
  if (lower.startsWith("xml:")) return XML_NS;
763
1111
  return null;
764
1112
  }
765
1113
  function setSafeAttribute(el, name, value, options = {}) {
1114
+ const written = commitSafeAttribute(el, name, value, options);
1115
+ if (el.localName === "link") settleAttributeProvenance(el, name, options.reactive ? "reactive" : "runtime");
1116
+ return written;
1117
+ }
1118
+ function commitSafeAttribute(el, name, value, options) {
766
1119
  const ns = namespaceFor(el, name);
767
1120
  const localName = ns ? name.slice(name.indexOf(":") + 1) : name;
768
1121
  if (isEventHandlerAttr(name)) {
@@ -775,6 +1128,14 @@ function setSafeAttribute(el, name, value, options = {}) {
775
1128
  else el.removeAttribute(name);
776
1129
  return false;
777
1130
  }
1131
+ const pending = value == null || value === false ? null : value === true ? "" : String(value);
1132
+ const refusal = contextualAttributeRefusal(el, name, pending, options.reactive ? "reactive" : "runtime");
1133
+ if (refusal !== ContextualRefusal.None) {
1134
+ warnContextualRefusal(options.label ?? "setSafeAttribute", name, refusal);
1135
+ if (ns) el.removeAttributeNS(ns, localName);
1136
+ else el.removeAttribute(name);
1137
+ return false;
1138
+ }
778
1139
  if (value == null) {
779
1140
  if (ns) el.removeAttributeNS(ns, localName);
780
1141
  else el.removeAttribute(name);
@@ -818,13 +1179,32 @@ function setSafeAttribute(el, name, value, options = {}) {
818
1179
  setProp(el, idlName, idlName === "checked" ? Boolean(value) : str);
819
1180
  return true;
820
1181
  }
821
- const safe = sanitizeAttributeString(name, str, { element: el });
1182
+ const safe = str === "" ? "" : resolveAttributeValue(name, str, { element: el });
1183
+ if (safe === null) {
1184
+ if (ns) el.removeAttributeNS(ns, localName);
1185
+ else el.removeAttribute(name);
1186
+ return true;
1187
+ }
822
1188
  const current = ns ? el.getAttributeNS(ns, localName) : el.getAttribute(name);
823
1189
  if (current === safe) return true;
824
1190
  if (ns) el.setAttributeNS(ns, name, safe);
825
1191
  else el.setAttribute(name, safe);
826
1192
  return true;
827
1193
  }
1194
+ function setTrustedAttribute(el, name, value) {
1195
+ if (isHtmlContentAttribute(name)) {
1196
+ if (DEV) devWarn(`html: refusing static attribute "${name}" \u2014 the browser parses it as a nested document.`);
1197
+ return false;
1198
+ }
1199
+ const refusal = contextualAttributeRefusal(el, name, value, "static");
1200
+ if (refusal !== ContextualRefusal.None) {
1201
+ warnContextualRefusal("html (static attribute)", name, refusal);
1202
+ return false;
1203
+ }
1204
+ el.setAttribute(name, value);
1205
+ if (el.localName === "link") settleAttributeProvenance(el, name, "static");
1206
+ return true;
1207
+ }
828
1208
 
829
1209
  // src/reactivity/track-core.ts
830
1210
  var POOL_MAX = 4096;
@@ -1317,7 +1697,7 @@ function forEachSubscriber(signal2, visit) {
1317
1697
  }
1318
1698
 
1319
1699
  // src/reactivity/track.ts
1320
- var _runtimeVersion = true ? "4.7.0" : "dev";
1700
+ var _runtimeVersion = true ? "4.8.0" : "dev";
1321
1701
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
1322
1702
  function resolveReactiveApi() {
1323
1703
  const g2 = globalThis;
@@ -1388,7 +1768,7 @@ function bindAttribute(el, attr, getter) {
1388
1768
  reportError(err, { phase: "binding", name: `bindAttribute("${attr}")`, node: el });
1389
1769
  return;
1390
1770
  }
1391
- setSafeAttribute(el, attr, value, { label: `bindAttribute("${attr}")` });
1771
+ setSafeAttribute(el, attr, value, { label: `bindAttribute("${attr}")`, reactive: true });
1392
1772
  }
1393
1773
  return reactiveBinding2(commit, el);
1394
1774
  }
@@ -1413,7 +1793,7 @@ function bindDynamic(el, nameGetter, valueGetter) {
1413
1793
  el.removeAttribute(prevName);
1414
1794
  prevName = null;
1415
1795
  }
1416
- if (!setSafeAttribute(el, name, value, { label: "bindDynamic" })) return;
1796
+ if (!setSafeAttribute(el, name, value, { label: "bindDynamic", reactive: true })) return;
1417
1797
  prevName = name;
1418
1798
  }
1419
1799
  const teardown = reactiveBinding2(commit, el);
@@ -1594,11 +1974,7 @@ function bindChildNode(placeholder, getter) {
1594
1974
  }
1595
1975
 
1596
1976
  // src/core/rendering/tagFactory.ts
1597
- var SVG_NS2 = "http://www.w3.org/2000/svg";
1598
- var BLOCKED_TAGS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
1599
- function isBlockedTag(tag) {
1600
- return BLOCKED_TAGS.has(tag.toLowerCase());
1601
- }
1977
+ var SVG_NS3 = "http://www.w3.org/2000/svg";
1602
1978
  var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
1603
1979
  "config",
1604
1980
  "location",
@@ -1643,11 +2019,12 @@ function applyStyle(el, style2) {
1643
2019
  }
1644
2020
  const next = [];
1645
2021
  for (const prop in value) {
2022
+ if (!Object.hasOwn(value, prop)) continue;
1646
2023
  const val = value[prop];
1647
2024
  if (val == null) continue;
1648
2025
  const name = toKebab(prop);
1649
2026
  next.push(name);
1650
- decl.setProperty(name, sanitizeCSSValue(String(val), { property: name, element: el }));
2027
+ decl.setProperty(name, sanitizeCSSDeclaration(name, String(val), { element: el }));
1651
2028
  }
1652
2029
  for (let i2 = 0; i2 < written.length; i2++) {
1653
2030
  if (next.indexOf(written[i2]) === -1) decl.removeProperty(written[i2]);
@@ -1663,16 +2040,17 @@ function applyStyle(el, style2) {
1663
2040
  }
1664
2041
  const htmlEl = el;
1665
2042
  for (const prop in style2) {
2043
+ if (!Object.hasOwn(style2, prop)) continue;
1666
2044
  const val = style2[prop];
1667
2045
  const name = toKebab(prop);
1668
2046
  if (typeof val === "function") {
1669
2047
  const getter = val;
1670
2048
  const teardown = reactiveBinding2(() => {
1671
- htmlEl.style.setProperty(name, sanitizeCSSValue(String(getter()), { property: name, element: el }));
2049
+ htmlEl.style.setProperty(name, sanitizeCSSDeclaration(name, String(getter()), { element: el }));
1672
2050
  }, el);
1673
2051
  registerDisposer(el, teardown);
1674
2052
  } else {
1675
- htmlEl.style.setProperty(name, sanitizeCSSValue(String(val), { property: name, element: el }));
2053
+ htmlEl.style.setProperty(name, sanitizeCSSDeclaration(name, String(val), { element: el }));
1676
2054
  }
1677
2055
  }
1678
2056
  }
@@ -1694,6 +2072,7 @@ function applyClass(el, cls) {
1694
2072
  let hasReactive = false;
1695
2073
  let result = "";
1696
2074
  for (const name in obj) {
2075
+ if (!Object.hasOwn(obj, name)) continue;
1697
2076
  const val = obj[name];
1698
2077
  if (typeof val === "function") {
1699
2078
  hasReactive = true;
@@ -1705,6 +2084,7 @@ function applyClass(el, cls) {
1705
2084
  const update = () => {
1706
2085
  let r = "";
1707
2086
  for (const name in obj) {
2087
+ if (!Object.hasOwn(obj, name)) continue;
1708
2088
  const val = obj[name];
1709
2089
  const active = typeof val === "function" ? val() : val;
1710
2090
  if (active) r = r ? `${r} ${name}` : name;
@@ -1768,7 +2148,7 @@ function appendChildren(el, nodes) {
1768
2148
  }
1769
2149
  }
1770
2150
  function tagFactory(tag, ns) {
1771
- const blocked = isBlockedTag(tag);
2151
+ const blocked = isBlockedElement(tag);
1772
2152
  return (first, second) => {
1773
2153
  if (blocked) {
1774
2154
  throw new Error(`tagFactory: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
@@ -1831,6 +2211,7 @@ function tagFactory(tag, ns) {
1831
2211
  const pOn = props.on;
1832
2212
  if (pOn) {
1833
2213
  for (const ev in pOn) {
2214
+ if (!Object.hasOwn(pOn, ev)) continue;
1834
2215
  const handler = pOn[ev];
1835
2216
  if (typeof handler === "function") {
1836
2217
  el.addEventListener(ev, handler);
@@ -1857,6 +2238,7 @@ function tagFactory(tag, ns) {
1857
2238
  continue;
1858
2239
  // already handled above / below
1859
2240
  default: {
2241
+ if (!Object.hasOwn(props, key)) continue;
1860
2242
  const value = props[key];
1861
2243
  if (value == null) continue;
1862
2244
  if (isEventHandlerAttr(key)) continue;
@@ -1946,7 +2328,7 @@ var param = tagFactory("param");
1946
2328
  var picture = tagFactory("picture");
1947
2329
  var portal = tagFactory("portal");
1948
2330
  var source = tagFactory("source");
1949
- var svg = tagFactory("svg", SVG_NS2);
2331
+ var svg = tagFactory("svg", SVG_NS3);
1950
2332
  var math = tagFactory("math");
1951
2333
  var canvas = tagFactory("canvas");
1952
2334
  var noscript = tagFactory("noscript");
@@ -1987,26 +2369,26 @@ var base = tagFactory("base");
1987
2369
  var link = tagFactory("link");
1988
2370
  var meta = tagFactory("meta");
1989
2371
  var style = tagFactory("style");
1990
- var circle = tagFactory("circle", SVG_NS2);
1991
- var ellipse = tagFactory("ellipse", SVG_NS2);
1992
- var g = tagFactory("g", SVG_NS2);
1993
- var line = tagFactory("line", SVG_NS2);
1994
- var path = tagFactory("path", SVG_NS2);
1995
- var polygon = tagFactory("polygon", SVG_NS2);
1996
- var polyline = tagFactory("polyline", SVG_NS2);
1997
- var rect = tagFactory("rect", SVG_NS2);
1998
- var text = tagFactory("text", SVG_NS2);
1999
- var tspan = tagFactory("tspan", SVG_NS2);
2000
- var defs = tagFactory("defs", SVG_NS2);
2001
- var clipPath = tagFactory("clipPath", SVG_NS2);
2002
- var mask = tagFactory("mask", SVG_NS2);
2003
- var pattern = tagFactory("pattern", SVG_NS2);
2004
- var linearGradient = tagFactory("linearGradient", SVG_NS2);
2005
- var radialGradient = tagFactory("radialGradient", SVG_NS2);
2006
- var stop = tagFactory("stop", SVG_NS2);
2007
- var use = tagFactory("use", SVG_NS2);
2008
- var symbol = tagFactory("symbol", SVG_NS2);
2009
- var marker = tagFactory("marker", SVG_NS2);
2372
+ var circle = tagFactory("circle", SVG_NS3);
2373
+ var ellipse = tagFactory("ellipse", SVG_NS3);
2374
+ var g = tagFactory("g", SVG_NS3);
2375
+ var line = tagFactory("line", SVG_NS3);
2376
+ var path = tagFactory("path", SVG_NS3);
2377
+ var polygon = tagFactory("polygon", SVG_NS3);
2378
+ var polyline = tagFactory("polyline", SVG_NS3);
2379
+ var rect = tagFactory("rect", SVG_NS3);
2380
+ var text = tagFactory("text", SVG_NS3);
2381
+ var tspan = tagFactory("tspan", SVG_NS3);
2382
+ var defs = tagFactory("defs", SVG_NS3);
2383
+ var clipPath = tagFactory("clipPath", SVG_NS3);
2384
+ var mask = tagFactory("mask", SVG_NS3);
2385
+ var pattern = tagFactory("pattern", SVG_NS3);
2386
+ var linearGradient = tagFactory("linearGradient", SVG_NS3);
2387
+ var radialGradient = tagFactory("radialGradient", SVG_NS3);
2388
+ var stop = tagFactory("stop", SVG_NS3);
2389
+ var use = tagFactory("use", SVG_NS3);
2390
+ var symbol = tagFactory("symbol", SVG_NS3);
2391
+ var marker = tagFactory("marker", SVG_NS3);
2010
2392
  var center = tagFactory("center");
2011
2393
  var font = tagFactory("font");
2012
2394
  var marquee = tagFactory("marquee");
@@ -3820,6 +4202,10 @@ function attachBranch(parent, anchor, branch, attachedOnce, where) {
3820
4202
  parent.insertBefore(node, anchor.nextSibling);
3821
4203
  return { node, owned };
3822
4204
  }
4205
+ function releaseBranchNode(node, owned) {
4206
+ if (owned) dispose(node);
4207
+ node.parentNode?.removeChild(node);
4208
+ }
3823
4209
  function when(condition, thenBranch, elseBranch) {
3824
4210
  const anchor = document.createComment("when");
3825
4211
  let currentNode = null;
@@ -3837,8 +4223,7 @@ function when(condition, thenBranch, elseBranch) {
3837
4223
  lastCondition = show2;
3838
4224
  const focused = currentNode ? captureFocusWithin([currentNode]) : null;
3839
4225
  if (currentNode?.parentNode) {
3840
- if (currentNodeOwned) dispose(currentNode);
3841
- currentNode.parentNode.removeChild(currentNode);
4226
+ releaseBranchNode(currentNode, currentNodeOwned);
3842
4227
  currentNode = null;
3843
4228
  }
3844
4229
  const branch = show2 ? thenBranch : elseBranch !== void 0 ? elseBranch : null;
@@ -3852,6 +4237,8 @@ function when(condition, thenBranch, elseBranch) {
3852
4237
  registerDisposer(anchor, () => {
3853
4238
  disposed = true;
3854
4239
  stopBinding();
4240
+ if (currentNode) releaseBranchNode(currentNode, currentNodeOwned);
4241
+ currentNode = null;
3855
4242
  });
3856
4243
  if (!initialized) {
3857
4244
  queueMicrotask(() => {
@@ -3877,8 +4264,7 @@ function match(value, cases, fallback) {
3877
4264
  lastKey = key;
3878
4265
  const focused = currentNode ? captureFocusWithin([currentNode]) : null;
3879
4266
  if (currentNode?.parentNode) {
3880
- if (currentNodeOwned) dispose(currentNode);
3881
- currentNode.parentNode.removeChild(currentNode);
4267
+ releaseBranchNode(currentNode, currentNodeOwned);
3882
4268
  currentNode = null;
3883
4269
  }
3884
4270
  const branch = Object.hasOwn(cases, key) ? cases[key] : fallback;
@@ -3892,6 +4278,8 @@ function match(value, cases, fallback) {
3892
4278
  registerDisposer(anchor, () => {
3893
4279
  disposed = true;
3894
4280
  stopBinding();
4281
+ if (currentNode) releaseBranchNode(currentNode, currentNodeOwned);
4282
+ currentNode = null;
3895
4283
  });
3896
4284
  if (!initialized) {
3897
4285
  queueMicrotask(() => {
@@ -4234,7 +4622,6 @@ function appendChild(frag, child) {
4234
4622
  }
4235
4623
 
4236
4624
  // src/core/rendering/htm.ts
4237
- var RAW_TEXT_TAGS = /* @__PURE__ */ new Set(["script", "style"]);
4238
4625
  var VOID_ELEMENTS = /* @__PURE__ */ new Set([
4239
4626
  "area",
4240
4627
  "base",
@@ -4457,7 +4844,7 @@ function parseTemplate(strings) {
4457
4844
  children.push({ t: 0, el: { tag, svg: SVG_TAGS.has(tag), attrs, children: [] } });
4458
4845
  } else {
4459
4846
  const inner = parseChildren();
4460
- if (RAW_TEXT_TAGS.has(tag.toLowerCase())) {
4847
+ if (isCodeTextElement(tag)) {
4461
4848
  for (let i2 = 0; i2 < inner.length; i2++) {
4462
4849
  if (inner[i2].t === 2) {
4463
4850
  throw new Error(
@@ -4483,12 +4870,12 @@ function parseTemplate(strings) {
4483
4870
  return parseChildren();
4484
4871
  }
4485
4872
  function executeElement(tmpl, values) {
4486
- const el = tmpl.svg ? document.createElementNS(SVG_NS2, tmpl.tag) : document.createElement(tmpl.tag);
4873
+ const el = tmpl.svg ? document.createElementNS(SVG_NS3, tmpl.tag) : document.createElement(tmpl.tag);
4487
4874
  for (let i2 = 0; i2 < tmpl.attrs.length; i2++) {
4488
4875
  const attr = tmpl.attrs[i2];
4489
4876
  switch (attr.t) {
4490
4877
  case 0:
4491
- el.setAttribute(attr.name, attr.value);
4878
+ setTrustedAttribute(el, attr.name, attr.value);
4492
4879
  break;
4493
4880
  case 1: {
4494
4881
  const name = attr.name;
@@ -4521,7 +4908,7 @@ function executeElement(tmpl, values) {
4521
4908
  break;
4522
4909
  }
4523
4910
  case 4:
4524
- el.setAttribute(attr.name, "");
4911
+ setTrustedAttribute(el, attr.name, "");
4525
4912
  break;
4526
4913
  }
4527
4914
  }
@@ -4566,6 +4953,12 @@ function html2(strings, ...values) {
4566
4953
  tmpl = parseTemplate(strings);
4567
4954
  cache.set(strings, tmpl);
4568
4955
  }
4956
+ return renderTemplate(tmpl, values);
4957
+ }
4958
+ function __renderParsedTemplate(tree, values) {
4959
+ return renderTemplate(tree, values);
4960
+ }
4961
+ function renderTemplate(tmpl, values) {
4569
4962
  if (tmpl.length === 1 && tmpl[0].t === 0) {
4570
4963
  return executeElement(tmpl[0].el, values);
4571
4964
  }
@@ -5654,7 +6047,7 @@ function enhance(target, setup) {
5654
6047
  bindNode(el, () => {
5655
6048
  const v = value();
5656
6049
  const next = v == null ? null : String(v);
5657
- setSafeAttribute(el, name, next, { syncValueProperty: false, label: "enhance attr()" });
6050
+ setSafeAttribute(el, name, next, { syncValueProperty: false, label: "enhance attr()", reactive: true });
5658
6051
  })
5659
6052
  );
5660
6053
  });
@@ -6026,6 +6419,7 @@ function nextTick() {
6026
6419
  Portal,
6027
6420
  SVG_NS,
6028
6421
  Suspense,
6422
+ __renderParsedTemplate,
6029
6423
  __resetIdCounter,
6030
6424
  a,
6031
6425
  abbr,