sibujs 1.4.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 (190) hide show
  1. package/README.md +105 -119
  2. package/dist/browser.cjs +288 -80
  3. package/dist/browser.d.cts +19 -9
  4. package/dist/browser.d.ts +19 -9
  5. package/dist/browser.js +6 -6
  6. package/dist/build.cjs +1019 -313
  7. package/dist/build.d.cts +1 -1
  8. package/dist/build.d.ts +1 -1
  9. package/dist/build.js +15 -13
  10. package/dist/cdn.global.js +17 -16
  11. package/dist/chunk-2RA7SHDA.js +65 -0
  12. package/dist/chunk-2UPRY23K.js +80 -0
  13. package/dist/chunk-3JHCYHWN.js +125 -0
  14. package/dist/{chunk-ZWKZCBO6.js → chunk-3LR7GLWQ.js} +154 -33
  15. package/dist/{chunk-3AIRKM3B.js → chunk-3NSGB5JN.js} +115 -34
  16. package/dist/{chunk-3ARAQO7B.js → chunk-52YJLLRO.js} +29 -6
  17. package/dist/chunk-54EDRCEF.js +93 -0
  18. package/dist/chunk-7JDB7I65.js +1327 -0
  19. package/dist/{chunk-WZSPOOER.js → chunk-CC65Y57T.js} +8 -5
  20. package/dist/{chunk-23VV7YD3.js → chunk-DFPFITST.js} +25 -30
  21. package/dist/{chunk-WR5D4EGH.js → chunk-GTBNNBJ6.js} +14 -2
  22. package/dist/chunk-HB24TBAF.js +121 -0
  23. package/dist/{chunk-CZUGLNJS.js → chunk-ITX6OO3F.js} +3 -3
  24. package/dist/{chunk-JAKHTMQU.js → chunk-JA6667UN.js} +206 -46
  25. package/dist/{chunk-77L6NL3X.js → chunk-JXMMDLBY.js} +306 -183
  26. package/dist/{chunk-3X2YG6YM.js → chunk-JYD2PWXH.js} +59 -28
  27. package/dist/{chunk-F3FA4F32.js → chunk-KLRMB5ZS.js} +135 -79
  28. package/dist/{chunk-5X6PP2UK.js → chunk-LMLD24FC.js} +2 -2
  29. package/dist/{chunk-M4NLBH4I.js → chunk-LYTCUZ7H.js} +3 -2
  30. package/dist/{chunk-TSOKIX5Z.js → chunk-MIUAXB7K.js} +126 -74
  31. package/dist/{chunk-QWZG56ET.js → chunk-ND2664SF.js} +558 -190
  32. package/dist/{chunk-JCI5M6U6.js → chunk-O2MNQFLP.js} +261 -79
  33. package/dist/{chunk-EWFVA3TJ.js → chunk-R73P76YZ.js} +1 -1
  34. package/dist/{chunk-2BYQDGN3.js → chunk-SAHNHTFC.js} +234 -63
  35. package/dist/chunk-UCS6AMJ7.js +79 -0
  36. package/dist/{chunk-ZD6OAMTH.js → chunk-VLPPXTYG.js} +90 -35
  37. package/dist/{chunk-OUZZEE4S.js → chunk-WOMYAHHI.js} +17 -11
  38. package/dist/{contracts-xo5ckdRP.d.cts → contracts-ey_Qh8ef.d.cts} +7 -8
  39. package/dist/{contracts-xo5ckdRP.d.ts → contracts-ey_Qh8ef.d.ts} +7 -8
  40. package/dist/{customElement-D2DJp_xn.d.cts → customElement-CPfIrbvg.d.cts} +18 -9
  41. package/dist/{customElement-D2DJp_xn.d.ts → customElement-CPfIrbvg.d.ts} +18 -9
  42. package/dist/data.cjs +452 -100
  43. package/dist/data.d.cts +20 -2
  44. package/dist/data.d.ts +20 -2
  45. package/dist/data.js +11 -9
  46. package/dist/devtools.cjs +535 -247
  47. package/dist/devtools.d.cts +1 -1
  48. package/dist/devtools.d.ts +1 -1
  49. package/dist/devtools.js +34 -30
  50. package/dist/ecosystem.cjs +499 -143
  51. package/dist/ecosystem.d.cts +13 -11
  52. package/dist/ecosystem.d.ts +13 -11
  53. package/dist/ecosystem.js +12 -11
  54. package/dist/extras.cjs +3639 -1629
  55. package/dist/extras.d.cts +11 -11
  56. package/dist/extras.d.ts +11 -11
  57. package/dist/extras.js +58 -45
  58. package/dist/index.cjs +1023 -313
  59. package/dist/index.d.cts +128 -55
  60. package/dist/index.d.ts +128 -55
  61. package/dist/index.js +28 -16
  62. package/dist/{introspect-BumjnBKr.d.cts → introspect-BWNjNw64.d.cts} +22 -2
  63. package/dist/{introspect-CZrlcaYy.d.ts → introspect-cY2pg9pW.d.ts} +22 -2
  64. package/dist/motion.cjs +90 -36
  65. package/dist/motion.d.cts +1 -1
  66. package/dist/motion.d.ts +1 -1
  67. package/dist/motion.js +4 -4
  68. package/dist/patterns.cjs +414 -81
  69. package/dist/patterns.d.cts +53 -20
  70. package/dist/patterns.d.ts +53 -20
  71. package/dist/patterns.js +7 -7
  72. package/dist/performance.cjs +364 -108
  73. package/dist/performance.d.cts +29 -17
  74. package/dist/performance.d.ts +29 -17
  75. package/dist/performance.js +13 -6
  76. package/dist/plugin-D30wlGW5.d.cts +71 -0
  77. package/dist/plugin-D30wlGW5.d.ts +71 -0
  78. package/dist/plugins.cjs +652 -271
  79. package/dist/plugins.d.cts +13 -6
  80. package/dist/plugins.d.ts +13 -6
  81. package/dist/plugins.js +116 -50
  82. package/dist/{ssr-Do_SiVoL.d.cts → ssr-CrVNy6Pa.d.cts} +9 -15
  83. package/dist/{ssr-Do_SiVoL.d.ts → ssr-CrVNy6Pa.d.ts} +9 -15
  84. package/dist/{ssr-4PBXAOO3.js → ssr-FXD2PPMC.js} +4 -3
  85. package/dist/ssr.cjs +648 -219
  86. package/dist/ssr.d.cts +27 -7
  87. package/dist/ssr.d.ts +27 -7
  88. package/dist/ssr.js +12 -11
  89. package/dist/{tagFactory-DaJ0YWX6.d.ts → tagFactory-S17H2qxu.d.cts} +9 -1
  90. package/dist/{tagFactory-DaJ0YWX6.d.cts → tagFactory-S17H2qxu.d.ts} +9 -1
  91. package/dist/testing.cjs +252 -63
  92. package/dist/testing.d.cts +17 -4
  93. package/dist/testing.d.ts +17 -4
  94. package/dist/testing.js +100 -44
  95. package/dist/ui.cjs +576 -168
  96. package/dist/ui.d.cts +13 -16
  97. package/dist/ui.d.ts +13 -16
  98. package/dist/ui.js +20 -17
  99. package/dist/widgets.cjs +1001 -93
  100. package/dist/widgets.d.cts +104 -2
  101. package/dist/widgets.d.ts +104 -2
  102. package/dist/widgets.js +9 -7
  103. package/package.json +8 -2
  104. package/dist/chunk-32DY64NT.js +0 -282
  105. package/dist/chunk-3CRQALYP.js +0 -877
  106. package/dist/chunk-4EI4AG32.js +0 -482
  107. package/dist/chunk-4MYMUBRS.js +0 -21
  108. package/dist/chunk-6HLLIF3K.js +0 -398
  109. package/dist/chunk-6LSNVCS2.js +0 -937
  110. package/dist/chunk-6SA3QQES.js +0 -61
  111. package/dist/chunk-7BF6TK55.js +0 -1097
  112. package/dist/chunk-7TQKR4PP.js +0 -294
  113. package/dist/chunk-7V26P53V.js +0 -712
  114. package/dist/chunk-AZ3ISID5.js +0 -298
  115. package/dist/chunk-B7SWRFUT.js +0 -332
  116. package/dist/chunk-BGN5ZMP4.js +0 -26
  117. package/dist/chunk-BTU3TJDS.js +0 -365
  118. package/dist/chunk-BW3WT46K.js +0 -937
  119. package/dist/chunk-C6KFWOFV.js +0 -616
  120. package/dist/chunk-CHF5OHIA.js +0 -61
  121. package/dist/chunk-CHJ27IGK.js +0 -26
  122. package/dist/chunk-CMBFNA7L.js +0 -27
  123. package/dist/chunk-DAHRH4ON.js +0 -331
  124. package/dist/chunk-DKOHBI74.js +0 -924
  125. package/dist/chunk-DTCOOBMX.js +0 -725
  126. package/dist/chunk-EBGIRKQY.js +0 -616
  127. package/dist/chunk-EUZND3CB.js +0 -27
  128. package/dist/chunk-EVCZO745.js +0 -365
  129. package/dist/chunk-FGOEVHY3.js +0 -60
  130. package/dist/chunk-G3BOQPVO.js +0 -365
  131. package/dist/chunk-GCOK2LC3.js +0 -282
  132. package/dist/chunk-HGMJFBC7.js +0 -654
  133. package/dist/chunk-K5ZUMYVS.js +0 -89
  134. package/dist/chunk-KQPDEVVS.js +0 -398
  135. package/dist/chunk-L6JRBDNS.js +0 -60
  136. package/dist/chunk-LA6KQEDU.js +0 -712
  137. package/dist/chunk-MDVXJWFN.js +0 -304
  138. package/dist/chunk-MEZVEBPN.js +0 -2008
  139. package/dist/chunk-MK4ERFYL.js +0 -2249
  140. package/dist/chunk-MLKGABMK.js +0 -9
  141. package/dist/chunk-MQ5GOYPH.js +0 -2249
  142. package/dist/chunk-N6IZB6KJ.js +0 -567
  143. package/dist/chunk-NEKUBFPT.js +0 -60
  144. package/dist/chunk-NHUC2QWH.js +0 -282
  145. package/dist/chunk-NMRUZALC.js +0 -1097
  146. package/dist/chunk-NYVAC6P5.js +0 -37
  147. package/dist/chunk-OF7UZIVB.js +0 -725
  148. package/dist/chunk-P6W3STU4.js +0 -2249
  149. package/dist/chunk-PBHF5WKN.js +0 -616
  150. package/dist/chunk-PTQJDMRT.js +0 -146
  151. package/dist/chunk-PZEGYCF5.js +0 -61
  152. package/dist/chunk-QBMDLBU2.js +0 -975
  153. package/dist/chunk-RQGQSLQK.js +0 -725
  154. package/dist/chunk-SDLZDHKP.js +0 -107
  155. package/dist/chunk-TNQWPPE6.js +0 -37
  156. package/dist/chunk-UHNL42EF.js +0 -2730
  157. package/dist/chunk-UNXCEF6S.js +0 -21
  158. package/dist/chunk-V2XTI523.js +0 -347
  159. package/dist/chunk-VAU366PN.js +0 -2241
  160. package/dist/chunk-VMVDTCXB.js +0 -712
  161. package/dist/chunk-VRW3FULF.js +0 -725
  162. package/dist/chunk-WADYRCO2.js +0 -304
  163. package/dist/chunk-WILQZRO4.js +0 -282
  164. package/dist/chunk-WUHJISPP.js +0 -298
  165. package/dist/chunk-XYU6TZOW.js +0 -182
  166. package/dist/chunk-Y6GP4QGG.js +0 -276
  167. package/dist/chunk-YECR7UIA.js +0 -347
  168. package/dist/chunk-YUTWTI4B.js +0 -654
  169. package/dist/chunk-Z65KYU7I.js +0 -26
  170. package/dist/chunk-Z6POF5YC.js +0 -975
  171. package/dist/chunk-ZBJP6WFL.js +0 -482
  172. package/dist/contracts-DDrwxvJ-.d.cts +0 -245
  173. package/dist/contracts-DDrwxvJ-.d.ts +0 -245
  174. package/dist/contracts-DOrhwbke.d.cts +0 -245
  175. package/dist/contracts-DOrhwbke.d.ts +0 -245
  176. package/dist/customElement-BKQfbSZQ.d.cts +0 -262
  177. package/dist/customElement-BKQfbSZQ.d.ts +0 -262
  178. package/dist/customElement-yz8uyk-0.d.cts +0 -308
  179. package/dist/customElement-yz8uyk-0.d.ts +0 -308
  180. package/dist/introspect-Cb0zgpi2.d.cts +0 -477
  181. package/dist/introspect-Y2xNXGSf.d.ts +0 -477
  182. package/dist/plugin-Bek4RhJY.d.cts +0 -43
  183. package/dist/plugin-Bek4RhJY.d.ts +0 -43
  184. package/dist/ssr-3RXHP5ES.js +0 -38
  185. package/dist/ssr-6GIMY5MX.js +0 -38
  186. package/dist/ssr-BA6sxxUd.d.cts +0 -135
  187. package/dist/ssr-BA6sxxUd.d.ts +0 -135
  188. package/dist/ssr-WKUPVSSK.js +0 -36
  189. package/dist/tagFactory-Dl8QCLga.d.cts +0 -23
  190. package/dist/tagFactory-Dl8QCLga.d.ts +0 -23
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  devWarn,
3
3
  isDev
