sibujs 4.7.0 → 4.9.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 (83) hide show
  1. package/dist/browser.cjs +48 -6
  2. package/dist/browser.d.cts +26 -2
  3. package/dist/browser.d.ts +26 -2
  4. package/dist/browser.js +6 -5
  5. package/dist/build.cjs +539 -96
  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-Z3OHK6QT.js → chunk-2K3Z3XO4.js} +5 -5
  14. package/dist/chunk-3ACAAQIN.js +224 -0
  15. package/dist/{chunk-WOLJZUFQ.js → chunk-562UVHMM.js} +32 -15
  16. package/dist/{chunk-UOL2ECCS.js → chunk-5MLWTIQE.js} +18 -12
  17. package/dist/{chunk-H3SRKIYX.js → chunk-62BDYGAG.js} +8 -0
  18. package/dist/{chunk-3QWBSL5R.js → chunk-7OV5Q2UU.js} +8 -5
  19. package/dist/{chunk-SLM3IA34.js → chunk-CDBKFGXN.js} +1 -1
  20. package/dist/{chunk-4AWA2PVD.js → chunk-CF2KCWRE.js} +10 -5
  21. package/dist/{chunk-BSY63EM6.js → chunk-DRMLIF6M.js} +20 -5
  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-BC2SECJD.js → chunk-FHCZMHHE.js} +1 -1
  25. package/dist/{chunk-XYV3EDB7.js → chunk-FNOK662L.js} +63 -38
  26. package/dist/{chunk-JWKYU5GV.js → chunk-G2WHYEL7.js} +1 -1
  27. package/dist/{chunk-DKXRACVN.js → chunk-K6K5ACO6.js} +6 -6
  28. package/dist/{chunk-VZSG24LS.js → chunk-KG25XMGP.js} +45 -17
  29. package/dist/{chunk-FNJXNGYZ.js → chunk-MPWDSTYK.js} +58 -6
  30. package/dist/{chunk-UNWRJRKC.js → chunk-NQMKWBKU.js} +1 -1
  31. package/dist/{chunk-7LUJQAOJ.js → chunk-QBKCK6MJ.js} +1 -1
  32. package/dist/{chunk-WEQ3DMVL.js → chunk-SBTZEYNI.js} +1 -1
  33. package/dist/{chunk-FQRUXCEE.js → chunk-SYHGGDNW.js} +1 -1
  34. package/dist/{chunk-XZR4PXRE.js → chunk-TV464N2M.js} +13 -10
  35. package/dist/{chunk-RUSSKG6G.js → chunk-X7NRHFZR.js} +1 -1
  36. package/dist/{chunk-2BPG2XDA.js → chunk-XJVTQUIV.js} +18 -36
  37. package/dist/{chunk-ZVL7TY4K.js → chunk-YW6HQKGO.js} +25 -10
  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 +29 -9
  41. package/dist/data.d.cts +23 -4
  42. package/dist/data.d.ts +23 -4
  43. package/dist/data.js +6 -6
  44. package/dist/devtools.cjs +1 -1
  45. package/dist/devtools.js +5 -5
  46. package/dist/ecosystem.cjs +400 -37
  47. package/dist/ecosystem.js +9 -8
  48. package/dist/extras.cjs +672 -269
  49. package/dist/extras.d.cts +2 -2
  50. package/dist/extras.d.ts +2 -2
  51. package/dist/extras.js +24 -23
  52. package/dist/index.cjs +490 -88
  53. package/dist/index.d.cts +34 -2
  54. package/dist/index.d.ts +34 -2
  55. package/dist/index.js +16 -12
  56. package/dist/motion.cjs +1 -1
  57. package/dist/motion.js +3 -3
  58. package/dist/patterns.cjs +10 -7
  59. package/dist/patterns.js +6 -6
  60. package/dist/performance.cjs +31 -2
  61. package/dist/performance.d.cts +12 -2
  62. package/dist/performance.d.ts +12 -2
  63. package/dist/performance.js +8 -6
  64. package/dist/plugins.cjs +571 -240
  65. package/dist/plugins.d.cts +14 -3
  66. package/dist/plugins.d.ts +14 -3
  67. package/dist/plugins.js +35 -37
  68. package/dist/{ssr-XOTUASDO.js → ssr-5OWAH3U2.js} +4 -2
  69. package/dist/{ssr-Bli9XRW5.d.ts → ssr-C8hgIAw7.d.cts} +6 -0
  70. package/dist/{ssr-Bli9XRW5.d.cts → ssr-C8hgIAw7.d.ts} +6 -0
  71. package/dist/ssr.cjs +484 -138
  72. package/dist/ssr.d.cts +59 -5
  73. package/dist/ssr.d.ts +59 -5
  74. package/dist/ssr.js +11 -9
  75. package/dist/testing.cjs +3 -3
  76. package/dist/testing.js +4 -4
  77. package/dist/ui.cjs +609 -241
  78. package/dist/ui.d.cts +1 -1
  79. package/dist/ui.d.ts +1 -1
  80. package/dist/ui.js +9 -8
  81. package/dist/widgets.cjs +1 -1
  82. package/dist/widgets.js +7 -7
  83. 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.9.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");
