sibujs 3.3.2 → 3.4.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 (77) hide show
  1. package/dist/browser.cjs +21 -4
  2. package/dist/browser.js +4 -4
  3. package/dist/build.cjs +3343 -3009
  4. package/dist/build.js +12 -11
  5. package/dist/cdn.global.js +7 -7
  6. package/dist/{chunk-AEOLHSSQ.js → chunk-3DVGCW7O.js} +72 -25
  7. package/dist/{chunk-6TCOWMGY.js → chunk-3Z2NGWQI.js} +1 -1
  8. package/dist/chunk-7ZHH77QA.js +9 -0
  9. package/dist/{chunk-2ARSB7NG.js → chunk-APFRCIRI.js} +2906 -2569
  10. package/dist/{chunk-62V653X2.js → chunk-AXFWGY32.js} +79 -44
  11. package/dist/{chunk-N5TQVEKE.js → chunk-BUKYCWHX.js} +1 -1
  12. package/dist/{chunk-655B7MMR.js → chunk-CEBWDD63.js} +15 -8
  13. package/dist/{chunk-YUBEOWII.js → chunk-ELXMRSVN.js} +16 -5
  14. package/dist/{chunk-FJIRS3FM.js → chunk-F7HW2NI5.js} +1 -3
  15. package/dist/{chunk-P7C7SEJV.js → chunk-FKQG7FTY.js} +5 -5
  16. package/dist/{chunk-RLTFJYDN.js → chunk-H5FI5WDP.js} +1 -1
  17. package/dist/{chunk-G6N3LMO2.js → chunk-ITWCTZYH.js} +1 -1
  18. package/dist/{chunk-YUR5SX7F.js → chunk-JCO7AHNU.js} +70 -59
  19. package/dist/{chunk-ZEUP4TUD.js → chunk-JNGGM2XE.js} +6 -6
  20. package/dist/{chunk-QCFBIVIQ.js → chunk-K35BAR4P.js} +1 -1
  21. package/dist/{chunk-JCQG2I2G.js → chunk-KZBEVFXZ.js} +1 -1
  22. package/dist/{chunk-FJO2ZL4Q.js → chunk-OAVXAFAY.js} +73 -16
  23. package/dist/{chunk-A7CZH3GN.js → chunk-ODXVQ3CS.js} +41 -20
  24. package/dist/{chunk-4NJEAPLI.js → chunk-OOUQUCNN.js} +1 -1
  25. package/dist/{chunk-5VH3GIDX.js → chunk-RT3IYFN2.js} +1 -1
  26. package/dist/{chunk-Q46YIQYW.js → chunk-S3V6ZXPI.js} +22 -5
  27. package/dist/{chunk-IQJ36UTJ.js → chunk-WSGLJYFI.js} +31 -24
  28. package/dist/{chunk-3JHCYHWN.js → chunk-WWV3SJ3L.js} +19 -13
  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.d.cts +1 -1
  37. package/dist/ecosystem.d.ts +1 -1
  38. package/dist/ecosystem.js +10 -9
  39. package/dist/extras.cjs +454 -250
  40. package/dist/extras.d.cts +2 -2
  41. package/dist/extras.d.ts +2 -2
  42. package/dist/extras.js +26 -22
  43. package/dist/index.cjs +3385 -3045
  44. package/dist/index.d.cts +1179 -1057
  45. package/dist/index.d.ts +1179 -1057
  46. package/dist/index.js +32 -19
  47. package/dist/motion.cjs +223 -204
  48. package/dist/motion.d.cts +8 -1
  49. package/dist/motion.d.ts +8 -1
  50. package/dist/motion.js +6 -3
  51. package/dist/patterns.cjs +13 -6
  52. package/dist/patterns.d.cts +4 -1
  53. package/dist/patterns.d.ts +4 -1
  54. package/dist/patterns.js +5 -5
  55. package/dist/performance.cjs +70 -56
  56. package/dist/performance.js +6 -5
  57. package/dist/plugins.cjs +98 -42
  58. package/dist/plugins.d.cts +2 -1
  59. package/dist/plugins.d.ts +2 -1
  60. package/dist/plugins.js +89 -36
  61. package/dist/ssr.cjs +112 -91
  62. package/dist/ssr.d.cts +8 -1
  63. package/dist/ssr.d.ts +8 -1
  64. package/dist/ssr.js +9 -8
  65. package/dist/{tagFactory-S17H2qxu.d.ts → tagFactory-Bzupt4Pj.d.cts} +1 -1
  66. package/dist/{tagFactory-S17H2qxu.d.cts → tagFactory-Bzupt4Pj.d.ts} +1 -1
  67. package/dist/testing.cjs +18 -4
  68. package/dist/testing.js +18 -7
  69. package/dist/ui.cjs +322 -281
  70. package/dist/ui.d.cts +0 -20
  71. package/dist/ui.d.ts +0 -20
  72. package/dist/ui.js +27 -21
  73. package/dist/widgets.cjs +75 -13
  74. package/dist/widgets.d.cts +6 -1
  75. package/dist/widgets.d.ts +6 -1
  76. package/dist/widgets.js +7 -6
  77. package/package.json +4 -1
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.4.0" : "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>;
package/dist/plugins.js CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  preloadCritical,
19
19
  prerenderRoutes,
