sibujs 1.5.0 → 2.0.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 (207) hide show
  1. package/dist/browser.cjs +238 -69
  2. package/dist/browser.d.cts +5 -0
  3. package/dist/browser.d.ts +5 -0
  4. package/dist/browser.js +6 -6
  5. package/dist/build.cjs +916 -292
  6. package/dist/build.js +15 -13
  7. package/dist/cdn.global.js +17 -16
  8. package/dist/chunk-2RA7SHDA.js +65 -0
  9. package/dist/chunk-2UPRY23K.js +80 -0
  10. package/dist/chunk-3JHCYHWN.js +125 -0
  11. package/dist/{chunk-VAPYJN4X.js → chunk-3LR7GLWQ.js} +93 -23
  12. package/dist/{chunk-RJ46C3CS.js → chunk-3NSGB5JN.js} +71 -20
  13. package/dist/{chunk-XUEEGU5O.js → chunk-52YJLLRO.js} +16 -4
  14. package/dist/{chunk-XHK6BDAJ.js → chunk-54EDRCEF.js} +25 -8
  15. package/dist/chunk-7JDB7I65.js +1327 -0
  16. package/dist/{chunk-WZSPOOER.js → chunk-CC65Y57T.js} +8 -5
  17. package/dist/{chunk-23VV7YD3.js → chunk-DFPFITST.js} +25 -30
  18. package/dist/{chunk-BGN5ZMP4.js → chunk-GTBNNBJ6.js} +14 -2
  19. package/dist/chunk-HB24TBAF.js +121 -0
  20. package/dist/{chunk-CZUGLNJS.js → chunk-ITX6OO3F.js} +3 -3
  21. package/dist/{chunk-BGTHZHJ5.js → chunk-JA6667UN.js} +188 -44
  22. package/dist/{chunk-7GRNSCFT.js → chunk-JXMMDLBY.js} +306 -183
  23. package/dist/{chunk-3X2YG6YM.js → chunk-JYD2PWXH.js} +59 -28
  24. package/dist/{chunk-SFKNRVCU.js → chunk-KLRMB5ZS.js} +135 -79
  25. package/dist/{chunk-5X6PP2UK.js → chunk-LMLD24FC.js} +2 -2
  26. package/dist/{chunk-M4NLBH4I.js → chunk-LYTCUZ7H.js} +3 -2
  27. package/dist/{chunk-BMPL52BF.js → chunk-MIUAXB7K.js} +118 -66
  28. package/dist/{chunk-JCDUJN2F.js → chunk-ND2664SF.js} +486 -153
  29. package/dist/{chunk-VQDZK23A.js → chunk-O2MNQFLP.js} +181 -66
  30. package/dist/{chunk-NHUC2QWH.js → chunk-R73P76YZ.js} +1 -1
  31. package/dist/{chunk-2BYQDGN3.js → chunk-SAHNHTFC.js} +234 -63
  32. package/dist/chunk-UCS6AMJ7.js +79 -0
  33. package/dist/{chunk-K4G4ZQNR.js → chunk-VLPPXTYG.js} +84 -38
  34. package/dist/{chunk-OUZZEE4S.js → chunk-WOMYAHHI.js} +17 -11
  35. package/dist/{customElement-BL3Uo8dL.d.cts → customElement-CPfIrbvg.d.cts} +14 -10
  36. package/dist/{customElement-BL3Uo8dL.d.ts → customElement-CPfIrbvg.d.ts} +14 -10
  37. package/dist/data.cjs +410 -99
  38. package/dist/data.d.cts +20 -2
  39. package/dist/data.d.ts +20 -2
  40. package/dist/data.js +11 -9
  41. package/dist/devtools.cjs +513 -223
  42. package/dist/devtools.d.cts +1 -1
  43. package/dist/devtools.d.ts +1 -1
  44. package/dist/devtools.js +12 -6
  45. package/dist/ecosystem.cjs +475 -144
  46. package/dist/ecosystem.d.cts +9 -7
  47. package/dist/ecosystem.d.ts +9 -7
  48. package/dist/ecosystem.js +12 -11
  49. package/dist/extras.cjs +3355 -1541
  50. package/dist/extras.d.cts +9 -9
  51. package/dist/extras.d.ts +9 -9
  52. package/dist/extras.js +58 -45
  53. package/dist/index.cjs +920 -292
  54. package/dist/index.d.cts +71 -8
  55. package/dist/index.d.ts +71 -8
  56. package/dist/index.js +28 -16
  57. package/dist/{introspect-BumjnBKr.d.cts → introspect-BWNjNw64.d.cts} +22 -2
  58. package/dist/{introspect-CZrlcaYy.d.ts → introspect-cY2pg9pW.d.ts} +22 -2
  59. package/dist/motion.cjs +77 -34
  60. package/dist/motion.js +4 -4
  61. package/dist/patterns.cjs +335 -69
  62. package/dist/patterns.d.cts +11 -12
  63. package/dist/patterns.d.ts +11 -12
  64. package/dist/patterns.js +7 -7
  65. package/dist/performance.cjs +279 -108
  66. package/dist/performance.d.cts +23 -16
  67. package/dist/performance.d.ts +23 -16
  68. package/dist/performance.js +13 -8
  69. package/dist/plugin-D30wlGW5.d.cts +71 -0
  70. package/dist/plugin-D30wlGW5.d.ts +71 -0
  71. package/dist/plugins.cjs +635 -260
  72. package/dist/plugins.d.cts +10 -3
  73. package/dist/plugins.d.ts +10 -3
  74. package/dist/plugins.js +106 -38
  75. package/dist/{ssr-Do_SiVoL.d.cts → ssr-CrVNy6Pa.d.cts} +9 -15
  76. package/dist/{ssr-Do_SiVoL.d.ts → ssr-CrVNy6Pa.d.ts} +9 -15
  77. package/dist/{ssr-4PBXAOO3.js → ssr-FXD2PPMC.js} +4 -3
  78. package/dist/ssr.cjs +642 -222
  79. package/dist/ssr.d.cts +26 -6
  80. package/dist/ssr.d.ts +26 -6
  81. package/dist/ssr.js +12 -11
  82. package/dist/{tagFactory-DaJ0YWX6.d.cts → tagFactory-S17H2qxu.d.cts} +9 -1
  83. package/dist/{tagFactory-DaJ0YWX6.d.ts → tagFactory-S17H2qxu.d.ts} +9 -1
  84. package/dist/testing.cjs +252 -63
  85. package/dist/testing.d.cts +17 -4
  86. package/dist/testing.d.ts +17 -4
  87. package/dist/testing.js +100 -44
  88. package/dist/ui.cjs +463 -137
  89. package/dist/ui.d.cts +1 -1
  90. package/dist/ui.d.ts +1 -1
  91. package/dist/ui.js +20 -17
  92. package/dist/widgets.cjs +977 -94
  93. package/dist/widgets.d.cts +104 -2
  94. package/dist/widgets.d.ts +104 -2
  95. package/dist/widgets.js +9 -7
  96. package/package.json +8 -2
  97. package/dist/chunk-32DY64NT.js +0 -282
  98. package/dist/chunk-3AIRKM3B.js +0 -1263
  99. package/dist/chunk-3ARAQO7B.js +0 -398
  100. package/dist/chunk-3CRQALYP.js +0 -877
  101. package/dist/chunk-4EI4AG32.js +0 -482
  102. package/dist/chunk-4MYMUBRS.js +0 -21
  103. package/dist/chunk-5ZYQ6KDD.js +0 -154
  104. package/dist/chunk-6BMPXPUW.js +0 -26
  105. package/dist/chunk-6HLLIF3K.js +0 -398
  106. package/dist/chunk-6LSNVCS2.js +0 -937
  107. package/dist/chunk-6SA3QQES.js +0 -61
  108. package/dist/chunk-77L6NL3X.js +0 -1097
  109. package/dist/chunk-7BF6TK55.js +0 -1097
  110. package/dist/chunk-7TQKR4PP.js +0 -294
  111. package/dist/chunk-7V26P53V.js +0 -712
  112. package/dist/chunk-AZ3ISID5.js +0 -298
  113. package/dist/chunk-B7SWRFUT.js +0 -332
  114. package/dist/chunk-BTU3TJDS.js +0 -365
  115. package/dist/chunk-BW3WT46K.js +0 -937
  116. package/dist/chunk-C6KFWOFV.js +0 -616
  117. package/dist/chunk-CHF5OHIA.js +0 -61
  118. package/dist/chunk-CHJ27IGK.js +0 -26
  119. package/dist/chunk-CMBFNA7L.js +0 -27
  120. package/dist/chunk-DAHRH4ON.js +0 -331
  121. package/dist/chunk-DKOHBI74.js +0 -924
  122. package/dist/chunk-DTCOOBMX.js +0 -725
  123. package/dist/chunk-EBGIRKQY.js +0 -616
  124. package/dist/chunk-EUZND3CB.js +0 -27
  125. package/dist/chunk-EVCZO745.js +0 -365
  126. package/dist/chunk-EWFVA3TJ.js +0 -282
  127. package/dist/chunk-F3FA4F32.js +0 -292
  128. package/dist/chunk-FGOEVHY3.js +0 -60
  129. package/dist/chunk-G3BOQPVO.js +0 -365
  130. package/dist/chunk-GCOK2LC3.js +0 -282
  131. package/dist/chunk-GJPXRJ45.js +0 -37
  132. package/dist/chunk-HGMJFBC7.js +0 -654
  133. package/dist/chunk-JAKHTMQU.js +0 -1000
  134. package/dist/chunk-JCI5M6U6.js +0 -956
  135. package/dist/chunk-K5ZUMYVS.js +0 -89
  136. package/dist/chunk-KQPDEVVS.js +0 -398
  137. package/dist/chunk-L6JRBDNS.js +0 -60
  138. package/dist/chunk-LA6KQEDU.js +0 -712
  139. package/dist/chunk-MB6QFH3I.js +0 -2776
  140. package/dist/chunk-MDVXJWFN.js +0 -304
  141. package/dist/chunk-MEZVEBPN.js +0 -2008
  142. package/dist/chunk-MK4ERFYL.js +0 -2249
  143. package/dist/chunk-MLKGABMK.js +0 -9
  144. package/dist/chunk-MQ5GOYPH.js +0 -2249
  145. package/dist/chunk-MYRV7VDM.js +0 -742
  146. package/dist/chunk-N6IZB6KJ.js +0 -567
  147. package/dist/chunk-NEKUBFPT.js +0 -60
  148. package/dist/chunk-NMRUZALC.js +0 -1097
  149. package/dist/chunk-NYVAC6P5.js +0 -37
  150. package/dist/chunk-NZIIMDWI.js +0 -84
  151. package/dist/chunk-OF7UZIVB.js +0 -725
  152. package/dist/chunk-P3XWXJZU.js +0 -282
  153. package/dist/chunk-P6W3STU4.js +0 -2249
  154. package/dist/chunk-PBHF5WKN.js +0 -616
  155. package/dist/chunk-PDZQY43A.js +0 -616
  156. package/dist/chunk-PTQJDMRT.js +0 -146
  157. package/dist/chunk-PZEGYCF5.js +0 -61
  158. package/dist/chunk-QBMDLBU2.js +0 -975
  159. package/dist/chunk-QWZG56ET.js +0 -2744
  160. package/dist/chunk-RQGQSLQK.js +0 -725
  161. package/dist/chunk-SDLZDHKP.js +0 -107
  162. package/dist/chunk-TDGZL5CU.js +0 -365
  163. package/dist/chunk-TNQWPPE6.js +0 -37
  164. package/dist/chunk-TSOKIX5Z.js +0 -654
  165. package/dist/chunk-UHNL42EF.js +0 -2730
  166. package/dist/chunk-UNXCEF6S.js +0 -21
  167. package/dist/chunk-V2XTI523.js +0 -347
  168. package/dist/chunk-VAU366PN.js +0 -2241
  169. package/dist/chunk-VMVDTCXB.js +0 -712
  170. package/dist/chunk-VQNQZCWJ.js +0 -61
  171. package/dist/chunk-VRW3FULF.js +0 -725
  172. package/dist/chunk-WADYRCO2.js +0 -304
  173. package/dist/chunk-WILQZRO4.js +0 -282
  174. package/dist/chunk-WR5D4EGH.js +0 -26
  175. package/dist/chunk-WUHJISPP.js +0 -298
  176. package/dist/chunk-XYU6TZOW.js +0 -182
  177. package/dist/chunk-Y6GP4QGG.js +0 -276
  178. package/dist/chunk-YECR7UIA.js +0 -347
  179. package/dist/chunk-YUTWTI4B.js +0 -654
  180. package/dist/chunk-Z65KYU7I.js +0 -26
  181. package/dist/chunk-Z6POF5YC.js +0 -975
  182. package/dist/chunk-ZBJP6WFL.js +0 -482
  183. package/dist/chunk-ZD6OAMTH.js +0 -277
  184. package/dist/chunk-ZWKZCBO6.js +0 -317
  185. package/dist/contracts-DDrwxvJ-.d.cts +0 -245
  186. package/dist/contracts-DDrwxvJ-.d.ts +0 -245
  187. package/dist/contracts-DOrhwbke.d.cts +0 -245
  188. package/dist/contracts-DOrhwbke.d.ts +0 -245
  189. package/dist/contracts-xo5ckdRP.d.cts +0 -240
  190. package/dist/contracts-xo5ckdRP.d.ts +0 -240
  191. package/dist/customElement-BKQfbSZQ.d.cts +0 -262
  192. package/dist/customElement-BKQfbSZQ.d.ts +0 -262
  193. package/dist/customElement-D2DJp_xn.d.cts +0 -313
  194. package/dist/customElement-D2DJp_xn.d.ts +0 -313
  195. package/dist/customElement-yz8uyk-0.d.cts +0 -308
  196. package/dist/customElement-yz8uyk-0.d.ts +0 -308
  197. package/dist/introspect-Cb0zgpi2.d.cts +0 -477
  198. package/dist/introspect-Y2xNXGSf.d.ts +0 -477
  199. package/dist/plugin-Bek4RhJY.d.cts +0 -43
  200. package/dist/plugin-Bek4RhJY.d.ts +0 -43
  201. package/dist/ssr-3RXHP5ES.js +0 -38
  202. package/dist/ssr-6GIMY5MX.js +0 -38
  203. package/dist/ssr-BA6sxxUd.d.cts +0 -135
  204. package/dist/ssr-BA6sxxUd.d.ts +0 -135
  205. package/dist/ssr-WKUPVSSK.js +0 -36
  206. package/dist/tagFactory-Dl8QCLga.d.cts +0 -23
  207. package/dist/tagFactory-Dl8QCLga.d.ts +0 -23