@@ -3584,37 +3966,44 @@ function action(element, action2, param2) {
3584
3966
  }
3585
3967
  }
3586
3968
  var clickOutside = (element, callback) => {
3969
+ const doc = element.ownerDocument;
3587
3970
  const handler = (e) => {
3588
- if (!element.contains(e.target)) {
3589
- callback();
3590
- }
3971
+ const target = e.target;
3972
+ if (!(typeof target?.nodeType === "number" && element.contains(target))) callback();
3591
3973
  };
3592
- document.addEventListener("pointerdown", handler, true);
3593
- return () => document.removeEventListener("pointerdown", handler, true);
3974
+ doc.addEventListener("pointerdown", handler, true);
3975
+ return () => doc.removeEventListener("pointerdown", handler, true);
3594
3976
  };
3977
+ var PRESS_END_EVENTS = ["pointerup", "pointerleave", "pointercancel"];
3595
3978
  var longPress = (element, options) => {
3596
3979
  const duration = options.duration ?? 500;
3597
3980
  let timer = null;
3598
- const start = () => {
3599
- timer = setTimeout(() => {
3600
- options.callback();
3601
- timer = null;
3602
- }, duration);
3603
- };
3981
+ let owner;
3604
3982
  const cancel = () => {
3605
3983
  if (timer !== null) {
3606
3984
  clearTimeout(timer);
3607
3985
  timer = null;
3608
3986
  }
3609
3987
  };
3988
+ const start = (e) => {
3989
+ const id = e.pointerId;
3990
+ if (timer !== null && id !== owner) return;
3991
+ cancel();
3992
+ owner = id;
3993
+ timer = setTimeout(() => {
3994
+ timer = null;
3995
+ options.callback();
3996
+ }, duration);
3997
+ };
3998
+ const end = (e) => {
3999
+ if (timer !== null && e.pointerId === owner) cancel();
4000
+ };
3610
4001
  element.addEventListener("pointerdown", start);
3611
- element.addEventListener("pointerup", cancel);
3612
- element.addEventListener("pointerleave", cancel);
4002
+ for (const type of PRESS_END_EVENTS) element.addEventListener(type, end);
3613
4003
  return () => {
3614
4004
  cancel();
3615
4005
  element.removeEventListener("pointerdown", start);
3616
- element.removeEventListener("pointerup", cancel);
3617
- element.removeEventListener("pointerleave", cancel);
4006
+ for (const type of PRESS_END_EVENTS) element.removeEventListener(type, end);
3618
4007
  };
3619
4008
  };
