sibujs 3.4.1 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +118 -15
  3. package/dist/browser.cjs +410 -101
  4. package/dist/browser.d.cts +50 -5
  5. package/dist/browser.d.ts +50 -5
  6. package/dist/browser.js +8 -6
  7. package/dist/build.cjs +784 -392
  8. package/dist/build.js +15 -15
  9. package/dist/cdn.global.js +11 -7
  10. package/dist/{chunk-PBZWJQNY.js → chunk-52ERIVFD.js} +8 -8
  11. package/dist/chunk-52XFPGSN.js +123 -0
  12. package/dist/{chunk-Y22QAKJX.js → chunk-5BVKQX2F.js} +4 -4
  13. package/dist/chunk-5INI7D2L.js +194 -0
  14. package/dist/{chunk-4I3M326N.js → chunk-AD5YSZAN.js} +19 -25
  15. package/dist/{chunk-F7HW2NI5.js → chunk-AW6HPJ3L.js} +1 -1
  16. package/dist/chunk-DHDZ7IVN.js +109 -0
  17. package/dist/{chunk-VQZDHAEK.js → chunk-E72G5JSK.js} +1 -1
  18. package/dist/{chunk-MPE75KOA.js → chunk-HPXTUPJD.js} +259 -124
  19. package/dist/{chunk-EX77FXTT.js → chunk-HYCCIYNS.js} +228 -51
  20. package/dist/{chunk-FWFEBYQ6.js → chunk-IKVUUE7D.js} +115 -41
  21. package/dist/{chunk-5MFF5EPT.js → chunk-J4WZMCIW.js} +5 -5
  22. package/dist/{chunk-BQLVTAUZ.js → chunk-JYXQCELN.js} +57 -22
  23. package/dist/{chunk-WEZ5SP7L.js → chunk-PHB3MCK4.js} +73 -34
  24. package/dist/chunk-PHRH66Y7.js +147 -0
  25. package/dist/{chunk-S2VW4NBA.js → chunk-PJDSI2K7.js} +295 -198
  26. package/dist/{chunk-QHPUFNHZ.js → chunk-PTLJ7NQX.js} +3 -3
  27. package/dist/{chunk-NXR2YFZB.js → chunk-QD4I7ZGZ.js} +24 -34
  28. package/dist/{chunk-S3NFJO6L.js → chunk-TIRZCERI.js} +36 -5
  29. package/dist/{chunk-7PNKW3FJ.js → chunk-TNEHT3NG.js} +232 -67
  30. package/dist/{chunk-335KJEN2.js → chunk-TVURNWDK.js} +5 -3
  31. package/dist/{chunk-CV7FAQ2R.js → chunk-UNAYBND2.js} +9 -3
  32. package/dist/chunk-VPP2FONR.js +142 -0
  33. package/dist/{chunk-X4JS367G.js → chunk-XDOMTQHM.js} +14 -10
  34. package/dist/chunk-XET2RUJF.js +61 -0
  35. package/dist/{chunk-3FFCUIGV.js → chunk-XZMCVZW6.js} +309 -188
  36. package/dist/{chunk-YDWP3ZOU.js → chunk-YLV26GAJ.js} +228 -86
  37. package/dist/{contracts-ey_Qh8ef.d.ts → contracts-Hg6ITAEF.d.cts} +6 -6
  38. package/dist/{contracts-ey_Qh8ef.d.cts → contracts-Hg6ITAEF.d.ts} +6 -6
  39. package/dist/{customElement-CPfIrbvg.d.cts → customElement-CKLoO63w.d.cts} +73 -11
  40. package/dist/{customElement-CPfIrbvg.d.ts → customElement-CKLoO63w.d.ts} +73 -11
  41. package/dist/data.cjs +483 -205
  42. package/dist/data.d.cts +139 -7
  43. package/dist/data.d.ts +139 -7
  44. package/dist/data.js +9 -9
  45. package/dist/devtools.cjs +222 -87
  46. package/dist/devtools.js +8 -8
  47. package/dist/dispose-4FZ6OFXR.js +19 -0
  48. package/dist/ecosystem.cjs +426 -182
  49. package/dist/ecosystem.js +11 -11
  50. package/dist/extras.cjs +1988 -772
  51. package/dist/extras.d.cts +7 -7
  52. package/dist/extras.d.ts +7 -7
  53. package/dist/extras.js +29 -26
  54. package/dist/index.cjs +791 -392
  55. package/dist/index.d.cts +299 -28
  56. package/dist/index.d.ts +299 -28
  57. package/dist/index.js +33 -18
  58. package/dist/motion.cjs +180 -50
  59. package/dist/motion.d.cts +26 -0
  60. package/dist/motion.d.ts +26 -0
  61. package/dist/motion.js +5 -5
  62. package/dist/patterns.cjs +437 -170
  63. package/dist/patterns.d.cts +60 -13
  64. package/dist/patterns.d.ts +60 -13
  65. package/dist/patterns.js +7 -7
  66. package/dist/performance.cjs +333 -148
  67. package/dist/performance.d.cts +55 -7
  68. package/dist/performance.d.ts +55 -7
  69. package/dist/performance.js +9 -9
  70. package/dist/plugins.cjs +1378 -583
  71. package/dist/plugins.d.cts +227 -9
  72. package/dist/plugins.d.ts +227 -9
  73. package/dist/plugins.js +610 -321
  74. package/dist/{ssr-D62yFwuw.d.cts → ssr-BiPRdZ6n.d.cts} +44 -15
  75. package/dist/{ssr-D62yFwuw.d.ts → ssr-BiPRdZ6n.d.ts} +44 -15
  76. package/dist/{ssr-2PPULEK2.js → ssr-JFP5535P.js} +5 -4
  77. package/dist/ssr.cjs +1111 -450
  78. package/dist/ssr.d.cts +230 -20
  79. package/dist/ssr.d.ts +230 -20
  80. package/dist/ssr.js +15 -12
  81. package/dist/{startup-0Qv6aosO.d.cts → startup-BMpaiMhP.d.cts} +1 -1
  82. package/dist/{startup-0Qv6aosO.d.ts → startup-BMpaiMhP.d.ts} +1 -1
  83. package/dist/testing.cjs +205 -63
  84. package/dist/testing.d.cts +1 -1
  85. package/dist/testing.d.ts +1 -1
  86. package/dist/testing.js +8 -10
  87. package/dist/ui.cjs +640 -199
  88. package/dist/ui.d.cts +2 -2
  89. package/dist/ui.d.ts +2 -2
  90. package/dist/ui.js +10 -10
  91. package/dist/widgets.cjs +207 -82
  92. package/dist/widgets.js +9 -9
  93. package/package.json +12 -7
  94. package/dist/chunk-5VGSK6D2.js +0 -80
  95. package/dist/chunk-6CAJU5TP.js +0 -38
  96. package/dist/chunk-COY6PUD2.js +0 -34
  97. package/dist/chunk-DLBFEAIS.js +0 -96
  98. package/dist/chunk-L3GAGWCC.js +0 -111
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  isSSR
3
- } from "./chunk-S3NFJO6L.js";
3
+ } from "./chunk-TIRZCERI.js";
4
4
  import {
5
5
  resumeTracking,
6
6
  suspendTracking,
7
7
  track
8
- } from "./chunk-BQLVTAUZ.js";
8
+ } from "./chunk-JYXQCELN.js";
9
9
  import {
10
10
  devAssert
11
- } from "./chunk-COY6PUD2.js";
11
+ } from "./chunk-VPP2FONR.js";
12
12
 