@@ -38,12 +38,12 @@ function isDev() {
38
38
  var _isDev = isDev();
39
39
  function devAssert(condition, message) {
40
40
  if (_isDev && !condition) {
41
- throw new Error(`[Sibu] ${message}`);
41
+ throw new Error(`[SibuJS] ${message}`);
42
42
  }
43
43
  }
44
44
  function devWarn(message) {
45
45
  if (_isDev) {
46
- console.warn(`[Sibu] ${message}`);
46
+ console.warn(`[SibuJS] ${message}`);
47
47
  }
48
48
  }
49
49
 
@@ -53,11 +53,11 @@ var subscriberStack = new Array(32);
53
53
  var stackCapacity = 32;
54
54
  var stackTop = -1;
55
55
  var currentSubscriber = null;
56
- var signalSubscribers = /* @__PURE__ */ new WeakMap();
57
56
  var SUBS = "__s";
58
57
  var notifyDepth = 0;
59
58
  var pendingQueue = [];
60
59
  var pendingSet = /* @__PURE__ */ new Set();
60
+ var propagateStack = [];
61
61
  function safeInvoke(sub) {
62
62
  try {
63
63
  sub();
@@ -66,6 +66,15 @@ function safeInvoke(sub) {
66
66
  }
67
67
  }
68
68
  var trackingSuspended = false;
69
+ function retrack(effectFn, subscriber) {
70
+ const prev = currentSubscriber;
71
+ currentSubscriber = subscriber;
72
+ try {
73
+ effectFn();
74
+ } finally {
75
+ currentSubscriber = prev;
76
+ }
77
+ }
69
78
  function track(effectFn, subscriber) {
70
79
  if (!subscriber) subscriber = effectFn;
71
80
  cleanup(subscriber);
@@ -104,7 +113,6 @@ function recordDependency(signal2) {
104
113
  let subs = signal2[SUBS];
105
114
  if (!subs) {
106
115
  subs = /* @__PURE__ */ new Set();
107
- signalSubscribers.set(signal2, subs);
108
116
  signal2[SUBS] = subs;
109
117
  }
110
118
  subs.add(currentSubscriber);
@@ -126,17 +134,17 @@ function queueSignalNotification(signal2) {
126
134
  }
127
135
  }
128
136
  }
129
- var MAX_DRAIN_ITERATIONS = 1e3;
137
+ var maxDrainIterations = 1e5;
130
138
  function drainNotificationQueue() {
131
139
  if (notifyDepth > 0) return;
132
140
  notifyDepth++;
133
141
  try {
134
142
  let i = 0;
135
143
  while (i < pendingQueue.length) {
136
- if (i >= MAX_DRAIN_ITERATIONS) {
144
+ if (i >= maxDrainIterations) {
137
145
  if (typeof console !== "undefined") {
138
146
  console.error(
139
- `[SibuJS] Notification queue exceeded ${MAX_DRAIN_ITERATIONS} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
147
+ `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
140
148
  );
141
149
  }
142
150
  break;
@@ -145,47 +153,52 @@ function drainNotificationQueue() {
145
153
  i++;
146
154
  }
147
155
  } finally {
148
- pendingQueue.length = 0;
149
- pendingSet.clear();
150
156
  notifyDepth--;
157
+ if (notifyDepth === 0) {
158
+ pendingQueue.length = 0;
159
+ pendingSet.clear();
160
+ }
151
161
  }
152
162
  }
153
163
  function propagateDirty(sub) {
154
164
  sub();
155
- let sig = sub._sig;
156
- while (sig) {
165
+ const rootSig = sub._sig;
166
+ if (!rootSig) return;
167
+ const stack = propagateStack;
168
+ const baseLen = stack.length;
169
+ stack.push(rootSig);
170
+ while (stack.length > baseLen) {
171
+ const sig = stack.pop();
157
172
  const first = sig.__f;
158
173
  if (first) {
159
174
  if (first._c) {
160
175
  const nSig = first._sig;
161
- nSig._d = true;
162
- sig = nSig;
163
- continue;
164
- }
165
- if (!pendingSet.has(first)) {
176
+ if (!nSig._d) {
177
+ nSig._d = true;
178
+ stack.push(nSig);
179
+ }
180
+ } else if (!pendingSet.has(first)) {
166
181
  pendingSet.add(first);
167
182
  pendingQueue.push(first);
168
183
  }
169
- break;
184
+ continue;
170
185
  }
171
186
  const subs = sig[SUBS];
172
- if (!subs) break;
173
- let nextSig;
187
+ if (!subs) continue;
174
188
  for (const s of subs) {
175
189
  if (s._c) {
176
- s();
177
190
  const nSig = s._sig;
178
- if (nSig && !nextSig) {
179
- nextSig = nSig;
180
- } else if (nSig) {
181
- propagateDirty(s);
191
+ if (nSig && !nSig._d) {
192
+ nSig._d = true;
193
+ stack.push(nSig);
194
+ } else if (!nSig) {
195
+ s();
182
196
  }
183
197
  } else if (!pendingSet.has(s)) {
184
198
  pendingSet.add(s);
185
199
  pendingQueue.push(s);
186
200
  }
187
201
  }
188
- sig = nextSig;
189
202
  }
190
203
  }
191
204
  function notifySubscribers(signal2) {
@@ -209,13 +222,23 @@ function notifySubscribers(signal2) {
209
222
  }
210
223
  let i = 0;
211
224
  while (i < pendingQueue.length) {
225
+ if (i >= maxDrainIterations) {
226
+ if (typeof console !== "undefined") {
227
+ console.error(
228
+ `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
229
+ );
230
+ }
231
+ break;
232
+ }
212
233
  safeInvoke(pendingQueue[i]);
213
234
  i++;
214
235
  }
215
236
  } finally {
216
- pendingQueue.length = 0;
217
- pendingSet.clear();
218
237
  notifyDepth--;
238
+ if (notifyDepth === 0) {
239
+ pendingQueue.length = 0;
240
+ pendingSet.clear();
241
+ }
219
242
  }
220
243
  return;
221
244
  }
@@ -235,30 +258,48 @@ function notifySubscribers(signal2) {
235
258
  notifyDepth++;
236
259
  try {
237
260
  let directCount = 0;
261
+ let hasComputedSub = false;
238
262
  for (const sub of subs) {
263
+ if (sub._c) hasComputedSub = true;
239
264
  pendingQueue[directCount++] = sub;
240
265
  }
241
- for (let i2 = 0; i2 < directCount; i2++) {
242
- if (pendingQueue[i2]._c) {
243
- propagateDirty(pendingQueue[i2]);
266
+ if (!hasComputedSub) {
267
+ for (let i2 = 0; i2 < directCount; i2++) {
268
+ safeInvoke(pendingQueue[i2]);
244
269
  }
245
- }
246
- for (let i2 = 0; i2 < directCount; i2++) {
247
- if (!pendingQueue[i2]._c) {
248
- if (!pendingSet.has(pendingQueue[i2])) {
249
- safeInvoke(pendingQueue[i2]);
270
+ } else {
271
+ for (let i2 = 0; i2 < directCount; i2++) {
272
+ if (pendingQueue[i2]._c) {
273
+ propagateDirty(pendingQueue[i2]);
274
+ }
275
+ }
276
+ for (let i2 = 0; i2 < directCount; i2++) {
277
+ const sub = pendingQueue[i2];
278
+ if (!sub._c && !pendingSet.has(sub)) {
279
+ pendingSet.add(sub);
280
+ safeInvoke(sub);
250
281
  }
251
282
  }
252
283
  }
253
284
  let i = directCount;
254
285
  while (i < pendingQueue.length) {
286
+ if (i - directCount >= maxDrainIterations) {
287
+ if (typeof console !== "undefined") {
288
+ console.error(
289
+ `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
290
+ );
291
+ }
292
+ break;
293
+ }
255
294
  safeInvoke(pendingQueue[i]);
256
295
  i++;
257
296
  }
258
297
  } finally {
259
- pendingQueue.length = 0;
260
- pendingSet.clear();
261
298
  notifyDepth--;
299
+ if (notifyDepth === 0) {
300
+ pendingQueue.length = 0;
301
+ pendingSet.clear();
302
+ }
262
303
  }
263
304
  }
264
305
  function cleanup(subscriber) {
@@ -269,7 +310,9 @@ function cleanup(subscriber) {
269
310
  if (subs) {
270
311
  subs.delete(subscriber);
271
312
  if (singleDep.__f === subscriber) {
272
- singleDep.__f = void 0;
313
+ singleDep.__f = subs.size === 1 ? subs.values().next().value : void 0;
314
+ } else if (subs.size === 1 && singleDep.__f === void 0) {
315
+ singleDep.__f = subs.values().next().value;
273
316
  }
274
317
  }
275
318
  sub._dep = void 0;
@@ -282,7 +325,9 @@ function cleanup(subscriber) {
282
325
  if (subs) {
283
326
  subs.delete(subscriber);
284
327
  if (signal2.__f === subscriber) {
285
- signal2.__f = void 0;
328
+ signal2.__f = subs.size === 1 ? subs.values().next().value : void 0;
329
+ } else if (subs.size === 1 && signal2.__f === void 0) {
330
+ signal2.__f = subs.values().next().value;
286
331
  }
287
332
  }
288
333
  }
@@ -290,9 +335,28 @@ function cleanup(subscriber) {
290
335
  }
291
336
 
292
337
  // src/core/ssr-context.ts
293
- var ssrMode = false;
338
+ var als = null;
339
+ try {
340
+ if (typeof process !== "undefined" && process.versions && process.versions.node) {
341
+ const req = Function("return typeof require==='function'?require:null")();
342
+ if (req) {
343
+ const mod = req("node:async_hooks");
344
+ als = new mod.AsyncLocalStorage();
345
+ }
346
+ }
347
+ } catch {
348
+ als = null;
349
+ }
350
+ var fallbackStore = { ssr: false, suspenseIdCounter: 0 };
351
+ function getSSRStore() {
352
+ if (als) {
353
+ const s = als.getStore();
354
+ if (s) return s;
355
+ }
356
+ return fallbackStore;
357
+ }
294
358
  function isSSR() {
295
- return ssrMode;
359
+ return getSSRStore().ssr;
296
360
  }
297
361
 
298
362
  // src/core/signals/effect.ts
@@ -302,26 +366,86 @@ function effect(effectFn, options) {
302
366
  if (isSSR()) return () => {
303
367
  };
304
368
  const onError = options?.onError;
369
+ let userCleanups = [];
370
+ const onCleanup = (fn) => {
371
+ userCleanups.push(fn);
372
+ };
373
+ const runUserCleanups = () => {
374
+ if (userCleanups.length === 0) return;
375
+ const list = userCleanups;
376
+ userCleanups = [];
377
+ for (let i = list.length - 1; i >= 0; i--) {
378
+ try {
379
+ list[i]();
380
+ } catch (err) {
381
+ if (typeof console !== "undefined") {
382
+ console.warn("[SibuJS effect] onCleanup threw:", err);
383
+ }
384
+ }
385
+ }
386
+ };
387
+ const invokeBody = () => effectFn(onCleanup);
305
388
  const wrappedFn = onError ? () => {
306
389
  try {
307
- effectFn();
390
+ invokeBody();
308
391
  } catch (err) {
309
392
  onError(err);
310
393
  }
311
- } : effectFn;
394
+ } : invokeBody;
312
395
  let cleanupHandle = () => {
313
396
  };
397
+ let running = false;
314
398
  const subscriber = () => {
315
- cleanupHandle();
316
- cleanupHandle = track(wrappedFn, subscriber);
399
+ if (running) {
400
+ if (_g.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
401
+ console.warn(
402
+ "[SibuJS] effect re-entered itself while running \u2014 the triggering update will be ignored. Wrap mutual writes in `batch()` or split the effect to avoid this."
403
+ );
404
+ }
405
+ return;
406
+ }
407
+ running = true;
408
+ try {
409
+ runUserCleanups();
410
+ cleanupHandle();
411
+ cleanupHandle = track(wrappedFn, subscriber);
412
+ } finally {
413
+ running = false;
414
+ }
317
415
  };
318
- cleanupHandle = track(wrappedFn, subscriber);
416
+ running = true;
417
+ try {
418
+ cleanupHandle = track(wrappedFn, subscriber);
419
+ } finally {
420
+ running = false;
421
+ }
319
422
  const hook = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
320
423
  if (hook) hook.emit("effect:create", { effectFn });
424
+ let disposed = false;
321
425
  return () => {
426
+ if (disposed) return;
427
+ disposed = true;
322
428
  const h = _g.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
323
- if (h) h.emit("effect:destroy", { effectFn });
324
- cleanupHandle();
429
+ if (h) {
430
+ try {
431
+ h.emit("effect:destroy", { effectFn });
432
+ } catch {
433
+ }
434
+ }
435
+ try {
436
+ runUserCleanups();
437
+ } catch (err) {
438
+ if (typeof console !== "undefined") {
439
+ console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
440
+ }
441
+ }
442
+ try {
443
+ cleanupHandle();
444
+ } catch (err) {
445
+ if (typeof console !== "undefined") {
446
+ console.warn("[SibuJS effect] dispose threw:", err);
447
+ }
448
+ }
325
449
  };
326
450
  }
327
451
 
@@ -345,10 +469,13 @@ function enqueueBatchedSignal(signal2) {
345
469
  return true;
346
470
  }
347
471
  function flushBatch() {
348
- for (const signal2 of pendingSignals) {
349
- queueSignalNotification(signal2);
472
+ try {
473
+ for (const signal2 of pendingSignals) {
474
+ queueSignalNotification(signal2);
475
+ }
476
+ } finally {
477
+ pendingSignals.clear();
350
478
  }
351
- pendingSignals.clear();
352
479
  drainNotificationQueue();
353
480
  }
354
481
 
@@ -391,6 +518,85 @@ function signal(initial, options) {
391
518
  }
392
519
 
393
520
  // src/plugins/plugin.ts
521
+ function createPluginRegistry() {
522
+ const installedPlugins = /* @__PURE__ */ new Set();
523
+ const hooks = { init: [], mount: [], unmount: [], error: [] };
524
+ const provided = /* @__PURE__ */ new Map();
525
+ const registry = {
526
+ installedPlugins,
527
+ hooks,
528
+ provided,
529
+ plugin(p, options) {
530
+ if (installedPlugins.has(p.name)) {
531
+ console.warn(`[Plugin] "${p.name}" is already installed.`);
532
+ return;
533
+ }
534
+ const ctx = {
535
+ onInit: (cb) => hooks.init.push(cb),
536
+ onMount: (cb) => hooks.mount.push(cb),
537
+ onUnmount: (cb) => hooks.unmount.push(cb),
538
+ onError: (cb) => hooks.error.push(cb),
539
+ provide: (key, value) => provided.set(key, value)
540
+ };
541
+ const initHooksBefore = hooks.init.length;
542
+ p.install(ctx, options);
543
+ installedPlugins.add(p.name);
544
+ const justAdded = hooks.init.slice(initHooksBefore);
545
+ for (const cb of justAdded) {
546
+ try {
547
+ cb();
548
+ } catch (e) {
549
+ console.error(`[Plugin] "${p.name}" init error:`, e);
550
+ }
551
+ }
552
+ },
553
+ inject(key, defaultValue) {
554
+ if (provided.has(key)) return provided.get(key);
555
+ if (defaultValue !== void 0) return defaultValue;
556
+ throw new Error(`[Plugin] No provider found for key "${key}"`);
557
+ },
558
+ triggerMount(element) {
559
+ const snapshot = hooks.mount.slice();
560
+ for (const hook of snapshot) {
561
+ try {
562
+ hook(element);
563
+ } catch (e) {
564
+ console.error("[Plugin] Mount hook error:", e);
565
+ }
566
+ }
567
+ },
568
+ triggerUnmount(element) {
569
+ const snapshot = hooks.unmount.slice();
570
+ for (const hook of snapshot) {
571
+ try {
572
+ hook(element);
573
+ } catch (e) {
574
+ console.error("[Plugin] Unmount hook error:", e);
575
+ }
576
+ }
577
+ },
578
+ triggerError(error) {
579
+ const snapshot = hooks.error.slice();
580
+ for (const hook of snapshot) {
581
+ try {
582
+ hook(error);
583
+ } catch (e) {
584
+ console.error("[Plugin] Error hook error:", e);
585
+ }
586
+ }
587
+ },
588
+ reset() {
589
+ installedPlugins.clear();
590
+ hooks.init.length = 0;
591
+ hooks.mount.length = 0;
592
+ hooks.unmount.length = 0;
593
+ hooks.error.length = 0;
594
+ provided.clear();
595
+ }
596
+ };
597
+ return registry;
598
+ }
599
+ var defaultRegistry = createPluginRegistry();
394
600
  function createPlugin(name, install) {
395
601
  return { name, install };
396
602
  }
@@ -401,7 +607,7 @@ function mobXAdapter(options) {
401
607
  const { autorun } = options;
402
608
  const disposers = [];
403
609
  function fromMobX(expression) {
404
- const [getValue, setValue] = signal(expression());
610
+ const [getValue, setValue] = signal(void 0);
405
611
  const disposer = autorun(() => {
406
612
  const newValue = expression();
407
613
  batch(() => {
@@ -409,7 +615,13 @@ function mobXAdapter(options) {
409
615
  });
410
616
  });
411
617
  disposers.push(disposer);
412
- return getValue;
618
+ const getter = (() => getValue());
619
+ getter.dispose = () => {
620
+ const i = disposers.indexOf(disposer);
621
+ if (i >= 0) disposers.splice(i, 1);
622
+ disposer();
623
+ };
624
+ return getter;
413
625
  }
414
626
  function toMobX(sibuGetter, callback) {
415
627
  return effect(() => {
@@ -431,6 +643,7 @@ function mobXAdapter(options) {
431
643
  function derived(getter, options) {
432
644
  devAssert(typeof getter === "function", "derived: argument must be a getter function.");
433
645
  const debugName = options?.name;
646
+ const equals = options?.equals;
434
647
  const cs = {};
435
648
  cs._d = false;
436
649
  cs._g = getter;
@@ -441,8 +654,14 @@ function derived(getter, options) {
441
654
  markDirty._c = 1;
442
655
  markDirty._sig = cs;
443
656
  track(() => {
444
- cs._d = false;
445
- cs._v = getter();
657
+ let threw = true;
658
+ try {
659
+ cs._v = getter();
660
+ cs._d = false;
661
+ threw = false;
662
+ } finally {
663
+ if (threw) cs._d = true;
664
+ }
446
665
  }, markDirty);
447
666
  const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
448
667
  let evaluating = false;
@@ -455,11 +674,16 @@ function derived(getter, options) {
455
674
  if (trackingSuspended) {
456
675
  if (cs._d) {
457
676
  evaluating = true;
677
+ let threw = true;
458
678
  try {
459
- cs._d = false;
460
- cs._v = getter();
679
+ retrack(() => {
680
+ cs._v = getter();
681
+ cs._d = false;
682
+ threw = false;
683
+ }, markDirty);
461
684
  } finally {
462
685
  evaluating = false;
686
+ if (threw) cs._d = true;
463
687
  }
464
688
  }
465
689
  return cs._v;
@@ -468,13 +692,17 @@ function derived(getter, options) {
468
692
  if (cs._d) {
469
693
  const oldValue = cs._v;
470
694
  evaluating = true;
695
+ let threw = true;
471
696
  try {
472
- track(() => {
697
+ retrack(() => {
698
+ const next = getter();
699
+ cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
473
700
  cs._d = false;
474
- cs._v = getter();
701
+ threw = false;
475
702
  }, markDirty);
476
703
  } finally {
477
704
  evaluating = false;
705
+ if (threw) cs._d = true;
478
706
  }
479
707
  if (hook && oldValue !== cs._v) {
480
708
  hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
@@ -501,12 +729,12 @@ function reduxAdapter(options) {
501
729
  setState(store.getState());
502
730
  });
503
731
  });
504
- function useSelector(selector) {
732
+ function select(selector) {
505
733
  return derived(() => selector(getState()));
506
734
  }
507
735
  const api = {
508
736
  getState,
509
- useSelector,
737
+ select,
510
738
  dispatch: store.dispatch.bind(store),
511
739
  destroy: unsubscribe
512
740
  };
@@ -524,12 +752,12 @@ function zustandAdapter(options) {
524
752
  setSibuState(state);
525
753
  });
526
754
  });
527
- function useSelector(selector) {
755
+ function select(selector) {
528
756
  return derived(() => selector(getState()));
529
757
  }
530
758
  const api = {
531
759
  getState,
532
- useSelector,
760
+ select,
533
761
  setState: store.setState.bind(store),
534
762
  destroy() {
535
763
  unsubscribe();
@@ -541,29 +769,79 @@ function zustandAdapter(options) {
541
769
  }
542
770
 
543
771
  // src/utils/sanitize.ts
772
+ var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
544
773
  function sanitizeUrl(url) {
545
774
  const trimmed = url.replace(/[\x00-\x20\x7f-\x9f]+/g, "").trim();
546
775
  if (!trimmed) return "";
547
776
  const lower = trimmed.toLowerCase();
548
- if (lower.startsWith("javascript:") || lower.startsWith("data:") || lower.startsWith("vbscript:") || lower.startsWith("blob:")) {
549
- return "";
777
+ let schemeEnd = -1;
778
+ for (let i = 0; i < lower.length; i++) {
779
+ const ch = lower.charCodeAt(i);
780
+ if (ch === 58) {
781
+ schemeEnd = i;
782
+ break;
783
+ }
784
+ if (ch === 47 || ch === 63 || ch === 35) break;
550
785
  }
786
+ if (schemeEnd === -1) return trimmed;
787
+ const scheme = lower.slice(0, schemeEnd + 1);
788
+ if (!/^[a-z][a-z0-9+.-]*:$/.test(scheme)) return trimmed;
789
+ if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
551
790
  return trimmed;
552
791
  }
792
+ function sanitizeSrcset(value) {
793
+ const parts = value.split(",");
794
+ const out = [];
795
+ for (let i = 0; i < parts.length; i++) {
796
+ const part = parts[i].trim();
797
+ if (!part) continue;
798
+ const m = part.match(/^(\S+)(\s+.+)?$/);
799
+ if (!m) continue;
800
+ const safe = sanitizeUrl(m[1]);
801
+ if (!safe) continue;
802
+ out.push(m[2] ? `${safe}${m[2]}` : safe);
803
+ }
804
+ return out.join(", ");
805
+ }
553
806
  function sanitizeCSSValue(value) {
554
- const lower = value.toLowerCase().replace(/\s+/g, "");
555
- if (lower.includes("url(") || lower.includes("expression(") || lower.includes("javascript:") || lower.includes("-moz-binding")) {
807
+ const decoded = value.replace(/\\([0-9a-fA-F]{1,6})\s?/g, (_m, hex) => {
808
+ const code = Number.parseInt(hex, 16);
809
+ if (!Number.isFinite(code) || code < 0 || code > 1114111) return "";
810
+ try {
811
+ return String.fromCodePoint(code);
812
+ } catch {
813
+ return "";
814
+ }
815
+ });
816
+ const lower = decoded.toLowerCase().replace(/\s+/g, "");
817
+ if (lower.includes("url(") || lower.includes("expression(") || lower.includes("javascript:") || lower.includes("vbscript:") || lower.includes("-moz-binding") || lower.includes("behavior:") || lower.includes("@import") || lower.includes("image-set(") || lower.includes("filter:progid")) {
556
818
  return "";
557
819
  }
558
820
  return value;
559
821
  }
560
- var URL_ATTRIBUTES = /* @__PURE__ */ new Set(["href", "src", "action", "formaction", "cite", "poster", "background", "srcset"]);
822
+ var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
823
+ "href",
824
+ "xlink:href",
825
+ "src",
826
+ "action",
827
+ "formaction",
828
+ "formtarget",
829
+ "cite",
830
+ "poster",
831
+ "background",
832
+ "srcset",
833
+ "ping",
834
+ "data"
835
+ ]);
561
836
  function isUrlAttribute(attr) {
562
837
  return URL_ATTRIBUTES.has(attr);
563
838
  }
564
839
 
565
840
  // src/reactivity/bindAttribute.ts
566
841
  var _isDev4 = isDev();
842
+ function setProp(el, key, val) {
843
+ el[key] = val;
844
+ }
567
845
  function isEventHandlerAttr(name) {
568
846
  if (name.length < 3) return false;
569
847
  const lower = name.toLowerCase();
@@ -589,7 +867,7 @@ function bindAttribute(el, attr, getter) {
589
867
  }
590
868
  if (typeof value === "boolean") {
591
869
  if (attr in el && (attr === "checked" || attr === "disabled" || attr === "selected")) {
592
- el[attr] = value;
870
+ setProp(el, attr, value);
593
871
  } else if (value) {
594
872
  el.setAttribute(attr, "");
595
873
  } else {
@@ -599,7 +877,7 @@ function bindAttribute(el, attr, getter) {
599
877
  }
600
878
  const str = String(value);
601
879
  if ((attr === "value" || attr === "checked") && attr in el) {
602
- el[attr] = attr === "checked" ? Boolean(value) : str;
880
+ setProp(el, attr, attr === "checked" ? Boolean(value) : str);
603
881
  } else {
604
882
  el.setAttribute(attr, isUrlAttribute(attr) ? sanitizeUrl(str) : str);
605
883
  }
@@ -636,24 +914,29 @@ function bindChildNode(placeholder, getter) {
636
914
  let newNodes;
637
915
  if (Array.isArray(result)) {
638
916
  newNodes = [];
917
+ const seen = /* @__PURE__ */ new Set();
639
918
  for (let i = 0; i < result.length; i++) {
640
919
  const item = result[i];
641
920
  if (item == null || typeof item === "boolean") continue;
642
- newNodes.push(item instanceof Node ? item : document.createTextNode(String(item)));
921
+ const node = item instanceof Node ? item : document.createTextNode(String(item));
922
+ if (seen.has(node)) {
923
+ if (_isDev5)
924
+ devWarn("bindChildNode: duplicate node reference in array \u2014 only the first occurrence is rendered.");
925
+ continue;
926
+ }
927
+ seen.add(node);
928
+ newNodes.push(node);
643
929
  }
644
930
  } else {
645
931
  const node = result instanceof Node ? result : document.createTextNode(String(result));
646
932
  newNodes = [node];
647
933
  }
648
- const reused = lastNodes.length > 0 && newNodes.length > 0 ? /* @__PURE__ */ new Set() : void 0;
649
- if (reused) {
934
+ let reused;
935
+ if (lastNodes.length > 0 && newNodes.length > 0) {
936
+ const lastSet = new Set(lastNodes);
937
+ reused = /* @__PURE__ */ new Set();
650
938
  for (let i = 0; i < newNodes.length; i++) {
651
- for (let j = 0; j < lastNodes.length; j++) {
652
- if (newNodes[i] === lastNodes[j]) {
653
- reused.add(newNodes[i]);
654
- break;
655
- }
656
- }
939
+ if (lastSet.has(newNodes[i])) reused.add(newNodes[i]);
657
940
  }
658
941
  }
659
942
  for (let i = 0; i < lastNodes.length; i++) {
@@ -692,6 +975,30 @@ function registerDisposer(node, teardown) {
692
975
  }
693
976
 
694
977
  // src/core/rendering/tagFactory.ts
978
+ var _isDev7 = isDev();
979
+ var BLOCKED_TAGS = /* @__PURE__ */ new Set(["script", "iframe", "object", "embed", "frame", "frameset"]);
980
+ function validateTagName(tag) {
981
+ const lower = tag.toLowerCase();
982
+ if (BLOCKED_TAGS.has(lower)) {
983
+ throw new Error(`tagFactory: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
984
+ }
985
+ }
986
+ var CLOBBER_RISKY_IDS = /* @__PURE__ */ new Set([
987
+ "config",
988
+ "location",
989
+ "history",
990
+ "document",
991
+ "window",
992
+ "navigator",
993
+ "name",
994
+ "top",
995
+ "parent",
996
+ "self",
997
+ "frames"
998
+ ]);
999
+ function setProp2(el, key, val) {
1000
+ el[key] = val;
1001
+ }
695
1002
  var kebabCache = /* @__PURE__ */ new Map();
696
1003
  function toKebab(prop) {
697
1004
  let cached = kebabCache.get(prop);
@@ -816,79 +1123,103 @@ function appendChildren(el, nodes) {
816
1123
  }
817
1124
  }
818
1125
  }
819
- var tagFactory = (tag, ns) => (first, second) => {
820
- const el = ns ? document.createElementNS(ns, tag) : document.createElement(tag);
821
- if (first === void 0) return el;
822
- if (typeof first === "string") {
823
- if (second !== void 0) {
824
- el.setAttribute("class", first);
825
- appendChildren(el, second);
1126
+ var tagFactory = (tag, ns) => {
1127
+ return (first, second) => {
1128
+ validateTagName(tag);
1129
+ const el = ns ? document.createElementNS(ns, tag) : document.createElement(tag);
1130
+ if (first === void 0) return el;
1131
+ if (typeof first === "string") {
1132
+ if (second !== void 0) {
1133
+ el.setAttribute("class", first);
1134
+ appendChildren(el, second);
1135
+ return el;
1136
+ }
1137
+ el.textContent = first;
826
1138
  return el;
827
1139
  }
828
- el.textContent = first;
829
- return el;
830
- }
831
- if (typeof first === "number") {
832
- el.textContent = String(first);
833
- return el;
834
- }
835
- if (Array.isArray(first) || first instanceof Node || typeof first === "function") {
836
- appendChildren(el, first);
837
- return el;
838
- }
839
- const props = first;
840
- const pClass = props.class;
841
- if (pClass != null) applyClass(el, pClass);
842
- const pId = props.id;
843
- if (pId != null) el.id = pId;
844
- const pNodes = second !== void 0 ? second : props.nodes;
845
- if (pNodes != null) appendChildren(el, pNodes);
846
- const pOn = props.on;
847
- if (pOn) {
848
- for (const ev in pOn) {
849
- el.addEventListener(ev, pOn[ev]);
1140
+ if (typeof first === "number") {
1141
+ el.textContent = String(first);
1142
+ return el;
850
1143
  }
851
- }
852
- const pStyle = props.style;
853
- if (pStyle != null) applyStyle(el, pStyle);
854
- const pRef = props.ref;
855
- if (pRef) pRef.current = el;
856
- for (const key in props) {
857
- switch (key) {
858
- case "class":
859
- case "id":
860
- case "nodes":
861
- case "on":
862
- case "style":
863
- case "ref":
864
- case "onElement":
865
- continue;
866
- // already handled above / below
867
- default: {
868
- const value = props[key];
869
- if (value == null) continue;
870
- if (key[0] === "o" && key[1] === "n") continue;
871
- if (typeof value === "function") {
872
- registerDisposer(el, bindAttribute(el, key, value));
873
- } else if (typeof value === "boolean") {
874
- if (key in el && (key === "checked" || key === "disabled" || key === "selected")) {
875
- el[key] = value;
876
- } else if (value) {
877
- el.setAttribute(key, "");
1144
+ if (Array.isArray(first) || first instanceof Node || typeof first === "function") {
1145
+ appendChildren(el, first);
1146
+ return el;
1147
+ }
1148
+ const props = first;
1149
+ const pClass = props.class;
1150
+ if (pClass != null) applyClass(el, pClass);
1151
+ const pId = props.id;
1152
+ if (pId != null) {
1153
+ if (_isDev7 && typeof pId === "string" && CLOBBER_RISKY_IDS.has(pId.toLowerCase())) {
1154
+ devWarn(
1155
+ `tagFactory: element id="${pId}" matches a common global and may cause DOM clobbering. Avoid setting ids from untrusted input.`
1156
+ );
1157
+ }
1158
+ el.id = pId;
1159
+ }
1160
+ const pNodes = second !== void 0 ? second : props.nodes;
1161
+ if (pNodes != null) appendChildren(el, pNodes);
1162
+ const pOn = props.on;
1163
+ if (pOn) {
1164
+ for (const ev in pOn) {
1165
+ const handler = pOn[ev];
1166
+ if (typeof handler === "function") {
1167
+ el.addEventListener(ev, handler);
1168
+ } else if (_isDev7) {
1169
+ devWarn(
1170
+ `tagFactory: on.${ev} handler is not a function (got ${typeof handler}). Event listener was not attached.`
1171
+ );
1172
+ }
1173
+ }
1174
+ }
1175
+ const pStyle = props.style;
1176
+ if (pStyle != null) applyStyle(el, pStyle);
1177
+ const pRef = props.ref;
1178
+ if (pRef) pRef.current = el;
1179
+ for (const key in props) {
1180
+ switch (key) {
1181
+ case "class":
1182
+ case "id":
1183
+ case "nodes":
1184
+ case "on":
1185
+ case "style":
1186
+ case "ref":
1187
+ case "onElement":
1188
+ continue;
1189
+ // already handled above / below
1190
+ default: {
1191
+ const value = props[key];
1192
+ if (value == null) continue;
1193
+ const lkey = key.toLowerCase();
1194
+ if (lkey[0] === "o" && lkey[1] === "n") continue;
1195
+ if (typeof value === "function") {
1196
+ registerDisposer(el, bindAttribute(el, key, value));
1197
+ } else if (typeof value === "boolean") {
1198
+ if (key in el && (key === "checked" || key === "disabled" || key === "selected")) {
1199
+ setProp2(el, key, value);
1200
+ } else if (value) {
1201
+ el.setAttribute(key, "");
1202
+ } else {
1203
+ el.removeAttribute(key);
1204
+ }
878
1205
  } else {
879
- el.removeAttribute(key);
1206
+ const str = String(value);
1207
+ if (lkey === "srcset") {
1208
+ el.setAttribute(key, sanitizeSrcset(str));
1209
+ } else if (isUrlAttribute(lkey)) {
1210
+ el.setAttribute(key, sanitizeUrl(str));
1211
+ } else {
1212
+ el.setAttribute(key, str);
1213
+ }
880
1214
  }
881
- } else {
882
- const str = String(value);
883
- el.setAttribute(key, isUrlAttribute(key) ? sanitizeUrl(str) : str);
884
1215
  }
885
1216
  }
886
1217
  }
887
- }
888
- if (props.onElement && typeof props.onElement === "function") {
889
- props.onElement(el);
890
- }
891
- return el;
1218
+ if (props.onElement && typeof props.onElement === "function") {
1219
+ props.onElement(el);
1220
+ }
1221
+ return el;
1222
+ };
892
1223
  };
893
1224
 
894
1225
  // src/ecosystem/ui/componentAdapter.ts