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
package/dist/ui.cjs CHANGED
@@ -23,6 +23,7 @@ __export(ui_exports, {
23
23
  FocusTrap: () => FocusTrap,
24
24
  RenderProp: () => RenderProp,
25
25
  VirtualList: () => VirtualList,
26
+ __resetDialogStack: () => __resetDialogStack,
26
27
  announce: () => announce,
27
28
  aria: () => aria,
28
29
  assertType: () => assertType,
@@ -91,12 +92,12 @@ function isDev() {
91
92
  var _isDev = isDev();
92
93
  function devAssert(condition, message) {
93
94
  if (_isDev && !condition) {
94
- throw new Error(`[Sibu] ${message}`);
95
+ throw new Error(`[SibuJS] ${message}`);
95
96
  }
96
97
  }
97
98
  function devWarn(message) {
98
99
  if (_isDev) {
99
- console.warn(`[Sibu] ${message}`);
100
+ console.warn(`[SibuJS] ${message}`);
100
101
  }
101
102
  }
102
103
 
@@ -106,11 +107,11 @@ var subscriberStack = new Array(32);
106
107
  var stackCapacity = 32;
107
108
  var stackTop = -1;
108
109
  var currentSubscriber = null;
109
- var signalSubscribers = /* @__PURE__ */ new WeakMap();
110
110
  var SUBS = "__s";
111
111
  var notifyDepth = 0;
112
112
  var pendingQueue = [];
113
113
  var pendingSet = /* @__PURE__ */ new Set();
114
+ var propagateStack = [];
114
115
  function safeInvoke(sub) {
115
116
  try {
116
117
  sub();
@@ -119,6 +120,15 @@ function safeInvoke(sub) {
119
120
  }
120
121
  }
121
122
  var trackingSuspended = false;
123
+ function retrack(effectFn, subscriber) {
124
+ const prev = currentSubscriber;
125
+ currentSubscriber = subscriber;
126
+ try {
127
+ effectFn();
128
+ } finally {
129
+ currentSubscriber = prev;
130
+ }
131
+ }
122
132
  function track(effectFn, subscriber) {
123
133
  if (!subscriber) subscriber = effectFn;
124
134
  cleanup(subscriber);
@@ -157,7 +167,6 @@ function recordDependency(signal2) {
157
167
  let subs = signal2[SUBS];
158
168
  if (!subs) {
159
169
  subs = /* @__PURE__ */ new Set();
160
- signalSubscribers.set(signal2, subs);
161
170
  signal2[SUBS] = subs;
162
171
  }
163
172
  subs.add(currentSubscriber);
@@ -167,42 +176,46 @@ function recordDependency(signal2) {
167
176
  signal2.__f = void 0;
168
177
  }
169
178
  }
179
+ var maxDrainIterations = 1e5;
170
180
  function propagateDirty(sub) {
171
181
  sub();
172
- let sig = sub._sig;
173
- while (sig) {
182
+ const rootSig = sub._sig;
183
+ if (!rootSig) return;
184
+ const stack = propagateStack;
185
+ const baseLen = stack.length;
186
+ stack.push(rootSig);
187
+ while (stack.length > baseLen) {
188
+ const sig = stack.pop();
174
189
  const first = sig.__f;
175
190
  if (first) {
176
191
  if (first._c) {
177
192
  const nSig = first._sig;
178
- nSig._d = true;
179
- sig = nSig;
180
- continue;
181
- }
182
- if (!pendingSet.has(first)) {
193
+ if (!nSig._d) {
194
+ nSig._d = true;
195
+ stack.push(nSig);
196
+ }
197
+ } else if (!pendingSet.has(first)) {
183
198
  pendingSet.add(first);
184
199
  pendingQueue.push(first);
185
200
  }
186
- break;
201
+ continue;
187
202
  }
188
203
  const subs = sig[SUBS];
189
- if (!subs) break;
190
- let nextSig;
204
+ if (!subs) continue;
191
205
  for (const s of subs) {
192
206
  if (s._c) {
193
- s();
194
207
  const nSig = s._sig;
195
- if (nSig && !nextSig) {
196
- nextSig = nSig;
197
- } else if (nSig) {
198
- propagateDirty(s);
208
+ if (nSig && !nSig._d) {
209
+ nSig._d = true;
210
+ stack.push(nSig);
211
+ } else if (!nSig) {
212
+ s();
199
213
  }
200
214
  } else if (!pendingSet.has(s)) {
201
215
  pendingSet.add(s);
202
216
  pendingQueue.push(s);
203
217
  }
204
218
  }
205
- sig = nextSig;
206
219
  }
207
220
  }
208
221
  function notifySubscribers(signal2) {
@@ -226,13 +239,23 @@ function notifySubscribers(signal2) {
226
239
  }
227
240
  let i = 0;
228
241
  while (i < pendingQueue.length) {
242
+ if (i >= maxDrainIterations) {
243
+ if (typeof console !== "undefined") {
244
+ console.error(
245
+ `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
246
+ );
247
+ }
248
+ break;
249
+ }
229
250
  safeInvoke(pendingQueue[i]);
230
251
  i++;
231
252
  }
232
253
  } finally {
233
- pendingQueue.length = 0;
234
- pendingSet.clear();
235
254
  notifyDepth--;
255
+ if (notifyDepth === 0) {
256
+ pendingQueue.length = 0;
257
+ pendingSet.clear();
258
+ }
236
259
  }
237
260
  return;
238
261
  }
@@ -252,30 +275,48 @@ function notifySubscribers(signal2) {
252
275
  notifyDepth++;
253
276
  try {
254
277
  let directCount = 0;
278
+ let hasComputedSub = false;
255
279
  for (const sub of subs) {
280
+ if (sub._c) hasComputedSub = true;
256
281
  pendingQueue[directCount++] = sub;
257
282
  }
258
- for (let i2 = 0; i2 < directCount; i2++) {
259
- if (pendingQueue[i2]._c) {
260
- propagateDirty(pendingQueue[i2]);
283
+ if (!hasComputedSub) {
284
+ for (let i2 = 0; i2 < directCount; i2++) {
285
+ safeInvoke(pendingQueue[i2]);
261
286
  }
262
- }
263
- for (let i2 = 0; i2 < directCount; i2++) {
264
- if (!pendingQueue[i2]._c) {
265
- if (!pendingSet.has(pendingQueue[i2])) {
266
- safeInvoke(pendingQueue[i2]);
287
+ } else {
288
+ for (let i2 = 0; i2 < directCount; i2++) {
289
+ if (pendingQueue[i2]._c) {
290
+ propagateDirty(pendingQueue[i2]);
291
+ }
292
+ }
293
+ for (let i2 = 0; i2 < directCount; i2++) {
294
+ const sub = pendingQueue[i2];
295
+ if (!sub._c && !pendingSet.has(sub)) {
296
+ pendingSet.add(sub);
297
+ safeInvoke(sub);
267
298
  }
268
299
  }
269
300
  }
270
301
  let i = directCount;
271
302
  while (i < pendingQueue.length) {
303
+ if (i - directCount >= maxDrainIterations) {
304
+ if (typeof console !== "undefined") {
305
+ console.error(
306
+ `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
307
+ );
308
+ }
309
+ break;
310
+ }
272
311
  safeInvoke(pendingQueue[i]);
273
312
  i++;
274
313
  }
275
314
  } finally {
276
- pendingQueue.length = 0;
277
- pendingSet.clear();
278
315
  notifyDepth--;
316
+ if (notifyDepth === 0) {
317
+ pendingQueue.length = 0;
318
+ pendingSet.clear();
319
+ }
279
320
  }
280
321
  }
281
322
  function cleanup(subscriber) {
@@ -286,7 +327,9 @@ function cleanup(subscriber) {
286
327
  if (subs) {
287
328
  subs.delete(subscriber);
288
329
  if (singleDep.__f === subscriber) {
289
- singleDep.__f = void 0;
330
+ singleDep.__f = subs.size === 1 ? subs.values().next().value : void 0;
331
+ } else if (subs.size === 1 && singleDep.__f === void 0) {
332
+ singleDep.__f = subs.values().next().value;
290
333
  }
291
334
  }
292
335
  sub._dep = void 0;
@@ -299,7 +342,9 @@ function cleanup(subscriber) {
299
342
  if (subs) {
300
343
  subs.delete(subscriber);
301
344
  if (signal2.__f === subscriber) {
302
- signal2.__f = void 0;
345
+ signal2.__f = subs.size === 1 ? subs.values().next().value : void 0;
346
+ } else if (subs.size === 1 && signal2.__f === void 0) {
347
+ signal2.__f = subs.values().next().value;
303
348
  }
304
349
  }
305
350
  }
@@ -310,6 +355,7 @@ function cleanup(subscriber) {
310
355
  function derived(getter, options) {
311
356
  devAssert(typeof getter === "function", "derived: argument must be a getter function.");
312
357
  const debugName = options?.name;
358
+ const equals = options?.equals;
313
359
  const cs = {};
314
360
  cs._d = false;
315
361
  cs._g = getter;
@@ -320,8 +366,14 @@ function derived(getter, options) {
320
366
  markDirty._c = 1;
321
367
  markDirty._sig = cs;
322
368
  track(() => {
323
- cs._d = false;
324
- cs._v = getter();
369
+ let threw = true;
370
+ try {
371
+ cs._v = getter();
372
+ cs._d = false;
373
+ threw = false;
374
+ } finally {
375
+ if (threw) cs._d = true;
376
+ }
325
377
  }, markDirty);
326
378
  const hook = globalThis.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
327
379
  let evaluating = false;
@@ -334,11 +386,16 @@ function derived(getter, options) {
334
386
  if (trackingSuspended) {
335
387
  if (cs._d) {
336
388
  evaluating = true;
389
+ let threw = true;
337
390
  try {
338
- cs._d = false;
339
- cs._v = getter();
391
+ retrack(() => {
392
+ cs._v = getter();
393
+ cs._d = false;
394
+ threw = false;
395
+ }, markDirty);
340
396
  } finally {
341
397
  evaluating = false;
398
+ if (threw) cs._d = true;
342
399
  }
343
400
  }
344
401
  return cs._v;
@@ -347,13 +404,17 @@ function derived(getter, options) {
347
404
  if (cs._d) {
348
405
  const oldValue = cs._v;
349
406
  evaluating = true;
407
+ let threw = true;
350
408
  try {
351
- track(() => {
409
+ retrack(() => {
410
+ const next = getter();
411
+ cs._v = equals && cs._v !== void 0 ? equals(cs._v, next) ? cs._v : next : next;
352
412
  cs._d = false;
353
- cs._v = getter();
413
+ threw = false;
354
414
  }, markDirty);
355
415
  } finally {
356
416
  evaluating = false;
417
+ if (threw) cs._d = true;
357
418
  }
358
419
  if (hook && oldValue !== cs._v) {
359
420
  hook.emit("computed:update", { signal: cs, oldValue, newValue: cs._v });
@@ -518,9 +579,18 @@ function form(config) {
518
579
  }
519
580
  return null;
520
581
  });
582
+ const wrappedSet = (next) => {
583
+ setValue(next);
584
+ setManualErrors((prev) => {
585
+ if (!(name in prev) || prev[name] == null) return prev;
586
+ const copy = { ...prev };
587
+ copy[name] = null;
588
+ return copy;
589
+ });
590
+ };
521
591
  fieldMap[name] = {
522
592
  value,
523
- set: setValue,
593
+ set: wrappedSet,
524
594
  error,
525
595
  touched: isTouched,
526
596
  touch: () => setTouched(true),
@@ -654,11 +724,77 @@ function registerDisposer(node, teardown) {
654
724
  disposers.push(teardown);
655
725
  if (_isDev4) activeBindingCount++;
656
726
  }
727
+ function dispose(node) {
728
+ const stack = [node];
729
+ const order = [];
730
+ while (stack.length > 0) {
731
+ const current = stack.pop();
732
+ order.push(current);
733
+ const children = Array.from(current.childNodes);
734
+ for (let i = 0; i < children.length; i++) {
735
+ stack.push(children[i]);
736
+ }
737
+ }
738
+ for (let i = order.length - 1; i >= 0; i--) {
739
+ const current = order[i];
740
+ const disposers = elementDisposers.get(current);
741
+ if (disposers) {
742
+ const snapshot = disposers.slice();
743
+ elementDisposers.delete(current);
744
+ if (_isDev4) activeBindingCount -= snapshot.length;
745
+ for (const d of snapshot) {
746
+ try {
747
+ d();
748
+ } catch (err) {
749
+ if (_isDev4 && typeof console !== "undefined") {
750
+ console.warn("[SibuJS] Disposer threw during cleanup:", err);
751
+ }
752
+ }
753
+ }
754
+ let extraPasses = 0;
755
+ while (extraPasses++ < 8) {
756
+ const added = elementDisposers.get(current);
757
+ if (!added || added.length === 0) break;
758
+ const moreSnapshot = added.slice();
759
+ elementDisposers.delete(current);
760
+ if (_isDev4) activeBindingCount -= moreSnapshot.length;
761
+ for (const d of moreSnapshot) {
762
+ try {
763
+ d();
764
+ } catch (err) {
765
+ if (_isDev4 && typeof console !== "undefined") {
766
+ console.warn("[SibuJS] Disposer threw during cleanup:", err);
767
+ }
768
+ }
769
+ }
770
+ }
771
+ }
772
+ }
773
+ }
657
774
 
658
775
  // src/core/ssr-context.ts
659
- var ssrMode = false;
776
+ var als = null;
777
+ try {
778
+ if (typeof process !== "undefined" && process.versions && process.versions.node) {
779
+ const req = Function("return typeof require==='function'?require:null")();
780
+ if (req) {
781
+ const mod = req("node:async_hooks");
782
+ als = new mod.AsyncLocalStorage();
783
+ }
784
+ }
785
+ } catch {
786
+ als = null;
787
+ }
788
+ var fallbackStore = { ssr: false, suspenseIdCounter: 0 };
789
+ function getSSRStore() {
790
+ if (als) {
791
+ const s = als.getStore();
792
+ if (s) return s;
793
+ }
794
+ return fallbackStore;
795
+ }
660
796
  function isSSR() {
661
- return ssrMode;
797
+ return getSSRStore().ssr;
662
798
  }
663
799
 
664
800
  // src/core/signals/effect.ts
@@ -668,26 +804,86 @@ function effect(effectFn, options) {
668
804
  if (isSSR()) return () => {
669
805
  };
670
806
  const onError = options?.onError;
807
+ let userCleanups = [];
808
+ const onCleanup = (fn) => {
809
+ userCleanups.push(fn);
810
+ };
811
+ const runUserCleanups = () => {
812
+ if (userCleanups.length === 0) return;
813
+ const list = userCleanups;
814
+ userCleanups = [];
815
+ for (let i = list.length - 1; i >= 0; i--) {
816
+ try {
817
+ list[i]();
818
+ } catch (err) {
819
+ if (typeof console !== "undefined") {
820
+ console.warn("[SibuJS effect] onCleanup threw:", err);
821
+ }
822
+ }
823
+ }
824
+ };
825
+ const invokeBody = () => effectFn(onCleanup);
671
826
  const wrappedFn = onError ? () => {
672
827
  try {
673
- effectFn();
828
+ invokeBody();
674
829
  } catch (err) {
675
830
  onError(err);
676
831
  }
677
- } : effectFn;
832
+ } : invokeBody;
678
833
  let cleanupHandle = () => {
679
834
  };
835
+ let running = false;
680
836
  const subscriber = () => {
681
- cleanupHandle();
682
- cleanupHandle = track(wrappedFn, subscriber);
837
+ if (running) {
838
+ if (_g2.__SIBU_DEV_WARN__ !== false && typeof console !== "undefined") {
839
+ console.warn(
840
+ "[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."
841
+ );
842
+ }
843
+ return;
844
+ }
845
+ running = true;
846
+ try {
847
+ runUserCleanups();
848
+ cleanupHandle();
849
+ cleanupHandle = track(wrappedFn, subscriber);
850
+ } finally {
851
+ running = false;
852
+ }
683
853
  };
684
- cleanupHandle = track(wrappedFn, subscriber);
854
+ running = true;
855
+ try {
856
+ cleanupHandle = track(wrappedFn, subscriber);
857
+ } finally {
858
+ running = false;
859
+ }
685
860
  const hook = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
686
861
  if (hook) hook.emit("effect:create", { effectFn });
862
+ let disposed = false;
687
863
  return () => {
864
+ if (disposed) return;
865
+ disposed = true;
688
866
  const h = _g2.__SIBU_DEVTOOLS_GLOBAL_HOOK__;
689
- if (h) h.emit("effect:destroy", { effectFn });
690
- cleanupHandle();
867
+ if (h) {
868
+ try {
869
+ h.emit("effect:destroy", { effectFn });
870
+ } catch {
871
+ }
872
+ }
873
+ try {
874
+ runUserCleanups();
875
+ } catch (err) {
876
+ if (typeof console !== "undefined") {
877
+ console.warn("[SibuJS effect] onCleanup threw during dispose:", err);
878
+ }
879
+ }
880
+ try {
881
+ cleanupHandle();
882
+ } catch (err) {
883
+ if (typeof console !== "undefined") {
884
+ console.warn("[SibuJS effect] dispose threw:", err);
885
+ }
886
+ }
691
887
  };
692
888
  }
693
889
 
@@ -739,6 +935,7 @@ function intersection(options) {
739
935
  let observer = null;
740
936
  let currentElement = null;
741
937
  function observe(element) {
938
+ if (typeof IntersectionObserver === "undefined") return;
742
939
  unobserve();
743
940
  currentElement = element;
744
941
  observer = new IntersectionObserver((entries) => {
@@ -766,6 +963,11 @@ function intersection(options) {
766
963
  };
767
964
  }
768
965
  function lazyLoad(element, loader, options) {
966
+ if (typeof IntersectionObserver === "undefined") {
967
+ loader();
968
+ return () => {
969
+ };
970
+ }
769
971
  const observer = new IntersectionObserver((entries) => {
770
972
  for (const entry of entries) {
771
973
  if (entry.isIntersecting) {
@@ -840,7 +1042,7 @@ function inputMask(options) {
840
1042
  const stripRegex = buildStripRegex();
841
1043
  const rawCharTest = options.pattern.includes("*") ? () => true : (c) => /[a-zA-Z0-9]/.test(c);
842
1044
  function bind(input) {
843
- input.addEventListener("input", () => {
1045
+ const onInput = () => {
844
1046
  const cursorBefore = input.selectionStart ?? input.value.length;
845
1047
  const oldValue = input.value;
846
1048
  const raw = oldValue.replace(stripRegex, "");
@@ -864,13 +1066,19 @@ function inputMask(options) {
864
1066
  }
865
1067
  }
866
1068
  input.setSelectionRange(newCursor, newCursor);
867
- });
868
- input.addEventListener("focus", () => {
1069
+ };
1070
+ const onFocus = () => {
869
1071
  if (!input.value) {
870
1072
  const display = options.pattern.replace(/9/g, placeholder).replace(/A/g, placeholder).replace(/\*/g, placeholder);
871
1073
  input.placeholder = display;
872
1074
  }
873
- });
1075
+ };
1076
+ input.addEventListener("input", onInput);
1077
+ input.addEventListener("focus", onFocus);
1078
+ return () => {
1079
+ input.removeEventListener("input", onInput);
1080
+ input.removeEventListener("focus", onFocus);
1081
+ };
874
1082
  }
875
1083
  return { value, rawValue, bind };
876
1084
  }
@@ -912,8 +1120,20 @@ function focus() {
912
1120
  let currentElement = null;
913
1121
  function bind(element) {
914
1122
  currentElement = element;
915
- element.addEventListener("focus", () => setIsFocused(true));
916
- element.addEventListener("blur", () => setIsFocused(false));
1123
+ const onFocus = () => setIsFocused(true);
1124
+ const onBlur = () => setIsFocused(false);
1125
+ element.addEventListener("focus", onFocus);
1126
+ element.addEventListener("blur", onBlur);
1127
+ let disposed = false;
1128
+ const dispose2 = () => {
1129
+ if (disposed) return;
1130
+ disposed = true;
1131
+ element.removeEventListener("focus", onFocus);
1132
+ element.removeEventListener("blur", onBlur);
1133
+ if (currentElement === element) currentElement = null;
1134
+ };
1135
+ registerDisposer(element, dispose2);
1136
+ return dispose2;
917
1137
  }
918
1138
  function focus2() {
919
1139
  currentElement?.focus();
@@ -928,11 +1148,35 @@ function FocusTrap(nodes, options = {}) {
928
1148
  container.setAttribute("data-sibu-focus-trap", "true");
929
1149
  container.appendChild(nodes);
930
1150
  const previouslyFocused = document.activeElement;
931
- container.addEventListener("keydown", (e) => {
1151
+ const FOCUSABLE_SELECTOR = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"]), [contenteditable]';
1152
+ function isEffectivelyVisible(el) {
1153
+ let node = el;
1154
+ while (node) {
1155
+ if (node.hasAttribute("inert")) return false;
1156
+ if (node.getAttribute("aria-hidden") === "true") return false;
1157
+ if (node.hidden) return false;
1158
+ node = node.parentElement;
1159
+ }
1160
+ if (el.offsetParent === null && el.getClientRects().length === 0) return false;
1161
+ return true;
1162
+ }
1163
+ function getFocusable() {
1164
+ const raw = Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR));
1165
+ const out = [];
1166
+ for (const el of raw) {
1167
+ if (el.hasAttribute("disabled")) continue;
1168
+ if (el.getAttribute("aria-hidden") === "true") continue;
1169
+ if (el.hasAttribute("inert")) continue;
1170
+ const ce = el.getAttribute("contenteditable");
1171
+ if (ce !== null && ce === "false") continue;
1172
+ if (!isEffectivelyVisible(el)) continue;
1173
+ out.push(el);
1174
+ }
1175
+ return out;
1176
+ }
1177
+ const onTrapKeydown = (e) => {
932
1178
  if (e.key !== "Tab") return;
933
- const focusable = container.querySelectorAll(
934
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
935
- );
1179
+ const focusable = getFocusable();
936
1180
  if (focusable.length === 0) {
937
1181
  e.preventDefault();
938
1182
  return;
@@ -950,18 +1194,18 @@ function FocusTrap(nodes, options = {}) {
950
1194
  first.focus();
951
1195
  }
952
1196
  }
953
- });
1197
+ };
1198
+ container.addEventListener("keydown", onTrapKeydown);
954
1199
  if (options.autoFocus !== false) {
955
1200
  queueMicrotask(() => {
956
- const first = container.querySelector(
957
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
958
- );
1201
+ const first = getFocusable()[0];
959
1202
  first?.focus();
960
1203
  });
961
1204
  }
962
1205
  let trapObserver = null;
963
1206
  function restoreFocusAndCleanup() {
964
1207
  if (options.restoreFocus !== false) previouslyFocused?.focus();
1208
+ container.removeEventListener("keydown", onTrapKeydown);
965
1209
  if (trapObserver) {
966
1210
  trapObserver.disconnect();
967
1211
  trapObserver = null;
@@ -975,7 +1219,7 @@ function FocusTrap(nodes, options = {}) {
975
1219
  });
976
1220
  queueMicrotask(() => {
977
1221
  if (container.isConnected) {
978
- trapObserver.observe(document.body, { childList: true, subtree: true });
1222
+ trapObserver.observe(container, { childList: true, subtree: true });
979
1223
  }
980
1224
  });
981
1225
  }
@@ -1012,7 +1256,16 @@ function hotkey(combo, handler, options = {}) {
1012
1256
  document.addEventListener("keydown", listener);
1013
1257
  return () => document.removeEventListener("keydown", listener);
1014
1258
  }
1015
- function announce(message, priority = "polite") {
1259
+ var announceQueues = {
1260
+ polite: [],
1261
+ assertive: []
1262
+ };
1263
+ var announceDraining = {
1264
+ polite: false,
1265
+ assertive: false
1266
+ };
1267
+ var ANNOUNCE_INTERVAL_MS = 150;
1268
+ function ensureLiveRegion(priority) {
1016
1269
  let region = document.getElementById(`sibu-announce-${priority}`);
1017
1270
  if (!region) {
1018
1271
  region = document.createElement("div");
@@ -1023,11 +1276,33 @@ function announce(message, priority = "polite") {
1023
1276
  region.style.cssText = "position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;";
1024
1277
  document.body.appendChild(region);
1025
1278
  }
1279
+ return region;
1280
+ }
1281
+ function drainAnnounceQueue(priority) {
1282
+ if (announceDraining[priority]) return;
1283
+ const queue = announceQueues[priority];
1284
+ if (queue.length === 0) return;
1285
+ announceDraining[priority] = true;
1286
+ const region = ensureLiveRegion(priority);
1287
+ const next = queue.shift();
1026
1288
  region.textContent = "";
1027
1289
  requestAnimationFrame(() => {
1028
- if (region) region.textContent = message;
1290
+ if (!region.isConnected) {
1291
+ announceDraining[priority] = false;
1292
+ return;
1293
+ }
1294
+ region.textContent = next;
1295
+ setTimeout(() => {
1296
+ announceDraining[priority] = false;
1297
+ drainAnnounceQueue(priority);
1298
+ }, ANNOUNCE_INTERVAL_MS);
1029
1299
  });
1030
1300
  }
1301
+ function announce(message, priority = "polite") {
1302
+ if (typeof document === "undefined") return;
1303
+ announceQueues[priority].push(message);
1304
+ drainAnnounceQueue(priority);
1305
+ }
1031
1306
 
1032
1307
  // src/core/rendering/createId.ts
1033
1308
  var idCounter = 0;
@@ -1121,22 +1396,22 @@ function createListbox(container, options = {}) {
1121
1396
  }
1122
1397
  }
1123
1398
  function select(value) {
1399
+ const previous = selectedValue();
1400
+ let nextSelectedSet;
1124
1401
  if (multiple) {
1125
- const current2 = selectedValue();
1126
- const set = new Set((current2 ?? "").split(",").filter(Boolean));
1127
- if (set.has(value)) set.delete(value);
1128
- else set.add(value);
1129
- setSelectedValue(Array.from(set).join(","));
1402
+ nextSelectedSet = new Set((previous ?? "").split(",").filter(Boolean));
1403
+ if (nextSelectedSet.has(value)) nextSelectedSet.delete(value);
1404
+ else nextSelectedSet.add(value);
1405
+ setSelectedValue(Array.from(nextSelectedSet).join(","));
1130
1406
  } else {
1407
+ nextSelectedSet = /* @__PURE__ */ new Set([value]);
1131
1408
  setSelectedValue(value);
1132
1409
  }
1133
1410
  options.onSelect?.(value);
1134
1411
  const opts = getOptions();
1135
- const current = selectedValue();
1136
- const selected = new Set((current ?? "").split(",").filter(Boolean));
1137
1412
  for (const opt of opts) {
1138
1413
  const ov = opt.dataset.value ?? "";
1139
- opt.setAttribute("aria-selected", selected.has(ov) ? "true" : "false");
1414
+ opt.setAttribute("aria-selected", nextSelectedSet.has(ov) ? "true" : "false");
1140
1415
  }
1141
1416
  }
1142
1417
  function moveActive(delta) {
@@ -1194,12 +1469,12 @@ function createListbox(container, options = {}) {
1194
1469
  }
1195
1470
  container.addEventListener("keydown", onKeyDown);
1196
1471
  container.addEventListener("click", onClick);
1197
- function dispose() {
1472
+ function dispose2() {
1198
1473
  container.removeEventListener("keydown", onKeyDown);
1199
1474
  container.removeEventListener("click", onClick);
1200
1475
  }
1201
- registerDisposer(container, dispose);
1202
- return { activeValue, selectedValue, activeDescendantId, dispose };
1476
+ registerDisposer(container, dispose2);
1477
+ return { activeValue, selectedValue, activeDescendantId, dispose: dispose2 };
1203
1478
  }
1204
1479
  function createDialogAria(element, options = {}) {
1205
1480
  const titleId = options.labelledBy ?? createId("dialog-title");
@@ -1287,22 +1562,49 @@ function removeScopedStyle(scopeId) {
1287
1562
  }
1288
1563
 
1289
1564
  // src/utils/sanitize.ts
1565
+ var SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:", "ftp:"];
1290
1566
  function sanitizeUrl(url) {
1291
1567
  const trimmed = url.replace(/[\x00-\x20\x7f-\x9f]+/g, "").trim();
1292
1568
  if (!trimmed) return "";
1293
1569
  const lower = trimmed.toLowerCase();
1294
- if (lower.startsWith("javascript:") || lower.startsWith("data:") || lower.startsWith("vbscript:") || lower.startsWith("blob:")) {
1295
- return "";
1570
+ let schemeEnd = -1;
1571
+ for (let i = 0; i < lower.length; i++) {
1572
+ const ch = lower.charCodeAt(i);
1573
+ if (ch === 58) {
1574
+ schemeEnd = i;
1575
+ break;
1576
+ }
1577
+ if (ch === 47 || ch === 63 || ch === 35) break;
1296
1578
  }
1579
+ if (schemeEnd === -1) return trimmed;
1580
+ const scheme = lower.slice(0, schemeEnd + 1);
1581
+ if (!/^[a-z][a-z0-9+.-]*:$/.test(scheme)) return trimmed;
1582
+ if (SAFE_URL_PROTOCOLS.indexOf(scheme) === -1) return "";
1297
1583
  return trimmed;
1298
1584
  }
1299
- var URL_ATTRIBUTES = /* @__PURE__ */ new Set(["href", "src", "action", "formaction", "cite", "poster", "background", "srcset"]);
1585
+ var URL_ATTRIBUTES = /* @__PURE__ */ new Set([
1586
+ "href",
1587
+ "xlink:href",
1588
+ "src",
1589
+ "action",
1590
+ "formaction",
1591
+ "formtarget",
1592
+ "cite",
1593
+ "poster",
1594
+ "background",
1595
+ "srcset",
1596
+ "ping",
1597
+ "data"
1598
+ ]);
1300
1599
  function isUrlAttribute(attr) {
1301
1600
  return URL_ATTRIBUTES.has(attr);
1302
1601
  }
1303
1602
 
1304
1603
  // src/reactivity/bindAttribute.ts
1305
1604
  var _isDev5 = isDev();
1605
+ function setProp(el, key, val) {
1606
+ el[key] = val;
1607
+ }
1306
1608
  function isEventHandlerAttr(name) {
1307
1609
  if (name.length < 3) return false;
1308
1610
  const lower = name.toLowerCase();
@@ -1328,7 +1630,7 @@ function bindAttribute(el, attr, getter) {
1328
1630
  }
1329
1631
  if (typeof value === "boolean") {
1330
1632
  if (attr in el && (attr === "checked" || attr === "disabled" || attr === "selected")) {
1331
- el[attr] = value;
1633
+ setProp(el, attr, value);
1332
1634
  } else if (value) {
1333
1635
  el.setAttribute(attr, "");
1334
1636
  } else {
@@ -1338,7 +1640,7 @@ function bindAttribute(el, attr, getter) {
1338
1640
  }
1339
1641
  const str = String(value);
1340
1642
  if ((attr === "value" || attr === "checked") && attr in el) {
1341
- el[attr] = attr === "checked" ? Boolean(value) : str;
1643
+ setProp(el, attr, attr === "checked" ? Boolean(value) : str);
1342
1644
  } else {
1343
1645
  el.setAttribute(attr, isUrlAttribute(attr) ? sanitizeUrl(str) : str);
1344
1646
  }
@@ -1408,66 +1710,91 @@ function bindData(el, key, getter) {
1408
1710
  }
1409
1711
 
1410
1712
  // src/ui/dialog.ts
1713
+ var dialogStack = [];
1714
+ var globalListenerAttached = false;
1715
+ function __resetDialogStack() {
1716
+ while (dialogStack.length > 0) dialogStack.pop();
1717
+ if (typeof window !== "undefined" && globalListenerAttached) {
1718
+ window.removeEventListener("keydown", handleGlobalKeydown);
1719
+ globalListenerAttached = false;
1720
+ }
1721
+ }
1722
+ function handleGlobalKeydown(event) {
1723
+ if (event.key !== "Escape") return;
1724
+ const top = dialogStack[dialogStack.length - 1];
1725
+ if (top) top.close();
1726
+ }
1727
+ function ensureGlobalListener() {
1728
+ if (typeof window === "undefined" || globalListenerAttached) return;
1729
+ window.addEventListener("keydown", handleGlobalKeydown);
1730
+ globalListenerAttached = true;
1731
+ }
1732
+ function removeGlobalListenerIfIdle() {
1733
+ if (typeof window === "undefined") return;
1734
+ if (!globalListenerAttached) return;
1735
+ if (dialogStack.length > 0) return;
1736
+ window.removeEventListener("keydown", handleGlobalKeydown);
1737
+ globalListenerAttached = false;
1738
+ }
1411
1739
  function dialog() {
1412
1740
  const [isOpen, setIsOpen] = signal(false);
1413
- let listenerAttached = false;
1414
- function handleKeydown(event) {
1415
- if (event.key === "Escape") {
1416
- close();
1417
- }
1418
- }
1419
- function attachListener() {
1420
- if (typeof window !== "undefined" && !listenerAttached) {
1421
- window.addEventListener("keydown", handleKeydown);
1422
- listenerAttached = true;
1423
- }
1741
+ const entry = { close: () => close() };
1742
+ function pushOnStack() {
1743
+ if (dialogStack.indexOf(entry) !== -1) return;
1744
+ dialogStack.push(entry);
1745
+ ensureGlobalListener();
1424
1746
  }
1425
- function detachListener() {
1426
- if (typeof window !== "undefined" && listenerAttached) {
1427
- window.removeEventListener("keydown", handleKeydown);
1428
- listenerAttached = false;
1429
- }
1747
+ function removeFromStack() {
1748
+ const idx = dialogStack.indexOf(entry);
1749
+ if (idx !== -1) dialogStack.splice(idx, 1);
1750
+ removeGlobalListenerIfIdle();
1430
1751
  }
1431
1752
  function open() {
1753
+ if (isOpen()) return;
1432
1754
  setIsOpen(true);
1433
- attachListener();
1755
+ pushOnStack();
1434
1756
  }
1435
1757
  function close() {
1758
+ if (!isOpen()) {
1759
+ removeFromStack();
1760
+ return;
1761
+ }
1436
1762
  setIsOpen(false);
1437
- detachListener();
1763
+ removeFromStack();
1438
1764
  }
1439
1765
  function toggle() {
1440
1766
  if (isOpen()) close();
1441
1767
  else open();
1442
1768
  }
1443
- function dispose() {
1444
- detachListener();
1769
+ function dispose2() {
1770
+ removeFromStack();
1445
1771
  setIsOpen(false);
1446
1772
  }
1447
- return { open, close, isOpen, toggle, dispose };
1773
+ return { open, close, isOpen, toggle, dispose: dispose2 };
1448
1774
  }
1449
1775
 
1450
1776
  // src/ui/toast.ts
1451
- var toastCounter = 0;
1452
1777
  function toast(options) {
1453
1778
  const duration = options?.duration ?? 3e3;
1454
1779
  const maxToasts = options?.maxToasts ?? Infinity;
1455
1780
  const [toasts, setToasts] = signal([]);
1456
1781
  const timers = /* @__PURE__ */ new Map();
1782
+ let toastCounter = 0;
1457
1783
  function show(message, type) {
1458
1784
  const id = `toast-${++toastCounter}`;
1459
1785
  const toast2 = { id, message, type };
1786
+ const trimmedIds = [];
1460
1787
  setToasts((prev) => {
1461
1788
  const next = [...prev, toast2];
1462
1789
  if (next.length > maxToasts) {
1463
1790
  const removed = next.splice(0, next.length - maxToasts);
1464
- for (const r of removed) {
1465
- clearTimerForToast(r.id);
1466
- }
1791
+ for (const r of removed) trimmedIds.push(r.id);
1467
1792
  }
1468
1793
  return next;
1469
1794
  });
1470
- if (duration > 0) {
1795
+ for (const tid of trimmedIds) clearTimerForToast(tid);
1796
+ const wasTrimmed = trimmedIds.indexOf(id) !== -1;
1797
+ if (duration > 0 && !wasTrimmed) {
1471
1798
  const timer = setTimeout(() => {
1472
1799
  dismiss(id);
1473
1800
  }, duration);
@@ -1553,14 +1880,14 @@ function infiniteScroll(options) {
1553
1880
  },
1554
1881
  configurable: true
1555
1882
  });
1556
- function dispose() {
1883
+ function dispose2() {
1557
1884
  disposed = true;
1558
1885
  if (observer) {
1559
1886
  observer.disconnect();
1560
1887
  observer = null;
1561
1888
  }
1562
1889
  }
1563
- return { sentinelRef: originalRef, loading, dispose };
1890
+ return { sentinelRef: originalRef, loading, dispose: dispose2 };
1564
1891
  }
1565
1892
 
1566
1893
  // src/ui/pagination.ts
@@ -1635,21 +1962,21 @@ function eventBus() {
1635
1962
  // src/ui/lazyEffect.ts
1636
1963
  function lazyEffect(element, effectFn, options) {
1637
1964
  if (typeof IntersectionObserver === "undefined") {
1638
- const dispose2 = effect(effectFn);
1639
- return dispose2;
1965
+ const dispose3 = effect(effectFn);
1966
+ return dispose3;
1640
1967
  }
1641
- let dispose = null;
1968
+ let dispose2 = null;
1642
1969
  let disposed = false;
1643
1970
  const observer = new IntersectionObserver(
1644
1971
  (entries) => {
1645
1972
  if (disposed) return;
1646
1973
  const entry = entries[0];
1647
1974
  if (!entry) return;
1648
- if (entry.isIntersecting && !dispose) {
1649
- dispose = effect(effectFn);
1650
- } else if (!entry.isIntersecting && dispose) {
1651
- dispose();
1652
- dispose = null;
1975
+ if (entry.isIntersecting && !dispose2) {
1976
+ dispose2 = effect(effectFn);
1977
+ } else if (!entry.isIntersecting && dispose2) {
1978
+ dispose2();
1979
+ dispose2 = null;
1653
1980
  }
1654
1981
  },
1655
1982
  { threshold: 0, ...options }
@@ -1658,9 +1985,9 @@ function lazyEffect(element, effectFn, options) {
1658
1985
  return () => {
1659
1986
  disposed = true;
1660
1987
  observer.disconnect();
1661
- if (dispose) {
1662
- dispose();
1663
- dispose = null;
1988
+ if (dispose2) {
1989
+ dispose2();
1990
+ dispose2 = null;
1664
1991
  }
1665
1992
  };
1666
1993
  }
@@ -1717,11 +2044,11 @@ function hover(target) {
1717
2044
  const onLeave = () => setHovered(false);
1718
2045
  target.addEventListener("pointerenter", onEnter);
1719
2046
  target.addEventListener("pointerleave", onLeave);
1720
- function dispose() {
2047
+ function dispose2() {
1721
2048
  target.removeEventListener("pointerenter", onEnter);
1722
2049
  target.removeEventListener("pointerleave", onLeave);
1723
2050
  }
1724
- return { hovered, dispose };
2051
+ return { hovered, dispose: dispose2 };
1725
2052
  }
1726
2053
 
1727
2054
  // src/ui/scrollLock.ts
@@ -1765,7 +2092,7 @@ function defineElement(name, component, options = {}) {
1765
2092
  class SibuElement extends HTMLElement {
1766
2093
  constructor() {
1767
2094
  super();
1768
- this._rendered = false;
2095
+ this._rendered = null;
1769
2096
  if (options.shadow !== false) {
1770
2097
  this._root = this.attachShadow({ mode: options.mode || "open" });
1771
2098
  } else {
@@ -1779,25 +2106,23 @@ function defineElement(name, component, options = {}) {
1779
2106
  this._render();
1780
2107
  }
1781
2108
  disconnectedCallback() {
1782
- if (this._root instanceof ShadowRoot) {
1783
- this._root.innerHTML = "";
1784
- }
1785
- this._rendered = false;
2109
+ this._teardown();
1786
2110
  }
1787
2111
  attributeChangedCallback() {
1788
2112
  if (this._rendered) {
1789
2113
  this._render();
1790
2114
  }
1791
2115
  }
2116
+ _teardown() {
2117
+ if (this._rendered) {
2118
+ dispose(this._rendered);
2119
+ this._rendered = null;
2120
+ }
2121
+ this._root.replaceChildren();
2122
+ }
1792
2123
  _render() {
2124
+ this._teardown();
1793
2125
  const props = this._getProps();
1794
- if (this._root instanceof ShadowRoot) {
1795
- this._root.innerHTML = "";
1796
- } else {
1797
- while (this._root.firstChild) {
1798
- this._root.removeChild(this._root.firstChild);
1799
- }
1800
- }
1801
2126
  if (options.styles && this._root instanceof ShadowRoot) {
1802
2127
  const styleEl = document.createElement("style");
1803
2128
  styleEl.textContent = options.styles;
@@ -1805,7 +2130,7 @@ function defineElement(name, component, options = {}) {
1805
2130
  }
1806
2131
  const el = component(props, this);
1807
2132
  this._root.appendChild(el);
1808
- this._rendered = true;
2133
+ this._rendered = el;
1809
2134
  }
1810
2135
  _getProps() {
1811
2136
  const props = {};
@@ -2004,6 +2329,7 @@ function createGuard(validator) {
2004
2329
  FocusTrap,
2005
2330
  RenderProp,
2006
2331
  VirtualList,
2332
+ __resetDialogStack,
2007
2333
  announce,
2008
2334
  aria,
2009
2335
  assertType,