13
13
  // src/core/signals/watch.ts
14
14
  function watch(getter, callback) {
@@ -1,23 +1,24 @@
1
1
  import {
2
- bindAttribute
3
- } from "./chunk-DLBFEAIS.js";
2
+ bindAttribute,
3
+ setSafeAttribute
4
+ } from "./chunk-PHRH66Y7.js";
4
5
  import {
5
6
  isEventHandlerAttr,
6
- sanitizeAttributeString,
7
- sanitizeCSSValue
8
- } from "./chunk-L3GAGWCC.js";
7
+ sanitizeCSSValue,
8
+ sanitizeStyleAttribute
9
+ } from "./chunk-5INI7D2L.js";
9
10
  import {
10
11
  dispose,
11
12
  registerDisposer
12
- } from "./chunk-5VGSK6D2.js";
13
+ } from "./chunk-DHDZ7IVN.js";
13
14
  import {
14
- reactiveBinding,
15
- track
16
- } from "./chunk-BQLVTAUZ.js";
15
+ reactiveBinding
16
+ } from "./chunk-JYXQCELN.js";
17
17
  import {
18
18
  devWarn,
19
- isDev
20
- } from "./chunk-COY6PUD2.js";
19
+ isDev,
20
+ reportError
21
+ } from "./chunk-VPP2FONR.js";
21
22
 
22
23
  // src/reactivity/bindChildNode.ts
23
24
  var _isDev = isDev();
