sibujs 3.3.2 → 3.3.3

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 (73) hide show
  1. package/dist/browser.cjs +21 -4
  2. package/dist/browser.js +4 -4
  3. package/dist/build.cjs +10 -3
  4. package/dist/build.js +11 -11
  5. package/dist/cdn.global.js +7 -7
  6. package/dist/{chunk-N5TQVEKE.js → chunk-23VT3KZB.js} +1 -1
  7. package/dist/{chunk-IQJ36UTJ.js → chunk-25LY5SRH.js} +31 -24
  8. package/dist/{chunk-6TCOWMGY.js → chunk-5K6RVA2S.js} +1 -1
  9. package/dist/{chunk-YUBEOWII.js → chunk-5Y34FWED.js} +16 -5
  10. package/dist/chunk-7ZHH77QA.js +9 -0
  11. package/dist/{chunk-G6N3LMO2.js → chunk-F3HO2MP7.js} +1 -1
  12. package/dist/{chunk-FJIRS3FM.js → chunk-F7HW2NI5.js} +1 -3
  13. package/dist/{chunk-AEOLHSSQ.js → chunk-IEYFHN5V.js} +72 -25
  14. package/dist/{chunk-FJO2ZL4Q.js → chunk-IQN5W7GE.js} +73 -16
  15. package/dist/{chunk-JCQG2I2G.js → chunk-IWFE4AHO.js} +1 -1
  16. package/dist/{chunk-2ARSB7NG.js → chunk-MYXEBADX.js} +27 -20
  17. package/dist/{chunk-A7CZH3GN.js → chunk-QCQQ2N5H.js} +41 -20
  18. package/dist/{chunk-Q46YIQYW.js → chunk-QTOOBABV.js} +22 -5
  19. package/dist/{chunk-ZEUP4TUD.js → chunk-RZKGMHH4.js} +6 -6
  20. package/dist/{chunk-QCFBIVIQ.js → chunk-SBPUXWCE.js} +1 -1
  21. package/dist/{chunk-RLTFJYDN.js → chunk-TBDTU7UO.js} +1 -1
  22. package/dist/{chunk-P7C7SEJV.js → chunk-TVCCXPU2.js} +5 -5
  23. package/dist/{chunk-4NJEAPLI.js → chunk-UOMYIAG6.js} +1 -1
  24. package/dist/{chunk-655B7MMR.js → chunk-WFUUT6TG.js} +15 -8
  25. package/dist/{chunk-YUR5SX7F.js → chunk-WTFMV2RU.js} +70 -59
  26. package/dist/{chunk-3JHCYHWN.js → chunk-WWV3SJ3L.js} +19 -13
  27. package/dist/{chunk-62V653X2.js → chunk-Y35NQNLG.js} +79 -44
  28. package/dist/{chunk-5VH3GIDX.js → chunk-ZXCZWMZT.js} +1 -1
  29. package/dist/data.cjs +16 -2
  30. package/dist/data.js +7 -6
  31. package/dist/devtools.cjs +71 -21
  32. package/dist/devtools.d.cts +12 -5
  33. package/dist/devtools.d.ts +12 -5
  34. package/dist/devtools.js +6 -5
  35. package/dist/ecosystem.cjs +11 -2
  36. package/dist/ecosystem.js +10 -9
  37. package/dist/extras.cjs +454 -250
  38. package/dist/extras.d.cts +1 -1
  39. package/dist/extras.d.ts +1 -1
  40. package/dist/extras.js +26 -22
  41. package/dist/index.cjs +10 -3
  42. package/dist/index.d.cts +4 -1
  43. package/dist/index.d.ts +4 -1
  44. package/dist/index.js +19 -19
  45. package/dist/motion.cjs +223 -204
  46. package/dist/motion.d.cts +8 -1
  47. package/dist/motion.d.ts +8 -1
  48. package/dist/motion.js +6 -3
  49. package/dist/patterns.cjs +13 -6
  50. package/dist/patterns.d.cts +4 -1
  51. package/dist/patterns.d.ts +4 -1
  52. package/dist/patterns.js +5 -5
  53. package/dist/performance.cjs +70 -56
  54. package/dist/performance.js +6 -5
  55. package/dist/plugins.cjs +98 -42
  56. package/dist/plugins.d.cts +2 -1
  57. package/dist/plugins.d.ts +2 -1
  58. package/dist/plugins.js +90 -37
  59. package/dist/ssr.cjs +112 -91
  60. package/dist/ssr.d.cts +8 -1
  61. package/dist/ssr.d.ts +8 -1
  62. package/dist/ssr.js +9 -8
  63. package/dist/testing.cjs +18 -4
  64. package/dist/testing.js +18 -7
  65. package/dist/ui.cjs +322 -281
  66. package/dist/ui.d.cts +0 -20
  67. package/dist/ui.d.ts +0 -20
  68. package/dist/ui.js +28 -22
  69. package/dist/widgets.cjs +75 -13
  70. package/dist/widgets.d.cts +6 -1
  71. package/dist/widgets.d.ts +6 -1
  72. package/dist/widgets.js +7 -6
  73. package/package.json +1 -1