3620
4009
  var copyOnClick = (element, getText) => {
@@ -3648,10 +4037,11 @@ var trapFocus = (element) => {
3648
4037
  if (elements.length === 0) return;
3649
4038
  const first = elements[0];
3650
4039
  const last = elements[elements.length - 1];
3651
- if (e.shiftKey && document.activeElement === first) {
4040
+ const active = element.ownerDocument.activeElement;
4041
+ if (e.shiftKey && active === first) {
3652
4042
  e.preventDefault();
3653
4043
  last.focus();
3654
- } else if (!e.shiftKey && document.activeElement === last) {
4044
+ } else if (!e.shiftKey && active === last) {
3655
4045
  e.preventDefault();
3656
4046
  first.focus();
3657
4047
  }
@@ -3820,6 +4210,10 @@ function attachBranch(parent, anchor, branch, attachedOnce, where) {
3820
4210
  parent.insertBefore(node, anchor.nextSibling);
3821
4211
  return { node, owned };
3822
4212
  }
4213
+ function releaseBranchNode(node, owned) {
4214
+ if (owned) dispose(node);
4215
+ node.parentNode?.removeChild(node);
4216
+ }
3823
4217
  function when(condition, thenBranch, elseBranch) {
3824
4218
  const anchor = document.createComment("when");
3825
4219
  let currentNode = null;
@@ -3837,8 +4231,7 @@ function when(condition, thenBranch, elseBranch) {
3837
4231
  lastCondition = show2;
3838
4232
  const focused = currentNode ? captureFocusWithin([currentNode]) : null;
3839
4233
  if (currentNode?.parentNode) {
3840
- if (currentNodeOwned) dispose(currentNode);
3841
- currentNode.parentNode.removeChild(currentNode);
4234
+ releaseBranchNode(currentNode, currentNodeOwned);
3842
4235
  currentNode = null;
3843
4236
  }
3844
4237
  const branch = show2 ? thenBranch : elseBranch !== void 0 ? elseBranch : null;
@@ -3852,6 +4245,8 @@ function when(condition, thenBranch, elseBranch) {
3852
4245
  registerDisposer(anchor, () => {
3853
4246
  disposed = true;
3854
4247
  stopBinding();
4248
+ if (currentNode) releaseBranchNode(currentNode, currentNodeOwned);
4249
+ currentNode = null;
3855
4250
  });
3856
4251
  if (!initialized) {
3857
4252
  queueMicrotask(() => {
@@ -3877,8 +4272,7 @@ function match(value, cases, fallback) {
3877
4272
  lastKey = key;
3878
4273
  const focused = currentNode ? captureFocusWithin([currentNode]) : null;
3879
4274
  if (currentNode?.parentNode) {
3880
- if (currentNodeOwned) dispose(currentNode);
3881
- currentNode.parentNode.removeChild(currentNode);
4275
+ releaseBranchNode(currentNode, currentNodeOwned);
3882
4276
  currentNode = null;
3883
4277
  }
3884
4278
  const branch = Object.hasOwn(cases, key) ? cases[key] : fallback;
@@ -3892,6 +4286,8 @@ function match(value, cases, fallback) {
3892
4286
  registerDisposer(anchor, () => {
3893
4287
  disposed = true;
3894
4288
  stopBinding();
4289
+ if (currentNode) releaseBranchNode(currentNode, currentNodeOwned);
4290
+ currentNode = null;
3895
4291
  });
3896
4292
  if (!initialized) {
3897
4293
  queueMicrotask(() => {
@@ -4234,7 +4630,6 @@ function appendChild(frag, child) {
4234
4630
  }
4235
4631
 
4236
4632
  // src/core/rendering/htm.ts
4237
- var RAW_TEXT_TAGS = /* @__PURE__ */ new Set(["script", "style"]);
4238
4633
  var VOID_ELEMENTS = /* @__PURE__ */ new Set([
4239
4634
  "area",
4240
4635
  "base",
@@ -4457,7 +4852,7 @@ function parseTemplate(strings) {
4457
4852
  children.push({ t: 0, el: { tag, svg: SVG_TAGS.has(tag), attrs, children: [] } });
4458
4853
  } else {
4459
4854
  const inner = parseChildren();
4460
- if (RAW_TEXT_TAGS.has(tag.toLowerCase())) {
4855
+ if (isCodeTextElement(tag)) {
4461
4856
  for (let i2 = 0; i2 < inner.length; i2++) {
4462
4857
  if (inner[i2].t === 2) {
4463
4858
  throw new Error(
@@ -4483,12 +4878,12 @@ function parseTemplate(strings) {
4483
4878
  return parseChildren();
4484
4879
  }
4485
4880
  function executeElement(tmpl, values) {
4486
- const el = tmpl.svg ? document.createElementNS(SVG_NS2, tmpl.tag) : document.createElement(tmpl.tag);
4881
+ const el = tmpl.svg ? document.createElementNS(SVG_NS3, tmpl.tag) : document.createElement(tmpl.tag);
4487
4882
  for (let i2 = 0; i2 < tmpl.attrs.length; i2++) {
4488
4883
  const attr = tmpl.attrs[i2];
4489
4884
  switch (attr.t) {
4490
4885
  case 0:
4491
- el.setAttribute(attr.name, attr.value);
4886
+ setTrustedAttribute(el, attr.name, attr.value);
4492
4887
  break;
4493
4888
  case 1: {
4494
4889
  const name = attr.name;
@@ -4521,7 +4916,7 @@ function executeElement(tmpl, values) {
4521
4916
  break;
4522
4917
  }
4523
4918
  case 4:
4524
- el.setAttribute(attr.name, "");
4919
+ setTrustedAttribute(el, attr.name, "");
4525
4920
  break;
4526
4921
  }
4527
4922
  }
@@ -4566,6 +4961,12 @@ function html2(strings, ...values) {
4566
4961
  tmpl = parseTemplate(strings);
4567
4962
  cache.set(strings, tmpl);
4568
4963
  }
4964
+ return renderTemplate(tmpl, values);
4965
+ }
4966
+ function __renderParsedTemplate(tree, values) {
4967
+ return renderTemplate(tree, values);
4968
+ }
4969
+ function renderTemplate(tmpl, values) {
4569
4970
  if (tmpl.length === 1 && tmpl[0].t === 0) {
4570
4971
  return executeElement(tmpl[0].el, values);
4571
4972
  }
@@ -4641,7 +5042,7 @@ function KeepAlive(activeKey, cases, options) {
4641
5042
  return;
4642
5043
  }
4643
5044
  node = factory();
4644
- if (node instanceof DocumentFragment) {
5045
+ if (node.nodeType === 11) {
4645
5046
  const wrapper = document.createElement("div");
4646
5047
  wrapper.style.display = "contents";
4647
5048
  wrapper.appendChild(node);
@@ -5654,7 +6055,7 @@ function enhance(target, setup) {
5654
6055
  bindNode(el, () => {
5655
6056
  const v = value();
5656
6057
  const next = v == null ? null : String(v);
5657
- setSafeAttribute(el, name, next, { syncValueProperty: false, label: "enhance attr()" });
6058
+ setSafeAttribute(el, name, next, { syncValueProperty: false, label: "enhance attr()", reactive: true });
5658
6059
  })
5659
6060
  );
5660
6061
  });
@@ -6026,6 +6427,7 @@ function nextTick() {
6026
6427
  Portal,
6027
6428
  SVG_NS,
6028
6429
  Suspense,
6430
+ __renderParsedTemplate,
6029
6431
  __resetIdCounter,
6030
6432
  a,
6031
6433
  abbr,