@@ -28,7 +29,7 @@ function bindChildNode(placeholder, getter) {
28
29
  try {
29
30
  result = getter();
30
31
  } catch (err) {
31
- if (_isDev) devWarn(`bindChildNode: getter threw: ${err instanceof Error ? err.message : String(err)}`);
32
+ reportError(err, { phase: "binding", name: "bindChildNode", node: placeholder });
32
33
  return;
33
34
  }
34
35
  if (result == null || typeof result === "boolean") {
@@ -89,7 +90,7 @@ function bindChildNode(placeholder, getter) {
89
90
  }
90
91
  lastNodes = newNodes;
91
92
  }
92
- return reactiveBinding(commit);
93
+ return reactiveBinding(commit, placeholder);
93
94
  }
94
95
 
95
96
  // src/core/rendering/tagFactory.ts
@@ -112,9 +113,6 @@ var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
112
113
  "self",
113
114
  "frames"
114
115
  ]);
115
- function setProp(el, key, val) {
116
- el[key] = val;
117
- }
118
116
  function looksLikeClassList(s) {
119
117
  const t = s.trim();
120
118
  if (!t) return false;
@@ -137,14 +135,14 @@ function toKebab(prop) {
137
135
  }
138
136
  function applyStyle(el, style) {
139
137
  if (typeof style === "function") {
140
- const teardown = track(() => {
141
- el.setAttribute("style", style());
142
- });
138
+ const teardown = reactiveBinding(() => {
139
+ el.setAttribute("style", sanitizeStyleAttribute(String(style())));
140
+ }, el);
143
141
  registerDisposer(el, teardown);
144
142
  return;
145
143
  }
146
144
  if (typeof style === "string") {
147
- el.setAttribute("style", style);
145
+ el.setAttribute("style", sanitizeStyleAttribute(style));
148
146
  return;
149
147
  }
150
148
  const htmlEl = el;
@@ -153,9 +151,9 @@ function applyStyle(el, style) {
153
151
  const name = toKebab(prop);
154
152
  if (typeof val === "function") {
155
153
  const getter = val;
156
- const teardown = track(() => {
154
+ const teardown = reactiveBinding(() => {
157
155
  htmlEl.style.setProperty(name, sanitizeCSSValue(String(getter())));
158
- });
156
+ }, el);
159
157
  registerDisposer(el, teardown);
160
158
  } else {
161
159
  htmlEl.style.setProperty(name, sanitizeCSSValue(String(val)));
@@ -168,9 +166,9 @@ function applyClass(el, cls) {
168
166
  return;
169
167
  }
170
168
  if (typeof cls === "function") {
171
- const teardown = track(() => {
169
+ const teardown = reactiveBinding(() => {
172
170
  el.setAttribute("class", cls());
173
- });
171
+ }, el);
174
172
  registerDisposer(el, teardown);
175
173
  return;
176
174
  }
@@ -195,7 +193,7 @@ function applyClass(el, cls) {
195
193
  }
196
194
  el.setAttribute("class", r);
197
195
  };
198
- const teardown = track(update);
196
+ const teardown = reactiveBinding(update, el);
199
197
  registerDisposer(el, teardown);
200
198
  } else {
201
199
  el.setAttribute("class", result);
@@ -329,16 +327,8 @@ var tagFactory = (tag, ns) => {
329
327
  if (isEventHandlerAttr(key)) continue;
330
328
  if (typeof value === "function") {
331
329
  registerDisposer(el, bindAttribute(el, key, value));
332
- } else if (typeof value === "boolean") {
333
- if (key in el && (key === "checked" || key === "disabled" || key === "selected")) {
334
- setProp(el, key, value);
335
- } else if (value) {
336
- el.setAttribute(key, "");
337
- } else {
338
- el.removeAttribute(key);
339
- }
340
330
  } else {
341
- el.setAttribute(key, sanitizeAttributeString(key, String(value)));
331
+ setSafeAttribute(el, key, value, { syncValueProperty: false, label: "tagFactory" });
342
332
  }
343
333
  }
344
334
  }
@@ -1,3 +1,8 @@
1
+ import {
2
+ __require,
3
+ devWarn
4
+ } from "./chunk-VPP2FONR.js";
5
+
1
6
  // src/core/ssr-context.ts
2
7
  var SSR_KEY = /* @__PURE__ */ Symbol.for("sibujs.ssr.v1");
3
8
  function detectSSRShared() {
@@ -8,20 +13,35 @@ function detectSSRShared() {
8
13
  const getBuiltin = process.getBuiltinModule;
9
14
  if (typeof getBuiltin === "function") {
10
15
  mod = getBuiltin("node:async_hooks");
11
- } else {
12
- const req = Function("return typeof require==='function'?require:null")();
13
- if (req) mod = req("node:async_hooks");
16
+ } else if (typeof __require === "function") {
17
+ mod = __require("async_hooks");
14
18
  }
15
19
  if (mod) detected = new mod.AsyncLocalStorage();
16
20
  }
17
21
  } catch {
18
22
  detected = null;
19
23
  }
20
- return { als: detected, fallbackStore: { ssr: false, suspenseIdCounter: 0 } };
24
+ return {
25
+ als: detected,
26
+ fallbackStore: { ssr: false, suspenseIdCounter: 0, locale: void 0 },
27
+ fallbackDepth: 0
28
+ };
21
29
  }
22
30
  var _shared = globalThis[SSR_KEY] ?? (globalThis[SSR_KEY] = detectSSRShared());
23
31
  var als = _shared.als;
24
32
  var fallbackStore = _shared.fallbackStore;
33
+ _shared.fallbackDepth ?? (_shared.fallbackDepth = 0);
34
+ var _alsWarned = false;
35
+ function warnMissingAsyncLocalStorage() {
36
+ if (_alsWarned || als) return;
37
+ const isNode = typeof process !== "undefined" && !!process.versions?.node;
38
+ if (!isNode) return;
39
+ _alsWarned = true;
40
+ const version = process.versions.node;
41
+ devWarn(
42
+ `SSR request isolation is UNAVAILABLE on this runtime (Node ${version}). AsyncLocalStorage could not be loaded, so concurrent requests share one SSR store: request state and the query cache can bleed between them. Node >= 22.3 is required for isolated SSR under ESM; the CommonJS build works on older versions. A fully synchronous render is unaffected.`
43
+ );
44
+ }
25
45
  function getSSRStore() {
26
46
  if (als) {
27
47
  const s = als.getStore();
@@ -29,6 +49,10 @@ function getSSRStore() {
29
49
  }
30
50
  return fallbackStore;
31
51
  }
52
+ function getRequestStore() {
53
+ if (als) return als.getStore() ?? null;
54
+ return _shared.fallbackDepth > 0 ? fallbackStore : null;
55
+ }
32
56
  function isSSR() {
33
57
  return getSSRStore().ssr;
34
58
  }
@@ -50,19 +74,25 @@ function disableSSR() {
50
74
  getSSRStore().ssr = false;
51
75
  }
52
76
  function runInSSRContext(fn) {
53
- const store = { ssr: true, suspenseIdCounter: 0 };
77
+ const store = { ssr: true, suspenseIdCounter: 0, locale: void 0 };
54
78
  if (als) {
55
79
  return als.run(store, fn);
56
80
  }
81
+ warnMissingAsyncLocalStorage();
57
82
  const prevSSR = fallbackStore.ssr;
58
83
  const prevCounter = fallbackStore.suspenseIdCounter;
84
+ const prevLocale = fallbackStore.locale;
59
85
  fallbackStore.ssr = true;
60
86
  fallbackStore.suspenseIdCounter = 0;
87
+ fallbackStore.locale = void 0;
88
+ _shared.fallbackDepth++;
61
89
  try {
62
90
  return fn();
63
91
  } finally {
92
+ _shared.fallbackDepth--;
64
93
  fallbackStore.ssr = prevSSR;
65
94
  fallbackStore.suspenseIdCounter = prevCounter;
95
+ fallbackStore.locale = prevLocale;
66
96
  }
67
97
  }
68
98
  function withSSR(fn) {
@@ -78,6 +108,7 @@ function withSSR(fn) {
78
108
 
79
109
  export {
80
110
  getSSRStore,
111
+ getRequestStore,
81
112
  isSSR,
82
113
  getRequestScopedCache,
83
114
  enableSSR,
@@ -1,25 +1,33 @@
1
1
  import {
2
- bindAttribute
3
- } from "./chunk-DLBFEAIS.js";
2
+ bindAttribute,
3
+ setSafeAttribute
4
+ } from "./chunk-PHRH66Y7.js";
4
5
  import {
5
6
  derived
6
- } from "./chunk-4I3M326N.js";
7
+ } from "./chunk-AD5YSZAN.js";
8
+ import {
9
+ isEventHandlerAttr
10
+ } from "./chunk-5INI7D2L.js";
7
11
  import {
8
12
  globalSingleton
9
13
  } from "./chunk-7ZHH77QA.js";
10
14
  import {
11
15
  effect
12
- } from "./chunk-X4JS367G.js";
16
+ } from "./chunk-XDOMTQHM.js";
13
17
  import {
14
18
  dispose,
15
- registerDisposer
16
- } from "./chunk-5VGSK6D2.js";
19
+ registerDisposer,
20
+ replaceChildrenSafely
21
+ } from "./chunk-DHDZ7IVN.js";
17
22
  import {
18
23
  signal
19
- } from "./chunk-335KJEN2.js";
24
+ } from "./chunk-TVURNWDK.js";
20
25
  import {
21
26
  track
22
- } from "./chunk-BQLVTAUZ.js";
27
+ } from "./chunk-JYXQCELN.js";
28
+ import {
29
+ reportError
30
+ } from "./chunk-VPP2FONR.js";
23
31
 
