sibujs 4.14.0 → 4.15.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 +297 -45
- package/dist/browser.js +6 -7
- package/dist/build.cjs +2189 -573
- package/dist/build.js +16 -15
- package/dist/cdn.dev.global.js +13 -12
- package/dist/cdn.full.dev.global.js +14 -13
- package/dist/cdn.full.global.js +12 -12
- package/dist/cdn.global.js +12 -12
- package/dist/{chunk-RVR5NPFL.js → chunk-2VKTFA7C.js} +1 -1
- package/dist/{chunk-7ILEHTVX.js → chunk-4AEFGRYW.js} +1 -1
- package/dist/{chunk-4TQDTWWN.js → chunk-6IV5ZRG6.js} +5 -7
- package/dist/{chunk-GVAMIU6K.js → chunk-75EAQH3U.js} +2 -2
- package/dist/{chunk-TLS4NVIB.js → chunk-7JO7DPSS.js} +4 -4
- package/dist/{chunk-SVULV7O4.js → chunk-AQH7WDSE.js} +6 -8
- package/dist/{chunk-S37PZD6I.js → chunk-BF3WBJJQ.js} +60 -10
- package/dist/{chunk-LJMX4SQ7.js → chunk-BG4BP44S.js} +3 -3
- package/dist/{chunk-N7A6FKWW.js → chunk-D44TAGCT.js} +2 -2
- package/dist/{chunk-CCKUNHVU.js → chunk-DAEXQJQA.js} +1 -1
- package/dist/chunk-DNCQDFJJ.js +22 -0
- package/dist/{chunk-BKZ5N6NK.js → chunk-DNCT2UXB.js} +4 -4
- package/dist/{chunk-BOYKGGVD.js → chunk-DRWOD7RZ.js} +4 -4
- package/dist/chunk-DS5V2PRE.js +64 -0
- package/dist/{chunk-VM2U5LEL.js → chunk-EHSJESRN.js} +595 -123
- package/dist/{chunk-MIRKTVH4.js → chunk-GFM5WWPU.js} +252 -5
- package/dist/{chunk-52XFPGSN.js → chunk-HTPOIAAL.js} +1 -1
- package/dist/{chunk-3HEX6QJQ.js → chunk-I2R5QALY.js} +2 -4
- package/dist/{chunk-4FJSAUKB.js → chunk-IUBV5WO5.js} +1 -1
- package/dist/{chunk-A454RAEK.js → chunk-KIDETDMU.js} +5 -7
- package/dist/{chunk-JTFQ7IL4.js → chunk-KPAXG5IR.js} +7 -9
- package/dist/{chunk-AE32RGWX.js → chunk-LGUXYHTZ.js} +3 -3
- package/dist/{chunk-Y4LUM2XS.js → chunk-LQWLPQOK.js} +6 -8
- package/dist/{chunk-CNPT6NKV.js → chunk-MINLMJUY.js} +48 -9
- package/dist/{chunk-BNXRWZZV.js → chunk-OURTGOJT.js} +8 -10
- package/dist/{chunk-F67F77IA.js → chunk-TQ24Y3IV.js} +2 -2
- package/dist/{chunk-2TTRW2TE.js → chunk-UM3M5PXS.js} +8 -8
- package/dist/{chunk-CJ7KS3DF.js → chunk-VSTX3XSX.js} +205 -15
- package/dist/{chunk-HQIAL7F2.js → chunk-XPDZ2LDR.js} +2 -2
- package/dist/{chunk-UUIKJJIK.js → chunk-Y7JM7GY2.js} +5 -7
- package/dist/{chunk-QS6GMWDD.js → chunk-YAFITBOK.js} +1269 -162
- package/dist/data.cjs +285 -33
- package/dist/data.js +6 -7
- package/dist/devtools.cjs +289 -39
- package/dist/devtools.js +5 -6
- package/dist/{dispose-EIHHHDC7.js → dispose-3WDBYJMH.js} +3 -1
- package/dist/ecosystem.cjs +345 -61
- package/dist/ecosystem.d.cts +1 -1
- package/dist/ecosystem.d.ts +1 -1
- package/dist/ecosystem.js +10 -10
- package/dist/extras.cjs +568 -248
- package/dist/extras.d.cts +1 -1
- package/dist/extras.d.ts +1 -1
- package/dist/extras.js +27 -27
- package/dist/index.cjs +2134 -515
- package/dist/index.d.cts +628 -211
- package/dist/index.d.ts +628 -211
- package/dist/index.js +22 -15
- package/dist/motion.cjs +286 -30
- package/dist/motion.js +4 -4
- package/dist/patterns.cjs +301 -43
- package/dist/patterns.js +6 -6
- package/dist/performance.cjs +286 -36
- package/dist/performance.js +9 -9
- package/dist/plugins.cjs +1237 -291
- package/dist/plugins.d.cts +3 -1
- package/dist/plugins.d.ts +3 -1
- package/dist/plugins.js +20 -19
- package/dist/{renderRoute-fxgsm2Ir.d.ts → renderRoute-B84MONaO.d.cts} +2 -2
- package/dist/{renderRoute-DP20XwMS.d.cts → renderRoute-_yxPuEQY.d.ts} +2 -2
- package/dist/{routeHead-CE9SV-cH.d.cts → routeHead-DLxlq15W.d.cts} +94 -0
- package/dist/{routeHead-DzVxPviY.d.ts → routeHead-w8nANZ3M.d.ts} +94 -0
- package/dist/{ssr-NECEU4X4.js → ssr-EF3IUHTE.js} +6 -6
- package/dist/ssr-dom.cjs +64 -9
- package/dist/ssr-dom.d.cts +2 -0
- package/dist/ssr-dom.d.ts +2 -0
- package/dist/ssr-dom.js +2 -1
- package/dist/ssr.cjs +850 -170
- package/dist/ssr.d.cts +5 -3
- package/dist/ssr.d.ts +5 -3
- package/dist/ssr.js +16 -15
- package/dist/{tagFactory-DkytnJws.d.cts → tagFactory-BfEh69VF.d.cts} +7 -0
- package/dist/{tagFactory-Bnd_Nph9.d.ts → tagFactory-pSYiLYyh.d.ts} +7 -0
- package/dist/testing.cjs +817 -132
- package/dist/testing.d.cts +4 -2
- package/dist/testing.d.ts +4 -2
- package/dist/testing.js +18 -17
- package/dist/track-core-0edROAF5.d.ts +187 -0
- package/dist/track-core-DN5fYLWi.d.cts +187 -0
- package/dist/ui.cjs +293 -43
- package/dist/ui.js +10 -12
- package/dist/widgets.cjs +285 -27
- package/dist/widgets.js +7 -7
- package/package.json +1 -1
- package/dist/chunk-7ZHH77QA.js +0 -9
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
import {
|
|
2
2
|
acquireTitle
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-HTPOIAAL.js";
|
|
4
|
+
import {
|
|
5
|
+
commitWhenActive
|
|
6
|
+
} from "./chunk-DS5V2PRE.js";
|
|
4
7
|
import {
|
|
5
8
|
STATIC_VALUE_RESOLVER,
|
|
6
9
|
planHeadElementEntry,
|
|
7
10
|
planMetaEntry,
|
|
8
11
|
recordServerHead,
|
|
9
12
|
serializeHeadEntry
|
|
10
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-DRWOD7RZ.js";
|
|
11
14
|
import {
|
|
12
15
|
appendChildren,
|
|
16
|
+
beginLoading,
|
|
17
|
+
registerNodesRange,
|
|
13
18
|
resolveClassValue
|
|
14
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-VSTX3XSX.js";
|
|
15
20
|
import {
|
|
16
21
|
setSafeAttribute
|
|
17
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-XPDZ2LDR.js";
|
|
18
23
|
import {
|
|
19
24
|
effect
|
|
20
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-LGUXYHTZ.js";
|
|
21
26
|
import {
|
|
22
27
|
sanitizeUrl,
|
|
23
28
|
stripControlChars
|
|
@@ -28,18 +33,21 @@ import {
|
|
|
28
33
|
} from "./chunk-UYTYNCMZ.js";
|
|
29
34
|
import {
|
|
30
35
|
signal
|
|
31
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-IUBV5WO5.js";
|
|
32
37
|
import {
|
|
33
38
|
bindOwnerScope,
|
|
39
|
+
captureFrozen,
|
|
34
40
|
getOwnerScope,
|
|
41
|
+
holdSubtree,
|
|
42
|
+
reactiveBinding,
|
|
35
43
|
runWithOwnerScope,
|
|
36
|
-
|
|
44
|
+
structuralBinding,
|
|
37
45
|
untracked
|
|
38
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-GFM5WWPU.js";
|
|
39
47
|
import {
|
|
40
48
|
dispose,
|
|
41
49
|
registerDisposer
|
|
42
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-BF3WBJJQ.js";
|
|
43
51
|
import {
|
|
44
52
|
captureScope,
|
|
45
53
|
devWarn,
|
|
@@ -929,7 +937,14 @@ var _ComponentLoader = class _ComponentLoader {
|
|
|
929
937
|
* is a configuration error, not something to chase.
|
|
930
938
|
*/
|
|
931
939
|
async instantiateFactory(component, route2, routePath, scope, depth = 0) {
|
|
932
|
-
const
|
|
940
|
+
const gate = scope?.gate;
|
|
941
|
+
if (gate) {
|
|
942
|
+
while (gate.held()) if (!await gate.until()) throw gate.cancellation();
|
|
943
|
+
if (scope?.current?.() === false) throw gate.cancellation();
|
|
944
|
+
}
|
|
945
|
+
const owner = scope?.owner;
|
|
946
|
+
const invoke = () => scope ? runWithOwnerScope(scope, component) : component();
|
|
947
|
+
const build = owner ? () => owner.run(invoke) : invoke;
|
|
933
948
|
const result = scope?.adopt ? inScope(scope.adopt, build) : build();
|
|
934
949
|
const value = this.isThenable(result) ? await result : result;
|
|
935
950
|
if (this.isElement(value)) return value;
|
|
@@ -1138,7 +1153,7 @@ var _SibuRouter = class _SibuRouter {
|
|
|
1138
1153
|
return this.loadedPromise;
|
|
1139
1154
|
}
|
|
1140
1155
|
createInitialRoute() {
|
|
1141
|
-
|
|
1156
|
+
const route2 = {
|
|
1142
1157
|
path: "/",
|
|
1143
1158
|
params: {},
|
|
1144
1159
|
query: {},
|
|
@@ -1147,6 +1162,8 @@ var _SibuRouter = class _SibuRouter {
|
|
|
1147
1162
|
meta: {},
|
|
1148
1163
|
matched: []
|
|
1149
1164
|
};
|
|
1165
|
+
bootstrapRoutes.add(route2);
|
|
1166
|
+
return route2;
|
|
1150
1167
|
}
|
|
1151
1168
|
handleLocationChange(skipHistory = true, initialResolution = false) {
|
|
1152
1169
|
const path = this.getCurrentPath();
|
|
@@ -1187,8 +1204,31 @@ var _SibuRouter = class _SibuRouter {
|
|
|
1187
1204
|
matched
|
|
1188
1205
|
};
|
|
1189
1206
|
}
|
|
1207
|
+
/**
|
|
1208
|
+
* Once no navigation is in flight: if the route is still the placeholder
|
|
1209
|
+
* the router started with — every navigation that could have replaced it
|
|
1210
|
+
* was cancelled by a guard, failed, or was a duplicate — that IS the
|
|
1211
|
+
* outcome, and the outlets that rendered nothing for it settle (see
|
|
1212
|
+
* `settleEmpty`). Checked when a navigation has definitively completed,
|
|
1213
|
+
* never from `isReady` (set before the guards run). A navigation still
|
|
1214
|
+
* pending — a newer one, or a guard that never resolves — keeps them
|
|
1215
|
+
* pending; an outlet's enter is bounded by its own deadline then.
|
|
1216
|
+
*/
|
|
1217
|
+
settleBootstrap() {
|
|
1218
|
+
if (this.destroyed || this.navigator.isNavigating) return;
|
|
1219
|
+
const current = untracked(() => this.currentRouteGetter());
|
|
1220
|
+
if (!bootstrapRoutes.delete(current)) return;
|
|
1221
|
+
const waiting = bootstrapWaiters.get(current);
|
|
1222
|
+
bootstrapWaiters.delete(current);
|
|
1223
|
+
if (waiting) for (const settle of waiting) settle();
|
|
1224
|
+
}
|
|
1190
1225
|
// Public API
|
|
1191
1226
|
async navigate(to, options = {}) {
|
|
1227
|
+
const result = await this.attemptNavigation(to, options);
|
|
1228
|
+
this.settleBootstrap();
|
|
1229
|
+
return result;
|
|
1230
|
+
}
|
|
1231
|
+
async attemptNavigation(to, options) {
|
|
1192
1232
|
try {
|
|
1193
1233
|
await this.navigator.navigate(async (signal2) => {
|
|
1194
1234
|
const targetPath = this.resolvePath(to);
|
|
@@ -1442,6 +1482,13 @@ var _SibuRouter = class _SibuRouter {
|
|
|
1442
1482
|
/**
|
|
1443
1483
|
* Create exactly one real instance from an already-resolved plan. With a
|
|
1444
1484
|
* `scope`, the factory runs in it (see `RouteScope`).
|
|
1485
|
+
*
|
|
1486
|
+
* When the scope belongs to an outlet whose branch is paused (playing a
|
|
1487
|
+
* leave it may still be taken back from), a lazy module that resolves does
|
|
1488
|
+
* not run its factory yet: the promise stays pending and continues once the
|
|
1489
|
+
* branch resumes. If the branch ends, or the outlet's pass was superseded
|
|
1490
|
+
* meanwhile, it rejects with a `DOMException` named `"AbortError"`. Genuine
|
|
1491
|
+
* loader and component failures reject with their own error, as before.
|
|
1445
1492
|
*/
|
|
1446
1493
|
async instantiateComponent(plan, route2, routePath, scope) {
|
|
1447
1494
|
return prerenderWait(this.loader.instantiate(plan, route2, routePath, scope), `router:render ${route2.path}`);
|
|
@@ -1690,6 +1737,21 @@ var RouteScope = class {
|
|
|
1690
1737
|
constructor(route2) {
|
|
1691
1738
|
/** Creation scope the instance is built in (adopting hydration); see `adoptScope`. */
|
|
1692
1739
|
this.adopt = null;
|
|
1740
|
+
/**
|
|
1741
|
+
* The outlet's pause gate: while the branch holding the outlet is paused (it
|
|
1742
|
+
* began a leave and may still be taken back), a lazy module that resolves
|
|
1743
|
+
* does not get its factory invoked yet; instantiation waits for the branch
|
|
1744
|
+
* to resume, and is cancelled if it ends.
|
|
1745
|
+
*/
|
|
1746
|
+
this.gate = null;
|
|
1747
|
+
/** Whether the outlet pass this instance is for is still the current one. */
|
|
1748
|
+
this.current = null;
|
|
1749
|
+
/**
|
|
1750
|
+
* The instance's structural owner, nested under the outlet's: its factory
|
|
1751
|
+
* runs as it, so what it creates is paused with the branch holding the
|
|
1752
|
+
* outlet, and ends (`lifecycleScope()` work included) with the instance.
|
|
1753
|
+
*/
|
|
1754
|
+
this.owner = null;
|
|
1693
1755
|
this.released = false;
|
|
1694
1756
|
const [get, set] = signal(route2);
|
|
1695
1757
|
this.get = get;
|
|
@@ -1716,6 +1778,112 @@ var RouteScope = class {
|
|
|
1716
1778
|
queueMicrotask(() => this.set(null));
|
|
1717
1779
|
}
|
|
1718
1780
|
};
|
|
1781
|
+
var NOOP = () => {
|
|
1782
|
+
};
|
|
1783
|
+
var bootstrapRoutes = /* @__PURE__ */ new WeakSet();
|
|
1784
|
+
var bootstrapWaiters = /* @__PURE__ */ new WeakMap();
|
|
1785
|
+
function settleEmpty(route2, loaded, current) {
|
|
1786
|
+
if (!bootstrapRoutes.has(route2)) {
|
|
1787
|
+
loaded.done();
|
|
1788
|
+
return;
|
|
1789
|
+
}
|
|
1790
|
+
let waiting = bootstrapWaiters.get(route2);
|
|
1791
|
+
if (waiting === void 0) bootstrapWaiters.set(route2, waiting = /* @__PURE__ */ new Set());
|
|
1792
|
+
waiting.add(() => {
|
|
1793
|
+
if (current()) loaded.done();
|
|
1794
|
+
});
|
|
1795
|
+
}
|
|
1796
|
+
var cancellations = /* @__PURE__ */ new WeakSet();
|
|
1797
|
+
function pauseGate(frozen) {
|
|
1798
|
+
let closed = false;
|
|
1799
|
+
const pending = /* @__PURE__ */ new Set();
|
|
1800
|
+
return {
|
|
1801
|
+
held: () => closed || frozen(),
|
|
1802
|
+
until: () => {
|
|
1803
|
+
if (closed) return Promise.resolve(false);
|
|
1804
|
+
return new Promise((resolve) => {
|
|
1805
|
+
const settle = (active) => {
|
|
1806
|
+
pending.delete(cancel);
|
|
1807
|
+
resolve(active && !closed);
|
|
1808
|
+
};
|
|
1809
|
+
const drop = frozen.wait(
|
|
1810
|
+
() => settle(true),
|
|
1811
|
+
() => settle(false)
|
|
1812
|
+
);
|
|
1813
|
+
const cancel = () => {
|
|
1814
|
+
drop();
|
|
1815
|
+
settle(false);
|
|
1816
|
+
};
|
|
1817
|
+
pending.add(cancel);
|
|
1818
|
+
});
|
|
1819
|
+
},
|
|
1820
|
+
cancellation: () => {
|
|
1821
|
+
const error = new DOMException("Route instantiation cancelled: its branch was released", "AbortError");
|
|
1822
|
+
cancellations.add(error);
|
|
1823
|
+
return error;
|
|
1824
|
+
},
|
|
1825
|
+
close: () => {
|
|
1826
|
+
closed = true;
|
|
1827
|
+
for (const cancel of [...pending]) cancel();
|
|
1828
|
+
},
|
|
1829
|
+
run: frozen.run,
|
|
1830
|
+
frozen,
|
|
1831
|
+
closed: () => closed,
|
|
1832
|
+
onClose: (fn) => {
|
|
1833
|
+
pending.add(fn);
|
|
1834
|
+
return () => {
|
|
1835
|
+
pending.delete(fn);
|
|
1836
|
+
};
|
|
1837
|
+
}
|
|
1838
|
+
};
|
|
1839
|
+
}
|
|
1840
|
+
function whenActive(gate, fn) {
|
|
1841
|
+
if (!gate.held()) fn();
|
|
1842
|
+
else
|
|
1843
|
+
void gate.until().then((active) => {
|
|
1844
|
+
if (active) whenActive(gate, fn);
|
|
1845
|
+
});
|
|
1846
|
+
}
|
|
1847
|
+
function commitPass(gate, c) {
|
|
1848
|
+
const frozen = gate.frozen;
|
|
1849
|
+
const held = {
|
|
1850
|
+
state: frozen.state,
|
|
1851
|
+
wait: (onActive, onEnd) => {
|
|
1852
|
+
let live = true;
|
|
1853
|
+
const later = (fn) => () => {
|
|
1854
|
+
void Promise.resolve().then(() => {
|
|
1855
|
+
if (live) fn();
|
|
1856
|
+
});
|
|
1857
|
+
};
|
|
1858
|
+
const drop = frozen.wait(later(onActive), later(onEnd));
|
|
1859
|
+
return () => {
|
|
1860
|
+
live = false;
|
|
1861
|
+
drop();
|
|
1862
|
+
};
|
|
1863
|
+
}
|
|
1864
|
+
};
|
|
1865
|
+
return new Promise((resolve, reject) => {
|
|
1866
|
+
const slot = { cancel: NOOP };
|
|
1867
|
+
const untrack = gate.onClose(() => slot.cancel());
|
|
1868
|
+
const settle = (fn) => () => {
|
|
1869
|
+
untrack();
|
|
1870
|
+
try {
|
|
1871
|
+
fn();
|
|
1872
|
+
resolve();
|
|
1873
|
+
} catch (error) {
|
|
1874
|
+
reject(error);
|
|
1875
|
+
}
|
|
1876
|
+
};
|
|
1877
|
+
commitWhenActive(slot, {
|
|
1878
|
+
held,
|
|
1879
|
+
node: c.node,
|
|
1880
|
+
owned: () => !gate.closed() && c.owned(),
|
|
1881
|
+
teardown: c.teardown,
|
|
1882
|
+
insert: settle(c.insert),
|
|
1883
|
+
discard: settle(c.discard)
|
|
1884
|
+
});
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1719
1887
|
function activeRouteScope() {
|
|
1720
1888
|
const scope = getOwnerScope();
|
|
1721
1889
|
return scope instanceof RouteScope ? scope : null;
|
|
@@ -1729,14 +1897,27 @@ function scopedRoute(router2) {
|
|
|
1729
1897
|
return router2.currentRoute;
|
|
1730
1898
|
}
|
|
1731
1899
|
var instanceScopes = /* @__PURE__ */ new WeakMap();
|
|
1732
|
-
async function instantiateScoped(router2, plan, routeDef, routePath, route2, adopt = null) {
|
|
1900
|
+
async function instantiateScoped(router2, plan, routeDef, routePath, route2, adopt = null, gate = null, current = null) {
|
|
1733
1901
|
const scope = new RouteScope(route2);
|
|
1734
1902
|
scope.adopt = adopt;
|
|
1735
|
-
|
|
1903
|
+
scope.gate = gate;
|
|
1904
|
+
scope.current = current;
|
|
1905
|
+
const owner = gate ? gate.run(() => structuralBinding(NOOP)) : structuralBinding(NOOP);
|
|
1906
|
+
scope.owner = owner;
|
|
1907
|
+
let node;
|
|
1908
|
+
try {
|
|
1909
|
+
node = await router2.instantiateComponent(plan, routeDef, routePath, scope);
|
|
1910
|
+
} catch (error) {
|
|
1911
|
+
owner.stop();
|
|
1912
|
+
throw error;
|
|
1913
|
+
}
|
|
1736
1914
|
if (node) {
|
|
1737
1915
|
instanceScopes.set(node, scope);
|
|
1738
|
-
registerDisposer(node, () =>
|
|
1739
|
-
|
|
1916
|
+
registerDisposer(node, () => {
|
|
1917
|
+
owner.stop();
|
|
1918
|
+
scope.release();
|
|
1919
|
+
});
|
|
1920
|
+
} else owner.stop();
|
|
1740
1921
|
return node;
|
|
1741
1922
|
}
|
|
1742
1923
|
function updateInstanceRoute(node, route2) {
|
|
@@ -1835,6 +2016,8 @@ function instanceKey(owner, records, route2) {
|
|
|
1835
2016
|
function Route() {
|
|
1836
2017
|
const anchor = document.createComment("route-outlet");
|
|
1837
2018
|
const adoptScope = captureScope();
|
|
2019
|
+
const frozen = captureFrozen();
|
|
2020
|
+
const gate = pauseGate(frozen);
|
|
1838
2021
|
let currentNode = null;
|
|
1839
2022
|
let loadingNode = null;
|
|
1840
2023
|
let errorNode = null;
|
|
@@ -1842,6 +2025,7 @@ function Route() {
|
|
|
1842
2025
|
let currentTopRoute = null;
|
|
1843
2026
|
let currentKey = null;
|
|
1844
2027
|
let routeTorn = false;
|
|
2028
|
+
const loaded = beginLoading(anchor);
|
|
1845
2029
|
const commitTarget = (seq) => routeTorn || seq !== navSeq ? null : anchor.parentNode;
|
|
1846
2030
|
const retryIfDetached = (seq) => {
|
|
1847
2031
|
if (!routeTorn && seq === navSeq && !anchor.parentNode) attachWait.request();
|
|
@@ -1886,24 +2070,54 @@ function Route() {
|
|
|
1886
2070
|
loadingNode = null;
|
|
1887
2071
|
}
|
|
1888
2072
|
};
|
|
1889
|
-
const showError = (error, routeDef) => {
|
|
2073
|
+
const showError = (seq, error, routeDef) => {
|
|
1890
2074
|
if (!anchor.parentNode) return;
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
2075
|
+
const view = errorView(error, routeDef);
|
|
2076
|
+
void commitPass(gate, {
|
|
2077
|
+
node: view,
|
|
2078
|
+
owned: () => !routeTorn && seq === navSeq,
|
|
2079
|
+
discard: () => dispose(view),
|
|
2080
|
+
teardown: () => {
|
|
2081
|
+
if (!anchor.parentNode || !(currentNode || loadingNode || errorNode)) return false;
|
|
2082
|
+
cleanupNodes();
|
|
2083
|
+
return true;
|
|
2084
|
+
},
|
|
2085
|
+
insert: () => {
|
|
2086
|
+
const parent = anchor.parentNode;
|
|
2087
|
+
if (!parent) {
|
|
2088
|
+
dispose(view);
|
|
2089
|
+
unshownFailure = { seq, error, routeDef };
|
|
2090
|
+
attachWait.request();
|
|
2091
|
+
return;
|
|
2092
|
+
}
|
|
2093
|
+
errorNode = view;
|
|
2094
|
+
try {
|
|
2095
|
+
parent.insertBefore(view, anchor.nextSibling);
|
|
2096
|
+
} catch (err) {
|
|
2097
|
+
if (errorNode === view) errorNode = null;
|
|
2098
|
+
release(view);
|
|
2099
|
+
throw err;
|
|
2100
|
+
}
|
|
2101
|
+
if (!routeTorn && seq === navSeq) loaded.done();
|
|
2102
|
+
}
|
|
2103
|
+
}).catch((err) => console.error("[Route] Error view failed:", err));
|
|
2104
|
+
};
|
|
2105
|
+
const errorView = (error, routeDef) => {
|
|
2106
|
+
const errorNode2 = document.createElement("div");
|
|
2107
|
+
errorNode2.className = "route-error";
|
|
2108
|
+
errorNode2.setAttribute("role", "alert");
|
|
2109
|
+
errorNode2.setAttribute("aria-live", "assertive");
|
|
1896
2110
|
if (routeDef && "component" in routeDef) {
|
|
1897
2111
|
const src = routeDef.component.toString();
|
|
1898
2112
|
const importMatch = src.match(/import\(["']([^"']+)["']\)/);
|
|
1899
2113
|
if (importMatch) {
|
|
1900
|
-
|
|
2114
|
+
errorNode2.setAttribute("data-component-source", importMatch[1]);
|
|
1901
2115
|
}
|
|
1902
2116
|
if (routeDef.component.name) {
|
|
1903
|
-
|
|
2117
|
+
errorNode2.setAttribute("data-component-name", routeDef.component.name);
|
|
1904
2118
|
}
|
|
1905
2119
|
}
|
|
1906
|
-
|
|
2120
|
+
errorNode2.__routeError = error;
|
|
1907
2121
|
const title = document.createElement("h3");
|
|
1908
2122
|
title.textContent = "Route Error";
|
|
1909
2123
|
title.className = "route-error-title";
|
|
@@ -1922,10 +2136,10 @@ function Route() {
|
|
|
1922
2136
|
};
|
|
1923
2137
|
retryButton.addEventListener("click", onRetryClick);
|
|
1924
2138
|
registerDisposer(retryButton, () => retryButton.removeEventListener("click", onRetryClick));
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
2139
|
+
errorNode2.appendChild(title);
|
|
2140
|
+
errorNode2.appendChild(message);
|
|
2141
|
+
errorNode2.appendChild(retryButton);
|
|
2142
|
+
return errorNode2;
|
|
1929
2143
|
};
|
|
1930
2144
|
const update = async () => {
|
|
1931
2145
|
routerRevision();
|
|
@@ -1938,12 +2152,14 @@ function Route() {
|
|
|
1938
2152
|
currentTopRoute = null;
|
|
1939
2153
|
currentKey = null;
|
|
1940
2154
|
cleanupNodes();
|
|
2155
|
+
settleEmpty(route2, loaded, () => !routeTorn && seq === navSeq);
|
|
1941
2156
|
return;
|
|
1942
2157
|
}
|
|
1943
2158
|
const routeDef = match.matched[0] || match.route;
|
|
1944
2159
|
const key = instanceKey(routeDef, [routeDef], route2);
|
|
1945
2160
|
if (routeDef === currentTopRoute && key === currentKey && currentNode) {
|
|
1946
2161
|
updateInstanceRoute(currentNode, route2);
|
|
2162
|
+
loaded.done();
|
|
1947
2163
|
return;
|
|
1948
2164
|
}
|
|
1949
2165
|
if ("redirect" in routeDef) {
|
|
@@ -1962,6 +2178,7 @@ function Route() {
|
|
|
1962
2178
|
showLoading();
|
|
1963
2179
|
}
|
|
1964
2180
|
const plan = await _routerRef.current.loadPlan(routeDef, route2.path);
|
|
2181
|
+
while (gate.held()) if (!await gate.until()) return;
|
|
1965
2182
|
if (!commitTarget(seq)) {
|
|
1966
2183
|
retryIfDetached(seq);
|
|
1967
2184
|
return;
|
|
@@ -1972,28 +2189,57 @@ function Route() {
|
|
|
1972
2189
|
routeDef,
|
|
1973
2190
|
route2.path,
|
|
1974
2191
|
route2,
|
|
1975
|
-
keyedScope(adoptScope, routeDef.path)
|
|
2192
|
+
keyedScope(adoptScope, routeDef.path),
|
|
2193
|
+
gate,
|
|
2194
|
+
() => commitTarget(seq) !== null
|
|
1976
2195
|
);
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
2196
|
+
await commitPass(gate, {
|
|
2197
|
+
node,
|
|
2198
|
+
owned: () => !routeTorn && seq === navSeq,
|
|
2199
|
+
discard: () => release(node),
|
|
2200
|
+
// The outgoing views go first — only when there is a page to
|
|
2201
|
+
// show, and a parent to show it in.
|
|
2202
|
+
teardown: () => {
|
|
2203
|
+
if (!node || !anchor.parentNode || !(currentNode || loadingNode || errorNode)) return false;
|
|
2204
|
+
cleanupNodes();
|
|
2205
|
+
return true;
|
|
2206
|
+
},
|
|
2207
|
+
insert: () => {
|
|
2208
|
+
const parent = commitTarget(seq);
|
|
2209
|
+
if (!parent) {
|
|
2210
|
+
release(node);
|
|
2211
|
+
retryIfDetached(seq);
|
|
2212
|
+
return;
|
|
2213
|
+
}
|
|
2214
|
+
if (node) {
|
|
2215
|
+
currentTopRoute = routeDef;
|
|
2216
|
+
currentKey = key;
|
|
2217
|
+
currentNode = node;
|
|
2218
|
+
try {
|
|
2219
|
+
parent.insertBefore(node, anchor.nextSibling);
|
|
2220
|
+
} catch (error) {
|
|
2221
|
+
if (currentNode === node) {
|
|
2222
|
+
currentNode = null;
|
|
2223
|
+
currentTopRoute = null;
|
|
2224
|
+
currentKey = null;
|
|
2225
|
+
}
|
|
2226
|
+
release(node);
|
|
2227
|
+
throw error;
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
if (!routeTorn && seq === navSeq) loaded.done();
|
|
2231
|
+
}
|
|
2232
|
+
});
|
|
1990
2233
|
} catch (error) {
|
|
2234
|
+
if (cancellations.has(error)) return;
|
|
1991
2235
|
if (routeTorn || seq !== navSeq) return;
|
|
1992
|
-
hideLoading();
|
|
1993
2236
|
console.error("[Route] Component error:", error);
|
|
2237
|
+
while (gate.held()) if (!await gate.until()) return;
|
|
2238
|
+
if (routeTorn || seq !== navSeq) return;
|
|
2239
|
+
hideLoading();
|
|
1994
2240
|
fail(seq, error, routeDef);
|
|
1995
2241
|
}
|
|
1996
|
-
}
|
|
2242
|
+
} else settleEmpty(route2, loaded, () => !routeTorn && seq === navSeq);
|
|
1997
2243
|
} catch (error) {
|
|
1998
2244
|
if (seq !== navSeq) return;
|
|
1999
2245
|
if (routeTorn) return;
|
|
@@ -2005,16 +2251,20 @@ function Route() {
|
|
|
2005
2251
|
const fail = (seq, error, routeDef) => {
|
|
2006
2252
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
2007
2253
|
if (anchor.parentNode) {
|
|
2008
|
-
showError(err, routeDef);
|
|
2254
|
+
showError(seq, err, routeDef);
|
|
2009
2255
|
return;
|
|
2010
2256
|
}
|
|
2011
2257
|
unshownFailure = { seq, error: err, routeDef };
|
|
2012
2258
|
attachWait.request();
|
|
2013
2259
|
};
|
|
2014
2260
|
const onAttached = () => {
|
|
2261
|
+
if (gate.held()) {
|
|
2262
|
+
void gate.until().then((active) => active && onAttached());
|
|
2263
|
+
return;
|
|
2264
|
+
}
|
|
2015
2265
|
const failure = unshownFailure;
|
|
2016
2266
|
unshownFailure = null;
|
|
2017
|
-
if (failure && failure.seq === navSeq) showError(failure.error, failure.routeDef);
|
|
2267
|
+
if (failure && failure.seq === navSeq) showError(failure.seq, failure.error, failure.routeDef);
|
|
2018
2268
|
else update();
|
|
2019
2269
|
};
|
|
2020
2270
|
let routeInitialized = false;
|
|
@@ -2024,11 +2274,16 @@ function Route() {
|
|
|
2024
2274
|
routeInitialized = true;
|
|
2025
2275
|
};
|
|
2026
2276
|
const attachWait = attachRetry(anchor, onAttached);
|
|
2027
|
-
const routeTeardown =
|
|
2277
|
+
const routeTeardown = reactiveBinding(wrappedUpdate, anchor);
|
|
2028
2278
|
if (!routeInitialized) {
|
|
2029
2279
|
queueMicrotask(
|
|
2030
2280
|
bindOwnerScope(() => {
|
|
2031
|
-
|
|
2281
|
+
whenActive(
|
|
2282
|
+
gate,
|
|
2283
|
+
bindOwnerScope(() => {
|
|
2284
|
+
if (!routeInitialized && anchor.parentNode) wrappedUpdate();
|
|
2285
|
+
})
|
|
2286
|
+
);
|
|
2032
2287
|
})
|
|
2033
2288
|
);
|
|
2034
2289
|
}
|
|
@@ -2036,6 +2291,8 @@ function Route() {
|
|
|
2036
2291
|
if (routeTorn) return;
|
|
2037
2292
|
routeTorn = true;
|
|
2038
2293
|
navSeq++;
|
|
2294
|
+
gate.close();
|
|
2295
|
+
loaded.cancel();
|
|
2039
2296
|
routeTeardown();
|
|
2040
2297
|
attachWait.cancel();
|
|
2041
2298
|
unshownFailure = null;
|
|
@@ -2043,6 +2300,7 @@ function Route() {
|
|
|
2043
2300
|
currentTopRoute = null;
|
|
2044
2301
|
currentKey = null;
|
|
2045
2302
|
};
|
|
2303
|
+
registerNodesRange(anchor, () => [currentNode, loadingNode, errorNode]);
|
|
2046
2304
|
registerDisposer(anchor, routeCleanup);
|
|
2047
2305
|
routeCleanups.push(routeCleanup);
|
|
2048
2306
|
return anchor;
|
|
@@ -2052,15 +2310,42 @@ function KeepAliveRoute(options) {
|
|
|
2052
2310
|
const anchor = document.createComment("keep-alive-route");
|
|
2053
2311
|
const cache = /* @__PURE__ */ new Map();
|
|
2054
2312
|
const lruOrder = [];
|
|
2313
|
+
const frozen = captureFrozen();
|
|
2314
|
+
const gate = pauseGate(frozen);
|
|
2055
2315
|
const routerOpts = _routerRef.current["options"];
|
|
2056
2316
|
const keepAliveOpt = routerOpts.keepAlive;
|
|
2057
2317
|
const maxCache = options?.max ?? (typeof keepAliveOpt === "number" ? keepAliveOpt : 20);
|
|
2058
2318
|
const includeNames = options?.include ?? (Array.isArray(keepAliveOpt) ? keepAliveOpt : void 0);
|
|
2319
|
+
const suspendInactive = options?.suspendInactive === true;
|
|
2320
|
+
const suspended = /* @__PURE__ */ new Map();
|
|
2321
|
+
const suspend = (node) => {
|
|
2322
|
+
if (!suspendInactive || suspended.has(node)) return;
|
|
2323
|
+
const owner = instanceScopes.get(node)?.owner ?? null;
|
|
2324
|
+
owner?.freeze?.();
|
|
2325
|
+
suspended.set(node, { owner, unhold: holdSubtree(node) });
|
|
2326
|
+
};
|
|
2327
|
+
const activate = (node) => {
|
|
2328
|
+
const paused = suspended.get(node);
|
|
2329
|
+
if (paused === void 0) return;
|
|
2330
|
+
suspended.delete(node);
|
|
2331
|
+
paused.unhold();
|
|
2332
|
+
paused.owner?.thaw?.();
|
|
2333
|
+
};
|
|
2334
|
+
const disposeCached = (node) => {
|
|
2335
|
+
const paused = suspended.get(node);
|
|
2336
|
+
suspended.delete(node);
|
|
2337
|
+
try {
|
|
2338
|
+
disposeOwned(node);
|
|
2339
|
+
} finally {
|
|
2340
|
+
paused?.unhold();
|
|
2341
|
+
}
|
|
2342
|
+
};
|
|
2059
2343
|
let currentNode = null;
|
|
2060
2344
|
let currentKey = "";
|
|
2061
2345
|
let currentCached = false;
|
|
2062
2346
|
let updateSeq = 0;
|
|
2063
2347
|
let kaTorn = false;
|
|
2348
|
+
const loaded = beginLoading(anchor);
|
|
2064
2349
|
const update = async () => {
|
|
2065
2350
|
routerRevision();
|
|
2066
2351
|
if (kaTorn || !_routerRef.current) return;
|
|
@@ -2068,7 +2353,10 @@ function KeepAliveRoute(options) {
|
|
|
2068
2353
|
const router2 = _routerRef.current;
|
|
2069
2354
|
const route2 = scopedRoute(router2);
|
|
2070
2355
|
const match = router2["matcher"].match(route2.path);
|
|
2071
|
-
if (!match)
|
|
2356
|
+
if (!match) {
|
|
2357
|
+
settleEmpty(route2, loaded, () => !kaTorn && seq === updateSeq);
|
|
2358
|
+
return;
|
|
2359
|
+
}
|
|
2072
2360
|
const { route: routeDef } = match;
|
|
2073
2361
|
if ("redirect" in routeDef) {
|
|
2074
2362
|
const redirectPath = typeof routeDef.redirect === "function" ? routeDef.redirect(route2) : routeDef.redirect;
|
|
@@ -2079,11 +2367,15 @@ function KeepAliveRoute(options) {
|
|
|
2079
2367
|
});
|
|
2080
2368
|
return;
|
|
2081
2369
|
}
|
|
2082
|
-
if (!("component" in routeDef))
|
|
2370
|
+
if (!("component" in routeDef)) {
|
|
2371
|
+
settleEmpty(route2, loaded, () => !kaTorn && seq === updateSeq);
|
|
2372
|
+
return;
|
|
2373
|
+
}
|
|
2083
2374
|
const cacheKey = JSON.stringify([route2.path, queryIdentity(route2.queryAll), route2.hash]);
|
|
2084
2375
|
const shouldCache = !includeNames || routeDef.name != null && includeNames.includes(routeDef.name);
|
|
2085
2376
|
if (cacheKey === currentKey && currentNode) {
|
|
2086
2377
|
updateInstanceRoute(currentNode, route2);
|
|
2378
|
+
loaded.done();
|
|
2087
2379
|
return;
|
|
2088
2380
|
}
|
|
2089
2381
|
if (!anchor.parentNode) {
|
|
@@ -2098,81 +2390,142 @@ function KeepAliveRoute(options) {
|
|
|
2098
2390
|
} else {
|
|
2099
2391
|
try {
|
|
2100
2392
|
const plan = await router2.loadPlan(routeDef, route2.path);
|
|
2393
|
+
while (gate.held()) if (!await gate.until()) return;
|
|
2101
2394
|
if (kaTorn || seq !== updateSeq) return;
|
|
2102
|
-
node = await instantiateScoped(
|
|
2395
|
+
node = await instantiateScoped(
|
|
2396
|
+
router2,
|
|
2397
|
+
plan,
|
|
2398
|
+
routeDef,
|
|
2399
|
+
route2.path,
|
|
2400
|
+
route2,
|
|
2401
|
+
null,
|
|
2402
|
+
gate,
|
|
2403
|
+
() => !kaTorn && seq === updateSeq
|
|
2404
|
+
);
|
|
2103
2405
|
} catch (error) {
|
|
2104
|
-
if (kaTorn || seq !== updateSeq) return;
|
|
2406
|
+
if (cancellations.has(error) || kaTorn || seq !== updateSeq) return;
|
|
2105
2407
|
console.error("[KeepAliveRoute] Component error:", error);
|
|
2408
|
+
loaded.cancel();
|
|
2106
2409
|
return;
|
|
2107
2410
|
}
|
|
2108
|
-
if (!node)
|
|
2109
|
-
|
|
2110
|
-
disposeOwned(node);
|
|
2411
|
+
if (!node) {
|
|
2412
|
+
if (!kaTorn && seq === updateSeq) loaded.done();
|
|
2111
2413
|
return;
|
|
2112
2414
|
}
|
|
2113
2415
|
}
|
|
2114
|
-
|
|
2115
|
-
|
|
2416
|
+
await commit(seq, node, fromCache, cacheKey, shouldCache, route2);
|
|
2417
|
+
};
|
|
2418
|
+
const commit = (seq, node, fromCache, cacheKey, shouldCache, route2) => commitPass(gate, {
|
|
2419
|
+
node: fromCache ? null : node,
|
|
2420
|
+
owned: () => !kaTorn && seq === updateSeq,
|
|
2421
|
+
discard: () => {
|
|
2116
2422
|
if (!fromCache) disposeOwned(node);
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2423
|
+
},
|
|
2424
|
+
// The outgoing view goes first: detached, and disposed unless it is
|
|
2425
|
+
// cached (then paused, with `suspendInactive`). Once only: it is no
|
|
2426
|
+
// longer the current view afterwards.
|
|
2427
|
+
teardown: () => {
|
|
2428
|
+
const outgoing = currentNode;
|
|
2429
|
+
if (outgoing === null || outgoing === node || !anchor.parentNode) return false;
|
|
2430
|
+
const wasCached = currentCached;
|
|
2431
|
+
currentNode = null;
|
|
2432
|
+
currentKey = "";
|
|
2433
|
+
currentCached = false;
|
|
2434
|
+
outgoing.parentNode?.removeChild(outgoing);
|
|
2435
|
+
if (!wasCached) disposeOwned(outgoing);
|
|
2436
|
+
else if (!kaTorn) suspend(outgoing);
|
|
2437
|
+
return true;
|
|
2438
|
+
},
|
|
2439
|
+
insert: () => {
|
|
2440
|
+
const parent = anchor.parentNode;
|
|
2441
|
+
if (!parent) {
|
|
2442
|
+
if (!fromCache) disposeOwned(node);
|
|
2443
|
+
attachWait.request();
|
|
2444
|
+
return;
|
|
2445
|
+
}
|
|
2446
|
+
if (fromCache) {
|
|
2447
|
+
updateInstanceRoute(node, route2);
|
|
2448
|
+
const idx = lruOrder.indexOf(cacheKey);
|
|
2449
|
+
if (idx !== -1) lruOrder.splice(idx, 1);
|
|
2450
|
+
lruOrder.push(cacheKey);
|
|
2451
|
+
} else if (shouldCache) {
|
|
2452
|
+
cache.set(cacheKey, node);
|
|
2453
|
+
lruOrder.push(cacheKey);
|
|
2454
|
+
}
|
|
2455
|
+
currentNode = node;
|
|
2456
|
+
currentCached = fromCache || shouldCache;
|
|
2457
|
+
currentKey = cacheKey;
|
|
2458
|
+
try {
|
|
2459
|
+
parent.insertBefore(node, anchor.nextSibling);
|
|
2460
|
+
} catch (error) {
|
|
2461
|
+
if (currentNode === node) {
|
|
2462
|
+
currentNode = null;
|
|
2463
|
+
currentKey = "";
|
|
2464
|
+
currentCached = false;
|
|
2465
|
+
}
|
|
2466
|
+
if (!fromCache) {
|
|
2467
|
+
if (cache.get(cacheKey) === node) {
|
|
2468
|
+
cache.delete(cacheKey);
|
|
2469
|
+
const at = lruOrder.lastIndexOf(cacheKey);
|
|
2470
|
+
if (at !== -1) lruOrder.splice(at, 1);
|
|
2471
|
+
}
|
|
2472
|
+
disposeOwned(node);
|
|
2473
|
+
}
|
|
2474
|
+
console.error("[KeepAliveRoute] Component error:", error);
|
|
2475
|
+
if (!kaTorn && seq === updateSeq) loaded.cancel();
|
|
2476
|
+
return;
|
|
2477
|
+
}
|
|
2478
|
+
if (kaTorn) return;
|
|
2479
|
+
if (seq === updateSeq) loaded.done();
|
|
2480
|
+
if (fromCache) activate(node);
|
|
2481
|
+
while (!kaTorn && lruOrder.length > maxCache) {
|
|
2133
2482
|
const evictKey = lruOrder.shift();
|
|
2134
2483
|
if (evictKey === cacheKey) {
|
|
2135
2484
|
lruOrder.push(evictKey);
|
|
2136
2485
|
break;
|
|
2137
2486
|
}
|
|
2138
2487
|
const evictNode = cache.get(evictKey);
|
|
2488
|
+
cache.delete(evictKey);
|
|
2139
2489
|
if (evictNode) {
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
cache.delete(evictKey);
|
|
2490
|
+
disposeCached(evictNode);
|
|
2491
|
+
evictNode.parentNode?.removeChild(evictNode);
|
|
2143
2492
|
}
|
|
2144
2493
|
}
|
|
2145
2494
|
}
|
|
2146
|
-
|
|
2147
|
-
currentCached = fromCache || shouldCache;
|
|
2148
|
-
currentKey = cacheKey;
|
|
2149
|
-
parent.insertBefore(node, anchor.nextSibling);
|
|
2150
|
-
};
|
|
2495
|
+
});
|
|
2151
2496
|
let initialized = false;
|
|
2152
2497
|
const wrappedUpdate = async () => {
|
|
2153
2498
|
await update();
|
|
2154
2499
|
initialized = true;
|
|
2155
2500
|
};
|
|
2156
|
-
const attachWait = attachRetry(anchor, update);
|
|
2157
|
-
const kaTeardown =
|
|
2501
|
+
const attachWait = attachRetry(anchor, () => whenActive(gate, update));
|
|
2502
|
+
const kaTeardown = reactiveBinding(wrappedUpdate, anchor);
|
|
2158
2503
|
if (!initialized) {
|
|
2159
2504
|
queueMicrotask(
|
|
2160
2505
|
bindOwnerScope(() => {
|
|
2161
|
-
|
|
2506
|
+
whenActive(
|
|
2507
|
+
gate,
|
|
2508
|
+
bindOwnerScope(() => {
|
|
2509
|
+
if (!initialized && anchor.parentNode) wrappedUpdate();
|
|
2510
|
+
})
|
|
2511
|
+
);
|
|
2162
2512
|
})
|
|
2163
2513
|
);
|
|
2164
2514
|
}
|
|
2165
2515
|
const kaCleanup = () => {
|
|
2166
2516
|
if (kaTorn) return;
|
|
2167
2517
|
kaTorn = true;
|
|
2518
|
+
gate.close();
|
|
2519
|
+
loaded.cancel();
|
|
2168
2520
|
updateSeq++;
|
|
2169
2521
|
kaTeardown();
|
|
2170
2522
|
attachWait.cancel();
|
|
2171
2523
|
for (const node of cache.values()) {
|
|
2172
|
-
|
|
2524
|
+
disposeCached(node);
|
|
2173
2525
|
if (node.parentNode) node.parentNode.removeChild(node);
|
|
2174
2526
|
}
|
|
2175
2527
|
cache.clear();
|
|
2528
|
+
suspended.clear();
|
|
2176
2529
|
lruOrder.length = 0;
|
|
2177
2530
|
if (currentNode?.parentNode) currentNode.parentNode.removeChild(currentNode);
|
|
2178
2531
|
if (currentNode && !currentCached) disposeOwned(currentNode);
|
|
@@ -2180,6 +2533,7 @@ function KeepAliveRoute(options) {
|
|
|
2180
2533
|
currentKey = "";
|
|
2181
2534
|
currentCached = false;
|
|
2182
2535
|
};
|
|
2536
|
+
registerNodesRange(anchor, () => [currentNode]);
|
|
2183
2537
|
registerDisposer(anchor, kaCleanup);
|
|
2184
2538
|
routeCleanups.push(kaCleanup);
|
|
2185
2539
|
return anchor;
|
|
@@ -2255,6 +2609,15 @@ function Suspense(props) {
|
|
|
2255
2609
|
const anchor = document.createComment("suspense-boundary");
|
|
2256
2610
|
let currentNode = null;
|
|
2257
2611
|
let fallbackNode = null;
|
|
2612
|
+
const frozen = captureFrozen();
|
|
2613
|
+
let contentOwner = structuralBinding(NOOP);
|
|
2614
|
+
let fallbackOwner = null;
|
|
2615
|
+
const endContent = () => {
|
|
2616
|
+
const owner = contentOwner;
|
|
2617
|
+
contentOwner = null;
|
|
2618
|
+
owner?.stop();
|
|
2619
|
+
};
|
|
2620
|
+
const loaded = beginLoading(anchor);
|
|
2258
2621
|
let isLoading = false;
|
|
2259
2622
|
let generation = 0;
|
|
2260
2623
|
let tornDown = false;
|
|
@@ -2269,21 +2632,36 @@ function Suspense(props) {
|
|
|
2269
2632
|
release(fallbackNode);
|
|
2270
2633
|
currentNode = null;
|
|
2271
2634
|
fallbackNode = null;
|
|
2635
|
+
endFallback();
|
|
2636
|
+
};
|
|
2637
|
+
const endFallback = () => {
|
|
2638
|
+
const owner = fallbackOwner;
|
|
2639
|
+
fallbackOwner = null;
|
|
2640
|
+
owner?.stop();
|
|
2272
2641
|
};
|
|
2273
2642
|
const showFallback = (myGeneration) => {
|
|
2274
2643
|
if (fallbackNode || !props.fallback || tornDown) return;
|
|
2275
2644
|
if (!anchor.parentNode) return;
|
|
2276
2645
|
let fallback;
|
|
2277
2646
|
try {
|
|
2278
|
-
|
|
2647
|
+
const factory = props.fallback;
|
|
2648
|
+
if (typeof factory === "function") {
|
|
2649
|
+
const owner = fallbackOwner = frozen.run(() => structuralBinding(NOOP));
|
|
2650
|
+
fallback = owner.run(factory);
|
|
2651
|
+
} else fallback = factory;
|
|
2279
2652
|
} catch (error) {
|
|
2280
2653
|
console.error("[Suspense] Fallback error:", error);
|
|
2654
|
+
endFallback();
|
|
2655
|
+
return;
|
|
2656
|
+
}
|
|
2657
|
+
if (!fallback || fallback.nodeType !== 1) {
|
|
2658
|
+
endFallback();
|
|
2281
2659
|
return;
|
|
2282
2660
|
}
|
|
2283
|
-
if (!fallback || fallback.nodeType !== 1) return;
|
|
2284
2661
|
const parent = commitTarget(myGeneration);
|
|
2285
2662
|
if (!parent) {
|
|
2286
2663
|
release(fallback);
|
|
2664
|
+
endFallback();
|
|
2287
2665
|
return;
|
|
2288
2666
|
}
|
|
2289
2667
|
fallbackNode = fallback;
|
|
@@ -2294,7 +2672,9 @@ function Suspense(props) {
|
|
|
2294
2672
|
isLoading = true;
|
|
2295
2673
|
const myGeneration = ++generation;
|
|
2296
2674
|
try {
|
|
2297
|
-
const
|
|
2675
|
+
const owner = contentOwner;
|
|
2676
|
+
if (owner === null) return;
|
|
2677
|
+
const result = owner.run(props.nodes);
|
|
2298
2678
|
let element;
|
|
2299
2679
|
const isNode = typeof result?.nodeType === "number";
|
|
2300
2680
|
if (!isNode && result != null && typeof result.then === "function") {
|
|
@@ -2303,35 +2683,84 @@ function Suspense(props) {
|
|
|
2303
2683
|
} else {
|
|
2304
2684
|
element = result;
|
|
2305
2685
|
}
|
|
2306
|
-
|
|
2307
|
-
if (!parent) {
|
|
2308
|
-
release(element);
|
|
2309
|
-
cleanupNodes();
|
|
2310
|
-
return;
|
|
2311
|
-
}
|
|
2312
|
-
cleanupNodes();
|
|
2313
|
-
parent.insertBefore(element, anchor.nextSibling);
|
|
2314
|
-
currentNode = element;
|
|
2686
|
+
settle(myGeneration, true, element);
|
|
2315
2687
|
} catch (error) {
|
|
2316
2688
|
console.error("[Suspense] Nodes error:", error);
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
if (!parent) return;
|
|
2320
|
-
const errorElement = document.createElement("div");
|
|
2321
|
-
errorElement.className = "suspense-error";
|
|
2322
|
-
errorElement.textContent = error instanceof Error ? error.message : "Failed to load";
|
|
2323
|
-
parent.insertBefore(errorElement, anchor.nextSibling);
|
|
2324
|
-
currentNode = errorElement;
|
|
2689
|
+
endContent();
|
|
2690
|
+
settle(myGeneration, false, error);
|
|
2325
2691
|
} finally {
|
|
2326
2692
|
isLoading = false;
|
|
2327
2693
|
}
|
|
2328
2694
|
};
|
|
2695
|
+
const committing = { cancel: NOOP };
|
|
2696
|
+
let dropWait = null;
|
|
2697
|
+
const settle = (myGeneration, ok, value) => {
|
|
2698
|
+
let view;
|
|
2699
|
+
if (ok) view = value;
|
|
2700
|
+
else {
|
|
2701
|
+
view = document.createElement("div");
|
|
2702
|
+
view.className = "suspense-error";
|
|
2703
|
+
view.textContent = value instanceof Error ? value.message : "Failed to load";
|
|
2704
|
+
}
|
|
2705
|
+
commitWhenActive(committing, {
|
|
2706
|
+
held: frozen,
|
|
2707
|
+
node: view,
|
|
2708
|
+
owned: () => !tornDown && myGeneration === generation,
|
|
2709
|
+
// Never shown: the content (or what is left of it) is abandoned.
|
|
2710
|
+
discard: () => {
|
|
2711
|
+
release(view);
|
|
2712
|
+
endContent();
|
|
2713
|
+
loaded.cancel();
|
|
2714
|
+
},
|
|
2715
|
+
teardown: () => {
|
|
2716
|
+
if (!anchor.parentNode || !(currentNode || fallbackNode || fallbackOwner)) return false;
|
|
2717
|
+
cleanupNodes();
|
|
2718
|
+
return true;
|
|
2719
|
+
},
|
|
2720
|
+
insert: () => {
|
|
2721
|
+
const parent = commitTarget(myGeneration);
|
|
2722
|
+
if (!parent) {
|
|
2723
|
+
release(view);
|
|
2724
|
+
cleanupNodes();
|
|
2725
|
+
endContent();
|
|
2726
|
+
loaded.cancel();
|
|
2727
|
+
return;
|
|
2728
|
+
}
|
|
2729
|
+
currentNode = view;
|
|
2730
|
+
try {
|
|
2731
|
+
parent.insertBefore(view, anchor.nextSibling);
|
|
2732
|
+
} catch (error) {
|
|
2733
|
+
if (currentNode === view) currentNode = null;
|
|
2734
|
+
release(view);
|
|
2735
|
+
endContent();
|
|
2736
|
+
console.error("[Suspense] Nodes error:", error);
|
|
2737
|
+
if (ok) settle(myGeneration, false, error);
|
|
2738
|
+
else loaded.cancel();
|
|
2739
|
+
return;
|
|
2740
|
+
}
|
|
2741
|
+
if (!tornDown && myGeneration === generation) loaded.done();
|
|
2742
|
+
}
|
|
2743
|
+
});
|
|
2744
|
+
};
|
|
2745
|
+
registerNodesRange(anchor, () => [currentNode, fallbackNode]);
|
|
2329
2746
|
registerDisposer(anchor, () => {
|
|
2330
2747
|
tornDown = true;
|
|
2331
2748
|
generation++;
|
|
2749
|
+
dropWait?.();
|
|
2750
|
+
dropWait = null;
|
|
2751
|
+
committing.cancel();
|
|
2332
2752
|
cleanupNodes();
|
|
2753
|
+
endContent();
|
|
2754
|
+
loaded.cancel();
|
|
2755
|
+
});
|
|
2756
|
+
const renderInScope = bindOwnerScope(() => {
|
|
2757
|
+
if (!tornDown) render();
|
|
2333
2758
|
});
|
|
2334
|
-
queueMicrotask(
|
|
2759
|
+
queueMicrotask(
|
|
2760
|
+
bindOwnerScope(() => {
|
|
2761
|
+
dropWait = frozen.wait(renderInScope, NOOP);
|
|
2762
|
+
})
|
|
2763
|
+
);
|
|
2335
2764
|
return anchor;
|
|
2336
2765
|
}
|
|
2337
2766
|
var LAZY_MARKER = /* @__PURE__ */ Symbol.for("sibujs:lazy");
|
|
@@ -2393,11 +2822,14 @@ function __removeRouterPagehideHandler() {
|
|
|
2393
2822
|
function Outlet() {
|
|
2394
2823
|
const anchor = document.createComment("route-outlet-nested");
|
|
2395
2824
|
const adoptScope = captureScope();
|
|
2825
|
+
const frozen = captureFrozen();
|
|
2826
|
+
const gate = pauseGate(frozen);
|
|
2396
2827
|
let currentNode = null;
|
|
2397
2828
|
let currentChild = null;
|
|
2398
2829
|
let currentKey = null;
|
|
2399
2830
|
let navSeq = 0;
|
|
2400
2831
|
let outletTorn = false;
|
|
2832
|
+
const loaded = beginLoading(anchor);
|
|
2401
2833
|
const clearCurrent = () => {
|
|
2402
2834
|
if (currentNode) {
|
|
2403
2835
|
disposeOwned(currentNode);
|
|
@@ -2423,21 +2855,25 @@ function Outlet() {
|
|
|
2423
2855
|
const route2 = scopedRoute(_routerRef.current);
|
|
2424
2856
|
if (route2.matched.length < 2) {
|
|
2425
2857
|
clearCurrent();
|
|
2858
|
+
settleEmpty(route2, loaded, () => !outletTorn && seq === navSeq);
|
|
2426
2859
|
return;
|
|
2427
2860
|
}
|
|
2428
2861
|
const childRoute = route2.matched[route2.matched.length - 1];
|
|
2429
2862
|
if (!childRoute || !("component" in childRoute)) {
|
|
2430
2863
|
clearCurrent();
|
|
2864
|
+
loaded.done();
|
|
2431
2865
|
return;
|
|
2432
2866
|
}
|
|
2433
2867
|
const key = instanceKey(childRoute, route2.matched.slice(1), route2);
|
|
2434
2868
|
if (childRoute === currentChild && key === currentKey && currentNode) {
|
|
2435
2869
|
updateInstanceRoute(currentNode, route2);
|
|
2870
|
+
loaded.done();
|
|
2436
2871
|
return;
|
|
2437
2872
|
}
|
|
2438
2873
|
try {
|
|
2439
2874
|
const cacheKey = `${route2.path}\0${childRoute.path}`;
|
|
2440
2875
|
const plan = await _routerRef.current.loadPlan(childRoute, cacheKey);
|
|
2876
|
+
while (gate.held()) if (!await gate.until()) return;
|
|
2441
2877
|
if (!commitTarget(seq)) {
|
|
2442
2878
|
retryIfDetached(seq);
|
|
2443
2879
|
return;
|
|
@@ -2448,31 +2884,64 @@ function Outlet() {
|
|
|
2448
2884
|
childRoute,
|
|
2449
2885
|
cacheKey,
|
|
2450
2886
|
route2,
|
|
2451
|
-
keyedScope(adoptScope, childRoute.path)
|
|
2887
|
+
keyedScope(adoptScope, childRoute.path),
|
|
2888
|
+
gate,
|
|
2889
|
+
() => commitTarget(seq) !== null
|
|
2452
2890
|
);
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2891
|
+
await commitPass(gate, {
|
|
2892
|
+
node,
|
|
2893
|
+
owned: () => !outletTorn && seq === navSeq,
|
|
2894
|
+
discard: () => release(node),
|
|
2895
|
+
teardown: () => {
|
|
2896
|
+
if (!node || !anchor.parentNode || !currentNode) return false;
|
|
2897
|
+
clearCurrent();
|
|
2898
|
+
return true;
|
|
2899
|
+
},
|
|
2900
|
+
insert: () => {
|
|
2901
|
+
const parent = commitTarget(seq);
|
|
2902
|
+
if (!parent) {
|
|
2903
|
+
release(node);
|
|
2904
|
+
retryIfDetached(seq);
|
|
2905
|
+
return;
|
|
2906
|
+
}
|
|
2907
|
+
if (node) {
|
|
2908
|
+
currentNode = node;
|
|
2909
|
+
currentChild = childRoute;
|
|
2910
|
+
currentKey = key;
|
|
2911
|
+
try {
|
|
2912
|
+
parent.insertBefore(node, anchor.nextSibling);
|
|
2913
|
+
} catch (error) {
|
|
2914
|
+
if (currentNode === node) {
|
|
2915
|
+
currentNode = null;
|
|
2916
|
+
currentChild = null;
|
|
2917
|
+
currentKey = null;
|
|
2918
|
+
}
|
|
2919
|
+
release(node);
|
|
2920
|
+
throw error;
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2923
|
+
if (!outletTorn && seq === navSeq) loaded.done();
|
|
2924
|
+
}
|
|
2925
|
+
});
|
|
2465
2926
|
} catch (error) {
|
|
2466
|
-
if (outletTorn || seq !== navSeq) return;
|
|
2927
|
+
if (cancellations.has(error) || outletTorn || seq !== navSeq) return;
|
|
2467
2928
|
console.error("[Outlet] Failed to render child route:", error);
|
|
2929
|
+
loaded.cancel();
|
|
2468
2930
|
}
|
|
2469
2931
|
};
|
|
2470
|
-
const attachWait = attachRetry(anchor, update);
|
|
2471
|
-
const outletTeardown =
|
|
2932
|
+
const attachWait = attachRetry(anchor, () => whenActive(gate, update));
|
|
2933
|
+
const outletTeardown = reactiveBinding(() => {
|
|
2934
|
+
void update();
|
|
2935
|
+
}, anchor);
|
|
2472
2936
|
if (!anchor.parentNode) {
|
|
2473
2937
|
queueMicrotask(
|
|
2474
2938
|
bindOwnerScope(() => {
|
|
2475
|
-
|
|
2939
|
+
whenActive(
|
|
2940
|
+
gate,
|
|
2941
|
+
bindOwnerScope(() => {
|
|
2942
|
+
if (anchor.parentNode) update();
|
|
2943
|
+
})
|
|
2944
|
+
);
|
|
2476
2945
|
})
|
|
2477
2946
|
);
|
|
2478
2947
|
}
|
|
@@ -2480,6 +2949,8 @@ function Outlet() {
|
|
|
2480
2949
|
if (outletTorn) return;
|
|
2481
2950
|
outletTorn = true;
|
|
2482
2951
|
navSeq++;
|
|
2952
|
+
gate.close();
|
|
2953
|
+
loaded.cancel();
|
|
2483
2954
|
outletTeardown();
|
|
2484
2955
|
attachWait.cancel();
|
|
2485
2956
|
if (currentNode) {
|
|
@@ -2490,6 +2961,7 @@ function Outlet() {
|
|
|
2490
2961
|
currentChild = null;
|
|
2491
2962
|
currentKey = null;
|
|
2492
2963
|
};
|
|
2964
|
+
registerNodesRange(anchor, () => [currentNode]);
|
|
2493
2965
|
registerDisposer(anchor, outletCleanup);
|
|
2494
2966
|
routeCleanups.push(outletCleanup);
|
|
2495
2967
|
return anchor;
|