4
- } from "./chunk-5X6PP2UK.js";
4
+ } from "./chunk-LMLD24FC.js";
5
5
 
6
6
  // src/reactivity/track.ts
7
7
  var _isDev = isDev();
@@ -9,11 +9,11 @@ var subscriberStack = new Array(32);
9
9
  var stackCapacity = 32;
10
10
  var stackTop = -1;
11
11
  var currentSubscriber = null;
12
- var signalSubscribers = /* @__PURE__ */ new WeakMap();
13
12
  var SUBS = "__s";
14
13
  var notifyDepth = 0;
15
14
  var pendingQueue = [];
16
15
  var pendingSet = /* @__PURE__ */ new Set();
16
+ var propagateStack = [];
17
17
  function safeInvoke(sub) {
18
18
  try {
19
19
  sub();
@@ -23,6 +23,15 @@ function safeInvoke(sub) {
23
23
  }
24
24
  var suspendDepth = 0;
25
25
  var trackingSuspended = false;
26
+ function retrack(effectFn, subscriber) {
27
+ const prev = currentSubscriber;
28
+ currentSubscriber = subscriber;
29
+ try {
30
+ effectFn();
31
+ } finally {
32
+ currentSubscriber = prev;
33
+ }
34
+ }
26
35
  function track(effectFn, subscriber) {
27
36
  if (!subscriber) subscriber = effectFn;
28
37
  cleanup(subscriber);
@@ -90,7 +99,6 @@ function recordDependency(signal) {
90
99
  let subs = signal[SUBS];
91
100
  if (!subs) {
92
101
  subs = /* @__PURE__ */ new Set();
93
- signalSubscribers.set(signal, subs);
94
102
  signal[SUBS] = subs;
95
103
  }
96
104
  subs.add(currentSubscriber);
@@ -112,57 +120,71 @@ function queueSignalNotification(signal) {
112
120
  }
113
121
  }
114
122
  }
123
+ var maxDrainIterations = 1e5;
115
124
  function drainNotificationQueue() {
116
125
  if (notifyDepth > 0) return;
117
126
  notifyDepth++;
118
127
  try {
119
128
  let i = 0;
120
129
  while (i < pendingQueue.length) {
130
+ if (i >= maxDrainIterations) {
131
+ if (typeof console !== "undefined") {
132
+ console.error(
133
+ `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
134
+ );
135
+ }
136
+ break;
137
+ }
121
138
  safeInvoke(pendingQueue[i]);
122
139
  i++;
123
140
  }
124
141
  } finally {
125
- pendingQueue.length = 0;
126
- pendingSet.clear();
127
142
  notifyDepth--;
143
+ if (notifyDepth === 0) {
144
+ pendingQueue.length = 0;
145
+ pendingSet.clear();
146
+ }
128
147
  }
129
148
  }
130
149
  function propagateDirty(sub) {
131
150
  sub();
132
- let sig = sub._sig;
133
- while (sig) {
151
+ const rootSig = sub._sig;
152
+ if (!rootSig) return;
153
+ const stack = propagateStack;
154
+ const baseLen = stack.length;
155
+ stack.push(rootSig);
156
+ while (stack.length > baseLen) {
157
+ const sig = stack.pop();
134
158
  const first = sig.__f;
135
159
  if (first) {
136
160
  if (first._c) {
137
161
  const nSig = first._sig;
138
- nSig._d = true;
139
- sig = nSig;
140
- continue;
141
- }
142
- if (!pendingSet.has(first)) {
162
+ if (!nSig._d) {
163
+ nSig._d = true;
164
+ stack.push(nSig);
165
+ }
166
+ } else if (!pendingSet.has(first)) {
143
167
  pendingSet.add(first);
144
168
  pendingQueue.push(first);
145
169
  }
146
- break;
170
+ continue;
147
171
  }
148
172
  const subs = sig[SUBS];
149
- if (!subs) break;
150
- let nextSig;
173
+ if (!subs) continue;
151
174
  for (const s of subs) {
152
175
  if (s._c) {
153
- s();
154
176
  const nSig = s._sig;
155
- if (nSig && !nextSig) {
156
- nextSig = nSig;
157
- } else if (nSig) {
158
- propagateDirty(s);
177
+ if (nSig && !nSig._d) {
178
+ nSig._d = true;
179
+ stack.push(nSig);
180
+ } else if (!nSig) {
181
+ s();
159
182
  }
160
183
  } else if (!pendingSet.has(s)) {
161
184
  pendingSet.add(s);
162
185
  pendingQueue.push(s);
163
186
  }
164
187
  }
165
- sig = nextSig;
166
188
  }
167
189
  }
168
190
  function notifySubscribers(signal) {
@@ -186,13 +208,23 @@ function notifySubscribers(signal) {
186
208
  }
187
209
  let i = 0;
188
210
  while (i < pendingQueue.length) {
211
+ if (i >= maxDrainIterations) {
212
+ if (typeof console !== "undefined") {
213
+ console.error(
214
+ `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
215
+ );
216
+ }
217
+ break;
218
+ }
189
219
  safeInvoke(pendingQueue[i]);
190
220
  i++;
191
221
  }
192
222
  } finally {
193
- pendingQueue.length = 0;
194
- pendingSet.clear();
195
223
  notifyDepth--;
224
+ if (notifyDepth === 0) {
225
+ pendingQueue.length = 0;
226
+ pendingSet.clear();
227
+ }
196
228
  }
197
229
  return;
198
230
  }
@@ -212,30 +244,48 @@ function notifySubscribers(signal) {
212
244
  notifyDepth++;
213
245
  try {
214
246
  let directCount = 0;
247
+ let hasComputedSub = false;
215
248
  for (const sub of subs) {
249
+ if (sub._c) hasComputedSub = true;
216
250
  pendingQueue[directCount++] = sub;
217
251
  }
218
- for (let i2 = 0; i2 < directCount; i2++) {
219
- if (pendingQueue[i2]._c) {
220
- propagateDirty(pendingQueue[i2]);
252
+ if (!hasComputedSub) {
253
+ for (let i2 = 0; i2 < directCount; i2++) {
254
+ safeInvoke(pendingQueue[i2]);
221
255
  }
222
- }
223
- for (let i2 = 0; i2 < directCount; i2++) {
224
- if (!pendingQueue[i2]._c) {
225
- if (!pendingSet.has(pendingQueue[i2])) {
226
- safeInvoke(pendingQueue[i2]);
256
+ } else {
257
+ for (let i2 = 0; i2 < directCount; i2++) {
258
+ if (pendingQueue[i2]._c) {
259
+ propagateDirty(pendingQueue[i2]);
260
+ }
261
+ }
262
+ for (let i2 = 0; i2 < directCount; i2++) {
263
+ const sub = pendingQueue[i2];
264
+ if (!sub._c && !pendingSet.has(sub)) {
265
+ pendingSet.add(sub);
266
+ safeInvoke(sub);
227
267
  }
228
268
  }
229
269
  }
230
270
  let i = directCount;
231
271
  while (i < pendingQueue.length) {
272
+ if (i - directCount >= maxDrainIterations) {
273
+ if (typeof console !== "undefined") {
274
+ console.error(
275
+ `[SibuJS] Notification queue exceeded ${maxDrainIterations} iterations \u2014 likely an effect that writes to a signal it reads. Breaking to prevent infinite loop.`
276
+ );
277
+ }
278
+ break;
279
+ }
232
280
  safeInvoke(pendingQueue[i]);
233
281
  i++;
234
282
  }
235
283
  } finally {
236
- pendingQueue.length = 0;
237
- pendingSet.clear();
238
284
  notifyDepth--;
285
+ if (notifyDepth === 0) {
286
+ pendingQueue.length = 0;
287
+ pendingSet.clear();
288
+ }
239
289
  }
240
290
  }
241
291
  function cleanup(subscriber) {
@@ -246,7 +296,9 @@ function cleanup(subscriber) {
246
296
  if (subs) {
247
297
  subs.delete(subscriber);
248
298
  if (singleDep.__f === subscriber) {
249
- singleDep.__f = void 0;
299
+ singleDep.__f = subs.size === 1 ? subs.values().next().value : void 0;
300
+ } else if (subs.size === 1 && singleDep.__f === void 0) {
301
+ singleDep.__f = subs.values().next().value;
250
302
  }
251
303
  }
252
304
  sub._dep = void 0;
@@ -259,7 +311,9 @@ function cleanup(subscriber) {
259
311
  if (subs) {
260
312
  subs.delete(subscriber);
261
313
  if (signal.__f === subscriber) {
262
- signal.__f = void 0;
314
+ signal.__f = subs.size === 1 ? subs.values().next().value : void 0;
315
+ } else if (subs.size === 1 && signal.__f === void 0) {
316
+ signal.__f = subs.values().next().value;
263
317
  }
264
318
  }
265
319
  }
@@ -268,6 +322,7 @@ function cleanup(subscriber) {
268
322
 
269
323
  export {
270
324
  trackingSuspended,
325
+ retrack,
271
326
  track,
272
327
  untracked,
273
328
  recordDependency,
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  createPlugin
3
- } from "./chunk-K5ZUMYVS.js";
3
+ } from "./chunk-3JHCYHWN.js";
4
4
  import {
5
5
  tagFactory
6
- } from "./chunk-B7SWRFUT.js";
6
+ } from "./chunk-KLRMB5ZS.js";
7
7
  import {
8
8
  derived
9
- } from "./chunk-L6JRBDNS.js";
9
+ } from "./chunk-54EDRCEF.js";
10
10
  import {
11
11
  effect
12
- } from "./chunk-6SA3QQES.js";
12
+ } from "./chunk-HB24TBAF.js";
13
13
  import {
14
14
  batch,
15
15
  signal
16
- } from "./chunk-V2XTI523.js";
16
+ } from "./chunk-CC65Y57T.js";
17
17
 
18
18
  // src/ecosystem/adapters/mobx.ts
19
19
  function mobXAdapter(options) {
@@ -21,7 +21,7 @@ function mobXAdapter(options) {
21
21
  const { autorun } = options;
22
22
  const disposers = [];
23
23
  function fromMobX(expression) {
24
- const [getValue, setValue] = signal(expression());
24
+ const [getValue, setValue] = signal(void 0);
25
25
  const disposer = autorun(() => {
26
26
  const newValue = expression();
27
27
  batch(() => {
@@ -29,7 +29,13 @@ function mobXAdapter(options) {
29
29
  });
30
30
  });
31
31
  disposers.push(disposer);
32
- return getValue;
32
+ const getter = (() => getValue());
33
+ getter.dispose = () => {
34
+ const i = disposers.indexOf(disposer);
35
+ if (i >= 0) disposers.splice(i, 1);
36
+ disposer();
37
+ };
38
+ return getter;
33
39
  }
34
40
  function toMobX(sibuGetter, callback) {
35
41
  return effect(() => {
@@ -57,12 +63,12 @@ function reduxAdapter(options) {
57
63
  setState(store.getState());
58
64
  });
59
65
  });
60
- function useSelector(selector) {
66
+ function select(selector) {
61
67
  return derived(() => selector(getState()));
62
68
  }
63
69
  const api = {
64
70
  getState,
65
- useSelector,
71
+ select,
66
72
  dispatch: store.dispatch.bind(store),
67
73
  destroy: unsubscribe
68
74
  };
@@ -80,12 +86,12 @@ function zustandAdapter(options) {
80
86
  setSibuState(state);
81
87
  });
82
88
  });
83
- function useSelector(selector) {
89
+ function select(selector) {
84
90
  return derived(() => selector(getState()));
85
91
  }
86
92
  const api = {
87
93
  getState,
88
- useSelector,
94
+ select,
89
95
  setState: store.setState.bind(store),
90
96
  destroy() {
91
97
  unsubscribe();
@@ -29,7 +29,7 @@ declare function withWrapper<P>(WrappedComponent: Component<P>, wrapper: (compon
29
29
  * @example
30
30
  * ```ts
31
31
  * const Button = withDefaults(RawButton, { type: "button", disabled: false });
32
- * Button({ nodes: "Click" }); // type="button", disabled=false automatically
32
+ * Button("Click"); // type="button", disabled=false automatically
33
33
  * ```
34
34
  */
35
35
  declare function withDefaults<P extends Record<string, unknown>>(component: Component<P>, defaults: Partial<P>): Component<Partial<P>>;
@@ -107,11 +107,10 @@ type WithNodes<Props> = Props & {
107
107
  * const Button = defineComponent<{ label: string; variant?: 'primary' | 'secondary'; disabled?: boolean }>({
108
108
  * defaults: { variant: 'primary', disabled: false },
109
109
  * setup(props) {
110
- * return button({
111
- * class: `btn btn-${props.variant}`,
112
- * disabled: props.disabled,
113
- * nodes: props.label
114
- * });
110
+ * return button(
111
+ * { class: `btn btn-${props.variant}`, disabled: props.disabled },
112
+ * props.label,
113
+ * );
115
114
  * }
116
115
  * });
117
116
  *
@@ -137,7 +136,7 @@ declare function defineComponent<Props extends Record<string, unknown>>(config:
137
136
  * const Card = defineSlottedComponent<{ title: string }>({
138
137
  * setup(props) {
139
138
  * const el = div({ class: 'card' });
140
- * el.appendChild(h2({ nodes: props.title }));
139
+ * el.appendChild(h2(props.title));
141
140
  * if (props.nodes) {
142
141
  * const nodes = Array.isArray(props.nodes) ? props.nodes : [props.nodes];
143
142
  * nodes.forEach(child => el.appendChild(child));
@@ -146,7 +145,7 @@ declare function defineComponent<Props extends Record<string, unknown>>(config:
146
145
  * }
147
146
  * });
148
147
  *
149
- * // Usage: Card({ title: 'Hello', nodes: p({ nodes: 'World' }) })
148
+ * // Usage: Card({ title: 'Hello', nodes: p('World') })
150
149
  * ```
151
150
  */
152
151
  declare function defineSlottedComponent<Props extends Record<string, unknown>>(config: {
@@ -29,7 +29,7 @@ declare function withWrapper<P>(WrappedComponent: Component<P>, wrapper: (compon
29
29
  * @example
30
30
  * ```ts
31
31
  * const Button = withDefaults(RawButton, { type: "button", disabled: false });
32
- * Button({ nodes: "Click" }); // type="button", disabled=false automatically
32
+ * Button("Click"); // type="button", disabled=false automatically
33
33
  * ```
34
34
  */
35
35
  declare function withDefaults<P extends Record<string, unknown>>(component: Component<P>, defaults: Partial<P>): Component<Partial<P>>;
@@ -107,11 +107,10 @@ type WithNodes<Props> = Props & {
107
107
  * const Button = defineComponent<{ label: string; variant?: 'primary' | 'secondary'; disabled?: boolean }>({
108
108
  * defaults: { variant: 'primary', disabled: false },
109
109
  * setup(props) {
110
- * return button({
111
- * class: `btn btn-${props.variant}`,
112
- * disabled: props.disabled,
113
- * nodes: props.label
114
- * });
110
+ * return button(
111
+ * { class: `btn btn-${props.variant}`, disabled: props.disabled },
112
+ * props.label,
113
+ * );
115
114
  * }
116
115
  * });
117
116
  *
@@ -137,7 +136,7 @@ declare function defineComponent<Props extends Record<string, unknown>>(config:
137
136
  * const Card = defineSlottedComponent<{ title: string }>({
138
137
  * setup(props) {
139
138
  * const el = div({ class: 'card' });
140
- * el.appendChild(h2({ nodes: props.title }));
139
+ * el.appendChild(h2(props.title));
141
140
  * if (props.nodes) {
142
141
  * const nodes = Array.isArray(props.nodes) ? props.nodes : [props.nodes];
143
142
  * nodes.forEach(child => el.appendChild(child));
@@ -146,7 +145,7 @@ declare function defineComponent<Props extends Record<string, unknown>>(config:
146
145
  * }
147
146
  * });
148
147
  *
149
- * // Usage: Card({ title: 'Hello', nodes: p({ nodes: 'World' }) })
148
+ * // Usage: Card({ title: 'Hello', nodes: p('World') })
150
149
  * ```
151
150
  */
152
151
  declare function defineSlottedComponent<Props extends Record<string, unknown>>(config: {
@@ -21,6 +21,8 @@ interface FormReturn<T extends Record<string, unknown>> {
21
21
  errors: () => Partial<Record<keyof T, string | null>>;
22
22
  isValid: () => boolean;
23
23
  isDirty: () => boolean;
24
+ /** True while an async handleSubmit callback is in flight. Prevents double-submit. */
25
+ submitting: () => boolean;
24
26
  touched: () => Partial<Record<keyof T, boolean>>;
25
27
  values: () => T;
26
28
  handleSubmit: (onSubmit: (values: T) => void | Promise<void>) => (e?: Event) => void;
@@ -112,7 +114,7 @@ interface MaskOptions {
112
114
  declare function inputMask(options: MaskOptions): {
113
115
  value: () => string;
114
116
  rawValue: () => string;
115
- bind: (input: HTMLInputElement) => void;
117
+ bind: (input: HTMLInputElement) => () => void;
116
118
  };
117
119
  /** Phone number mask: (999) 999-9999 */
118
120
  declare function phoneMask(): MaskOptions;
@@ -138,7 +140,7 @@ declare function focus(): {
138
140
  isFocused: () => boolean;
139
141
  focus: () => void;
140
142
  blur: () => void;
141
- bind: (element: HTMLElement) => void;
143
+ bind: (element: HTMLElement) => () => void;
142
144
  };
143
145
  /**
144
146
  * FocusTrap traps focus within a container element.
@@ -150,7 +152,12 @@ declare function FocusTrap(nodes: HTMLElement, options?: {
150
152
  }): HTMLElement;
151
153
  /**
152
154
  * hotkey registers a keyboard shortcut handler.
153
- * Returns a cleanup function.
155
+ *
156
+ * Returns a `dispose()` cleanup function — call it from the owning
157
+ * component's unmount path to remove the `keydown` listener from
158
+ * `document`. The returned function is idempotent only via the
159
+ * browser's default `removeEventListener` semantics, so callers
160
+ * should invoke it exactly once.
154
161
  *
155
162
  * Supports two calling styles:
156
163
  * - String combo: hotkey("ctrl+shift+z", handler)
@@ -161,12 +168,8 @@ declare function hotkey(combo: string, handler: (e: KeyboardEvent) => void, opti
161
168
  shift?: boolean;
162
169
  alt?: boolean;
163
170
  meta?: boolean;
164
- global?: boolean;
165
171
  preventDefault?: boolean;
166
172
  }): () => void;
167
- /**
168
- * announce creates a screen reader announcement using ARIA live regions.
169
- */
170
173
  declare function announce(message: string, priority?: "polite" | "assertive"): void;
171
174
 
172
175
  /**
@@ -213,13 +216,19 @@ declare function bindBoolAttr(el: HTMLElement, attr: string, getter: boolean | (
213
216
  declare function bindData(el: HTMLElement, key: string, getter: string | (() => string)): () => void;
214
217
 
215
218
  /**
216
- * dialog provides reactive dialog state management with escape-to-close support.
219
+ * Test-only helper to reset the module-level stack between specs. Client-only:
220
+ * in SSR dialog() is never meaningfully invoked. In production the stack is
221
+ * bounded by open dialog count and cleaned via removeFromStack/dispose.
222
+ *
223
+ * @internal
217
224
  */
225
+ declare function __resetDialogStack(): void;
218
226
  declare function dialog(): {
219
227
  open: () => void;
220
228
  close: () => void;
221
229
  isOpen: () => boolean;
222
230
  toggle: () => void;
231
+ dispose: () => void;
223
232
  };
224
233
 
225
234
  /**
@@ -310,4 +319,4 @@ declare function defineElement(name: string, component: (props: Record<string, u
310
319
  */
311
320
  declare function svgElement(tag: string, props?: Record<string, unknown>, ...nodes: (SVGElement | string)[]): SVGElement;
312
321
 
313
- export { lazyLoad as A, type BoundFieldProps as B, type CustomElementOptions as C, matchesPattern as D, max as E, type FieldConfig as F, maxLength as G, min as H, type IntersectionResult as I, minLength as J, pagination as K, phoneMask as L, type MaskOptions as M, removeScopedStyle as N, required as O, scopedStyle as P, ssnMask as Q, svgElement as R, timeMask as S, type Toast as T, toast as U, type ValidatorFn as V, withScopedStyle as W, zipMask as X, FocusTrap as a, type FormConfig as b, type FormField as c, type FormReturn as d, type ToastInstance as e, VirtualList as f, type VirtualListProps as g, announce as h, aria as i, bindAttrs as j, bindBoolAttr as k, bindData as l, bindField as m, creditCardMask as n, custom as o, dateMask as p, defineElement as q, dialog as r, email as s, eventBus as t, focus as u, form as v, hotkey as w, infiniteScroll as x, inputMask as y, intersection as z };
322
+ export { lazyLoad as A, type BoundFieldProps as B, type CustomElementOptions as C, matchesPattern as D, max as E, type FieldConfig as F, maxLength as G, min as H, type IntersectionResult as I, minLength as J, pagination as K, phoneMask as L, type MaskOptions as M, removeScopedStyle as N, required as O, scopedStyle as P, ssnMask as Q, svgElement as R, timeMask as S, type Toast as T, toast as U, type ValidatorFn as V, withScopedStyle as W, zipMask as X, __resetDialogStack as _, FocusTrap as a, type FormConfig as b, type FormField as c, type FormReturn as d, type ToastInstance as e, VirtualList as f, type VirtualListProps as g, announce as h, aria as i, bindAttrs as j, bindBoolAttr as k, bindData as l, bindField as m, creditCardMask as n, custom as o, dateMask as p, defineElement as q, dialog as r, email as s, eventBus as t, focus as u, form as v, hotkey as w, infiniteScroll as x, inputMask as y, intersection as z };
@@ -21,6 +21,8 @@ interface FormReturn<T extends Record<string, unknown>> {
21
21
  errors: () => Partial<Record<keyof T, string | null>>;
22
22
  isValid: () => boolean;
23
23
  isDirty: () => boolean;
24
+ /** True while an async handleSubmit callback is in flight. Prevents double-submit. */
25
+ submitting: () => boolean;
24
26
  touched: () => Partial<Record<keyof T, boolean>>;
25
27
  values: () => T;
26
28
  handleSubmit: (onSubmit: (values: T) => void | Promise<void>) => (e?: Event) => void;
@@ -112,7 +114,7 @@ interface MaskOptions {
112
114
  declare function inputMask(options: MaskOptions): {
113
115
  value: () => string;
114
116
  rawValue: () => string;
115
- bind: (input: HTMLInputElement) => void;
117
+ bind: (input: HTMLInputElement) => () => void;
116
118
  };
117
119
  /** Phone number mask: (999) 999-9999 */
118
120
  declare function phoneMask(): MaskOptions;
@@ -138,7 +140,7 @@ declare function focus(): {
138
140
  isFocused: () => boolean;
139
141
  focus: () => void;
140
142
  blur: () => void;
141
- bind: (element: HTMLElement) => void;
143
+ bind: (element: HTMLElement) => () => void;
142
144
  };
143
145
  /**
144
146
  * FocusTrap traps focus within a container element.
@@ -150,7 +152,12 @@ declare function FocusTrap(nodes: HTMLElement, options?: {
150
152
  }): HTMLElement;
151
153
  /**
152
154
  * hotkey registers a keyboard shortcut handler.
153
- * Returns a cleanup function.
155
+ *
156
+ * Returns a `dispose()` cleanup function — call it from the owning
157
+ * component's unmount path to remove the `keydown` listener from
158
+ * `document`. The returned function is idempotent only via the
159
+ * browser's default `removeEventListener` semantics, so callers
160
+ * should invoke it exactly once.
154
161
  *
155
162
  * Supports two calling styles:
156
163
  * - String combo: hotkey("ctrl+shift+z", handler)
@@ -161,12 +168,8 @@ declare function hotkey(combo: string, handler: (e: KeyboardEvent) => void, opti
161
168
  shift?: boolean;
162
169
  alt?: boolean;
163
170
  meta?: boolean;
164
- global?: boolean;
165
171
  preventDefault?: boolean;
166
172
  }): () => void;
167
- /**
168
- * announce creates a screen reader announcement using ARIA live regions.
169
- */
170
173
  declare function announce(message: string, priority?: "polite" | "assertive"): void;
171
174
 
172
175
  /**
@@ -213,13 +216,19 @@ declare function bindBoolAttr(el: HTMLElement, attr: string, getter: boolean | (
213
216
  declare function bindData(el: HTMLElement, key: string, getter: string | (() => string)): () => void;
214
217
 
215
218
  /**
216
- * dialog provides reactive dialog state management with escape-to-close support.
219
+ * Test-only helper to reset the module-level stack between specs. Client-only:
220
+ * in SSR dialog() is never meaningfully invoked. In production the stack is
221
+ * bounded by open dialog count and cleaned via removeFromStack/dispose.
222
+ *
223
+ * @internal
217
224
  */
225
+ declare function __resetDialogStack(): void;
218
226
  declare function dialog(): {
219
227
  open: () => void;
220
228
  close: () => void;
221
229
  isOpen: () => boolean;
222
230
  toggle: () => void;
231
+ dispose: () => void;
223
232
  };
224
233
 
225
234
  /**
@@ -310,4 +319,4 @@ declare function defineElement(name: string, component: (props: Record<string, u
310
319
  */
311
320
  declare function svgElement(tag: string, props?: Record<string, unknown>, ...nodes: (SVGElement | string)[]): SVGElement;
312
321
 
313
- export { lazyLoad as A, type BoundFieldProps as B, type CustomElementOptions as C, matchesPattern as D, max as E, type FieldConfig as F, maxLength as G, min as H, type IntersectionResult as I, minLength as J, pagination as K, phoneMask as L, type MaskOptions as M, removeScopedStyle as N, required as O, scopedStyle as P, ssnMask as Q, svgElement as R, timeMask as S, type Toast as T, toast as U, type ValidatorFn as V, withScopedStyle as W, zipMask as X, FocusTrap as a, type FormConfig as b, type FormField as c, type FormReturn as d, type ToastInstance as e, VirtualList as f, type VirtualListProps as g, announce as h, aria as i, bindAttrs as j, bindBoolAttr as k, bindData as l, bindField as m, creditCardMask as n, custom as o, dateMask as p, defineElement as q, dialog as r, email as s, eventBus as t, focus as u, form as v, hotkey as w, infiniteScroll as x, inputMask as y, intersection as z };
322
+ export { lazyLoad as A, type BoundFieldProps as B, type CustomElementOptions as C, matchesPattern as D, max as E, type FieldConfig as F, maxLength as G, min as H, type IntersectionResult as I, minLength as J, pagination as K, phoneMask as L, type MaskOptions as M, removeScopedStyle as N, required as O, scopedStyle as P, ssnMask as Q, svgElement as R, timeMask as S, type Toast as T, toast as U, type ValidatorFn as V, withScopedStyle as W, zipMask as X, __resetDialogStack as _, FocusTrap as a, type FormConfig as b, type FormField as c, type FormReturn as d, type ToastInstance as e, VirtualList as f, type VirtualListProps as g, announce as h, aria as i, bindAttrs as j, bindBoolAttr as k, bindData as l, bindField as m, creditCardMask as n, custom as o, dateMask as p, defineElement as q, dialog as r, email as s, eventBus as t, focus as u, form as v, hotkey as w, infiniteScroll as x, inputMask as y, intersection as z };