@timber-js/app 0.2.0-alpha.68 → 0.2.0-alpha.69
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/client/index.js +216 -144
- package/dist/client/index.js.map +1 -1
- package/dist/client/link-pending-store.d.ts +3 -3
- package/dist/client/navigation-api.d.ts.map +1 -1
- package/dist/client/{transition-root.d.ts → navigation-root.d.ts} +31 -9
- package/dist/client/navigation-root.d.ts.map +1 -0
- package/dist/client/router.d.ts +1 -1
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/top-loader.d.ts +2 -2
- package/dist/server/index.js.map +1 -1
- package/dist/server/route-element-builder.d.ts +10 -0
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts +3 -3
- package/package.json +1 -1
- package/src/client/browser-entry.ts +15 -11
- package/src/client/link-pending-store.ts +3 -3
- package/src/client/link.tsx +2 -2
- package/src/client/navigation-api.ts +10 -0
- package/src/client/navigation-context.ts +2 -2
- package/src/client/navigation-root.tsx +346 -0
- package/src/client/router.ts +38 -2
- package/src/client/top-loader.tsx +2 -2
- package/src/client/use-navigation-pending.ts +1 -1
- package/src/server/route-element-builder.ts +69 -21
- package/src/server/slot-resolver.ts +37 -35
- package/src/server/ssr-entry.ts +1 -1
- package/src/server/ssr-wrappers.tsx +10 -10
- package/dist/client/transition-root.d.ts.map +0 -1
- package/src/client/transition-root.tsx +0 -205
package/dist/client/index.js
CHANGED
|
@@ -114,6 +114,211 @@ function unmountLinkForCurrentNavigation(link) {
|
|
|
114
114
|
*/
|
|
115
115
|
function setNavLinkMetadata(metadata) {}
|
|
116
116
|
//#endregion
|
|
117
|
+
//#region src/client/navigation-context.ts
|
|
118
|
+
/**
|
|
119
|
+
* NavigationContext — React context for navigation state.
|
|
120
|
+
*
|
|
121
|
+
* Holds the current route params and pathname, updated atomically
|
|
122
|
+
* with the RSC tree on each navigation. This replaces the previous
|
|
123
|
+
* useSyncExternalStore approach for useSegmentParams() and usePathname(),
|
|
124
|
+
* which suffered from a timing gap: the new tree could commit before
|
|
125
|
+
* the external store re-renders fired, causing a frame where both
|
|
126
|
+
* old and new active states were visible simultaneously.
|
|
127
|
+
*
|
|
128
|
+
* By wrapping the RSC payload element in NavigationProvider inside
|
|
129
|
+
* renderRoot(), the context value and the element tree are passed to
|
|
130
|
+
* reactRoot.render() in the same call — atomic by construction.
|
|
131
|
+
* All consumers (useParams, usePathname) see the new values in the
|
|
132
|
+
* same render pass as the new tree.
|
|
133
|
+
*
|
|
134
|
+
* During SSR, no NavigationProvider is mounted. Hooks fall back to
|
|
135
|
+
* the ALS-backed getSsrData() for per-request isolation.
|
|
136
|
+
*
|
|
137
|
+
* IMPORTANT: createContext and useContext are NOT available in the RSC
|
|
138
|
+
* environment (React Server Components use a stripped-down React).
|
|
139
|
+
* The context is lazily initialized on first access, and all functions
|
|
140
|
+
* that depend on these APIs are safe to call from any environment —
|
|
141
|
+
* they return null or no-op when the APIs aren't available.
|
|
142
|
+
*
|
|
143
|
+
* SINGLETON GUARANTEE: All shared mutable state uses globalThis via
|
|
144
|
+
* Symbol.for keys. The RSC client bundler can duplicate this module
|
|
145
|
+
* across chunks (browser-entry graph + client-reference graph). With
|
|
146
|
+
* ESM output, each chunk gets its own module scope — module-level
|
|
147
|
+
* variables would create separate singleton instances per chunk.
|
|
148
|
+
* globalThis guarantees a single instance regardless of duplication.
|
|
149
|
+
*
|
|
150
|
+
* This workaround will be removed when Rolldown ships `format: 'app'`
|
|
151
|
+
* (module registry format that deduplicates like webpack/Turbopack).
|
|
152
|
+
* See design/27-chunking-strategy.md.
|
|
153
|
+
*
|
|
154
|
+
* See design/19-client-navigation.md §"NavigationContext"
|
|
155
|
+
*/
|
|
156
|
+
/**
|
|
157
|
+
* The context is created lazily to avoid calling createContext at module
|
|
158
|
+
* level. In the RSC environment, React.createContext doesn't exist —
|
|
159
|
+
* calling it at import time would crash the server.
|
|
160
|
+
*
|
|
161
|
+
* Context instances are stored on globalThis (NOT in module-level
|
|
162
|
+
* variables) because the ESM bundler can duplicate this module across
|
|
163
|
+
* chunks. Module-level variables would create separate instances per
|
|
164
|
+
* chunk — the provider in NavigationRoot (index chunk) would use
|
|
165
|
+
* context A while the consumer in useNavigationPending (shared chunk)
|
|
166
|
+
* reads from context B. globalThis guarantees a single instance.
|
|
167
|
+
*
|
|
168
|
+
* See design/27-chunking-strategy.md §"Singleton Safety"
|
|
169
|
+
*/
|
|
170
|
+
var NAV_CTX_KEY = Symbol.for("__timber_nav_ctx");
|
|
171
|
+
var PENDING_CTX_KEY = Symbol.for("__timber_pending_nav_ctx");
|
|
172
|
+
function getOrCreateContext() {
|
|
173
|
+
const existing = globalThis[NAV_CTX_KEY];
|
|
174
|
+
if (existing !== void 0) return existing;
|
|
175
|
+
if (typeof React.createContext === "function") {
|
|
176
|
+
const ctx = React.createContext(null);
|
|
177
|
+
globalThis[NAV_CTX_KEY] = ctx;
|
|
178
|
+
return ctx;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Read the navigation context. Returns null during SSR (no provider)
|
|
183
|
+
* or in the RSC environment (no context available).
|
|
184
|
+
* Internal — used by useSegmentParams() and usePathname().
|
|
185
|
+
*/
|
|
186
|
+
function useNavigationContext() {
|
|
187
|
+
const ctx = getOrCreateContext();
|
|
188
|
+
if (!ctx) return null;
|
|
189
|
+
if (typeof React.useContext !== "function") return null;
|
|
190
|
+
return React.useContext(ctx);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Wraps children with NavigationContext.Provider.
|
|
194
|
+
*
|
|
195
|
+
* Used in browser-entry.ts renderRoot to wrap the RSC payload element
|
|
196
|
+
* so that navigation state updates atomically with the tree render.
|
|
197
|
+
*/
|
|
198
|
+
function NavigationProvider({ value, children }) {
|
|
199
|
+
const ctx = getOrCreateContext();
|
|
200
|
+
if (!ctx) return children;
|
|
201
|
+
return createElement(ctx.Provider, { value }, children);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Navigation state communicated between the router and renderRoot.
|
|
205
|
+
*
|
|
206
|
+
* The router calls setNavigationState() before renderRoot(). The
|
|
207
|
+
* renderRoot callback reads via getNavigationState() to create the
|
|
208
|
+
* NavigationProvider with the correct params/pathname.
|
|
209
|
+
*
|
|
210
|
+
* This is NOT used by hooks directly — hooks read from React context.
|
|
211
|
+
*
|
|
212
|
+
* Stored on globalThis (like the context instances above) because the
|
|
213
|
+
* router lives in one chunk while renderRoot lives in another. Module-
|
|
214
|
+
* level variables would be separate per chunk.
|
|
215
|
+
*/
|
|
216
|
+
var NAV_STATE_KEY = Symbol.for("__timber_nav_state");
|
|
217
|
+
function _getNavStateStore() {
|
|
218
|
+
const g = globalThis;
|
|
219
|
+
if (!g[NAV_STATE_KEY]) g[NAV_STATE_KEY] = { current: {
|
|
220
|
+
params: {},
|
|
221
|
+
pathname: "/"
|
|
222
|
+
} };
|
|
223
|
+
return g[NAV_STATE_KEY];
|
|
224
|
+
}
|
|
225
|
+
function setNavigationState(state) {
|
|
226
|
+
_getNavStateStore().current = state;
|
|
227
|
+
}
|
|
228
|
+
function getNavigationState() {
|
|
229
|
+
return _getNavStateStore().current;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Separate context for the in-flight navigation URL. Provided by
|
|
233
|
+
* NavigationRoot (urgent useState), consumed by useNavigationPending
|
|
234
|
+
* and TopLoader. Per-link pending state uses useOptimistic instead
|
|
235
|
+
* (see link-pending-store.ts).
|
|
236
|
+
*
|
|
237
|
+
* Uses globalThis via Symbol.for for the same reason as NavigationContext
|
|
238
|
+
* above — the bundler may duplicate this module across chunks, and module-
|
|
239
|
+
* level variables would create separate context instances.
|
|
240
|
+
*/
|
|
241
|
+
function getOrCreatePendingContext() {
|
|
242
|
+
const existing = globalThis[PENDING_CTX_KEY];
|
|
243
|
+
if (existing !== void 0) return existing;
|
|
244
|
+
if (typeof React.createContext === "function") {
|
|
245
|
+
const ctx = React.createContext(null);
|
|
246
|
+
globalThis[PENDING_CTX_KEY] = ctx;
|
|
247
|
+
return ctx;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Read the pending navigation URL from context.
|
|
252
|
+
* Returns null during SSR (no provider) or in the RSC environment.
|
|
253
|
+
*/
|
|
254
|
+
function usePendingNavigationUrl() {
|
|
255
|
+
const ctx = getOrCreatePendingContext();
|
|
256
|
+
if (!ctx) return null;
|
|
257
|
+
if (typeof React.useContext !== "function") return null;
|
|
258
|
+
return React.useContext(ctx);
|
|
259
|
+
}
|
|
260
|
+
//#endregion
|
|
261
|
+
//#region src/client/top-loader.tsx
|
|
262
|
+
/**
|
|
263
|
+
* TopLoader — Built-in progress bar for client navigations.
|
|
264
|
+
*
|
|
265
|
+
* Shows an animated progress bar at the top of the viewport while an RSC
|
|
266
|
+
* navigation is in flight. Injected automatically by the framework into
|
|
267
|
+
* NavigationRoot — users never render this component directly.
|
|
268
|
+
*
|
|
269
|
+
* Configuration is via timber.config.ts `topLoader` key. Enabled by default.
|
|
270
|
+
* Users who want a fully custom progress indicator disable the built-in one
|
|
271
|
+
* (`topLoader: { enabled: false }`) and use `useNavigationPending()` directly.
|
|
272
|
+
*
|
|
273
|
+
* Animation approach: pure CSS @keyframes. The bar crawls from 0% to ~90%
|
|
274
|
+
* width over ~30s using ease-out timing. When navigation completes, the bar
|
|
275
|
+
* snaps to 100% and fades out over 200ms. No JS animation loops (RAF, setInterval).
|
|
276
|
+
*
|
|
277
|
+
* Phase transitions are derived synchronously during render (React's
|
|
278
|
+
* getDerivedStateFromProps pattern) — no useEffect needed for state tracking.
|
|
279
|
+
* The finishing → hidden cleanup uses onTransitionEnd from the CSS transition.
|
|
280
|
+
*
|
|
281
|
+
* When delay > 0, CSS animation-delay + a visibility keyframe ensure the bar
|
|
282
|
+
* stays invisible during the delay period. If navigation finishes before the
|
|
283
|
+
* delay, the bar was never visible so the finish transition is also invisible.
|
|
284
|
+
*
|
|
285
|
+
* See design/19-client-navigation.md §"useNavigationPending()"
|
|
286
|
+
* See LOCAL-336 for design decisions.
|
|
287
|
+
*/
|
|
288
|
+
//#endregion
|
|
289
|
+
//#region src/client/navigation-root.tsx
|
|
290
|
+
/**
|
|
291
|
+
* Module-level flag indicating a hard (MPA) navigation is in progress.
|
|
292
|
+
*
|
|
293
|
+
* When true:
|
|
294
|
+
* - NavigationRoot throws an unresolved thenable to suspend forever,
|
|
295
|
+
* preventing React from rendering children during page teardown
|
|
296
|
+
* (avoids "Rendered more hooks" crashes).
|
|
297
|
+
* - The Navigation API handler skips interception, letting the browser
|
|
298
|
+
* perform a full page load (prevents infinite loops where
|
|
299
|
+
* window.location.href → navigate event → router.navigate → 500 →
|
|
300
|
+
* window.location.href → ...).
|
|
301
|
+
*
|
|
302
|
+
* Uses globalThis for singleton guarantee across chunks (same pattern
|
|
303
|
+
* as NavigationContext). See design/19-client-navigation.md §"Singleton
|
|
304
|
+
* Guarantee via globalThis".
|
|
305
|
+
*/
|
|
306
|
+
var HARD_NAV_KEY = Symbol.for("__timber_hard_navigating");
|
|
307
|
+
function getHardNavStore() {
|
|
308
|
+
const g = globalThis;
|
|
309
|
+
if (!g[HARD_NAV_KEY]) g[HARD_NAV_KEY] = { value: false };
|
|
310
|
+
return g[HARD_NAV_KEY];
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Set the hard-navigating flag. Call this BEFORE setting
|
|
314
|
+
* window.location.href or window.location.reload() to prevent:
|
|
315
|
+
* 1. React from rendering children during page teardown
|
|
316
|
+
* 2. Navigation API from intercepting the hard navigation
|
|
317
|
+
*/
|
|
318
|
+
function setHardNavigating(value) {
|
|
319
|
+
getHardNavStore().value = value;
|
|
320
|
+
}
|
|
321
|
+
//#endregion
|
|
117
322
|
//#region src/client/navigation-api.ts
|
|
118
323
|
/**
|
|
119
324
|
* Returns true if the Navigation API is available in the current environment.
|
|
@@ -485,150 +690,6 @@ var HistoryStack = class {
|
|
|
485
690
|
}
|
|
486
691
|
};
|
|
487
692
|
//#endregion
|
|
488
|
-
//#region src/client/navigation-context.ts
|
|
489
|
-
/**
|
|
490
|
-
* NavigationContext — React context for navigation state.
|
|
491
|
-
*
|
|
492
|
-
* Holds the current route params and pathname, updated atomically
|
|
493
|
-
* with the RSC tree on each navigation. This replaces the previous
|
|
494
|
-
* useSyncExternalStore approach for useSegmentParams() and usePathname(),
|
|
495
|
-
* which suffered from a timing gap: the new tree could commit before
|
|
496
|
-
* the external store re-renders fired, causing a frame where both
|
|
497
|
-
* old and new active states were visible simultaneously.
|
|
498
|
-
*
|
|
499
|
-
* By wrapping the RSC payload element in NavigationProvider inside
|
|
500
|
-
* renderRoot(), the context value and the element tree are passed to
|
|
501
|
-
* reactRoot.render() in the same call — atomic by construction.
|
|
502
|
-
* All consumers (useParams, usePathname) see the new values in the
|
|
503
|
-
* same render pass as the new tree.
|
|
504
|
-
*
|
|
505
|
-
* During SSR, no NavigationProvider is mounted. Hooks fall back to
|
|
506
|
-
* the ALS-backed getSsrData() for per-request isolation.
|
|
507
|
-
*
|
|
508
|
-
* IMPORTANT: createContext and useContext are NOT available in the RSC
|
|
509
|
-
* environment (React Server Components use a stripped-down React).
|
|
510
|
-
* The context is lazily initialized on first access, and all functions
|
|
511
|
-
* that depend on these APIs are safe to call from any environment —
|
|
512
|
-
* they return null or no-op when the APIs aren't available.
|
|
513
|
-
*
|
|
514
|
-
* SINGLETON GUARANTEE: All shared mutable state uses globalThis via
|
|
515
|
-
* Symbol.for keys. The RSC client bundler can duplicate this module
|
|
516
|
-
* across chunks (browser-entry graph + client-reference graph). With
|
|
517
|
-
* ESM output, each chunk gets its own module scope — module-level
|
|
518
|
-
* variables would create separate singleton instances per chunk.
|
|
519
|
-
* globalThis guarantees a single instance regardless of duplication.
|
|
520
|
-
*
|
|
521
|
-
* This workaround will be removed when Rolldown ships `format: 'app'`
|
|
522
|
-
* (module registry format that deduplicates like webpack/Turbopack).
|
|
523
|
-
* See design/27-chunking-strategy.md.
|
|
524
|
-
*
|
|
525
|
-
* See design/19-client-navigation.md §"NavigationContext"
|
|
526
|
-
*/
|
|
527
|
-
/**
|
|
528
|
-
* The context is created lazily to avoid calling createContext at module
|
|
529
|
-
* level. In the RSC environment, React.createContext doesn't exist —
|
|
530
|
-
* calling it at import time would crash the server.
|
|
531
|
-
*
|
|
532
|
-
* Context instances are stored on globalThis (NOT in module-level
|
|
533
|
-
* variables) because the ESM bundler can duplicate this module across
|
|
534
|
-
* chunks. Module-level variables would create separate instances per
|
|
535
|
-
* chunk — the provider in TransitionRoot (index chunk) would use
|
|
536
|
-
* context A while the consumer in useNavigationPending (shared chunk)
|
|
537
|
-
* reads from context B. globalThis guarantees a single instance.
|
|
538
|
-
*
|
|
539
|
-
* See design/27-chunking-strategy.md §"Singleton Safety"
|
|
540
|
-
*/
|
|
541
|
-
var NAV_CTX_KEY = Symbol.for("__timber_nav_ctx");
|
|
542
|
-
var PENDING_CTX_KEY = Symbol.for("__timber_pending_nav_ctx");
|
|
543
|
-
function getOrCreateContext() {
|
|
544
|
-
const existing = globalThis[NAV_CTX_KEY];
|
|
545
|
-
if (existing !== void 0) return existing;
|
|
546
|
-
if (typeof React.createContext === "function") {
|
|
547
|
-
const ctx = React.createContext(null);
|
|
548
|
-
globalThis[NAV_CTX_KEY] = ctx;
|
|
549
|
-
return ctx;
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
/**
|
|
553
|
-
* Read the navigation context. Returns null during SSR (no provider)
|
|
554
|
-
* or in the RSC environment (no context available).
|
|
555
|
-
* Internal — used by useSegmentParams() and usePathname().
|
|
556
|
-
*/
|
|
557
|
-
function useNavigationContext() {
|
|
558
|
-
const ctx = getOrCreateContext();
|
|
559
|
-
if (!ctx) return null;
|
|
560
|
-
if (typeof React.useContext !== "function") return null;
|
|
561
|
-
return React.useContext(ctx);
|
|
562
|
-
}
|
|
563
|
-
/**
|
|
564
|
-
* Wraps children with NavigationContext.Provider.
|
|
565
|
-
*
|
|
566
|
-
* Used in browser-entry.ts renderRoot to wrap the RSC payload element
|
|
567
|
-
* so that navigation state updates atomically with the tree render.
|
|
568
|
-
*/
|
|
569
|
-
function NavigationProvider({ value, children }) {
|
|
570
|
-
const ctx = getOrCreateContext();
|
|
571
|
-
if (!ctx) return children;
|
|
572
|
-
return createElement(ctx.Provider, { value }, children);
|
|
573
|
-
}
|
|
574
|
-
/**
|
|
575
|
-
* Navigation state communicated between the router and renderRoot.
|
|
576
|
-
*
|
|
577
|
-
* The router calls setNavigationState() before renderRoot(). The
|
|
578
|
-
* renderRoot callback reads via getNavigationState() to create the
|
|
579
|
-
* NavigationProvider with the correct params/pathname.
|
|
580
|
-
*
|
|
581
|
-
* This is NOT used by hooks directly — hooks read from React context.
|
|
582
|
-
*
|
|
583
|
-
* Stored on globalThis (like the context instances above) because the
|
|
584
|
-
* router lives in one chunk while renderRoot lives in another. Module-
|
|
585
|
-
* level variables would be separate per chunk.
|
|
586
|
-
*/
|
|
587
|
-
var NAV_STATE_KEY = Symbol.for("__timber_nav_state");
|
|
588
|
-
function _getNavStateStore() {
|
|
589
|
-
const g = globalThis;
|
|
590
|
-
if (!g[NAV_STATE_KEY]) g[NAV_STATE_KEY] = { current: {
|
|
591
|
-
params: {},
|
|
592
|
-
pathname: "/"
|
|
593
|
-
} };
|
|
594
|
-
return g[NAV_STATE_KEY];
|
|
595
|
-
}
|
|
596
|
-
function setNavigationState(state) {
|
|
597
|
-
_getNavStateStore().current = state;
|
|
598
|
-
}
|
|
599
|
-
function getNavigationState() {
|
|
600
|
-
return _getNavStateStore().current;
|
|
601
|
-
}
|
|
602
|
-
/**
|
|
603
|
-
* Separate context for the in-flight navigation URL. Provided by
|
|
604
|
-
* TransitionRoot (urgent useState), consumed by useNavigationPending
|
|
605
|
-
* and TopLoader. Per-link pending state uses useOptimistic instead
|
|
606
|
-
* (see link-pending-store.ts).
|
|
607
|
-
*
|
|
608
|
-
* Uses globalThis via Symbol.for for the same reason as NavigationContext
|
|
609
|
-
* above — the bundler may duplicate this module across chunks, and module-
|
|
610
|
-
* level variables would create separate context instances.
|
|
611
|
-
*/
|
|
612
|
-
function getOrCreatePendingContext() {
|
|
613
|
-
const existing = globalThis[PENDING_CTX_KEY];
|
|
614
|
-
if (existing !== void 0) return existing;
|
|
615
|
-
if (typeof React.createContext === "function") {
|
|
616
|
-
const ctx = React.createContext(null);
|
|
617
|
-
globalThis[PENDING_CTX_KEY] = ctx;
|
|
618
|
-
return ctx;
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
/**
|
|
622
|
-
* Read the pending navigation URL from context.
|
|
623
|
-
* Returns null during SSR (no provider) or in the RSC environment.
|
|
624
|
-
*/
|
|
625
|
-
function usePendingNavigationUrl() {
|
|
626
|
-
const ctx = getOrCreatePendingContext();
|
|
627
|
-
if (!ctx) return null;
|
|
628
|
-
if (typeof React.useContext !== "function") return null;
|
|
629
|
-
return React.useContext(ctx);
|
|
630
|
-
}
|
|
631
|
-
//#endregion
|
|
632
693
|
//#region src/client/use-params.ts
|
|
633
694
|
/**
|
|
634
695
|
* Set the current route params in the module-level store.
|
|
@@ -1269,6 +1330,7 @@ function createRouter(deps) {
|
|
|
1269
1330
|
restoreScrollAfterPaint(scroll ? 0 : currentScrollY);
|
|
1270
1331
|
} catch (error) {
|
|
1271
1332
|
if (error instanceof VersionSkewError) {
|
|
1333
|
+
setHardNavigating(true);
|
|
1272
1334
|
const { triggerStaleReload } = await import("../_chunks/stale-reload-BeyHXZ5B.js");
|
|
1273
1335
|
triggerStaleReload();
|
|
1274
1336
|
return new Promise(() => {});
|
|
@@ -1280,12 +1342,14 @@ function createRouter(deps) {
|
|
|
1280
1342
|
return;
|
|
1281
1343
|
}
|
|
1282
1344
|
if (error instanceof ServerErrorResponse) {
|
|
1345
|
+
setHardNavigating(true);
|
|
1283
1346
|
window.location.href = error.url;
|
|
1284
1347
|
return new Promise(() => {});
|
|
1285
1348
|
}
|
|
1286
1349
|
if (isAbortError(error)) return;
|
|
1287
1350
|
throw error;
|
|
1288
1351
|
} finally {
|
|
1352
|
+
if (currentNavAbort === navAbort) currentNavAbort = null;
|
|
1289
1353
|
setPending(false);
|
|
1290
1354
|
deps.completeRouterNavigation?.();
|
|
1291
1355
|
}
|
|
@@ -1304,7 +1368,11 @@ function createRouter(deps) {
|
|
|
1304
1368
|
navState
|
|
1305
1369
|
};
|
|
1306
1370
|
}));
|
|
1371
|
+
} catch (error) {
|
|
1372
|
+
if (isAbortError(error)) return;
|
|
1373
|
+
throw error;
|
|
1307
1374
|
} finally {
|
|
1375
|
+
if (currentNavAbort === navAbort) currentNavAbort = null;
|
|
1308
1376
|
setPending(false);
|
|
1309
1377
|
deps.completeRouterNavigation?.();
|
|
1310
1378
|
}
|
|
@@ -1330,7 +1398,11 @@ function createRouter(deps) {
|
|
|
1330
1398
|
};
|
|
1331
1399
|
}));
|
|
1332
1400
|
restoreScrollAfterPaint(scrollY);
|
|
1401
|
+
} catch (error) {
|
|
1402
|
+
if (isAbortError(error)) return;
|
|
1403
|
+
throw error;
|
|
1333
1404
|
} finally {
|
|
1405
|
+
if (currentNavAbort === navAbort) currentNavAbort = null;
|
|
1334
1406
|
setPending(false);
|
|
1335
1407
|
}
|
|
1336
1408
|
}
|