package/dist/patterns.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  optimisticList,
6
6
  persisted,
7
7
  timeline
8
- } from "./chunk-655B7MMR.js";
8
+ } from "./chunk-WFUUT6TG.js";
9
9
  import {
10
10
  RenderProp,
11
11
  assertType,
@@ -23,11 +23,11 @@ import {
23
23
  withWrapper
24
24
  } from "./chunk-VJE6DDYM.js";
25
25
  import "./chunk-H3SRKIYX.js";
26
- import "./chunk-G6N3LMO2.js";
27
- import "./chunk-N5TQVEKE.js";
26
+ import "./chunk-F3HO2MP7.js";
27
+ import "./chunk-23VT3KZB.js";
28
28
  import "./chunk-S3NFJO6L.js";
29
- import "./chunk-JCQG2I2G.js";
30
- import "./chunk-4NJEAPLI.js";
29
+ import "./chunk-IWFE4AHO.js";
30
+ import "./chunk-UOMYIAG6.js";
31
31
  import "./chunk-COY6PUD2.js";
32
32
  export {
33
33
  RenderProp,
@@ -58,6 +58,12 @@ __export(performance_exports, {
58
58
  });
59
59
  module.exports = __toCommonJS(performance_exports);
60
60
 
61
+ // src/utils/globalSingleton.ts
62
+ function globalSingleton(key, create) {
63
+ const g = globalThis;
64
+ return g[key] ?? (g[key] = create());
65
+ }
66
+
61
67
  // src/performance/scheduler.ts
62
68
  var Priority = {
63
69
  IMMEDIATE: 0,
@@ -66,12 +72,15 @@ var Priority = {
66
72
  LOW: 3,
67
73
  IDLE: 4
68
74
  };
69
- var taskIdCounter = 0;
70
- var taskQueue = [];
71
- var isProcessing = false;
72
- var scheduledKind = null;
73
- var scheduledHandle = null;
74
- var microtaskScheduled = false;
75
+ var _sched = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.scheduler.v1"), () => ({
76
+ taskIdCounter: 0,
77
+ taskQueue: [],
78
+ isProcessing: false,
79
+ scheduledKind: null,
80
+ scheduledHandle: null,
81
+ microtaskScheduled: false
82
+ }));
83
+ var taskQueue = _sched.taskQueue;
75
84
  function insertTask(task) {
76
85
  let i = taskQueue.length;
77
86
  while (i > 0 && taskQueue[i - 1].priority > task.priority) {
@@ -80,8 +89,8 @@ function insertTask(task) {
80
89
  taskQueue.splice(i, 0, task);
81
90
  }
82
91
  function processQueue() {
83
- if (isProcessing || taskQueue.length === 0) return;
84
- isProcessing = true;
92
+ if (_sched.isProcessing || taskQueue.length === 0) return;
93
+ _sched.isProcessing = true;
85
94
  const startTime = performance.now();
86
95
  const timeSlice = 5;
87
96
  while (taskQueue.length > 0) {
@@ -100,64 +109,69 @@ function processQueue() {
100
109
  console.error("[Scheduler] Task error:", e);
101
110
  }
102
111
  }
103
- isProcessing = false;
112
+ _sched.isProcessing = false;
104
113
  if (taskQueue.length > 0) {
105
114
  scheduleFrame();
106
115
  }
107
116
  }
108
117
  var TIER_SPEED = { microtask: 0, frame: 1, timeout: 2, idle: 3 };
109
118
  function cancelScheduled() {
110
- if (scheduledHandle !== null) {
111
- if (scheduledKind === "frame") cancelAnimationFrame(scheduledHandle);
112
- else if (scheduledKind === "idle" && typeof cancelIdleCallback !== "undefined") cancelIdleCallback(scheduledHandle);
113
- else if (scheduledKind === "timeout") clearTimeout(scheduledHandle);
119
+ if (_sched.scheduledHandle !== null) {
120
+ if (_sched.scheduledKind === "frame") cancelAnimationFrame(_sched.scheduledHandle);
121
+ else if (_sched.scheduledKind === "idle" && typeof cancelIdleCallback !== "undefined")
122
+ cancelIdleCallback(_sched.scheduledHandle);
123
+ else if (_sched.scheduledKind === "timeout") clearTimeout(_sched.scheduledHandle);
114
124
  }
115
- scheduledHandle = null;
116
- scheduledKind = null;
125
+ _sched.scheduledHandle = null;
126
+ _sched.scheduledKind = null;
117
127
  }
118
128
  function scheduleFrame() {
119
129
  const nextTask = taskQueue.find((t) => !t.cancelled);
120
130
  if (!nextTask) return;
121
- const desired = nextTask.priority <= Priority.USER_BLOCKING ? "microtask" : nextTask.priority === Priority.IDLE ? typeof requestIdleCallback !== "undefined" ? "idle" : "timeout" : "frame";
122
- if (microtaskScheduled) return;
123
- if (scheduledKind !== null) {
124
- if (TIER_SPEED[scheduledKind] <= TIER_SPEED[desired]) return;
131
+ const desired = nextTask.priority <= Priority.USER_BLOCKING ? "microtask" : nextTask.priority === Priority.IDLE ? typeof requestIdleCallback !== "undefined" ? "idle" : "timeout" : (
132
+ // NORMAL/LOW prefer a frame, but rAF is absent under SSR — fall back
133
+ // to a timeout so startTransition()/deferredValue() don't throw.
134
+ typeof requestAnimationFrame !== "undefined" ? "frame" : "timeout"
135
+ );
136
+ if (_sched.microtaskScheduled) return;
137
+ if (_sched.scheduledKind !== null) {
138
+ if (TIER_SPEED[_sched.scheduledKind] <= TIER_SPEED[desired]) return;
125
139
  cancelScheduled();
126
140
  }
127
141
  if (desired === "microtask") {
128
- microtaskScheduled = true;
129
- scheduledKind = "microtask";
142
+ _sched.microtaskScheduled = true;
143
+ _sched.scheduledKind = "microtask";
130
144
  queueMicrotask(() => {
131
- microtaskScheduled = false;
132
- scheduledKind = null;
145
+ _sched.microtaskScheduled = false;
146
+ _sched.scheduledKind = null;
133
147
  processQueue();
134
148
  });
135
149
  } else if (desired === "idle") {
136
- scheduledKind = "idle";
137
- scheduledHandle = requestIdleCallback(() => {
138
- scheduledKind = null;
139
- scheduledHandle = null;
150
+ _sched.scheduledKind = "idle";
151
+ _sched.scheduledHandle = requestIdleCallback(() => {
152
+ _sched.scheduledKind = null;
153
+ _sched.scheduledHandle = null;
140
154
  processQueue();
141
155
  });
142
156
  } else if (desired === "timeout") {
143
- scheduledKind = "timeout";
144
- scheduledHandle = setTimeout(() => {
145
- scheduledKind = null;
146
- scheduledHandle = null;
157
+ _sched.scheduledKind = "timeout";
158
+ _sched.scheduledHandle = setTimeout(() => {
159
+ _sched.scheduledKind = null;
160
+ _sched.scheduledHandle = null;
147
161
  processQueue();
148
162
  }, 50);
149
163
  } else {
150
- scheduledKind = "frame";
151
- scheduledHandle = requestAnimationFrame(() => {
152
- scheduledKind = null;
153
- scheduledHandle = null;
164
+ _sched.scheduledKind = "frame";
165
+ _sched.scheduledHandle = requestAnimationFrame(() => {
166
+ _sched.scheduledKind = null;
167
+ _sched.scheduledHandle = null;
154
168
  processQueue();
155
169
  });
156
170
  }
157
171
  }
158
172
  function scheduleUpdate(priority, callback) {
159
173
  const task = {
160
- id: taskIdCounter++,
174
+ id: _sched.taskIdCounter++,
161
175
  priority,
162
176
  callback,
163
177
  cancelled: false
@@ -178,15 +192,15 @@ function scheduleUpdate(priority, callback) {
178
192
  };
179
193
  }
180
194
  function flushScheduler() {
181
- if (scheduledHandle !== null) {
182
- if (scheduledKind === "frame") cancelAnimationFrame(scheduledHandle);
183
- else if (scheduledKind === "idle" && typeof cancelIdleCallback !== "undefined") {
184
- cancelIdleCallback(scheduledHandle);
185
- } else if (scheduledKind === "timeout") clearTimeout(scheduledHandle);
186
- }
187
- scheduledHandle = null;
188
- scheduledKind = null;
189
- microtaskScheduled = false;
195
+ if (_sched.scheduledHandle !== null) {
196
+ if (_sched.scheduledKind === "frame") cancelAnimationFrame(_sched.scheduledHandle);
197
+ else if (_sched.scheduledKind === "idle" && typeof cancelIdleCallback !== "undefined") {
198
+ cancelIdleCallback(_sched.scheduledHandle);
199
+ } else if (_sched.scheduledKind === "timeout") clearTimeout(_sched.scheduledHandle);
200
+ }
201
+ _sched.scheduledHandle = null;
202
+ _sched.scheduledKind = null;
203
+ _sched.microtaskScheduled = false;
190
204
  while (taskQueue.length > 0) {
191
205
  const task = taskQueue.shift();
192
206
  if (!task) break;
@@ -194,7 +208,7 @@ function flushScheduler() {
194
208
  task.callback();
195
209
  }
196
210
  }
197
- isProcessing = false;
211
+ _sched.isProcessing = false;
198
212
  }
199
213
  function pendingTasks() {
200
214
  return taskQueue.filter((t) => !t.cancelled).length;
@@ -654,7 +668,7 @@ function forEachSubscriber(signal2, visit) {
654
668
 
655
669
  // src/reactivity/track.ts
656
670
  var _isDev3 = isDev();
657
- var _runtimeVersion = true ? "3.3.2" : "dev";
671
+ var _runtimeVersion = true ? "3.3.3" : "dev";
658
672
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
659
673
  function resolveReactiveApi() {
660
674
  const g = globalThis;
@@ -1012,16 +1026,18 @@ function transitionState() {
1012
1026
  }
1013
1027
  return [isPending, transition];
1014
1028
  }
1015
- var idCounter = 0;
1016
- var idPrefix = "sibu";
1029
+ var _ids = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.uniqueId.v1"), () => ({
1030
+ counter: 0,
1031
+ prefix: "sibu"
1032
+ }));
1017
1033
  function resetIdCounter() {
1018
- idCounter = 0;
1034
+ _ids.counter = 0;
1019
1035
  }
1020
1036
  function setIdPrefix(prefix) {
1021
- idPrefix = prefix;
1037
+ _ids.prefix = prefix;
1022
1038
  }
1023
1039
  function uniqueId(suffix) {
1024
- const id = `${idPrefix}-${idCounter++}`;
1040
+ const id = `${_ids.prefix}-${_ids.counter++}`;
1025
1041
  return suffix ? `${id}-${suffix}` : id;
1026
1042
  }
1027
1043
 
@@ -1291,7 +1307,6 @@ function normalizedStore(schema) {
1291
1307
  }
1292
1308
  function normalize(data, schema) {
1293
1309
  const entities = {};
1294
- const idKey = schema.idKey || "id";
1295
1310
  function ensureTable(name) {
1296
1311
  if (!entities[name]) {
1297
1312
  entities[name] = {};
@@ -1307,7 +1322,7 @@ function normalize(data, schema) {
1307
1322
  for (const [field, relationType] of Object.entries(entitySchema.relations)) {
1308
1323
  const value = entity[field];
1309
1324
  if (value == null) continue;
1310
- const relSchema = { name: relationType, idKey };
1325
+ const relSchema = { name: relationType };
1311
1326
  if (Array.isArray(value)) {
1312
1327
  flat[field] = value.map((item) => normalizeEntity(item, relSchema));
1313
1328
  } else if (typeof value === "object") {
@@ -1330,13 +1345,12 @@ function denormalize(id, entities, schema) {
1330
1345
  if (!table) return void 0;
1331
1346
  const entity = table[id];
1332
1347
  if (!entity) return void 0;
1333
- const idKey = schema.idKey || "id";
1334
1348
  const result = { ...entity };
1335
1349
  if (schema.relations) {
1336
1350
  for (const [field, relationType] of Object.entries(schema.relations)) {
1337
1351
  const value = entity[field];
1338
1352
  if (value == null) continue;
1339
- const relSchema = { name: relationType, idKey };
1353
+ const relSchema = { name: relationType };
1340
1354
  if (Array.isArray(value)) {
1341
1355
  result[field] = value.map((relId) => denormalize(relId, entities, relSchema));
1342
1356
  } else if (typeof value === "string") {
@@ -33,16 +33,17 @@ import {
33
33
  transitionState,
34
34
  uniqueId,
35
35
  yieldToMain
36
- } from "./chunk-YUR5SX7F.js";
36
+ } from "./chunk-WTFMV2RU.js";
37
+ import "./chunk-7ZHH77QA.js";
37
38
  import {
38
39
  trustHTML
39
40
  } from "./chunk-EX77FXTT.js";
40
- import "./chunk-5VGSK6D2.js";
41
41
  import "./chunk-L3GAGWCC.js";
42
- import "./chunk-N5TQVEKE.js";
42
+ import "./chunk-23VT3KZB.js";
43
43
  import "./chunk-S3NFJO6L.js";
44
- import "./chunk-JCQG2I2G.js";
45
- import "./chunk-4NJEAPLI.js";
44
+ import "./chunk-5VGSK6D2.js";
45
+ import "./chunk-IWFE4AHO.js";
46
+ import "./chunk-UOMYIAG6.js";
46
47
  import "./chunk-COY6PUD2.js";
47
48
  export {
48
49
  DOMPool,
package/dist/plugins.cjs CHANGED
@@ -1228,7 +1228,7 @@ function forEachSubscriber(signal2, visit) {
1228
1228
 
1229
1229
  // src/reactivity/track.ts
1230
1230
  var _isDev3 = isDev();
1231
- var _runtimeVersion = true ? "3.3.2" : "dev";
1231
+ var _runtimeVersion = true ? "3.3.3" : "dev";
1232
1232
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
1233
1233
  function resolveReactiveApi() {
1234
1234
  const g2 = globalThis;
@@ -1983,9 +1983,19 @@ function signal(initial, options) {
1983
1983
  return [get, set];
1984
1984
  }
1985
1985
 
1986
+ // src/utils/globalSingleton.ts
1987
+ function globalSingleton(key, create) {
1988
+ const g2 = globalThis;
1989
+ return g2[key] ?? (g2[key] = create());
1990
+ }
1991
+
1986
1992
  // src/plugins/i18n.ts
1987
- var [currentLocale, setLocaleInternal] = signal("en");
1988
- var locales = {};
1993
+ var _i18n = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.i18n.v1"), () => ({
1994
+ locale: signal("en"),
1995
+ locales: {}
1996
+ }));
1997
+ var [currentLocale, setLocaleInternal] = _i18n.locale;
1998
+ var locales = _i18n.locales;
1989
1999
  function setLocale(locale) {
1990
2000
  setLocaleInternal(locale);
1991
2001
  }
@@ -2212,14 +2222,39 @@ var NavigationController = class {
2212
2222
  return this.currentController !== null;
2213
2223
  }
2214
2224
  };
2215
- var RouteMatcher = class {
2225
+ var RouteMatcher = class _RouteMatcher {
2216
2226
  constructor(routes) {
2217
2227
  this.routeTrie = /* @__PURE__ */ new Map();
2218
2228
  this.parentChain = /* @__PURE__ */ new Map();
2219
2229
  this.namedRoutes = /* @__PURE__ */ new Map();
2220
2230
  this.compiledPatterns = new LRUCache(50);
2231
+ // Pattern routes (those with params/wildcards) ordered most-specific-first,
2232
+ // rebuilt lazily after any mutation. Static full paths are served by the
2233
+ // exact-match map and excluded here.
2234
+ this.patternOrder = null;
2221
2235
  this.buildIndex(routes);
2222
2236
  }
2237
+ // Specificity per segment: static (2) > param `:x` (1) > wildcard `*` (0).
2238
+ static specificity(path2) {
2239
+ return path2.split("/").filter(Boolean).map((seg) => seg.startsWith(":") ? 1 : seg.includes("*") ? 0 : 2);
2240
+ }
2241
+ getPatternOrder() {
2242
+ if (this.patternOrder) return this.patternOrder;
2243
+ const patterns = [...this.routeTrie].filter(([p2]) => p2.includes(":") || p2.includes("*"));
2244
+ patterns.sort(([a2], [b2]) => {
2245
+ const ka = _RouteMatcher.specificity(a2);
2246
+ const kb = _RouteMatcher.specificity(b2);
2247
+ const len = Math.max(ka.length, kb.length);
2248
+ for (let i2 = 0; i2 < len; i2++) {
2249
+ const va = ka[i2] ?? -1;
2250
+ const vb = kb[i2] ?? -1;
2251
+ if (va !== vb) return vb - va;
2252
+ }
2253
+ return 0;
2254
+ });
2255
+ this.patternOrder = patterns;
2256
+ return patterns;
2257
+ }
2223
2258
  buildIndex(routes, parentPath = "", ancestors = []) {
2224
2259
  for (const route2 of routes) {
2225
2260
  const fullPath = parentPath + route2.path;
@@ -2246,7 +2281,7 @@ var RouteMatcher = class {
2246
2281
  if (exactMatch) {
2247
2282
  return { route: exactMatch, params: {}, matched: this.parentChain.get(path2) || [exactMatch] };
2248
2283
  }
2249
- for (const [routePath, route2] of this.routeTrie) {
2284
+ for (const [routePath, route2] of this.getPatternOrder()) {
2250
2285
  const match = this.matchPattern(path2, routePath);
2251
2286
  if (match) {
2252
2287
  return { route: route2, params: match.params, matched: this.parentChain.get(routePath) || [route2] };
@@ -2318,9 +2353,11 @@ var RouteMatcher = class {
2318
2353
  this.parentChain.clear();
2319
2354
  this.namedRoutes.clear();
2320
2355
  this.compiledPatterns.clear();
2356
+ this.patternOrder = null;
2321
2357
  this.buildIndex(routes);
2322
2358
  }
2323
2359
  addRoute(route2, parentPath = "") {
2360
+ this.patternOrder = null;
2324
2361
  const fullPath = parentPath + route2.path;
2325
2362
  const parentAncestors = this.parentChain.get(parentPath) || [];
2326
2363
  const chain = [...parentAncestors, route2];
@@ -2335,6 +2372,7 @@ var RouteMatcher = class {
2335
2372
  }
2336
2373
  removeRoute(path2) {
2337
2374
  this.compiledPatterns.clear();
2375
+ this.patternOrder = null;
2338
2376
  const root = this.routeTrie.get(path2);
2339
2377
  if (!root) return;
2340
2378
  const removed = /* @__PURE__ */ new Set();
@@ -2601,14 +2639,16 @@ var _SibuRouter = class _SibuRouter {
2601
2639
  this.initialize();
2602
2640
  }
2603
2641
  initialize() {
2604
- if (this.options.mode === "history") {
2605
- const popstateHandler = () => this.handleLocationChange(true);
2606
- window.addEventListener("popstate", popstateHandler);
2607
- this.cleanup.push(() => window.removeEventListener("popstate", popstateHandler));
2608
- } else {
2609
- const hashHandler = () => this.handleLocationChange(true);
2610
- window.addEventListener("hashchange", hashHandler);
2611
- this.cleanup.push(() => window.removeEventListener("hashchange", hashHandler));
2642
+ if (typeof window !== "undefined") {
2643
+ if (this.options.mode === "history") {
2644
+ const popstateHandler = () => this.handleLocationChange(true);
2645
+ window.addEventListener("popstate", popstateHandler);
2646
+ this.cleanup.push(() => window.removeEventListener("popstate", popstateHandler));
2647
+ } else {
2648
+ const hashHandler = () => this.handleLocationChange(true);
2649
+ window.addEventListener("hashchange", hashHandler);
2650
+ this.cleanup.push(() => window.removeEventListener("hashchange", hashHandler));
2651
+ }
2612
2652
  }
2613
2653
  queueMicrotask(() => {
2614
2654
  this.handleLocationChange(true);
@@ -3149,10 +3189,15 @@ function Route() {
3149
3189
  if (!routeInitialized && anchor.parentNode) wrappedUpdate();
3150
3190
  });
3151
3191
  }
3152
- routeCleanups.push(() => {
3192
+ let routeTorn = false;
3193
+ const routeCleanup = () => {
3194
+ if (routeTorn) return;
3195
+ routeTorn = true;
3153
3196
  routeTeardown();
3154
3197
  cleanupNodes();
3155
- });
3198
+ };
3199
+ registerDisposer(anchor, routeCleanup);
3200
+ routeCleanups.push(routeCleanup);
3156
3201
  return anchor;
3157
3202
  }
3158
3203
  function KeepAliveRoute(options) {
@@ -3262,7 +3307,10 @@ function KeepAliveRoute(options) {
3262
3307
  if (!initialized && anchor.parentNode) wrappedUpdate();
3263
3308
  });
3264
3309
  }
3265
- routeCleanups.push(() => {
3310
+ let kaTorn = false;
3311
+ const kaCleanup = () => {
3312
+ if (kaTorn) return;
3313
+ kaTorn = true;
3266
3314
  kaTeardown();
3267
3315
  for (const node of cache.values()) {
3268
3316
  dispose(node);
@@ -3272,12 +3320,15 @@ function KeepAliveRoute(options) {
3272
3320
  lruOrder.length = 0;
3273
3321
  if (currentNode?.parentNode) currentNode.parentNode.removeChild(currentNode);
3274
3322
  currentNode = null;
3275
- });
3323
+ };
3324
+ registerDisposer(anchor, kaCleanup);
3325
+ routeCleanups.push(kaCleanup);
3276
3326
  return anchor;
3277
3327
  }
3278
- function RouterLink(props) {
3328
+ function RouterLink(props, children) {
3279
3329
  if (!_routerRef.current) throw new Error("Router not initialized. Call createRouter() first.");
3280
3330
  const { to, replace: replace2 = false, activeClass, exactActiveClass, nodes, target, rel, class: classAttr, ...attrs } = props;
3331
+ const content = children !== void 0 ? children : nodes;
3281
3332
  const baseClass = typeof classAttr === "string" ? classAttr : "";
3282
3333
  const routeGetter = _routerRef.current.routeGetter;
3283
3334
  const rawHref = _routerRef.current["resolvePath"](to);
@@ -3327,12 +3378,12 @@ function RouterLink(props) {
3327
3378
  }
3328
3379
  }
3329
3380
  });
3330
- if (typeof nodes === "string") {
3331
- link2.textContent = nodes;
3332
- } else if (nodes instanceof Node) {
3333
- link2.appendChild(nodes);
3334
- } else if (Array.isArray(nodes)) {
3335
- nodes.forEach((child) => {
3381
+ if (typeof content === "string") {
3382
+ link2.textContent = content;
3383
+ } else if (content instanceof Node) {
3384
+ link2.appendChild(content);
3385
+ } else if (Array.isArray(content)) {
3386
+ content.forEach((child) => {
3336
3387
  if (typeof child === "string") {
3337
3388
  link2.appendChild(document.createTextNode(child));
3338
3389
  } else if (child instanceof Node) {
@@ -3527,14 +3578,19 @@ function Outlet() {
3527
3578
  if (anchor.parentNode) update();
3528
3579
  });
3529
3580
  }
3530
- routeCleanups.push(() => {
3581
+ let outletTorn = false;
3582
+ const outletCleanup = () => {
3583
+ if (outletTorn) return;
3584
+ outletTorn = true;
3531
3585
  outletTeardown();
3532
3586
  if (currentNode) {
3533
3587
  dispose(currentNode);
3534
3588
  if (currentNode.parentNode) currentNode.parentNode.removeChild(currentNode);
3535
3589
  currentNode = null;
3536
3590
  }
3537
- });
3591
+ };
3592
+ registerDisposer(anchor, outletCleanup);
3593
+ routeCleanups.push(outletCleanup);
3538
3594
  return anchor;
3539
3595
  }
3540
3596
  function addRoute(route2, parentPath) {
@@ -4011,39 +4067,41 @@ function createPluginRegistry() {
4011
4067
  };
4012
4068
  return registry;
4013
4069
  }
4014
- var defaultRegistry = createPluginRegistry();
4015
- var defaultRegistryTouched = false;
4070
+ var _defaults = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.plugins.defaultRegistry.v1"), () => ({
4071
+ registry: createPluginRegistry(),
4072
+ touched: false
4073
+ }));
4016
4074
  function createPlugin(name, install) {
4017
4075
  return { name, install };
4018
4076
  }
4019
4077
  function plugin(plugin2, options) {
4020
- defaultRegistryTouched = true;
4021
- defaultRegistry.plugin(plugin2, options);
4078
+ _defaults.touched = true;
4079
+ _defaults.registry.plugin(plugin2, options);
4022
4080
  }
4023
4081
  function inject(key, defaultValue) {
4024
- return defaultRegistry.inject(key, defaultValue);
4082
+ return _defaults.registry.inject(key, defaultValue);
4025
4083
  }
4026
4084
  function triggerPluginMount(element) {
4027
- defaultRegistry.triggerMount(element);
4085
+ _defaults.registry.triggerMount(element);
4028
4086
  }
4029
4087
  function triggerPluginUnmount(element) {
4030
- defaultRegistry.triggerUnmount(element);
4088
+ _defaults.registry.triggerUnmount(element);
4031
4089
  }
4032
4090
  function triggerPluginError(error) {
4033
- defaultRegistry.triggerError(error);
4091
+ _defaults.registry.triggerError(error);
4034
4092
  }
4035
4093
  function resetPlugins() {
4036
- defaultRegistry.reset();
4037
- defaultRegistryTouched = false;
4094
+ _defaults.registry.reset();
4095
+ _defaults.touched = false;
4038
4096
  }
4039
4097
  function setDefaultPluginRegistry(registry) {
4040
- if (defaultRegistryTouched && defaultRegistry.installedPlugins.size > 0) {
4098
+ if (_defaults.touched && _defaults.registry.installedPlugins.size > 0) {
4041
4099
  console.warn(
4042
4100
  "[Plugin] Replacing default plugin registry while plugins are already installed on the singleton. This may indicate mixed singleton/registry usage."
4043
4101
  );
4044
4102
  }
4045
- defaultRegistry = registry;
4046
- defaultRegistryTouched = true;
4103
+ _defaults.registry = registry;
4104
+ _defaults.touched = true;
4047
4105
  }
4048
4106
 
4049
4107
  // src/plugins/modular.ts
@@ -4145,9 +4203,7 @@ function lazyModule(loader) {
4145
4203
  return loadedFlag;
4146
4204
  },
4147
4205
  async get() {
4148
- if (loadedFlag && cached !== void 0) {
4149
- return cached;
4150
- }
4206
+ if (loadedFlag) return cached;
4151
4207
  cached = await loader();
4152
4208
  loadedFlag = true;
4153
4209
  return cached;
@@ -254,11 +254,12 @@ declare function RouterLink(props: {
254
254
  replace?: boolean;
255
255
  activeClass?: string;
256
256
  exactActiveClass?: string;
257
+ /** @deprecated Pass children positionally: `RouterLink(props, children)`. */
257
258
  nodes?: string | Node | (string | Node)[];
258
259
  target?: string;
259
260
  rel?: string;
260
261
  [key: string]: unknown;
261
- }): HTMLElement;
262
+ }, children?: string | Node | (string | Node)[]): HTMLElement;
262
263
  declare function Suspense(props: {
263
264
  fallback?: () => HTMLElement | HTMLElement;
264
265
  nodes: () => HTMLElement | Promise<HTMLElement>;
package/dist/plugins.d.ts CHANGED
@@ -254,11 +254,12 @@ declare function RouterLink(props: {
254
254
  replace?: boolean;
255
255
  activeClass?: string;
256
256
  exactActiveClass?: string;
257
+ /** @deprecated Pass children positionally: `RouterLink(props, children)`. */
257
258
  nodes?: string | Node | (string | Node)[];
258
259
  target?: string;
259
260
  rel?: string;
260
261
  [key: string]: unknown;
261
- }): HTMLElement;
262
+ }, children?: string | Node | (string | Node)[]): HTMLElement;
262
263
  declare function Suspense(props: {
263
264
  fallback?: () => HTMLElement | HTMLElement;
264
265
  nodes: () => HTMLElement | Promise<HTMLElement>;