sibujs 4.8.0 → 4.10.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.
- package/dist/browser.cjs +44 -6
- package/dist/browser.d.cts +3 -2
- package/dist/browser.d.ts +3 -2
- package/dist/browser.js +4 -4
- package/dist/build.cjs +128 -56
- package/dist/build.js +10 -10
- package/dist/cdn.dev.global.js +14 -14
- package/dist/cdn.full.dev.global.js +13 -13
- package/dist/cdn.full.global.js +12 -12
- package/dist/cdn.global.js +15 -15
- package/dist/{chunk-J3YQ457H.js → chunk-2NWHJ2UJ.js} +99 -61
- package/dist/{chunk-JUTFX2RM.js → chunk-4DCVJ4YA.js} +42 -15
- package/dist/{chunk-QGMSESDD.js → chunk-54F4TPHK.js} +2 -2
- package/dist/{chunk-KJ3UKABJ.js → chunk-5PC7OTQW.js} +1 -1
- package/dist/{chunk-V3LHZSU5.js → chunk-7WIHYHWD.js} +8 -1
- package/dist/{chunk-44MTL7ED.js → chunk-BMCR7TXG.js} +3 -3
- package/dist/{chunk-TQQUN4WR.js → chunk-D6HYFOWR.js} +39 -4
- package/dist/{chunk-VWT3VXPL.js → chunk-EVI4ZQO3.js} +2 -2
- package/dist/{chunk-CZPRSWSS.js → chunk-EVOK663Z.js} +1 -1
- package/dist/{chunk-DSID757X.js → chunk-FYUEL5IW.js} +1 -1
- package/dist/{chunk-UCNP3HVM.js → chunk-GMMDHJJT.js} +30 -12
- package/dist/{chunk-C7AA2CZX.js → chunk-GOL3FU5Q.js} +1 -1
- package/dist/{chunk-EGUQLBHE.js → chunk-GTS35FLA.js} +5 -4
- package/dist/{chunk-GSGNX35Q.js → chunk-IFRIBZ4O.js} +4 -4
- package/dist/{chunk-C5PEWEGH.js → chunk-IL5MMSCL.js} +19 -12
- package/dist/{chunk-ZVLHNEEL.js → chunk-ITEL5KPL.js} +6 -6
- package/dist/{chunk-RGLPEBDE.js → chunk-JCKUWWHU.js} +3 -3
- package/dist/{chunk-Q5J2LVKH.js → chunk-N6U4GOIU.js} +1 -1
- package/dist/{chunk-LI4W3U6C.js → chunk-TOPRMXFY.js} +1 -1
- package/dist/{chunk-4WMSTZ7J.js → chunk-VWPMWV7O.js} +4 -4
- package/dist/{chunk-O6TRVMJI.js → chunk-XUQUQJYE.js} +1 -1
- package/dist/data.cjs +67 -12
- package/dist/data.d.cts +32 -5
- package/dist/data.d.ts +32 -5
- package/dist/data.js +5 -5
- package/dist/devtools.cjs +41 -4
- package/dist/devtools.js +4 -4
- package/dist/ecosystem.cjs +41 -4
- package/dist/ecosystem.js +7 -7
- package/dist/extras.cjs +125 -41
- package/dist/extras.js +20 -20
- package/dist/index.cjs +128 -56
- package/dist/index.d.cts +22 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +10 -10
- package/dist/motion.cjs +36 -4
- package/dist/motion.js +3 -3
- package/dist/patterns.cjs +41 -4
- package/dist/patterns.js +5 -5
- package/dist/performance.cjs +55 -14
- package/dist/performance.js +4 -4
- package/dist/plugins.cjs +176 -60
- package/dist/plugins.d.cts +62 -2
- package/dist/plugins.d.ts +62 -2
- package/dist/plugins.js +143 -61
- package/dist/ssr.cjs +77 -16
- package/dist/ssr.d.cts +4 -0
- package/dist/ssr.d.ts +4 -0
- package/dist/ssr.js +7 -7
- package/dist/testing.cjs +41 -4
- package/dist/testing.js +2 -2
- package/dist/ui.cjs +42 -5
- package/dist/ui.js +7 -7
- package/dist/widgets.cjs +36 -4
- package/dist/widgets.js +6 -6
- package/package.json +1 -1
package/dist/plugins.d.ts
CHANGED
|
@@ -180,6 +180,12 @@ type Params = Record<string, string>;
|
|
|
180
180
|
interface RouteContext {
|
|
181
181
|
readonly path: string;
|
|
182
182
|
readonly params: Params;
|
|
183
|
+
/**
|
|
184
|
+
* The decoded query (`+` is a space, `%XX` is decoded). A repeated key keeps
|
|
185
|
+
* its last value: `?tag=a&tag=b` is `{ tag: "b" }`. Two locations are the
|
|
186
|
+
* same route — for duplicate detection and `RouterLink` exact-active — when
|
|
187
|
+
* their queries have the same entries in any order.
|
|
188
|
+
*/
|
|
183
189
|
readonly query: Params;
|
|
184
190
|
readonly hash: string;
|
|
185
191
|
readonly meta: RouteMeta;
|
|
@@ -421,8 +427,11 @@ declare class SibuRouter {
|
|
|
421
427
|
* anything. Pair with {@link instantiateComponent} at the commit boundary.
|
|
422
428
|
*/
|
|
423
429
|
loadPlan(route: RouteDef, routePath: string): Promise<RoutePlan>;
|
|
424
|
-
/**
|
|
425
|
-
|
|
430
|
+
/**
|
|
431
|
+
* Create exactly one real instance from an already-resolved plan. With a
|
|
432
|
+
* `scope`, the factory runs in it (see `RouteScope`).
|
|
433
|
+
*/
|
|
434
|
+
instantiateComponent(plan: RoutePlan, route: RouteDef, routePath: string, scope?: RouteScope): Promise<Element>;
|
|
426
435
|
/** Resolve a route's module/factory without creating any component instance. */
|
|
427
436
|
preloadPlan(route: RouteDef, routePath: string): Promise<void>;
|
|
428
437
|
beforeEach(guard: NavigationGuard): () => void;
|
|
@@ -469,6 +478,50 @@ declare function createRouter(routesOrOptions: RouteDef[] | RouterOptions, optio
|
|
|
469
478
|
* Set routes on the global router (replaces existing routes).
|
|
470
479
|
*/
|
|
471
480
|
declare function setRoutes(routes: RouteDef[]): void;
|
|
481
|
+
/**
|
|
482
|
+
* The route one mounted route instance was committed with.
|
|
483
|
+
*
|
|
484
|
+
* A navigation commits the router's route first; the outlet swaps the
|
|
485
|
+
* component afterwards — a microtask later for a synchronous page, a whole
|
|
486
|
+
* chunk download later for a lazy one. If route instances read the
|
|
487
|
+
* router-global route, the outgoing page re-runs its effects against the
|
|
488
|
+
* INCOMING route's params in that window, and its teardown sees them too.
|
|
489
|
+
*
|
|
490
|
+
* So each instance reads its own scope instead. Outlets create one per
|
|
491
|
+
* instance, run the component factory in it (an owner scope, see
|
|
492
|
+
* reactivity/track-core.ts, so every computation the page creates — now or
|
|
493
|
+
* later, through its directives — inherits it), and then:
|
|
494
|
+
*
|
|
495
|
+
* - an instance the outlet KEEPS across a navigation (same record and instance
|
|
496
|
+
* key: a query/hash-only change, or a layout whose child changed) is handed
|
|
497
|
+
* the new route — it follows the navigation, as before;
|
|
498
|
+
* - an instance being REPLACED is never updated: it keeps observing its own
|
|
499
|
+
* route until it is disposed, and its teardown runs in its scope;
|
|
500
|
+
* - a KeepAlive view keeps its route while cached and gets the new route when
|
|
501
|
+
* it is shown again.
|
|
502
|
+
*
|
|
503
|
+
* Once the instance is disposed the scope is released: a computation that
|
|
504
|
+
* outlived it (an app-lifetime derived that happened to be created while the
|
|
505
|
+
* page rendered) is not the page's, and falls back to the router-global route.
|
|
506
|
+
*/
|
|
507
|
+
declare class RouteScope {
|
|
508
|
+
private readonly get;
|
|
509
|
+
private readonly set;
|
|
510
|
+
private released;
|
|
511
|
+
constructor(route: RouteContext);
|
|
512
|
+
/** The instance's route, or `null` once released. Reactive. */
|
|
513
|
+
read(): RouteContext | null;
|
|
514
|
+
/** Hand a kept instance the route of the navigation that kept it. */
|
|
515
|
+
update(route: RouteContext): void;
|
|
516
|
+
/**
|
|
517
|
+
* Called when the instance is disposed. The switch to "no scope" is
|
|
518
|
+
* published a microtask later, once the whole dispose has finished: a
|
|
519
|
+
* teardown the instance registered after this one (an `onMount` effect, say)
|
|
520
|
+
* may still be alive at this point, and must not re-run against the
|
|
521
|
+
* router-global route on its way out.
|
|
522
|
+
*/
|
|
523
|
+
release(): void;
|
|
524
|
+
}
|
|
472
525
|
/**
|
|
473
526
|
* Read the current route as a plain snapshot.
|
|
474
527
|
*
|
|
@@ -477,6 +530,13 @@ declare function setRoutes(routes: RouteDef[]): void;
|
|
|
477
530
|
* `RouteBase.key`). Inside a getter — `() => route().params.id` — the read is
|
|
478
531
|
* reactive, which is what a long-lived layout or a constant-`key` route needs.
|
|
479
532
|
*
|
|
533
|
+
* Inside a route instance (anything its component creates, and any effect,
|
|
534
|
+
* derived or binding created from there) this is the route THAT INSTANCE was
|
|
535
|
+
* committed with. An instance the outlet keeps across a navigation follows it;
|
|
536
|
+
* an instance being replaced keeps its own route until it is disposed, so its
|
|
537
|
+
* effects and teardown never observe the next page's params. Everywhere else
|
|
538
|
+
* it is the router's current route.
|
|
539
|
+
*
|
|
480
540
|
* @returns The active {@link RouteContext} (path, params, query, hash).
|
|
481
541
|
* @throws If no router has been created yet.
|
|
482
542
|
*/
|
package/dist/plugins.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
preloadCritical,
|
|
20
20
|
prerenderRoutes,
|
|
21
21
|
satisfies
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-54F4TPHK.js";
|
|
23
23
|
import {
|
|
24
24
|
PluginInstallCancelledError,
|
|
25
25
|
createPlugin,
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
} from "./chunk-J6FW5TV6.js";
|
|
36
36
|
import {
|
|
37
37
|
span
|
|
38
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-N6U4GOIU.js";
|
|
39
39
|
import {
|
|
40
40
|
escapeScriptJson,
|
|
41
41
|
renderToString,
|
|
@@ -48,17 +48,17 @@ import {
|
|
|
48
48
|
import {
|
|
49
49
|
appendChildren,
|
|
50
50
|
resolveClassValue
|
|
51
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-EVI4ZQO3.js";
|
|
52
52
|
import {
|
|
53
53
|
setSafeAttribute
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-XUQUQJYE.js";
|
|
55
55
|
import "./chunk-3ACAAQIN.js";
|
|
56
56
|
import {
|
|
57
57
|
globalSingleton
|
|
58
58
|
} from "./chunk-7ZHH77QA.js";
|
|
59
59
|
import {
|
|
60
60
|
effect
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-7WIHYHWD.js";
|
|
62
62
|
import {
|
|
63
63
|
sanitizeUrl,
|
|
64
64
|
stripControlChars
|
|
@@ -69,11 +69,14 @@ import {
|
|
|
69
69
|
import "./chunk-5HZXGZ6T.js";
|
|
70
70
|
import {
|
|
71
71
|
signal
|
|
72
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-FYUEL5IW.js";
|
|
73
73
|
import {
|
|
74
|
+
bindOwnerScope,
|
|
75
|
+
getOwnerScope,
|
|
76
|
+
runWithOwnerScope,
|
|
74
77
|
track,
|
|
75
78
|
untracked
|
|
76
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-D6HYFOWR.js";
|
|
77
80
|
import {
|
|
78
81
|
devWarn,
|
|
79
82
|
dispose,
|
|
@@ -180,9 +183,14 @@ function normalizePathname(path) {
|
|
|
180
183
|
const trimmed = path.length > 1 ? path.replace(/\/+$/, "") : path;
|
|
181
184
|
return trimmed || "/";
|
|
182
185
|
}
|
|
183
|
-
function
|
|
184
|
-
|
|
185
|
-
|
|
186
|
+
function parseQuery(query) {
|
|
187
|
+
return Object.fromEntries(new URLSearchParams(query));
|
|
188
|
+
}
|
|
189
|
+
function paramsIdentity(params) {
|
|
190
|
+
return JSON.stringify(Object.entries(params).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0));
|
|
191
|
+
}
|
|
192
|
+
function queryIdentity(query) {
|
|
193
|
+
return paramsIdentity(typeof query === "string" ? parseQuery(query) : query);
|
|
186
194
|
}
|
|
187
195
|
function isPathnameAncestor(target, current) {
|
|
188
196
|
if (target === current) return true;
|
|
@@ -647,12 +655,12 @@ var _ComponentLoader = class _ComponentLoader {
|
|
|
647
655
|
* resolved, so the import happens once and later mounts call the module's
|
|
648
656
|
* factory directly.
|
|
649
657
|
*/
|
|
650
|
-
async instantiate(plan, route2, routePath) {
|
|
658
|
+
async instantiate(plan, route2, routePath, scope) {
|
|
651
659
|
if (plan.kind === "factory") {
|
|
652
|
-
return this.instantiateFactory(plan.component, route2, routePath);
|
|
660
|
+
return this.instantiateFactory(plan.component, route2, routePath, scope);
|
|
653
661
|
}
|
|
654
662
|
const factory = await this.resolveModuleFactory(plan, route2, routePath);
|
|
655
|
-
return this.instantiateFactory(factory, route2, routePath);
|
|
663
|
+
return this.instantiateFactory(factory, route2, routePath, scope);
|
|
656
664
|
}
|
|
657
665
|
/**
|
|
658
666
|
* Resolve a deferred plan's module and cache the factory it exports —
|
|
@@ -697,14 +705,14 @@ var _ComponentLoader = class _ComponentLoader {
|
|
|
697
705
|
* `depth` bounds that unwrapping; a module whose default is itself a module
|
|
698
706
|
* is a configuration error, not something to chase.
|
|
699
707
|
*/
|
|
700
|
-
async instantiateFactory(component, route2, routePath, depth = 0) {
|
|
701
|
-
const result = component();
|
|
708
|
+
async instantiateFactory(component, route2, routePath, scope, depth = 0) {
|
|
709
|
+
const result = scope ? runWithOwnerScope(scope, component) : component();
|
|
702
710
|
const value = this.isThenable(result) ? await result : result;
|
|
703
711
|
if (this.isElement(value)) return value;
|
|
704
712
|
if (depth === 0 && this.isFactoryLike(value)) {
|
|
705
713
|
const factory = this.extractFactory(value, routePath);
|
|
706
714
|
this.planCache.set(this.keyFor(route2), { kind: "factory", component: factory });
|
|
707
|
-
return this.instantiateFactory(factory, route2, routePath, depth + 1);
|
|
715
|
+
return this.instantiateFactory(factory, route2, routePath, scope, depth + 1);
|
|
708
716
|
}
|
|
709
717
|
throw new Error(`Component for route "${routePath}" must return Element, got ${typeof value}`);
|
|
710
718
|
}
|
|
@@ -883,7 +891,7 @@ var _SibuRouter = class _SibuRouter {
|
|
|
883
891
|
}
|
|
884
892
|
createRouteContext(fullPath) {
|
|
885
893
|
const { path, query: queryString, hash } = splitRouteUrl(fullPath);
|
|
886
|
-
const query =
|
|
894
|
+
const query = parseQuery(queryString);
|
|
887
895
|
const match = this.matcher.match(path || "/");
|
|
888
896
|
const params = match?.params || {};
|
|
889
897
|
const meta = match?.route.meta || {};
|
|
@@ -1047,7 +1055,7 @@ var _SibuRouter = class _SibuRouter {
|
|
|
1047
1055
|
}
|
|
1048
1056
|
isSameRoute(from, to) {
|
|
1049
1057
|
if (from.matched.length === 0 && to.matched.length > 0) return false;
|
|
1050
|
-
return from.path === to.path &&
|
|
1058
|
+
return from.path === to.path && paramsIdentity(from.params) === paramsIdentity(to.params) && queryIdentity(from.query) === queryIdentity(to.query) && from.hash === to.hash;
|
|
1051
1059
|
}
|
|
1052
1060
|
updateHistory(to, options) {
|
|
1053
1061
|
const fullPath = this.options.base + to.path + (Object.keys(to.query).length ? `?${new URLSearchParams(to.query).toString()}` : "") + (to.hash ? `#${to.hash}` : "");
|
|
@@ -1109,9 +1117,12 @@ var _SibuRouter = class _SibuRouter {
|
|
|
1109
1117
|
async loadPlan(route2, routePath) {
|
|
1110
1118
|
return this.loader.loadPlan(route2, routePath);
|
|
1111
1119
|
}
|
|
1112
|
-
/**
|
|
1113
|
-
|
|
1114
|
-
|
|
1120
|
+
/**
|
|
1121
|
+
* Create exactly one real instance from an already-resolved plan. With a
|
|
1122
|
+
* `scope`, the factory runs in it (see `RouteScope`).
|
|
1123
|
+
*/
|
|
1124
|
+
async instantiateComponent(plan, route2, routePath, scope) {
|
|
1125
|
+
return this.loader.instantiate(plan, route2, routePath, scope);
|
|
1115
1126
|
}
|
|
1116
1127
|
/** Resolve a route's module/factory without creating any component instance. */
|
|
1117
1128
|
async preloadPlan(route2, routePath) {
|
|
@@ -1267,14 +1278,72 @@ function setRoutes(routes) {
|
|
|
1267
1278
|
if (!_routerRef.current) throw new Error("Router not initialized. Call createRouter() first.");
|
|
1268
1279
|
_routerRef.current.updateRoutes(normalizeRoutes(routes));
|
|
1269
1280
|
}
|
|
1281
|
+
var RouteScope = class {
|
|
1282
|
+
constructor(route2) {
|
|
1283
|
+
this.released = false;
|
|
1284
|
+
const [get, set] = signal(route2);
|
|
1285
|
+
this.get = get;
|
|
1286
|
+
this.set = set;
|
|
1287
|
+
}
|
|
1288
|
+
/** The instance's route, or `null` once released. Reactive. */
|
|
1289
|
+
read() {
|
|
1290
|
+
return this.get();
|
|
1291
|
+
}
|
|
1292
|
+
/** Hand a kept instance the route of the navigation that kept it. */
|
|
1293
|
+
update(route2) {
|
|
1294
|
+
if (!this.released) this.set(route2);
|
|
1295
|
+
}
|
|
1296
|
+
/**
|
|
1297
|
+
* Called when the instance is disposed. The switch to "no scope" is
|
|
1298
|
+
* published a microtask later, once the whole dispose has finished: a
|
|
1299
|
+
* teardown the instance registered after this one (an `onMount` effect, say)
|
|
1300
|
+
* may still be alive at this point, and must not re-run against the
|
|
1301
|
+
* router-global route on its way out.
|
|
1302
|
+
*/
|
|
1303
|
+
release() {
|
|
1304
|
+
if (this.released) return;
|
|
1305
|
+
this.released = true;
|
|
1306
|
+
queueMicrotask(() => this.set(null));
|
|
1307
|
+
}
|
|
1308
|
+
};
|
|
1309
|
+
function activeRouteScope() {
|
|
1310
|
+
const scope = getOwnerScope();
|
|
1311
|
+
return scope instanceof RouteScope ? scope : null;
|
|
1312
|
+
}
|
|
1313
|
+
function scopedRoute(router2) {
|
|
1314
|
+
const scope = activeRouteScope();
|
|
1315
|
+
if (scope) {
|
|
1316
|
+
const committed = scope.read();
|
|
1317
|
+
if (committed !== null) return committed;
|
|
1318
|
+
}
|
|
1319
|
+
return router2.currentRoute;
|
|
1320
|
+
}
|
|
1321
|
+
var instanceScopes = /* @__PURE__ */ new WeakMap();
|
|
1322
|
+
async function instantiateScoped(router2, plan, routeDef, routePath, route2) {
|
|
1323
|
+
const scope = new RouteScope(route2);
|
|
1324
|
+
const node = await router2.instantiateComponent(plan, routeDef, routePath, scope);
|
|
1325
|
+
if (node) {
|
|
1326
|
+
instanceScopes.set(node, scope);
|
|
1327
|
+
registerDisposer(node, () => scope.release());
|
|
1328
|
+
}
|
|
1329
|
+
return node;
|
|
1330
|
+
}
|
|
1331
|
+
function updateInstanceRoute(node, route2) {
|
|
1332
|
+
if (node) instanceScopes.get(node)?.update(route2);
|
|
1333
|
+
}
|
|
1334
|
+
function disposeOwned(node) {
|
|
1335
|
+
const scope = instanceScopes.get(node);
|
|
1336
|
+
if (scope) runWithOwnerScope(scope, () => dispose(node));
|
|
1337
|
+
else dispose(node);
|
|
1338
|
+
}
|
|
1270
1339
|
function route() {
|
|
1271
1340
|
if (!_routerRef.current) throw new Error("Router not initialized. Call createRouter() first.");
|
|
1272
|
-
return _routerRef.current
|
|
1341
|
+
return scopedRoute(_routerRef.current);
|
|
1273
1342
|
}
|
|
1274
1343
|
function router() {
|
|
1275
1344
|
if (!_routerRef.current) throw new Error("Router not initialized. Call createRouter() first.");
|
|
1276
1345
|
return {
|
|
1277
|
-
currentRoute: _routerRef.current
|
|
1346
|
+
currentRoute: scopedRoute(_routerRef.current),
|
|
1278
1347
|
isReady: _routerRef.current.isReady,
|
|
1279
1348
|
isNavigating: _routerRef.current.isNavigating,
|
|
1280
1349
|
push: (to) => _routerRef.current?.push(to),
|
|
@@ -1360,13 +1429,13 @@ function Route() {
|
|
|
1360
1429
|
const commitTarget = (seq) => routeTorn || seq !== navSeq ? null : anchor.parentNode;
|
|
1361
1430
|
const release = (node) => {
|
|
1362
1431
|
if (!node) return;
|
|
1363
|
-
|
|
1432
|
+
disposeOwned(node);
|
|
1364
1433
|
node.parentNode?.removeChild(node);
|
|
1365
1434
|
};
|
|
1366
1435
|
const cleanupNodes = () => {
|
|
1367
1436
|
[currentNode, loadingNode, errorNode].forEach((node) => {
|
|
1368
1437
|
if (!node) return;
|
|
1369
|
-
|
|
1438
|
+
disposeOwned(node);
|
|
1370
1439
|
if (node.parentNode) {
|
|
1371
1440
|
node.parentNode.removeChild(node);
|
|
1372
1441
|
}
|
|
@@ -1442,7 +1511,7 @@ function Route() {
|
|
|
1442
1511
|
const update = async () => {
|
|
1443
1512
|
if (routeTorn || !_routerRef.current) return;
|
|
1444
1513
|
const seq = ++navSeq;
|
|
1445
|
-
const route2 = _routerRef.current
|
|
1514
|
+
const route2 = scopedRoute(_routerRef.current);
|
|
1446
1515
|
try {
|
|
1447
1516
|
const match = _routerRef.current["matcher"].match(route2.path);
|
|
1448
1517
|
if (!match) {
|
|
@@ -1454,6 +1523,7 @@ function Route() {
|
|
|
1454
1523
|
const routeDef = match.matched[0] || match.route;
|
|
1455
1524
|
const key = instanceKey(routeDef, [routeDef], route2);
|
|
1456
1525
|
if (routeDef === currentTopRoute && key === currentKey && currentNode) {
|
|
1526
|
+
updateInstanceRoute(currentNode, route2);
|
|
1457
1527
|
return;
|
|
1458
1528
|
}
|
|
1459
1529
|
if ("redirect" in routeDef) {
|
|
@@ -1473,7 +1543,7 @@ function Route() {
|
|
|
1473
1543
|
}
|
|
1474
1544
|
const plan = await _routerRef.current.loadPlan(routeDef, route2.path);
|
|
1475
1545
|
if (!commitTarget(seq)) return;
|
|
1476
|
-
const node = await _routerRef.current
|
|
1546
|
+
const node = await instantiateScoped(_routerRef.current, plan, routeDef, route2.path, route2);
|
|
1477
1547
|
const parent = commitTarget(seq);
|
|
1478
1548
|
if (!parent) {
|
|
1479
1549
|
release(node);
|
|
@@ -1508,9 +1578,11 @@ function Route() {
|
|
|
1508
1578
|
};
|
|
1509
1579
|
const routeTeardown = track(wrappedUpdate);
|
|
1510
1580
|
if (!routeInitialized) {
|
|
1511
|
-
queueMicrotask(
|
|
1512
|
-
|
|
1513
|
-
|
|
1581
|
+
queueMicrotask(
|
|
1582
|
+
bindOwnerScope(() => {
|
|
1583
|
+
if (!routeInitialized && anchor.parentNode) wrappedUpdate();
|
|
1584
|
+
})
|
|
1585
|
+
);
|
|
1514
1586
|
}
|
|
1515
1587
|
const routeCleanup = () => {
|
|
1516
1588
|
if (routeTorn) return;
|
|
@@ -1543,7 +1615,7 @@ function KeepAliveRoute(options) {
|
|
|
1543
1615
|
if (kaTorn || !_routerRef.current) return;
|
|
1544
1616
|
const seq = ++updateSeq;
|
|
1545
1617
|
const router2 = _routerRef.current;
|
|
1546
|
-
const route2 = router2
|
|
1618
|
+
const route2 = scopedRoute(router2);
|
|
1547
1619
|
const match = router2["matcher"].match(route2.path);
|
|
1548
1620
|
if (!match) return;
|
|
1549
1621
|
const { route: routeDef } = match;
|
|
@@ -1557,10 +1629,12 @@ function KeepAliveRoute(options) {
|
|
|
1557
1629
|
return;
|
|
1558
1630
|
}
|
|
1559
1631
|
if (!("component" in routeDef)) return;
|
|
1560
|
-
const
|
|
1561
|
-
const cacheKey = `${route2.path}${queryStr}${route2.hash ? `#${route2.hash}` : ""}`;
|
|
1632
|
+
const cacheKey = JSON.stringify([route2.path, queryIdentity(route2.query), route2.hash]);
|
|
1562
1633
|
const shouldCache = !includeNames || routeDef.name != null && includeNames.includes(routeDef.name);
|
|
1563
|
-
if (cacheKey === currentKey && currentNode)
|
|
1634
|
+
if (cacheKey === currentKey && currentNode) {
|
|
1635
|
+
updateInstanceRoute(currentNode, route2);
|
|
1636
|
+
return;
|
|
1637
|
+
}
|
|
1564
1638
|
if (!anchor.parentNode) return;
|
|
1565
1639
|
let node = null;
|
|
1566
1640
|
let fromCache = false;
|
|
@@ -1571,7 +1645,7 @@ function KeepAliveRoute(options) {
|
|
|
1571
1645
|
try {
|
|
1572
1646
|
const plan = await router2.loadPlan(routeDef, route2.path);
|
|
1573
1647
|
if (kaTorn || seq !== updateSeq) return;
|
|
1574
|
-
node = await router2
|
|
1648
|
+
node = await instantiateScoped(router2, plan, routeDef, route2.path, route2);
|
|
1575
1649
|
} catch (error) {
|
|
1576
1650
|
if (kaTorn || seq !== updateSeq) return;
|
|
1577
1651
|
console.error("[KeepAliveRoute] Component error:", error);
|
|
@@ -1579,20 +1653,21 @@ function KeepAliveRoute(options) {
|
|
|
1579
1653
|
}
|
|
1580
1654
|
if (!node) return;
|
|
1581
1655
|
if (kaTorn || seq !== updateSeq) {
|
|
1582
|
-
|
|
1656
|
+
disposeOwned(node);
|
|
1583
1657
|
return;
|
|
1584
1658
|
}
|
|
1585
1659
|
}
|
|
1586
1660
|
const parent = anchor.parentNode;
|
|
1587
1661
|
if (!parent) {
|
|
1588
|
-
if (!fromCache)
|
|
1662
|
+
if (!fromCache) disposeOwned(node);
|
|
1589
1663
|
return;
|
|
1590
1664
|
}
|
|
1591
1665
|
if (currentNode && currentNode !== node) {
|
|
1592
1666
|
if (currentNode.parentNode) currentNode.parentNode.removeChild(currentNode);
|
|
1593
|
-
if (!currentCached)
|
|
1667
|
+
if (!currentCached) disposeOwned(currentNode);
|
|
1594
1668
|
}
|
|
1595
1669
|
if (fromCache) {
|
|
1670
|
+
updateInstanceRoute(node, route2);
|
|
1596
1671
|
const idx = lruOrder.indexOf(cacheKey);
|
|
1597
1672
|
if (idx !== -1) lruOrder.splice(idx, 1);
|
|
1598
1673
|
lruOrder.push(cacheKey);
|
|
@@ -1607,7 +1682,7 @@ function KeepAliveRoute(options) {
|
|
|
1607
1682
|
}
|
|
1608
1683
|
const evictNode = cache.get(evictKey);
|
|
1609
1684
|
if (evictNode) {
|
|
1610
|
-
|
|
1685
|
+
disposeOwned(evictNode);
|
|
1611
1686
|
if (evictNode.parentNode) evictNode.parentNode.removeChild(evictNode);
|
|
1612
1687
|
cache.delete(evictKey);
|
|
1613
1688
|
}
|
|
@@ -1625,9 +1700,11 @@ function KeepAliveRoute(options) {
|
|
|
1625
1700
|
};
|
|
1626
1701
|
const kaTeardown = track(wrappedUpdate);
|
|
1627
1702
|
if (!initialized) {
|
|
1628
|
-
queueMicrotask(
|
|
1629
|
-
|
|
1630
|
-
|
|
1703
|
+
queueMicrotask(
|
|
1704
|
+
bindOwnerScope(() => {
|
|
1705
|
+
if (!initialized && anchor.parentNode) wrappedUpdate();
|
|
1706
|
+
})
|
|
1707
|
+
);
|
|
1631
1708
|
}
|
|
1632
1709
|
const kaCleanup = () => {
|
|
1633
1710
|
if (kaTorn) return;
|
|
@@ -1635,13 +1712,13 @@ function KeepAliveRoute(options) {
|
|
|
1635
1712
|
updateSeq++;
|
|
1636
1713
|
kaTeardown();
|
|
1637
1714
|
for (const node of cache.values()) {
|
|
1638
|
-
|
|
1715
|
+
disposeOwned(node);
|
|
1639
1716
|
if (node.parentNode) node.parentNode.removeChild(node);
|
|
1640
1717
|
}
|
|
1641
1718
|
cache.clear();
|
|
1642
1719
|
lruOrder.length = 0;
|
|
1643
1720
|
if (currentNode?.parentNode) currentNode.parentNode.removeChild(currentNode);
|
|
1644
|
-
if (currentNode && !currentCached)
|
|
1721
|
+
if (currentNode && !currentCached) disposeOwned(currentNode);
|
|
1645
1722
|
currentNode = null;
|
|
1646
1723
|
currentKey = "";
|
|
1647
1724
|
currentCached = false;
|
|
@@ -1660,7 +1737,7 @@ function RouterLink(props, children) {
|
|
|
1660
1737
|
const href = kind === "unsafe" ? "#" : rawHref;
|
|
1661
1738
|
const { path: hrefPathRaw, query: hrefQueryRaw, hash: hrefHash } = splitRouteUrl(href);
|
|
1662
1739
|
const targetPath = normalizePathname(hrefPathRaw);
|
|
1663
|
-
const targetQuery =
|
|
1740
|
+
const targetQuery = queryIdentity(hrefQueryRaw);
|
|
1664
1741
|
const link = document.createElement("a");
|
|
1665
1742
|
link.href = href;
|
|
1666
1743
|
if (target) {
|
|
@@ -1678,7 +1755,7 @@ function RouterLink(props, children) {
|
|
|
1678
1755
|
const route2 = routeGetter();
|
|
1679
1756
|
const currentPath = normalizePathname(route2.path);
|
|
1680
1757
|
const isActive = kind === "internal" && isPathnameAncestor(targetPath, currentPath);
|
|
1681
|
-
const isExactActive = kind === "internal" && currentPath === targetPath &&
|
|
1758
|
+
const isExactActive = kind === "internal" && currentPath === targetPath && queryIdentity(route2.query) === targetQuery && route2.hash === hrefHash;
|
|
1682
1759
|
const classes = [];
|
|
1683
1760
|
if (isActive) {
|
|
1684
1761
|
if (activeClass) classes.push(activeClass);
|
|
@@ -1797,7 +1874,7 @@ function Suspense(props) {
|
|
|
1797
1874
|
generation++;
|
|
1798
1875
|
cleanupNodes();
|
|
1799
1876
|
});
|
|
1800
|
-
queueMicrotask(render);
|
|
1877
|
+
queueMicrotask(bindOwnerScope(render));
|
|
1801
1878
|
return anchor;
|
|
1802
1879
|
}
|
|
1803
1880
|
var LAZY_MARKER = /* @__PURE__ */ Symbol.for("sibujs:lazy");
|
|
@@ -1865,7 +1942,7 @@ function Outlet() {
|
|
|
1865
1942
|
let outletTorn = false;
|
|
1866
1943
|
const clearCurrent = () => {
|
|
1867
1944
|
if (currentNode) {
|
|
1868
|
-
|
|
1945
|
+
disposeOwned(currentNode);
|
|
1869
1946
|
if (currentNode.parentNode) currentNode.parentNode.removeChild(currentNode);
|
|
1870
1947
|
currentNode = null;
|
|
1871
1948
|
}
|
|
@@ -1875,13 +1952,13 @@ function Outlet() {
|
|
|
1875
1952
|
const commitTarget = (seq) => outletTorn || seq !== navSeq ? null : anchor.parentNode;
|
|
1876
1953
|
const release = (node) => {
|
|
1877
1954
|
if (!node) return;
|
|
1878
|
-
|
|
1955
|
+
disposeOwned(node);
|
|
1879
1956
|
node.parentNode?.removeChild(node);
|
|
1880
1957
|
};
|
|
1881
1958
|
const update = async () => {
|
|
1882
1959
|
if (outletTorn || !_routerRef.current) return;
|
|
1883
1960
|
const seq = ++navSeq;
|
|
1884
|
-
const route2 = _routerRef.current
|
|
1961
|
+
const route2 = scopedRoute(_routerRef.current);
|
|
1885
1962
|
if (route2.matched.length < 2) {
|
|
1886
1963
|
clearCurrent();
|
|
1887
1964
|
return;
|
|
@@ -1892,12 +1969,15 @@ function Outlet() {
|
|
|
1892
1969
|
return;
|
|
1893
1970
|
}
|
|
1894
1971
|
const key = instanceKey(childRoute, route2.matched.slice(1), route2);
|
|
1895
|
-
if (childRoute === currentChild && key === currentKey && currentNode)
|
|
1972
|
+
if (childRoute === currentChild && key === currentKey && currentNode) {
|
|
1973
|
+
updateInstanceRoute(currentNode, route2);
|
|
1974
|
+
return;
|
|
1975
|
+
}
|
|
1896
1976
|
try {
|
|
1897
1977
|
const cacheKey = `${route2.path}\0${childRoute.path}`;
|
|
1898
1978
|
const plan = await _routerRef.current.loadPlan(childRoute, cacheKey);
|
|
1899
1979
|
if (!commitTarget(seq)) return;
|
|
1900
|
-
const node = await _routerRef.current
|
|
1980
|
+
const node = await instantiateScoped(_routerRef.current, plan, childRoute, cacheKey, route2);
|
|
1901
1981
|
const parent = commitTarget(seq);
|
|
1902
1982
|
if (!parent) {
|
|
1903
1983
|
release(node);
|
|
@@ -1916,9 +1996,11 @@ function Outlet() {
|
|
|
1916
1996
|
};
|
|
1917
1997
|
const outletTeardown = track(update);
|
|
1918
1998
|
if (!anchor.parentNode) {
|
|
1919
|
-
queueMicrotask(
|
|
1920
|
-
|
|
1921
|
-
|
|
1999
|
+
queueMicrotask(
|
|
2000
|
+
bindOwnerScope(() => {
|
|
2001
|
+
if (anchor.parentNode) update();
|
|
2002
|
+
})
|
|
2003
|
+
);
|
|
1922
2004
|
}
|
|
1923
2005
|
const outletCleanup = () => {
|
|
1924
2006
|
if (outletTorn) return;
|
|
@@ -1926,7 +2008,7 @@ function Outlet() {
|
|
|
1926
2008
|
navSeq++;
|
|
1927
2009
|
outletTeardown();
|
|
1928
2010
|
if (currentNode) {
|
|
1929
|
-
|
|
2011
|
+
disposeOwned(currentNode);
|
|
1930
2012
|
if (currentNode.parentNode) currentNode.parentNode.removeChild(currentNode);
|
|
1931
2013
|
currentNode = null;
|
|
1932
2014
|
}
|
|
@@ -1949,11 +2031,11 @@ function routerState() {
|
|
|
1949
2031
|
if (!_routerRef.current) throw new Error("Router not initialized. Call createRouter() first.");
|
|
1950
2032
|
const router2 = _routerRef.current;
|
|
1951
2033
|
return {
|
|
1952
|
-
currentPath: () => router2.
|
|
1953
|
-
params: () => router2.
|
|
1954
|
-
query: () => router2.
|
|
1955
|
-
hash: () => router2.
|
|
1956
|
-
meta: () => router2.
|
|
2034
|
+
currentPath: () => scopedRoute(router2).path,
|
|
2035
|
+
params: () => scopedRoute(router2).params,
|
|
2036
|
+
query: () => scopedRoute(router2).query,
|
|
2037
|
+
hash: () => scopedRoute(router2).hash,
|
|
2038
|
+
meta: () => scopedRoute(router2).meta,
|
|
1957
2039
|
isNavigating: () => router2.isNavigating,
|
|
1958
2040
|
isReady: () => router2.isReady
|
|
1959
2041
|
};
|