20
20
  satisfies
21
- } from "./chunk-FJIRS3FM.js";
21
+ } from "./chunk-F7HW2NI5.js";
22
22
  import {
23
23
  isUnsafeKey
24
24
  } from "./chunk-H3SRKIYX.js";
@@ -32,21 +32,20 @@ import {
32
32
  triggerPluginError,
33
33
  triggerPluginMount,
34
34
  triggerPluginUnmount
35
- } from "./chunk-3JHCYHWN.js";
35
+ } from "./chunk-WWV3SJ3L.js";
36
36
  import {
37
37
  span
38
- } from "./chunk-6TCOWMGY.js";
38
+ } from "./chunk-3Z2NGWQI.js";
39
39
  import {
40
40
  escapeScriptJson,
41
41
  isDangerousMetaRefresh,
42
42
  renderToString
43
43
  } from "./chunk-EX77FXTT.js";
44
- import "./chunk-ZEUP4TUD.js";
45
- import "./chunk-QCFBIVIQ.js";
44
+ import "./chunk-JNGGM2XE.js";
45
+ import "./chunk-K35BAR4P.js";
46
46
  import {
47
- dispose,
48
- registerDisposer
49
- } from "./chunk-5VGSK6D2.js";
47
+ globalSingleton
48
+ } from "./chunk-7ZHH77QA.js";
50
49
  import {
51
50
  isUrlAttribute,
52
51
  sanitizeCSSValue,
@@ -55,19 +54,27 @@ import {
55
54
  } from "./chunk-L3GAGWCC.js";
56
55
  import {
57
56
  effect
58
- } from "./chunk-N5TQVEKE.js";
57
+ } from "./chunk-BUKYCWHX.js";
59
58
  import "./chunk-S3NFJO6L.js";
59
+ import {
60
+ dispose,
61
+ registerDisposer
62
+ } from "./chunk-5VGSK6D2.js";
60
63
  import {
61
64
  signal
62
- } from "./chunk-JCQG2I2G.js";
65
+ } from "./chunk-KZBEVFXZ.js";
63
66
  import {
64
67
  track
65
- } from "./chunk-4NJEAPLI.js";
68
+ } from "./chunk-OOUQUCNN.js";
66
69
  import "./chunk-COY6PUD2.js";
67
70
 
68
71
  // src/plugins/i18n.ts
69
- var [currentLocale, setLocaleInternal] = signal("en");
70
- var locales = {};
72
+ var _i18n = globalSingleton(/* @__PURE__ */ Symbol.for("sibujs.i18n.v1"), () => ({
73
+ locale: signal("en"),
74
+ locales: {}
75
+ }));
76
+ var [currentLocale, setLocaleInternal] = _i18n.locale;
77
+ var locales = _i18n.locales;
71
78
  function setLocale(locale) {
72
79
  setLocaleInternal(locale);
73
80
  }
@@ -170,14 +177,39 @@ var NavigationController = class {
170
177
  return this.currentController !== null;
171
178
  }
172
179
  };