24
32
  // src/ui/form.ts
25
33
  function required(message = "This field is required") {
@@ -114,6 +122,8 @@ function bindField(field, extras) {
114
122
  }
115
123
  };
116
124
  return {
125
+ // The field's own getter, no longer widened to `unknown` — that widening is
126
+ // what forced every consumer to cast. (TYPE-010)
117
127
  value: field.value,
118
128
  on: mergedOn,
119
129
  onElement,
@@ -691,21 +701,169 @@ function sanitizeCSS(css) {
691
701
  sanitized = sanitized.replace(/behavior\s*:[^;]+;/gi, "/* behavior removed */");
692
702
  return sanitized;
693
703
  }
704
+ function firstCompoundEnd(selector) {
705
+ let parens = 0;
706
+ let brackets = 0;
707
+ let quote = null;
708
+ for (let i = 0; i < selector.length; i++) {
709
+ const ch = selector[i];
710
+ if (quote) {
711
+ if (ch === "\\") i++;
712
+ else if (ch === quote) quote = null;
713
+ continue;
714
+ }
715
+ if (ch === '"' || ch === "'") {
716
+ quote = ch;
717
+ continue;
718
+ }
719
+ if (ch === "\\") {
720
+ i++;
721
+ continue;
722
+ }
723
+ if (ch === "(") parens++;
724
+ else if (ch === ")") parens--;
725
+ else if (ch === "[") brackets++;
726
+ else if (ch === "]") brackets--;
727
+ if (parens > 0 || brackets > 0) continue;
728
+ if (ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f") return i;
729
+ if (ch === ">" || ch === "+" || ch === "~") return i;
730
+ if (ch === ":" && selector[i + 1] === ":") return i;
731
+ }
732
+ return selector.length;
733
+ }
734
+ function scopeSelector(selector, attr) {
735
+ const end = firstCompoundEnd(selector);
736
+ const selfForm = `${selector.slice(0, end)}[${attr}]${selector.slice(end)}`;
737
+ const descendantForm = `[${attr}] ${selector}`;
738
+ return `${descendantForm}, ${selfForm}`;
739
+ }
740
+ function skipNonCode(text, i) {
741
+ const ch = text[i];
742
+ if (ch === "\\") return i + 2;
743
+ if (ch === '"' || ch === "'") {
744
+ let j = i + 1;
745
+ while (j < text.length) {
746
+ if (text[j] === "\\") {
747
+ j += 2;
748
+ continue;
749
+ }
750
+ if (text[j] === ch) return j + 1;
751
+ j++;
752
+ }
753
+ return text.length;
754
+ }
755
+ if (ch === "/" && text[i + 1] === "*") {
756
+ const end = text.indexOf("*/", i + 2);
757
+ return end === -1 ? text.length : end + 2;
758
+ }
759
+ return -1;
760
+ }
761
+ function splitSelectorList(prelude) {
762
+ const parts = [];
763
+ let parens = 0;
764
+ let brackets = 0;
765
+ let start = 0;
766
+ for (let i = 0; i < prelude.length; i++) {
767
+ const skip = skipNonCode(prelude, i);
768
+ if (skip !== -1) {
769
+ i = skip - 1;
770
+ continue;
771
+ }
772
+ const ch = prelude[i];
773
+ if (ch === "(") parens++;
774
+ else if (ch === ")") parens--;
775
+ else if (ch === "[") brackets++;
776
+ else if (ch === "]") brackets--;
777
+ else if (ch === "," && parens === 0 && brackets === 0) {
778
+ parts.push(prelude.slice(start, i));
779
+ start = i + 1;
780
+ }
781
+ }
782
+ parts.push(prelude.slice(start));
783
+ return parts;
784
+ }
785
+ function findBlockEnd(css, openBrace) {
786
+ let depth = 0;
787
+ for (let i = openBrace; i < css.length; i++) {
788
+ const skip = skipNonCode(css, i);
789
+ if (skip !== -1) {
790
+ i = skip - 1;
791
+ continue;
792
+ }
793
+ const ch = css[i];
794
+ if (ch === "{") depth++;
795
+ else if (ch === "}") {
796
+ depth--;
797
+ if (depth === 0) return i;
798
+ }
799
+ }
800
+ return css.length;
801
+ }
802
+ var NESTED_AT_RULE = /^@(media|supports|layer|container|scope|document)\b/i;
803
+ function scopeStylesheet(css, attr) {
804
+ let out = "";
805
+ let preludeStart = 0;
806
+ let parens = 0;
807
+ let brackets = 0;
808
+ let i = 0;
809
+ while (i < css.length) {
810
+ const skip = skipNonCode(css, i);
811
+ if (skip !== -1) {
812
+ i = skip;
813
+ continue;
814
+ }
815
+ const ch = css[i];
816
+ if (ch === "(") {
817
+ parens++;
818
+ i++;
819
+ continue;
820
+ }
821
+ if (ch === ")") {
822
+ parens--;
823
+ i++;
824
+ continue;
825
+ }
826
+ if (ch === "[") {
827
+ brackets++;
828
+ i++;
829
+ continue;
830
+ }
831
+ if (ch === "]") {
832
+ brackets--;
833
+ i++;
834
+ continue;
835
+ }
836
+ if (ch === "{" && parens === 0 && brackets === 0) {
837
+ const prelude = css.slice(preludeStart, i);
838
+ const bodyEnd = findBlockEnd(css, i);
839
+ const body = css.slice(i + 1, bodyEnd);
840
+ const trimmed = prelude.trim();
841
+ const lead = prelude.slice(0, prelude.length - prelude.trimStart().length);
842
+ if (trimmed === "") {
843
+ out += `${prelude}{${body}}`;
844
+ } else if (trimmed.startsWith("@")) {
845
+ out += NESTED_AT_RULE.test(trimmed) ? `${prelude}{${scopeStylesheet(body, attr)}}` : `${prelude}{${body}}`;
846
+ } else {
847
+ const scoped = splitSelectorList(trimmed).map((part) => {
848
+ const selector = part.trim();
849
+ return selector ? scopeSelector(selector, attr) : part;
850
+ }).join(", ");
851
+ out += `${lead}${scoped}{${body}}`;
852
+ }
853
+ i = bodyEnd + 1;
854
+ preludeStart = i;
855
+ continue;
856
+ }
857
+ i++;
858
+ }
859
+ out += css.slice(preludeStart);
860
+ return out;
861
+ }
694
862
  function scopedStyle(css) {
695
863
  const id = `sibu-s${_scope.n++}`;
696
864
  const attr = `data-${id}`;
697
865
  const safeCss = sanitizeCSS(css);
698
- const scopedCSS = safeCss.replace(/([^\r\n,{}]+)(,(?=[^}]*{)|\s*{)/g, (match, selector, delimiter) => {
699
- const trimmed = selector.trim();
700
- if (trimmed.startsWith("@") || trimmed.startsWith("from") || trimmed.startsWith("to") || /^\d+%$/.test(trimmed)) {
701
- return match;
702
- }
703
- const pseudoIdx = trimmed.indexOf("::");
704
- if (pseudoIdx >= 0) {
705
- return `${trimmed.slice(0, pseudoIdx)}[${attr}]${trimmed.slice(pseudoIdx)}${delimiter}`;
706
- }
707
- return `${trimmed}[${attr}]${delimiter}`;
708
- });
866
+ const scopedCSS = scopeStylesheet(safeCss, attr);
709
867
  if (typeof document !== "undefined") {
710
868
  const styleEl = document.createElement("style");
711
869
  styleEl.setAttribute("data-sibu-scope", id);
@@ -721,18 +879,10 @@ function withScopedStyle(css, component) {
721
879
  style = scopedStyle(css);
722
880
  }
723
881
  const el = component(props);
724
- applyScopeRecursive(el, style.attr);
882
+ el.setAttribute(style.attr, "");
725
883
  return el;
726
884
  };
727
885
  }
728
- function applyScopeRecursive(element, attr) {
729
- element.setAttribute(attr, "");
730
- for (const child of Array.from(element.children)) {
731
- if (child instanceof HTMLElement) {
732
- applyScopeRecursive(child, attr);
733
- }
734
- }
735
- }
736
886
  function removeScopedStyle(scopeId) {
737
887
  const el = document.head.querySelector(`style[data-sibu-scope="${scopeId}"]`);
738
888
  if (el) el.remove();
@@ -745,14 +895,8 @@ function bindAttrs(el, attrs) {
745
895
  if (typeof value === "function") {
746
896
  const teardown = bindAttribute(el, attr, value);
747
897
  teardowns.push(teardown);
748
- } else if (typeof value === "boolean") {
749
- if (value) {
750
- el.setAttribute(attr, "");
751
- } else {
752
- el.removeAttribute(attr);
753
- }
754
898
  } else {
755
- el.setAttribute(attr, String(value));
899
+ setSafeAttribute(el, attr, value, { label: "bindAttrs" });
756
900
  }
757
901
  }
758
902
  return () => {
@@ -763,11 +907,7 @@ function bindAttrs(el, attrs) {
763
907
  }
764
908
  function bindBoolAttr(el, attr, getter) {
765
909
  if (typeof getter !== "function") {
766
- if (getter) {
767
- el.setAttribute(attr, "");
768
- } else {
769
- el.removeAttribute(attr);
770
- }
910
+ setSafeAttribute(el, attr, getter, { label: "bindBoolAttr" });
771
911
  return () => {
772
912
  };
773
913
  }
@@ -779,11 +919,7 @@ function bindBoolAttr(el, attr, getter) {
779
919
  } catch {
780
920
  return;
781
921
  }
782
- if (value) {
783
- el.setAttribute(attr, "");
784
- } else {
785
- el.removeAttribute(attr);
786
- }
922
+ setSafeAttribute(el, attr, Boolean(value), { label: "bindBoolAttr" });
787
923
  }
788
924
  const teardown = track(commit);
789
925
  return teardown;
@@ -791,7 +927,7 @@ function bindBoolAttr(el, attr, getter) {
791
927
  function bindData(el, key, getter) {
792
928
  const dataAttr = `data-${key}`;
793
929
  if (typeof getter !== "function") {
794
- el.setAttribute(dataAttr, String(getter));
930
+ setSafeAttribute(el, dataAttr, getter, { label: "bindData" });
795
931
  return () => {
796
932
  };
797
933
  }
@@ -931,31 +1067,58 @@ function infiniteScroll(options) {
931
1067
  const sentinelRef = { current: null };
932
1068
  let observer = null;
933
1069
  let disposed = false;
1070
+ let generation = 0;
1071
+ function safeHasMore() {
1072
+ try {
1073
+ return hasMore();
1074
+ } catch (err) {
1075
+ reportError(err, { phase: "async", name: "infiniteScroll(hasMore)" });
1076
+ return false;
1077
+ }
1078
+ }
1079
+ function ownsAttachment(owner) {
1080
+ return !disposed && generation === owner.generation && observer === owner.observer && _current === owner.sentinel;
1081
+ }
934
1082
  function createObserver() {
935
1083
  if (typeof IntersectionObserver === "undefined") return;
936
- observer = new IntersectionObserver(
1084
+ let createdObserver;
1085
+ createdObserver = new IntersectionObserver(
937
1086
  (entries) => {
938
1087
  const entry = entries[0];
939
- if (entry?.isIntersecting && !loading() && hasMore() && !disposed) {
940
- loadMore();
941
- }
1088
+ if (!entry?.isIntersecting) return;
1089
+ const sentinel = _current;
1090
+ if (!sentinel) return;
1091
+ const owner = { generation, observer: createdObserver, sentinel };
1092
+ if (!ownsAttachment(owner) || loading()) return;
1093
+ const shouldLoad = safeHasMore();
1094
+ if (!shouldLoad || !ownsAttachment(owner)) return;
1095
+ void loadMore(owner);
942
1096
  },
943
1097
  { threshold }
944
1098
  );
1099
+ observer = createdObserver;
945
1100
  if (sentinelRef.current) {
946
- observer.observe(sentinelRef.current);
1101
+ createdObserver.observe(sentinelRef.current);
947
1102
  }
948
1103
  }
949
- async function loadMore() {
950
- setLoading(true);
1104
+ async function loadMore(owner) {
951
1105
  try {
952
- await onLoadMore();
953
- } finally {
954
- setLoading(false);
955
- if (!disposed && observer && _current && hasMore()) {
956
- observer.unobserve(_current);
957
- observer.observe(_current);
1106
+ setLoading(true);
1107
+ if (!ownsAttachment(owner)) return;
1108
+ try {
1109
+ await onLoadMore();
1110
+ } catch (err) {
1111
+ reportError(err, { phase: "async", name: "infiniteScroll(onLoadMore)" });
958
1112
  }
1113
+ if (!ownsAttachment(owner)) return;
1114
+ setLoading(false);
1115
+ if (!ownsAttachment(owner)) return;
1116
+ const shouldContinue = safeHasMore();
1117
+ if (!shouldContinue || !ownsAttachment(owner)) return;
1118
+ owner.observer.unobserve(owner.sentinel);
1119
+ owner.observer.observe(owner.sentinel);
1120
+ } catch (err) {
1121
+ reportError(err, { phase: "async", name: "infiniteScroll(loadMore)" });
959
1122
  }
960
1123
  }
961
1124
  const originalRef = sentinelRef;
@@ -965,7 +1128,10 @@ function infiniteScroll(options) {
965
1128
  return _current;
966
1129
  },
967
1130
  set(el) {
1131
+ if (el === _current) return;
968
1132
  _current = el;
1133
+ generation++;
1134
+ setLoading(false);
969
1135
  if (observer) {
970
1136
  observer.disconnect();
971
1137
  observer = null;
@@ -978,10 +1144,12 @@ function infiniteScroll(options) {
978
1144
  });
979
1145
  function dispose2() {
980
1146
  disposed = true;
1147
+ generation++;
981
1148
  if (observer) {
982
1149
  observer.disconnect();
983
1150
  observer = null;
984
1151
  }
1152
+ setLoading(false);
985
1153
  }
986
1154
  return { sentinelRef: originalRef, loading, dispose: dispose2 };
987
1155
  }
@@ -1057,6 +1225,7 @@ function eventBus() {
1057
1225
  }
1058
1226
 
1059
1227
  // src/platform/customElement.ts
1228
+ var SVG_NS = "http://www.w3.org/2000/svg";
1060
1229
  function defineElement(name, component, options = {}) {
1061
1230
  if (customElements.get(name)) return;
1062
1231
  const observed = options.observedAttributes || [];
@@ -1085,11 +1254,8 @@ function defineElement(name, component, options = {}) {
1085
1254
  }
1086
1255
  }
1087
1256
  _teardown() {
1088
- if (this._rendered) {
1089
- dispose(this._rendered);
1090
- this._rendered = null;
1091
- }
1092
- this._root.replaceChildren();
1257
+ this._rendered = null;
1258
+ replaceChildrenSafely(this._root);
1093
1259
  }
1094
1260
  _render() {
1095
1261
  this._teardown();
@@ -1114,14 +1280,13 @@ function defineElement(name, component, options = {}) {
1114
1280
  customElements.define(name, SibuElement);
1115
1281
  }
1116
1282
  function svgElement(tag, props = {}, ...nodes) {
1117
- const SVG_NS = "http://www.w3.org/2000/svg";
1118
1283
  const el = document.createElementNS(SVG_NS, tag);
1119
1284
  for (const [key, value] of Object.entries(props)) {
1120
1285
  if (key === "nodes") continue;
1121
- if (typeof value === "function" && key.startsWith("on")) {
1286
+ if (typeof value === "function" && isEventHandlerAttr(key)) {
1122
1287
  el.addEventListener(key.slice(2).toLowerCase(), value);
1123
1288
  } else if (value != null) {
1124
- el.setAttribute(key, String(value));
1289
+ setSafeAttribute(el, key, value, { label: "svgElement" });
1125
1290
  }
1126
1291
  }
1127
1292
  for (const child of nodes) {
@@ -3,10 +3,10 @@ import {
3
3
  notifySubscribers,
4
4
  queueSignalNotification,
5
5
  recordDependency
6
- } from "./chunk-BQLVTAUZ.js";
6
+ } from "./chunk-JYXQCELN.js";
7
7
  import {
8
8
  isDev
9
- } from "./chunk-COY6PUD2.js";
9
+ } from "./chunk-VPP2FONR.js";
10
10
 
11
11
  // src/reactivity/batch.ts
12
12
  var batchDepth = 0;
@@ -69,7 +69,9 @@ function signal(initial, options) {
69
69
  subsHead: null,
70
70
  subsTail: null,
71
71
  __activeNode: null,
72
- __name: void 0
72
+ __name: void 0,
73
+ _d: false,
74
+ _validate: void 0
73
75
  };
74
76
  const debugName = _isDev ? options?.name : void 0;
75
77
  const equalsFn = options?.equals;