@vesk/runtime 0.2.22 → 0.2.24
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/hmr-client.d.ts +3 -3
- package/dist/hmr-client.d.ts.map +1 -1
- package/dist/hmr-client.js +17 -5
- package/dist/hydrate.d.ts +30 -0
- package/dist/hydrate.d.ts.map +1 -1
- package/dist/hydrate.js +253 -51
- package/dist/index-client.d.ts +2 -2
- package/dist/index-client.d.ts.map +1 -1
- package/dist/index-client.js +2 -2
- package/dist/reconcile.d.ts +20 -1
- package/dist/reconcile.d.ts.map +1 -1
- package/dist/reconcile.js +48 -4
- package/dist/resource.d.ts +1 -1
- package/dist/resource.d.ts.map +1 -1
- package/dist/resource.js +58 -10
- package/dist/router-components.d.ts +16 -1
- package/dist/router-components.d.ts.map +1 -1
- package/dist/router-components.js +88 -17
- package/dist/router-match.d.ts +1 -0
- package/dist/router-match.d.ts.map +1 -1
- package/dist/router-match.js +13 -3
- package/dist/router.d.ts +1 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +168 -25
- package/package.json +27 -2
package/dist/reconcile.d.ts
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
1
|
import type { Block } from '@vesk/runtime/src/ripple-runtime';
|
|
2
|
-
export
|
|
2
|
+
export type KeyedClaimFn = (key: string) => {
|
|
3
|
+
el: Element;
|
|
4
|
+
} | null;
|
|
5
|
+
export type KeyedPeekFn = (key: string) => Element | null;
|
|
6
|
+
export interface KeyedHydrateWalker {
|
|
7
|
+
peekKey?: KeyedPeekFn;
|
|
8
|
+
claimByKey?: KeyedClaimFn;
|
|
9
|
+
}
|
|
10
|
+
export declare function reconcile<T>(anchor: Node, endAnchor: Node, items: T[], keyFn: (item: T) => string, createItem: (item: T, index: number, effs: Block[], root: Element | null) => void, claim?: KeyedClaimFn): (newItems: T[]) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Keyed-list hydration (claim-by-key). Positions the map's `anchor`/`endAnchor`
|
|
13
|
+
* around the SSR-claimed item elements so the map region stays inside the
|
|
14
|
+
* containing element, then hands off to `reconcile` with the walker's
|
|
15
|
+
* `claimByKey` as the claim function. Items that never had SSR markers (the
|
|
16
|
+
* list was empty or the client data grew) anchor at the end of the region and
|
|
17
|
+
* render fresh. Ordering is exact when SSR data matches the client data;
|
|
18
|
+
* divergence degrades to appending fresh items at the region tail instead of
|
|
19
|
+
* duplicating already-claimed SSR content.
|
|
20
|
+
*/
|
|
21
|
+
export declare function reconcileHydrated<T>(anchor: Node, endAnchor: Node, items: T[], keyFn: (item: T) => string, createItem: (item: T, index: number, effs: Block[], root: Element | null) => void, walker: KeyedHydrateWalker, parent: Node): (newItems: T[]) => void;
|
|
3
22
|
//# sourceMappingURL=reconcile.d.ts.map
|
package/dist/reconcile.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconcile.d.ts","sourceRoot":"","sources":["../src/reconcile.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kCAAkC,CAAC;AAO9D,wBAAgB,SAAS,CAAC,CAAC,EAC1B,MAAM,EAAE,IAAI,EACZ,SAAS,EAAE,IAAI,EACf,KAAK,EAAE,CAAC,EAAE,EACV,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,EAC1B,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,IAAI,
|
|
1
|
+
{"version":3,"file":"reconcile.d.ts","sourceRoot":"","sources":["../src/reconcile.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kCAAkC,CAAC;AAO9D,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK;IAAE,EAAE,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAAC;AACnE,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC;AAE1D,MAAM,WAAW,kBAAkB;IAClC,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,UAAU,CAAC,EAAE,YAAY,CAAC;CAC1B;AAED,wBAAgB,SAAS,CAAC,CAAC,EAC1B,MAAM,EAAE,IAAI,EACZ,SAAS,EAAE,IAAI,EACf,KAAK,EAAE,CAAC,EAAE,EACV,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,EAC1B,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,EACjF,KAAK,CAAC,EAAE,YAAY,GAClB,CAAC,QAAQ,EAAE,CAAC,EAAE,KAAK,IAAI,CAkDzB;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAClC,MAAM,EAAE,IAAI,EACZ,SAAS,EAAE,IAAI,EACf,KAAK,EAAE,CAAC,EAAE,EACV,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,EAC1B,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,EACjF,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,IAAI,GACV,CAAC,QAAQ,EAAE,CAAC,EAAE,KAAK,IAAI,CA0BzB"}
|
package/dist/reconcile.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { destroy_block } from '@vesk/runtime/src/ripple-blocks';
|
|
2
|
-
export function reconcile(anchor, endAnchor, items, keyFn, createItem) {
|
|
2
|
+
export function reconcile(anchor, endAnchor, items, keyFn, createItem, claim) {
|
|
3
3
|
const parent = anchor.parentNode;
|
|
4
4
|
const map = new Map();
|
|
5
5
|
for (let i = 0; i < items.length; i++) {
|
|
@@ -7,8 +7,12 @@ export function reconcile(anchor, endAnchor, items, keyFn, createItem) {
|
|
|
7
7
|
const key = keyFn(item);
|
|
8
8
|
const marker = document.createComment('k:' + key);
|
|
9
9
|
const effs = [];
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
// When hydrated, the item's SSR root element (if any) is claimed here;
|
|
11
|
+
// the marker is anchored to it so `removeRange`/`moveBefore` operate on
|
|
12
|
+
// the claimed content instead of duplicating it.
|
|
13
|
+
const c = claim ? claim(key) : null;
|
|
14
|
+
parent.insertBefore(marker, c ? c.el : endAnchor);
|
|
15
|
+
createItem(item, i, effs, c ? c.el : null);
|
|
12
16
|
map.set(key, { marker, effs });
|
|
13
17
|
}
|
|
14
18
|
return (newItems) => {
|
|
@@ -37,13 +41,53 @@ export function reconcile(anchor, endAnchor, items, keyFn, createItem) {
|
|
|
37
41
|
const marker = document.createComment('k:' + key);
|
|
38
42
|
const effs = [];
|
|
39
43
|
parent.insertBefore(marker, ref);
|
|
40
|
-
createItem(newItems[i], i, effs);
|
|
44
|
+
createItem(newItems[i], i, effs, null);
|
|
41
45
|
map.set(key, { marker, effs });
|
|
42
46
|
ref = marker;
|
|
43
47
|
}
|
|
44
48
|
}
|
|
45
49
|
};
|
|
46
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Keyed-list hydration (claim-by-key). Positions the map's `anchor`/`endAnchor`
|
|
53
|
+
* around the SSR-claimed item elements so the map region stays inside the
|
|
54
|
+
* containing element, then hands off to `reconcile` with the walker's
|
|
55
|
+
* `claimByKey` as the claim function. Items that never had SSR markers (the
|
|
56
|
+
* list was empty or the client data grew) anchor at the end of the region and
|
|
57
|
+
* render fresh. Ordering is exact when SSR data matches the client data;
|
|
58
|
+
* divergence degrades to appending fresh items at the region tail instead of
|
|
59
|
+
* duplicating already-claimed SSR content.
|
|
60
|
+
*/
|
|
61
|
+
export function reconcileHydrated(anchor, endAnchor, items, keyFn, createItem, walker, parent) {
|
|
62
|
+
// Discover the region's SSR bounds without consuming any markers.
|
|
63
|
+
const claimedEls = [];
|
|
64
|
+
for (let i = 0; i < items.length; i++) {
|
|
65
|
+
const el = walker.peekKey ? walker.peekKey(keyFn(items[i])) : null;
|
|
66
|
+
if (el)
|
|
67
|
+
claimedEls.push(el);
|
|
68
|
+
}
|
|
69
|
+
if (claimedEls.length > 0) {
|
|
70
|
+
const order = new Map();
|
|
71
|
+
const kids = parent.childNodes;
|
|
72
|
+
for (let i = 0; i < kids.length; i++)
|
|
73
|
+
order.set(kids[i], i);
|
|
74
|
+
let first = claimedEls[0];
|
|
75
|
+
let last = claimedEls[0];
|
|
76
|
+
for (const el of claimedEls) {
|
|
77
|
+
if ((order.get(el) ?? -1) < (order.get(first) ?? -1))
|
|
78
|
+
first = el;
|
|
79
|
+
if ((order.get(el) ?? -1) > (order.get(last) ?? -1))
|
|
80
|
+
last = el;
|
|
81
|
+
}
|
|
82
|
+
parent.insertBefore(anchor, first);
|
|
83
|
+
parent.insertBefore(endAnchor, last.nextSibling);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
parent.appendChild(anchor);
|
|
87
|
+
parent.appendChild(endAnchor);
|
|
88
|
+
}
|
|
89
|
+
return reconcile(anchor, endAnchor, items, keyFn, createItem, (key) => walker.claimByKey(key));
|
|
90
|
+
}
|
|
47
91
|
function removeRange(start, end) {
|
|
48
92
|
let n = start.nextSibling;
|
|
49
93
|
while (n && n !== end && !(n.nodeType === 8 && n.nodeValue && n.nodeValue.startsWith('k:'))) {
|
package/dist/resource.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export interface SsrDataSink {
|
|
|
36
36
|
}
|
|
37
37
|
export declare function setSsrSink(sink: SsrDataSink | null): void;
|
|
38
38
|
export declare function getSsrData(key: string): unknown;
|
|
39
|
-
export declare function setSsrData(key: string, value: unknown): void;
|
|
39
|
+
export declare function setSsrData(key: string, value: unknown, ownerToken?: string): void;
|
|
40
40
|
export declare function clearSsrData(): void;
|
|
41
41
|
export declare function mutate(key: string, data?: unknown): void;
|
|
42
42
|
export declare function createResource<T>(fn: () => Promise<T>, key?: string, into?: Tracked, options?: UseFetchOptions<T>): Resource<T>;
|
package/dist/resource.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAC;AAQhE,MAAM,WAAW,QAAQ,CAAC,CAAC,CAAE,SAAQ,WAAW,CAAC,CAAC,CAAC;IAClD,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,CAAC,GAAG,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,CAAE,SAAQ,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gGAAgG;IAChG,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,SAAU,SAAQ,KAAK;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;gBACP,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CAM9C;AAED,qBAAa,YAAa,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI3B;AAKD,MAAM,WAAW,WAAW;IAC3B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACvC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IACtC,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,KAAK,IAAI,IAAI,CAAC;CACd;AAID,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAEzD;
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"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"}
|
package/dist/resource.js
CHANGED
|
@@ -46,10 +46,34 @@ function getRegistry() {
|
|
|
46
46
|
g().__vsk_fetch_registry = map;
|
|
47
47
|
return map;
|
|
48
48
|
}
|
|
49
|
+
// Per-render data attributed to a specific render token. The resource promise
|
|
50
|
+
// callbacks that call setSsrData run outside AsyncLocalStorage scope (native
|
|
51
|
+
// fetch async contexts) so they cannot be attributed via the sink/store; a
|
|
52
|
+
// token captured synchronously at fetch start (startRequest) or read from the
|
|
53
|
+
// live global token for synchronous writes (md hook) gives renderFullPage /
|
|
54
|
+
// renderPageStream an isolated, deterministic channel that still never mixes
|
|
55
|
+
// concurrent requests.
|
|
56
|
+
function ssrSlotFor(token) {
|
|
57
|
+
if (!token)
|
|
58
|
+
return undefined;
|
|
59
|
+
return g()[`__vsk_ssr_data_${token}`] || undefined;
|
|
60
|
+
}
|
|
61
|
+
function writeSsrSlot(token, key, value) {
|
|
62
|
+
if (!token)
|
|
63
|
+
return;
|
|
64
|
+
const slot = g()[`__vsk_ssr_data_${token}`] || (g()[`__vsk_ssr_data_${token}`] = {});
|
|
65
|
+
slot[key] = value;
|
|
66
|
+
}
|
|
49
67
|
export function getSsrData(key) {
|
|
50
68
|
const sink = ssrSink;
|
|
51
|
-
if (sink)
|
|
52
|
-
|
|
69
|
+
if (sink) {
|
|
70
|
+
const value = sink.get(key);
|
|
71
|
+
if (value !== undefined)
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
const slot = ssrSlotFor(g().__vsk_ssr_token || undefined);
|
|
75
|
+
if (slot && slot[key] !== undefined)
|
|
76
|
+
return slot[key];
|
|
53
77
|
const store = g().__vsk_ssr_data;
|
|
54
78
|
if (!store)
|
|
55
79
|
return undefined;
|
|
@@ -75,23 +99,34 @@ function getSsrFailures() {
|
|
|
75
99
|
}
|
|
76
100
|
return store;
|
|
77
101
|
}
|
|
78
|
-
export function setSsrData(key, value) {
|
|
102
|
+
export function setSsrData(key, value, ownerToken) {
|
|
79
103
|
const sink = ssrSink;
|
|
80
|
-
if (sink)
|
|
104
|
+
if (sink)
|
|
81
105
|
sink.set(key, value);
|
|
82
|
-
|
|
83
|
-
|
|
106
|
+
// Also mirror into globalThis: the sink is AsyncLocalStorage-scoped and in
|
|
107
|
+
// some server bundles the write lands in a different store than the one
|
|
108
|
+
// renderFullPage/renderPageStream snapshots (duplicated ssr-store copies /
|
|
109
|
+
// native fetch async contexts). globalThis is the deterministic channel.
|
|
84
110
|
if (!g().__vsk_ssr_data)
|
|
85
111
|
g().__vsk_ssr_data = {};
|
|
86
112
|
g().__vsk_ssr_data[key] = value;
|
|
113
|
+
// Per-render slot (see ssrSlotFor): resolved resource callbacks and the md
|
|
114
|
+
// hook must be attributed to the render that started them. A stale token can
|
|
115
|
+
// not leak into later requests — renderFullPage/renderPageStream delete the
|
|
116
|
+
// slot after merging and start fresh alongside the flat store.
|
|
117
|
+
if (ownerToken)
|
|
118
|
+
writeSsrSlot(ownerToken, key, value);
|
|
119
|
+
else
|
|
120
|
+
writeSsrSlot(g().__vsk_ssr_token || undefined, key, value);
|
|
87
121
|
}
|
|
88
122
|
export function clearSsrData() {
|
|
89
123
|
const sink = ssrSink;
|
|
90
|
-
if (sink)
|
|
124
|
+
if (sink)
|
|
91
125
|
sink.clear();
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
126
|
delete g().__vsk_ssr_data;
|
|
127
|
+
const tk = g().__vsk_ssr_token;
|
|
128
|
+
if (tk)
|
|
129
|
+
delete g()[`__vsk_ssr_data_${tk}`];
|
|
95
130
|
}
|
|
96
131
|
function setInto(into, data) {
|
|
97
132
|
if (into && typeof into === 'object' && typeof into.f === 'number') {
|
|
@@ -360,11 +395,17 @@ function startRequest(handle, skipCache) {
|
|
|
360
395
|
return settled;
|
|
361
396
|
}
|
|
362
397
|
const existing = getInflight().get(key);
|
|
398
|
+
// Capture the render token at fetch start: the resolution callback below
|
|
399
|
+
// runs outside AsyncLocalStorage scope, so setSsrData cannot read the
|
|
400
|
+
// token from the live render context anymore. An explicit owner token
|
|
401
|
+
// keeps the data attributed to this request's render slot even when the
|
|
402
|
+
// token has been torn down by the time the fetch resolves.
|
|
403
|
+
const startToken = g().__vsk_ssr_token || undefined;
|
|
363
404
|
const prom = existing ?? runFetcher(handle, options.timeout || 0);
|
|
364
405
|
if (!existing) {
|
|
365
406
|
getInflight().set(key, prom);
|
|
366
407
|
prom.then(data => {
|
|
367
|
-
setSsrData(key, data);
|
|
408
|
+
setSsrData(key, data, startToken);
|
|
368
409
|
settle(handle, data);
|
|
369
410
|
}, error => {
|
|
370
411
|
getSsrFailures()?.set(key, error);
|
|
@@ -538,6 +579,13 @@ export function createResource(fn, key, into, options = {}) {
|
|
|
538
579
|
}
|
|
539
580
|
const ssrData = getSsrData(resourceKey);
|
|
540
581
|
if (ssrData !== undefined) {
|
|
582
|
+
// The hit may come from the flat globalThis store a PREVIOUS request left
|
|
583
|
+
// behind (dev-server keeps it warm across requests). The handoff for THIS
|
|
584
|
+
// render is a different channel (per-request sink / per-token slot), so
|
|
585
|
+
// re-emit the value into the current render — otherwise snapshot() comes
|
|
586
|
+
// back empty and the page ships without its ssr-data script.
|
|
587
|
+
if (isServer())
|
|
588
|
+
setSsrData(resourceKey, ssrData);
|
|
541
589
|
settle(handle, ssrData);
|
|
542
590
|
writeCache(resourceKey, ssrData);
|
|
543
591
|
return accessor;
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { createHydrateWalker } from '@vesk/runtime/src/hydrate';
|
|
2
|
+
/** Navigation scroll behavior: how the router moves the window when
|
|
3
|
+
* navigating. Passed through `<Link scrollBehavior="smooth">` /
|
|
4
|
+
* `<NavLink scrollBehavior="smooth">` and honored by `window.scrollTo`. */
|
|
5
|
+
export type ScrollBehavior = 'auto' | 'instant' | 'smooth';
|
|
2
6
|
interface Router {
|
|
3
7
|
start(): Router;
|
|
4
8
|
navigate(path: string, opts?: {
|
|
5
9
|
replace?: boolean;
|
|
10
|
+
scrollBehavior?: ScrollBehavior;
|
|
6
11
|
}): void;
|
|
7
12
|
prefetch(path: string): void;
|
|
8
13
|
readonly currentPath: string;
|
|
@@ -37,6 +42,13 @@ export declare const _state: {
|
|
|
37
42
|
};
|
|
38
43
|
export declare const _scrollPositions: Map<string, number>;
|
|
39
44
|
export declare let _isPopStateNavigation: boolean;
|
|
45
|
+
export declare let _initialScrollRestored: boolean;
|
|
46
|
+
export declare let _initialSavedScroll: number;
|
|
47
|
+
/** Capture the browser's pre-hydration scroll position and re-arm the
|
|
48
|
+
* one-shot initial restore. Called at the top of `router.start()` on a
|
|
49
|
+
* fresh page load so a refresh lands back on the viewport the browser
|
|
50
|
+
* had scrolled to instead of the top. */
|
|
51
|
+
export declare function captureInitialScroll(): void;
|
|
40
52
|
export declare function setIsPopStateNavigation(v: boolean): void;
|
|
41
53
|
export declare function setCurrentRouter(r: Router | null): void;
|
|
42
54
|
export declare function getCurrentRouter(): Router | null;
|
|
@@ -46,7 +58,7 @@ export declare function findNotFoundComponent(chain: Record<string, unknown>[]):
|
|
|
46
58
|
export declare function findOfflineComponent(chain: Record<string, unknown>[]): Function | string | null;
|
|
47
59
|
export declare function findNetworkComponent(chain: Record<string, unknown>[]): Function | string | null;
|
|
48
60
|
export declare function showLoadingInContainer(container: HTMLElement, loadingFn: Function, params: Record<string, string>): void;
|
|
49
|
-
export declare function handleScroll(pathname: string, isReplace?: boolean): void;
|
|
61
|
+
export declare function handleScroll(pathname: string, isReplace?: boolean, scrollBehavior?: ScrollBehavior): void;
|
|
50
62
|
export declare function applyHead(headHtml: string): void;
|
|
51
63
|
interface OutletProps {
|
|
52
64
|
children?: unknown;
|
|
@@ -59,6 +71,8 @@ interface LinkProps {
|
|
|
59
71
|
style?: string;
|
|
60
72
|
target?: string;
|
|
61
73
|
rel?: string;
|
|
74
|
+
/** Scroll behavior used when this link navigates (`auto` | `instant` | `smooth`). */
|
|
75
|
+
scrollBehavior?: ScrollBehavior;
|
|
62
76
|
[k: string]: unknown;
|
|
63
77
|
}
|
|
64
78
|
type HydrateWalker = ReturnType<typeof createHydrateWalker>;
|
|
@@ -70,6 +84,7 @@ interface NavLinkProps extends LinkProps {
|
|
|
70
84
|
export declare function NavLink(props: NavLinkProps, registry?: Map<string, unknown>, hydrate?: HydrateWalker): Node | string;
|
|
71
85
|
export declare function useNavigate(): (path: string, opts?: {
|
|
72
86
|
replace?: boolean;
|
|
87
|
+
scrollBehavior?: ScrollBehavior;
|
|
73
88
|
}) => void;
|
|
74
89
|
export declare function useParams(): Record<string, string>;
|
|
75
90
|
export declare function usePathname(): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router-components.d.ts","sourceRoot":"","sources":["../src/router-components.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAGhE,UAAU,MAAM;IACf,KAAK,IAAI,MAAM,CAAC;IAChB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"router-components.d.ts","sourceRoot":"","sources":["../src/router-components.ts"],"names":[],"mappings":"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"}
|
|
@@ -56,6 +56,18 @@ export const _state = {
|
|
|
56
56
|
};
|
|
57
57
|
export const _scrollPositions = new Map();
|
|
58
58
|
export let _isPopStateNavigation = false;
|
|
59
|
+
export let _initialScrollRestored = false;
|
|
60
|
+
export let _initialSavedScroll = 0;
|
|
61
|
+
/** Capture the browser's pre-hydration scroll position and re-arm the
|
|
62
|
+
* one-shot initial restore. Called at the top of `router.start()` on a
|
|
63
|
+
* fresh page load so a refresh lands back on the viewport the browser
|
|
64
|
+
* had scrolled to instead of the top. */
|
|
65
|
+
export function captureInitialScroll() {
|
|
66
|
+
if (typeof window === 'undefined')
|
|
67
|
+
return;
|
|
68
|
+
_initialSavedScroll = window.scrollY || 0;
|
|
69
|
+
_initialScrollRestored = false;
|
|
70
|
+
}
|
|
59
71
|
export function setIsPopStateNavigation(v) {
|
|
60
72
|
_isPopStateNavigation = v;
|
|
61
73
|
}
|
|
@@ -128,18 +140,25 @@ export function showLoadingInContainer(container, loadingFn, params) {
|
|
|
128
140
|
container.innerHTML = loadingContent;
|
|
129
141
|
}
|
|
130
142
|
}
|
|
131
|
-
export function handleScroll(pathname, isReplace) {
|
|
143
|
+
export function handleScroll(pathname, isReplace, scrollBehavior) {
|
|
132
144
|
if (typeof window === 'undefined' || typeof window.scrollTo !== 'function')
|
|
133
145
|
return;
|
|
146
|
+
const behavior = scrollBehavior === 'smooth' || scrollBehavior === 'instant' ? scrollBehavior : 'auto';
|
|
134
147
|
if (_isPopStateNavigation) {
|
|
135
148
|
setIsPopStateNavigation(false);
|
|
136
149
|
const savedY = _scrollPositions.get(pathname);
|
|
137
150
|
requestAnimationFrame(() => {
|
|
138
|
-
window.scrollTo(
|
|
151
|
+
window.scrollTo({ top: savedY !== undefined ? savedY : 0, behavior });
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
else if (isReplace && !_initialScrollRestored) {
|
|
155
|
+
_initialScrollRestored = true;
|
|
156
|
+
requestAnimationFrame(() => {
|
|
157
|
+
window.scrollTo({ top: _initialSavedScroll, behavior });
|
|
139
158
|
});
|
|
140
159
|
}
|
|
141
160
|
else if (!isReplace) {
|
|
142
|
-
requestAnimationFrame(() => window.scrollTo(0,
|
|
161
|
+
requestAnimationFrame(() => window.scrollTo({ top: 0, behavior }));
|
|
143
162
|
}
|
|
144
163
|
}
|
|
145
164
|
const HEAD_MARKER = 'data-vesk-head';
|
|
@@ -245,7 +264,7 @@ export function Link(props, registry, hydrate) {
|
|
|
245
264
|
e.preventDefault();
|
|
246
265
|
e.stopPropagation();
|
|
247
266
|
const nav = useNavigate();
|
|
248
|
-
nav(href);
|
|
267
|
+
nav(href, { scrollBehavior: props.scrollBehavior });
|
|
249
268
|
});
|
|
250
269
|
return claimed ? document.createDocumentFragment() : a;
|
|
251
270
|
}
|
|
@@ -263,7 +282,11 @@ export function Link(props, registry, hydrate) {
|
|
|
263
282
|
: '';
|
|
264
283
|
}
|
|
265
284
|
if (typeof document === 'undefined') {
|
|
266
|
-
|
|
285
|
+
// The marker makes the anchor claimable: hydrated call sites run
|
|
286
|
+
// `nextElement('a')` inside the component's boundary walker, and
|
|
287
|
+
// without a marker the claim lands on the next sibling's marker,
|
|
288
|
+
// eats it, and cascades into fresh-node fallback.
|
|
289
|
+
return `<!--vsk--><a ${attrs}>${childStr}</a>`;
|
|
267
290
|
}
|
|
268
291
|
const a = document.createElement('a');
|
|
269
292
|
applyLinkDom(a, props, href);
|
|
@@ -283,7 +306,7 @@ export function Link(props, registry, hydrate) {
|
|
|
283
306
|
e.preventDefault();
|
|
284
307
|
e.stopPropagation();
|
|
285
308
|
const nav = useNavigate();
|
|
286
|
-
nav(href);
|
|
309
|
+
nav(href, { scrollBehavior: props.scrollBehavior });
|
|
287
310
|
});
|
|
288
311
|
return a;
|
|
289
312
|
}
|
|
@@ -303,20 +326,67 @@ export function NavLink(props, registry, hydrate) {
|
|
|
303
326
|
if (typeof document === 'undefined') {
|
|
304
327
|
return Link(props, registry, hydrate);
|
|
305
328
|
}
|
|
329
|
+
// Always prefer the walker when it is available, regardless of the global
|
|
330
|
+
// __isHydrating flag. The flag is only a hint for the querySelector
|
|
331
|
+
// fallback; relying on it to gate walker claims leaves SSR markers
|
|
332
|
+
// unconsumed when the flag is stale (layout-chain hydration) and
|
|
333
|
+
// produces duplicate anchor text.
|
|
334
|
+
if (hydrate && hydrate.nextElement) {
|
|
335
|
+
let a = hydrate.nextElement('a');
|
|
336
|
+
if (a && !a.parentNode && hydrate.root) {
|
|
337
|
+
const existing = hydrate.root.querySelector('a');
|
|
338
|
+
if (existing)
|
|
339
|
+
a = existing;
|
|
340
|
+
}
|
|
341
|
+
const claimed = a ? a.parentNode !== null : false;
|
|
342
|
+
if (!a)
|
|
343
|
+
a = document.createElement('a');
|
|
344
|
+
applyLinkDom(a, props, props.href);
|
|
345
|
+
if (props.children != null) {
|
|
346
|
+
if (typeof props.children === 'string' || typeof props.children === 'number') {
|
|
347
|
+
a.textContent = String(props.children);
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
a.replaceChildren();
|
|
351
|
+
mountLinkChildren(a, props.children);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
a.addEventListener('click', (e) => {
|
|
355
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0)
|
|
356
|
+
return;
|
|
357
|
+
if (props.target === '_blank')
|
|
358
|
+
return;
|
|
359
|
+
if (!isRouteHref(props.href))
|
|
360
|
+
return;
|
|
361
|
+
e.preventDefault();
|
|
362
|
+
e.stopPropagation();
|
|
363
|
+
const nav = useNavigate();
|
|
364
|
+
nav(props.href, { scrollBehavior: props.scrollBehavior });
|
|
365
|
+
});
|
|
366
|
+
const path = usePathname();
|
|
367
|
+
const routeHref = routeHrefOf(props.href);
|
|
368
|
+
const isActive = routeHref === path || (routeHref !== '/' && path.startsWith(routeHref) && (path.length === routeHref.length || path[routeHref.length] === '/' || path[routeHref.length] === '?'));
|
|
369
|
+
if (isActive) {
|
|
370
|
+
a.classList.add(props.activeClass || 'active');
|
|
371
|
+
if (props.ariaCurrent !== false)
|
|
372
|
+
a.setAttribute('aria-current', 'page');
|
|
373
|
+
}
|
|
374
|
+
return claimed ? document.createDocumentFragment() : a;
|
|
375
|
+
}
|
|
306
376
|
if (__isHydrating) {
|
|
307
|
-
const
|
|
308
|
-
if (
|
|
309
|
-
applyLinkDom(
|
|
377
|
+
const q = document.querySelector(`a[href="${props.href}"]`);
|
|
378
|
+
if (q) {
|
|
379
|
+
applyLinkDom(q, props, props.href);
|
|
310
380
|
if (props.children != null) {
|
|
311
381
|
if (typeof props.children === 'string' || typeof props.children === 'number') {
|
|
312
|
-
|
|
382
|
+
q.textContent = String(props.children);
|
|
313
383
|
}
|
|
314
384
|
else {
|
|
315
|
-
|
|
316
|
-
mountLinkChildren(
|
|
385
|
+
q.replaceChildren();
|
|
386
|
+
mountLinkChildren(q, props.children);
|
|
317
387
|
}
|
|
318
388
|
}
|
|
319
|
-
|
|
389
|
+
q.addEventListener('click', (e) => {
|
|
320
390
|
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0)
|
|
321
391
|
return;
|
|
322
392
|
if (props.target === '_blank')
|
|
@@ -326,17 +396,18 @@ export function NavLink(props, registry, hydrate) {
|
|
|
326
396
|
e.preventDefault();
|
|
327
397
|
e.stopPropagation();
|
|
328
398
|
const nav = useNavigate();
|
|
329
|
-
nav(props.href);
|
|
399
|
+
nav(props.href, { scrollBehavior: props.scrollBehavior });
|
|
330
400
|
});
|
|
331
401
|
const path = usePathname();
|
|
332
402
|
const routeHref = routeHrefOf(props.href);
|
|
333
403
|
const isActive = routeHref === path || (routeHref !== '/' && path.startsWith(routeHref) && (path.length === routeHref.length || path[routeHref.length] === '/' || path[routeHref.length] === '?'));
|
|
334
404
|
if (isActive) {
|
|
335
|
-
|
|
405
|
+
q.classList.add(props.activeClass || 'active');
|
|
336
406
|
if (props.ariaCurrent !== false)
|
|
337
|
-
|
|
407
|
+
q.setAttribute('aria-current', 'page');
|
|
338
408
|
}
|
|
339
|
-
|
|
409
|
+
const claimed = q.parentNode !== null;
|
|
410
|
+
return claimed ? document.createDocumentFragment() : q;
|
|
340
411
|
}
|
|
341
412
|
}
|
|
342
413
|
const a = Link(props, registry, hydrate);
|
package/dist/router-match.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router-match.d.ts","sourceRoot":"","sources":["../src/router-match.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IAC1B,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,aAAa;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAiBnE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"router-match.d.ts","sourceRoot":"","sources":["../src/router-match.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IAC1B,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,aAAa;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAiBnE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,EAAE,CA6B/G;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAO5E;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAc1F;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,GAAE,SAAS,EAAO,GAAG,SAAS,EAAE,CAqChH;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAwBjF;AAED,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EAChC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,SAAS,EAAE,CA0Bb"}
|
package/dist/router-match.js
CHANGED
|
@@ -26,18 +26,26 @@ export function collectLayouts(nodes, pathParts) {
|
|
|
26
26
|
layouts.push(...childLayouts);
|
|
27
27
|
continue;
|
|
28
28
|
}
|
|
29
|
+
// Root node (fullPath '/') always matches as a container; recurse into children.
|
|
30
|
+
const isRoot = node.fullPath === '/';
|
|
31
|
+
const matched = isRoot ? true : matchRouteNode(node, pathParts);
|
|
32
|
+
if (node.standalone && matched && !isRoot) {
|
|
33
|
+
layouts.length = 0;
|
|
34
|
+
}
|
|
29
35
|
if (node.layout) {
|
|
30
36
|
layouts.push({ layout: node.layout, node });
|
|
31
37
|
}
|
|
32
|
-
|
|
33
|
-
const matched = matchRouteNode(node, pathParts);
|
|
34
|
-
if (matched) {
|
|
38
|
+
if (matched && !isRoot) {
|
|
35
39
|
const remaining = pathParts.slice(node.segmentCount != null ? node.segmentCount : 1);
|
|
36
40
|
if (remaining.length > 0 && (node.children || []).length > 0) {
|
|
37
41
|
const childLayouts = collectLayouts(node.children || [], remaining);
|
|
38
42
|
layouts.push(...childLayouts);
|
|
39
43
|
}
|
|
40
44
|
}
|
|
45
|
+
else if (isRoot && (node.children || []).length > 0) {
|
|
46
|
+
const childLayouts = collectLayouts(node.children || [], pathParts);
|
|
47
|
+
layouts.push(...childLayouts);
|
|
48
|
+
}
|
|
41
49
|
}
|
|
42
50
|
return layouts;
|
|
43
51
|
}
|
|
@@ -96,6 +104,8 @@ export function flattenLayoutChain(tree, pathParts, result = []) {
|
|
|
96
104
|
const consumeCount = node.isCatchAll ? pathParts.length : segCount;
|
|
97
105
|
const remaining = pathParts.slice(consumeCount);
|
|
98
106
|
const isLeaf = remaining.length === 0 || remaining.every(p => p === '');
|
|
107
|
+
if (node.standalone)
|
|
108
|
+
result.length = 0;
|
|
99
109
|
result.push(node);
|
|
100
110
|
if (isLeaf) {
|
|
101
111
|
break;
|
package/dist/router.d.ts
CHANGED
package/dist/router.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5E,OAAO,
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
|