173
- var RouteMatcher = class {
180
+ var RouteMatcher = class _RouteMatcher {
174
181
  constructor(routes) {
175
182
  this.routeTrie = /* @__PURE__ */ new Map();
176
183
  this.parentChain = /* @__PURE__ */ new Map();
177
184
  this.namedRoutes = /* @__PURE__ */ new Map();
178
185
  this.compiledPatterns = new LRUCache(50);
186
+ // Pattern routes (those with params/wildcards) ordered most-specific-first,
187
+ // rebuilt lazily after any mutation. Static full paths are served by the
188
+ // exact-match map and excluded here.
189
+ this.patternOrder = null;
179
190
  this.buildIndex(routes);
180
191
  }
192
+ // Specificity per segment: static (2) > param `:x` (1) > wildcard `*` (0).
193
+ static specificity(path) {
194
+ return path.split("/").filter(Boolean).map((seg) => seg.startsWith(":") ? 1 : seg.includes("*") ? 0 : 2);
195
+ }
196
+ getPatternOrder() {
197
+ if (this.patternOrder) return this.patternOrder;
198
+ const patterns = [...this.routeTrie].filter(([p]) => p.includes(":") || p.includes("*"));
199
+ patterns.sort(([a], [b]) => {
200
+ const ka = _RouteMatcher.specificity(a);
201
+ const kb = _RouteMatcher.specificity(b);
202
+ const len = Math.max(ka.length, kb.length);
203
+ for (let i = 0; i < len; i++) {
204
+ const va = ka[i] ?? -1;
205
+ const vb = kb[i] ?? -1;
206
+ if (va !== vb) return vb - va;
207
+ }
208
+ return 0;
209
+ });
210
+ this.patternOrder = patterns;
211
+ return patterns;
212
+ }
181
213
  buildIndex(routes, parentPath = "", ancestors = []) {
182
214
  for (const route2 of routes) {
183
215
  const fullPath = parentPath + route2.path;
@@ -204,7 +236,7 @@ var RouteMatcher = class {
204
236
  if (exactMatch) {
205
237
  return { route: exactMatch, params: {}, matched: this.parentChain.get(path) || [exactMatch] };
206
238
  }
207
- for (const [routePath, route2] of this.routeTrie) {
239
+ for (const [routePath, route2] of this.getPatternOrder()) {
208
240
  const match = this.matchPattern(path, routePath);
209
241
  if (match) {
210
242
  return { route: route2, params: match.params, matched: this.parentChain.get(routePath) || [route2] };
@@ -276,9 +308,11 @@ var RouteMatcher = class {
276
308
  this.parentChain.clear();
277
309
  this.namedRoutes.clear();
278
310
  this.compiledPatterns.clear();
311
+ this.patternOrder = null;
279
312
  this.buildIndex(routes);
280
313
  }
281
314
  addRoute(route2, parentPath = "") {
315
+ this.patternOrder = null;
282
316
  const fullPath = parentPath + route2.path;
283
317
  const parentAncestors = this.parentChain.get(parentPath) || [];
284
318
  const chain = [...parentAncestors, route2];
@@ -293,6 +327,7 @@ var RouteMatcher = class {
293
327
  }
294
328
  removeRoute(path) {
295
329
  this.compiledPatterns.clear();
330
+ this.patternOrder = null;
296
331
  const root = this.routeTrie.get(path);
297
332
  if (!root) return;
298
333
  const removed = /* @__PURE__ */ new Set();
@@ -559,14 +594,16 @@ var _SibuRouter = class _SibuRouter {
559
594
  this.initialize();
560
595
  }
561
596
  initialize() {
562
- if (this.options.mode === "history") {
563
- const popstateHandler = () => this.handleLocationChange(true);
564
- window.addEventListener("popstate", popstateHandler);
565
- this.cleanup.push(() => window.removeEventListener("popstate", popstateHandler));
566
- } else {
567
- const hashHandler = () => this.handleLocationChange(true);
568
- window.addEventListener("hashchange", hashHandler);
569
- this.cleanup.push(() => window.removeEventListener("hashchange", hashHandler));
597
+ if (typeof window !== "undefined") {
598
+ if (this.options.mode === "history") {
599
+ const popstateHandler = () => this.handleLocationChange(true);
600
+ window.addEventListener("popstate", popstateHandler);
601
+ this.cleanup.push(() => window.removeEventListener("popstate", popstateHandler));
602
+ } else {
603
+ const hashHandler = () => this.handleLocationChange(true);
604
+ window.addEventListener("hashchange", hashHandler);
605
+ this.cleanup.push(() => window.removeEventListener("hashchange", hashHandler));
606
+ }
570
607
  }
571
608
  queueMicrotask(() => {
572
609
  this.handleLocationChange(true);
@@ -1107,10 +1144,15 @@ function Route() {
1107
1144
  if (!routeInitialized && anchor.parentNode) wrappedUpdate();
1108
1145
  });
1109
1146
  }
1110
- routeCleanups.push(() => {
1147
+ let routeTorn = false;
1148
+ const routeCleanup = () => {
1149
+ if (routeTorn) return;
1150
+ routeTorn = true;
1111
1151
  routeTeardown();
1112
1152
  cleanupNodes();
1113
- });
1153
+ };
1154
+ registerDisposer(anchor, routeCleanup);
1155
+ routeCleanups.push(routeCleanup);
1114
1156
  return anchor;
1115
1157
  }
1116
1158
  function KeepAliveRoute(options) {
@@ -1220,7 +1262,10 @@ function KeepAliveRoute(options) {
1220
1262
  if (!initialized && anchor.parentNode) wrappedUpdate();
1221
1263
  });
1222
1264
  }
1223
- routeCleanups.push(() => {
1265
+ let kaTorn = false;
1266
+ const kaCleanup = () => {
1267
+ if (kaTorn) return;
1268
+ kaTorn = true;
1224
1269
  kaTeardown();
1225
1270
  for (const node of cache.values()) {
1226
1271
  dispose(node);
@@ -1230,12 +1275,15 @@ function KeepAliveRoute(options) {
1230
1275
  lruOrder.length = 0;
1231
1276
  if (currentNode?.parentNode) currentNode.parentNode.removeChild(currentNode);
1232
1277
  currentNode = null;
1233
- });
1278
+ };
1279
+ registerDisposer(anchor, kaCleanup);
1280
+ routeCleanups.push(kaCleanup);
1234
1281
  return anchor;
1235
1282
  }
1236
- function RouterLink(props) {
1283
+ function RouterLink(props, children) {
1237
1284
  if (!_routerRef.current) throw new Error("Router not initialized. Call createRouter() first.");
1238
1285
  const { to, replace: replace2 = false, activeClass, exactActiveClass, nodes, target, rel, class: classAttr, ...attrs } = props;
1286
+ const content = children !== void 0 ? children : nodes;
1239
1287
  const baseClass = typeof classAttr === "string" ? classAttr : "";
1240
1288
  const routeGetter = _routerRef.current.routeGetter;
1241
1289
  const rawHref = _routerRef.current["resolvePath"](to);
@@ -1285,12 +1333,12 @@ function RouterLink(props) {
1285
1333
  }
1286
1334
  }
1287
1335
  });
1288
- if (typeof nodes === "string") {
1289
- link.textContent = nodes;
1290
- } else if (nodes instanceof Node) {
1291
- link.appendChild(nodes);
1292
- } else if (Array.isArray(nodes)) {
1293
- nodes.forEach((child) => {
1336
+ if (typeof content === "string") {
1337
+ link.textContent = content;
1338
+ } else if (content instanceof Node) {
1339
+ link.appendChild(content);
1340
+ } else if (Array.isArray(content)) {
1341
+ content.forEach((child) => {
1294
1342
  if (typeof child === "string") {
1295
1343
  link.appendChild(document.createTextNode(child));
1296
1344
  } else if (child instanceof Node) {
@@ -1485,14 +1533,19 @@ function Outlet() {
1485
1533
  if (anchor.parentNode) update();
1486
1534
  });
1487
1535
  }
1488
- routeCleanups.push(() => {
1536
+ let outletTorn = false;
1537
+ const outletCleanup = () => {
1538
+ if (outletTorn) return;
1539
+ outletTorn = true;
1489
1540
  outletTeardown();
1490
1541
  if (currentNode) {
1491
1542
  dispose(currentNode);
1492
1543
  if (currentNode.parentNode) currentNode.parentNode.removeChild(currentNode);
1493
1544
  currentNode = null;
1494
1545
  }
1495
- });
1546
+ };
1547
+ registerDisposer(anchor, outletCleanup);
1548
+ routeCleanups.push(outletCleanup);
1496
1549
  return anchor;
1497
1550
  }
1498
1551
  function addRoute(route2, parentPath) {