@tanstack/router-core 0.0.1-beta.34 → 0.0.1-beta.36
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/build/cjs/path.js +2 -2
- package/build/cjs/path.js.map +1 -1
- package/build/cjs/route.js +0 -1
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/routeConfig.js.map +1 -1
- package/build/cjs/routeMatch.js +2 -2
- package/build/cjs/routeMatch.js.map +1 -1
- package/build/cjs/router.js +93 -83
- package/build/cjs/router.js.map +1 -1
- package/build/esm/index.js +97 -88
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +136 -136
- package/build/types/index.d.ts +9 -12
- package/build/umd/index.development.js +97 -88
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +1 -1
- package/src/path.ts +2 -2
- package/src/route.ts +0 -1
- package/src/routeConfig.ts +7 -2
- package/src/routeMatch.ts +4 -2
- package/src/router.ts +151 -114
package/package.json
CHANGED
package/src/path.ts
CHANGED
|
@@ -165,10 +165,10 @@ export function matchByPath(
|
|
|
165
165
|
from: string,
|
|
166
166
|
matchLocation: Pick<MatchLocation, 'to' | 'caseSensitive' | 'fuzzy'>,
|
|
167
167
|
): Record<string, string> | undefined {
|
|
168
|
-
if (
|
|
168
|
+
if (!from.startsWith(basepath)) {
|
|
169
169
|
return undefined
|
|
170
170
|
}
|
|
171
|
-
from =
|
|
171
|
+
from = basepath != '/' ? from.substring(basepath.length) : from
|
|
172
172
|
const baseSegments = parsePathname(from)
|
|
173
173
|
const to = `${matchLocation.to ?? '*'}`
|
|
174
174
|
const routeSegments = parsePathname(to)
|
package/src/route.ts
CHANGED
package/src/routeConfig.ts
CHANGED
|
@@ -123,12 +123,17 @@ export type RouteOptions<
|
|
|
123
123
|
// An asynchronous function made available to the route for performing asynchronous or mutative actions that
|
|
124
124
|
// might invalidate the route's data.
|
|
125
125
|
action?: ActionFn<TActionPayload, TActionResponse>
|
|
126
|
-
// This async function is called before a route is loaded.
|
|
127
|
-
// If
|
|
126
|
+
// This async function is called before a route is loaded.
|
|
127
|
+
// If an error is thrown here, the route's loader will not be called.
|
|
128
|
+
// If thrown during a navigation, the navigation will be cancelled and the error will be passed to the `onLoadError` function.
|
|
129
|
+
// If thrown during a preload event, the error will be logged to the console.
|
|
128
130
|
beforeLoad?: (opts: {
|
|
129
131
|
router: Router<any, any, unknown>
|
|
130
132
|
match: RouteMatch
|
|
131
133
|
}) => Promise<void> | void
|
|
134
|
+
// This function will be called if the route's loader throws an error **during an attempted navigation**.
|
|
135
|
+
// If you want to redirect due to an error, call `router.navigate()` from within this function.
|
|
136
|
+
onLoadError?: (err: any) => void
|
|
132
137
|
// This function is called
|
|
133
138
|
// when moving from an inactive state to an active one. Likewise, when moving from
|
|
134
139
|
// an active to an inactive state, the return function (if provided) is called.
|
package/src/routeMatch.ts
CHANGED
|
@@ -111,7 +111,7 @@ export function createRouteMatch<
|
|
|
111
111
|
validate: () => {
|
|
112
112
|
// Validate the search params and stabilize them
|
|
113
113
|
const parentSearch =
|
|
114
|
-
routeMatch.parentMatch?.search ?? router.
|
|
114
|
+
routeMatch.parentMatch?.search ?? router.state.currentLocation.search
|
|
115
115
|
|
|
116
116
|
try {
|
|
117
117
|
const prevSearch = routeMatch.routeSearch
|
|
@@ -180,7 +180,9 @@ export function createRouteMatch<
|
|
|
180
180
|
if (loaderOpts?.preload && minMaxAge > 0) {
|
|
181
181
|
// If the match is currently active, don't preload it
|
|
182
182
|
if (
|
|
183
|
-
router.state.
|
|
183
|
+
router.state.currentMatches.find(
|
|
184
|
+
(d) => d.matchId === routeMatch.matchId,
|
|
185
|
+
)
|
|
184
186
|
) {
|
|
185
187
|
return
|
|
186
188
|
}
|
package/src/router.ts
CHANGED
|
@@ -201,21 +201,18 @@ export interface RouterState<
|
|
|
201
201
|
TState extends LocationState = LocationState,
|
|
202
202
|
> {
|
|
203
203
|
status: 'idle' | 'loading'
|
|
204
|
-
|
|
205
|
-
|
|
204
|
+
latestLocation: Location<TSearchObj, TState>
|
|
205
|
+
currentMatches: RouteMatch[]
|
|
206
|
+
currentLocation: Location<TSearchObj, TState>
|
|
207
|
+
pendingMatches?: RouteMatch[]
|
|
208
|
+
pendingLocation?: Location<TSearchObj, TState>
|
|
206
209
|
lastUpdated: number
|
|
207
210
|
actions: Record<string, Action>
|
|
208
211
|
loaders: Record<string, Loader>
|
|
209
|
-
pending?: PendingState
|
|
210
212
|
isFetching: boolean
|
|
211
213
|
isPreloading: boolean
|
|
212
214
|
}
|
|
213
215
|
|
|
214
|
-
export interface PendingState {
|
|
215
|
-
location: Location
|
|
216
|
-
matches: RouteMatch[]
|
|
217
|
-
}
|
|
218
|
-
|
|
219
216
|
type Listener = (router: Router<any, any, any>) => void
|
|
220
217
|
|
|
221
218
|
export type ListenerFn = () => void
|
|
@@ -259,13 +256,13 @@ type LinkCurrentTargetElement = {
|
|
|
259
256
|
export interface DehydratedRouterState
|
|
260
257
|
extends Pick<
|
|
261
258
|
RouterState,
|
|
262
|
-
'status' | '
|
|
259
|
+
'status' | 'latestLocation' | 'currentLocation' | 'lastUpdated'
|
|
263
260
|
> {
|
|
264
|
-
|
|
261
|
+
currentMatches: DehydratedRouteMatch[]
|
|
265
262
|
}
|
|
266
263
|
|
|
267
264
|
export interface DehydratedRouter<TRouterContext = unknown> {
|
|
268
|
-
location: Router['__location']
|
|
265
|
+
// location: Router['__location']
|
|
269
266
|
state: DehydratedRouterState
|
|
270
267
|
context: TRouterContext
|
|
271
268
|
}
|
|
@@ -304,7 +301,7 @@ export interface Router<
|
|
|
304
301
|
basepath: string
|
|
305
302
|
// Internal:
|
|
306
303
|
listeners: Listener[]
|
|
307
|
-
__location: Location<TAllRouteInfo['fullSearchSchema']>
|
|
304
|
+
// __location: Location<TAllRouteInfo['fullSearchSchema']>
|
|
308
305
|
navigateTimeout?: Timeout
|
|
309
306
|
nextAction?: 'push' | 'replace'
|
|
310
307
|
state: RouterState<TAllRouteInfo['fullSearchSchema']>
|
|
@@ -403,8 +400,9 @@ const createDefaultHistory = () =>
|
|
|
403
400
|
function getInitialRouterState(): RouterState {
|
|
404
401
|
return {
|
|
405
402
|
status: 'idle',
|
|
406
|
-
|
|
407
|
-
|
|
403
|
+
latestLocation: null!,
|
|
404
|
+
currentLocation: null!,
|
|
405
|
+
currentMatches: [],
|
|
408
406
|
actions: {},
|
|
409
407
|
loaders: {},
|
|
410
408
|
lastUpdated: Date.now(),
|
|
@@ -444,7 +442,6 @@ export function createRouter<
|
|
|
444
442
|
basepath: '',
|
|
445
443
|
routeTree: undefined!,
|
|
446
444
|
routesById: {} as any,
|
|
447
|
-
__location: undefined!,
|
|
448
445
|
//
|
|
449
446
|
resolveNavigation: () => {},
|
|
450
447
|
matchCache: {},
|
|
@@ -466,12 +463,14 @@ export function createRouter<
|
|
|
466
463
|
notify: (): void => {
|
|
467
464
|
const isFetching =
|
|
468
465
|
router.state.status === 'loading' ||
|
|
469
|
-
router.state.
|
|
466
|
+
router.state.currentMatches.some((d) => d.isFetching)
|
|
470
467
|
|
|
471
468
|
const isPreloading = Object.values(router.matchCache).some(
|
|
472
469
|
(d) =>
|
|
473
470
|
d.match.isFetching &&
|
|
474
|
-
!router.state.
|
|
471
|
+
!router.state.currentMatches.find(
|
|
472
|
+
(dd) => dd.matchId === d.match.matchId,
|
|
473
|
+
),
|
|
475
474
|
)
|
|
476
475
|
|
|
477
476
|
if (
|
|
@@ -485,21 +484,20 @@ export function createRouter<
|
|
|
485
484
|
}
|
|
486
485
|
}
|
|
487
486
|
|
|
488
|
-
cascadeLoaderData(router.state.
|
|
487
|
+
cascadeLoaderData(router.state.currentMatches)
|
|
489
488
|
router.listeners.forEach((listener) => listener(router))
|
|
490
489
|
},
|
|
491
490
|
|
|
492
491
|
dehydrate: () => {
|
|
493
492
|
return {
|
|
494
|
-
location: router.__location,
|
|
495
493
|
state: {
|
|
496
494
|
...pick(router.state, [
|
|
495
|
+
'latestLocation',
|
|
496
|
+
'currentLocation',
|
|
497
497
|
'status',
|
|
498
|
-
'location',
|
|
499
498
|
'lastUpdated',
|
|
500
|
-
'location',
|
|
501
499
|
]),
|
|
502
|
-
|
|
500
|
+
currentMatches: router.state.currentMatches.map((match) =>
|
|
503
501
|
pick(match, [
|
|
504
502
|
'matchId',
|
|
505
503
|
'status',
|
|
@@ -516,18 +514,22 @@ export function createRouter<
|
|
|
516
514
|
|
|
517
515
|
hydrate: (dehydratedState) => {
|
|
518
516
|
// Update the location
|
|
519
|
-
router.
|
|
517
|
+
router.state.latestLocation = dehydratedState.state.latestLocation
|
|
518
|
+
router.state.currentLocation = dehydratedState.state.currentLocation
|
|
520
519
|
|
|
521
520
|
// Update the context
|
|
522
521
|
router.options.context = dehydratedState.context
|
|
523
522
|
|
|
524
523
|
// Match the routes
|
|
525
|
-
const
|
|
526
|
-
|
|
527
|
-
|
|
524
|
+
const currentMatches = router.matchRoutes(
|
|
525
|
+
router.state.latestLocation.pathname,
|
|
526
|
+
{
|
|
527
|
+
strictParseParams: true,
|
|
528
|
+
},
|
|
529
|
+
)
|
|
528
530
|
|
|
529
|
-
|
|
530
|
-
const dehydratedMatch = dehydratedState.state.
|
|
531
|
+
currentMatches.forEach((match, index) => {
|
|
532
|
+
const dehydratedMatch = dehydratedState.state.currentMatches[index]
|
|
531
533
|
invariant(
|
|
532
534
|
dehydratedMatch,
|
|
533
535
|
'Oh no! Dehydrated route matches did not match the active state of the router 😬',
|
|
@@ -535,34 +537,24 @@ export function createRouter<
|
|
|
535
537
|
Object.assign(match, dehydratedMatch)
|
|
536
538
|
})
|
|
537
539
|
|
|
538
|
-
|
|
540
|
+
currentMatches.forEach((match) => match.__.validate())
|
|
539
541
|
|
|
540
542
|
router.state = {
|
|
541
543
|
...router.state,
|
|
542
544
|
...dehydratedState,
|
|
543
|
-
|
|
545
|
+
currentMatches,
|
|
544
546
|
}
|
|
545
547
|
},
|
|
546
548
|
|
|
547
549
|
mount: () => {
|
|
548
|
-
|
|
549
|
-
to: '.',
|
|
550
|
-
search: true,
|
|
551
|
-
hash: true,
|
|
552
|
-
})
|
|
553
|
-
|
|
554
|
-
// If the current location isn't updated, trigger a navigation
|
|
555
|
-
// to the current location. Otherwise, load the current location.
|
|
556
|
-
// if (next.href !== router.__location.href) {
|
|
557
|
-
// router.__.commitLocation(next, true)
|
|
558
|
-
// }
|
|
559
|
-
|
|
560
|
-
if (!router.state.matches.length) {
|
|
550
|
+
if (!router.state.currentMatches.length) {
|
|
561
551
|
router.load()
|
|
562
552
|
}
|
|
563
553
|
|
|
564
554
|
const unsub = router.history.listen((event) => {
|
|
565
|
-
router.load(
|
|
555
|
+
router.load(
|
|
556
|
+
router.__.parseLocation(event.location, router.state.latestLocation),
|
|
557
|
+
)
|
|
566
558
|
})
|
|
567
559
|
|
|
568
560
|
// addEventListener does not exist in React Native, but window does
|
|
@@ -589,12 +581,14 @@ export function createRouter<
|
|
|
589
581
|
|
|
590
582
|
update: (opts) => {
|
|
591
583
|
const newHistory = opts?.history !== router.history
|
|
592
|
-
if (!router.
|
|
584
|
+
if (!router.state.latestLocation || newHistory) {
|
|
593
585
|
if (opts?.history) {
|
|
594
586
|
router.history = opts.history
|
|
595
587
|
}
|
|
596
|
-
router.
|
|
597
|
-
|
|
588
|
+
router.state.latestLocation = router.__.parseLocation(
|
|
589
|
+
router.history.location,
|
|
590
|
+
)
|
|
591
|
+
router.state.currentLocation = router.state.latestLocation
|
|
598
592
|
}
|
|
599
593
|
|
|
600
594
|
Object.assign(router.options, opts)
|
|
@@ -613,8 +607,8 @@ export function createRouter<
|
|
|
613
607
|
|
|
614
608
|
cancelMatches: () => {
|
|
615
609
|
;[
|
|
616
|
-
...router.state.
|
|
617
|
-
...(router.state.
|
|
610
|
+
...router.state.currentMatches,
|
|
611
|
+
...(router.state.pendingMatches ?? []),
|
|
618
612
|
].forEach((match) => {
|
|
619
613
|
match.cancel()
|
|
620
614
|
})
|
|
@@ -626,63 +620,52 @@ export function createRouter<
|
|
|
626
620
|
|
|
627
621
|
if (next) {
|
|
628
622
|
// Ingest the new location
|
|
629
|
-
router.
|
|
623
|
+
router.state.latestLocation = next
|
|
630
624
|
}
|
|
631
625
|
|
|
632
626
|
// Cancel any pending matches
|
|
633
627
|
router.cancelMatches()
|
|
634
628
|
|
|
635
629
|
// Match the routes
|
|
636
|
-
const matches = router.matchRoutes(router.
|
|
630
|
+
const matches = router.matchRoutes(router.state.latestLocation.pathname, {
|
|
637
631
|
strictParseParams: true,
|
|
638
632
|
})
|
|
639
633
|
|
|
640
634
|
if (typeof document !== 'undefined') {
|
|
641
635
|
router.state = {
|
|
642
636
|
...router.state,
|
|
643
|
-
pending: {
|
|
644
|
-
matches: matches,
|
|
645
|
-
location: router.__location,
|
|
646
|
-
},
|
|
647
637
|
status: 'loading',
|
|
638
|
+
pendingMatches: matches,
|
|
639
|
+
pendingLocation: router.state.latestLocation,
|
|
648
640
|
}
|
|
649
641
|
} else {
|
|
650
642
|
router.state = {
|
|
651
643
|
...router.state,
|
|
652
|
-
matches: matches,
|
|
653
|
-
location: router.__location,
|
|
654
644
|
status: 'loading',
|
|
645
|
+
currentMatches: matches,
|
|
646
|
+
currentLocation: router.state.latestLocation,
|
|
655
647
|
}
|
|
656
648
|
}
|
|
657
649
|
|
|
658
|
-
// Check if each match middleware to see if the route can be accessed
|
|
659
|
-
try {
|
|
660
|
-
await Promise.all(
|
|
661
|
-
matches.map((match) =>
|
|
662
|
-
match.options.beforeLoad?.({
|
|
663
|
-
router: router as any,
|
|
664
|
-
match,
|
|
665
|
-
}),
|
|
666
|
-
),
|
|
667
|
-
)
|
|
668
|
-
} catch (err: any) {
|
|
669
|
-
if (err?.then) {
|
|
670
|
-
await new Promise(() => {})
|
|
671
|
-
}
|
|
672
|
-
throw err
|
|
673
|
-
}
|
|
674
|
-
|
|
675
650
|
router.notify()
|
|
676
651
|
|
|
677
652
|
// Load the matches
|
|
678
|
-
|
|
653
|
+
try {
|
|
654
|
+
await router.loadMatches(matches)
|
|
655
|
+
} catch (err: any) {
|
|
656
|
+
console.log(err)
|
|
657
|
+
invariant(
|
|
658
|
+
false,
|
|
659
|
+
'Matches failed to load due to error above ☝️. Navigation cancelled!',
|
|
660
|
+
)
|
|
661
|
+
}
|
|
679
662
|
|
|
680
663
|
if (router.startedLoadingAt !== id) {
|
|
681
664
|
// Ignore side-effects of match loading
|
|
682
665
|
return router.navigationPromise
|
|
683
666
|
}
|
|
684
667
|
|
|
685
|
-
const previousMatches = router.state.
|
|
668
|
+
const previousMatches = router.state.currentMatches
|
|
686
669
|
|
|
687
670
|
const exiting: RouteMatch[] = [],
|
|
688
671
|
staying: RouteMatch[] = []
|
|
@@ -712,10 +695,12 @@ export function createRouter<
|
|
|
712
695
|
d.status = 'idle'
|
|
713
696
|
d.error = undefined
|
|
714
697
|
}
|
|
698
|
+
|
|
715
699
|
const gc = Math.max(
|
|
716
700
|
d.options.loaderGcMaxAge ?? router.options.defaultLoaderGcMaxAge ?? 0,
|
|
717
701
|
d.options.loaderMaxAge ?? router.options.defaultLoaderMaxAge ?? 0,
|
|
718
702
|
)
|
|
703
|
+
|
|
719
704
|
if (gc > 0) {
|
|
720
705
|
router.matchCache[d.matchId] = {
|
|
721
706
|
gc: gc == Infinity ? Number.MAX_SAFE_INTEGER : now + gc,
|
|
@@ -754,10 +739,11 @@ export function createRouter<
|
|
|
754
739
|
|
|
755
740
|
router.state = {
|
|
756
741
|
...router.state,
|
|
757
|
-
location: router.__location,
|
|
758
|
-
matches,
|
|
759
|
-
pending: undefined,
|
|
760
742
|
status: 'idle',
|
|
743
|
+
currentLocation: router.state.latestLocation,
|
|
744
|
+
currentMatches: matches,
|
|
745
|
+
pendingLocation: undefined,
|
|
746
|
+
pendingMatches: undefined,
|
|
761
747
|
}
|
|
762
748
|
|
|
763
749
|
router.notify()
|
|
@@ -785,7 +771,7 @@ export function createRouter<
|
|
|
785
771
|
})
|
|
786
772
|
},
|
|
787
773
|
|
|
788
|
-
loadRoute: async (navigateOpts = router.
|
|
774
|
+
loadRoute: async (navigateOpts = router.state.latestLocation) => {
|
|
789
775
|
const next = router.buildNext(navigateOpts)
|
|
790
776
|
const matches = router.matchRoutes(next.pathname, {
|
|
791
777
|
strictParseParams: true,
|
|
@@ -794,11 +780,15 @@ export function createRouter<
|
|
|
794
780
|
return matches
|
|
795
781
|
},
|
|
796
782
|
|
|
797
|
-
preloadRoute: async (
|
|
783
|
+
preloadRoute: async (
|
|
784
|
+
navigateOpts = router.state.latestLocation,
|
|
785
|
+
loaderOpts,
|
|
786
|
+
) => {
|
|
798
787
|
const next = router.buildNext(navigateOpts)
|
|
799
788
|
const matches = router.matchRoutes(next.pathname, {
|
|
800
789
|
strictParseParams: true,
|
|
801
790
|
})
|
|
791
|
+
|
|
802
792
|
await router.loadMatches(matches, {
|
|
803
793
|
preload: true,
|
|
804
794
|
maxAge:
|
|
@@ -825,8 +815,8 @@ export function createRouter<
|
|
|
825
815
|
}
|
|
826
816
|
|
|
827
817
|
const existingMatches = [
|
|
828
|
-
...router.state.
|
|
829
|
-
...(router.state.
|
|
818
|
+
...router.state.currentMatches,
|
|
819
|
+
...(router.state.pendingMatches ?? []),
|
|
830
820
|
]
|
|
831
821
|
|
|
832
822
|
const recurse = async (routes: Route<any, any>[]): Promise<void> => {
|
|
@@ -857,6 +847,14 @@ export function createRouter<
|
|
|
857
847
|
route.options.caseSensitive ?? router.options.caseSensitive,
|
|
858
848
|
})
|
|
859
849
|
|
|
850
|
+
// console.log(
|
|
851
|
+
// router.basepath,
|
|
852
|
+
// route.fullPath,
|
|
853
|
+
// fuzzy,
|
|
854
|
+
// pathname,
|
|
855
|
+
// matchParams,
|
|
856
|
+
// )
|
|
857
|
+
|
|
860
858
|
if (matchParams) {
|
|
861
859
|
let parsedParams
|
|
862
860
|
|
|
@@ -923,10 +921,30 @@ export function createRouter<
|
|
|
923
921
|
},
|
|
924
922
|
|
|
925
923
|
loadMatches: async (resolvedMatches, loaderOpts) => {
|
|
926
|
-
|
|
924
|
+
resolvedMatches.forEach(async (match) => {
|
|
927
925
|
// Validate the match (loads search params etc)
|
|
928
926
|
match.__.validate()
|
|
927
|
+
})
|
|
928
|
+
|
|
929
|
+
// Check each match middleware to see if the route can be accessed
|
|
930
|
+
await Promise.all(
|
|
931
|
+
resolvedMatches.map(async (match) => {
|
|
932
|
+
try {
|
|
933
|
+
await match.options.beforeLoad?.({
|
|
934
|
+
router: router as any,
|
|
935
|
+
match,
|
|
936
|
+
})
|
|
937
|
+
} catch (err) {
|
|
938
|
+
if (!loaderOpts?.preload) {
|
|
939
|
+
match.options.onLoadError?.(err)
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
throw err
|
|
943
|
+
}
|
|
944
|
+
}),
|
|
945
|
+
)
|
|
929
946
|
|
|
947
|
+
const matchPromises = resolvedMatches.map(async (match) => {
|
|
930
948
|
const search = match.search as { __data?: any }
|
|
931
949
|
|
|
932
950
|
if (search.__data?.matchId && search.__data.matchId !== match.matchId) {
|
|
@@ -996,8 +1014,8 @@ export function createRouter<
|
|
|
996
1014
|
.matchRoutes(next.pathname)
|
|
997
1015
|
.map((d) => d.matchId)
|
|
998
1016
|
;[
|
|
999
|
-
...router.state.
|
|
1000
|
-
...(router.state.
|
|
1017
|
+
...router.state.currentMatches,
|
|
1018
|
+
...(router.state.pendingMatches ?? []),
|
|
1001
1019
|
].forEach((match) => {
|
|
1002
1020
|
if (unloadedMatchIds.includes(match.matchId)) {
|
|
1003
1021
|
match.invalidate()
|
|
@@ -1029,12 +1047,13 @@ export function createRouter<
|
|
|
1029
1047
|
const next = router.buildNext(location)
|
|
1030
1048
|
|
|
1031
1049
|
if (opts?.pending) {
|
|
1032
|
-
if (!router.state.
|
|
1050
|
+
if (!router.state.pendingLocation) {
|
|
1033
1051
|
return false
|
|
1034
1052
|
}
|
|
1053
|
+
|
|
1035
1054
|
return !!matchPathname(
|
|
1036
1055
|
router.basepath,
|
|
1037
|
-
router.state.
|
|
1056
|
+
router.state.pendingLocation.pathname,
|
|
1038
1057
|
{
|
|
1039
1058
|
...opts,
|
|
1040
1059
|
to: next.pathname,
|
|
@@ -1042,10 +1061,14 @@ export function createRouter<
|
|
|
1042
1061
|
)
|
|
1043
1062
|
}
|
|
1044
1063
|
|
|
1045
|
-
return !!matchPathname(
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1064
|
+
return !!matchPathname(
|
|
1065
|
+
router.basepath,
|
|
1066
|
+
router.state.currentLocation.pathname,
|
|
1067
|
+
{
|
|
1068
|
+
...opts,
|
|
1069
|
+
to: next.pathname,
|
|
1070
|
+
},
|
|
1071
|
+
)
|
|
1049
1072
|
},
|
|
1050
1073
|
|
|
1051
1074
|
navigate: async ({ from, to = '.', search, hash, replace, params }) => {
|
|
@@ -1124,13 +1147,14 @@ export function createRouter<
|
|
|
1124
1147
|
userPreloadDelay ?? router.options.defaultPreloadDelay ?? 0
|
|
1125
1148
|
|
|
1126
1149
|
// Compare path/hash for matches
|
|
1127
|
-
const pathIsEqual =
|
|
1128
|
-
|
|
1150
|
+
const pathIsEqual =
|
|
1151
|
+
router.state.currentLocation.pathname === next.pathname
|
|
1152
|
+
const currentPathSplit = router.state.currentLocation.pathname.split('/')
|
|
1129
1153
|
const nextPathSplit = next.pathname.split('/')
|
|
1130
1154
|
const pathIsFuzzyEqual = nextPathSplit.every(
|
|
1131
1155
|
(d, i) => d === currentPathSplit[i],
|
|
1132
1156
|
)
|
|
1133
|
-
const hashIsEqual = router.state.
|
|
1157
|
+
const hashIsEqual = router.state.currentLocation.hash === next.hash
|
|
1134
1158
|
// Combine the matches based on user options
|
|
1135
1159
|
const pathTest = activeOptions?.exact ? pathIsEqual : pathIsFuzzyEqual
|
|
1136
1160
|
const hashTest = activeOptions?.includeHash ? hashIsEqual : true
|
|
@@ -1160,10 +1184,15 @@ export function createRouter<
|
|
|
1160
1184
|
// The click handler
|
|
1161
1185
|
const handleFocus = (e: MouseEvent) => {
|
|
1162
1186
|
if (preload) {
|
|
1163
|
-
router
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1187
|
+
router
|
|
1188
|
+
.preloadRoute(nextOpts, {
|
|
1189
|
+
maxAge: userPreloadMaxAge,
|
|
1190
|
+
gcMaxAge: userPreloadGcMaxAge,
|
|
1191
|
+
})
|
|
1192
|
+
.catch((err) => {
|
|
1193
|
+
console.log(err)
|
|
1194
|
+
console.warn('Error preloading route! ☝️')
|
|
1195
|
+
})
|
|
1167
1196
|
}
|
|
1168
1197
|
}
|
|
1169
1198
|
|
|
@@ -1177,10 +1206,15 @@ export function createRouter<
|
|
|
1177
1206
|
|
|
1178
1207
|
target.preloadTimeout = setTimeout(() => {
|
|
1179
1208
|
target.preloadTimeout = null
|
|
1180
|
-
router
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1209
|
+
router
|
|
1210
|
+
.preloadRoute(nextOpts, {
|
|
1211
|
+
maxAge: userPreloadMaxAge,
|
|
1212
|
+
gcMaxAge: userPreloadGcMaxAge,
|
|
1213
|
+
})
|
|
1214
|
+
.catch((err) => {
|
|
1215
|
+
console.log(err)
|
|
1216
|
+
console.warn('Error preloading route! ☝️')
|
|
1217
|
+
})
|
|
1184
1218
|
}, preloadDelay)
|
|
1185
1219
|
}
|
|
1186
1220
|
}
|
|
@@ -1290,8 +1324,8 @@ export function createRouter<
|
|
|
1290
1324
|
|
|
1291
1325
|
buildLocation: (dest: BuildNextOptions = {}): Location => {
|
|
1292
1326
|
const fromPathname = dest.fromCurrent
|
|
1293
|
-
? router.
|
|
1294
|
-
: dest.from ?? router.
|
|
1327
|
+
? router.state.latestLocation.pathname
|
|
1328
|
+
: dest.from ?? router.state.latestLocation.pathname
|
|
1295
1329
|
|
|
1296
1330
|
let pathname = resolvePath(
|
|
1297
1331
|
router.basepath ?? '/',
|
|
@@ -1299,9 +1333,12 @@ export function createRouter<
|
|
|
1299
1333
|
`${dest.to ?? '.'}`,
|
|
1300
1334
|
)
|
|
1301
1335
|
|
|
1302
|
-
const fromMatches = router.matchRoutes(
|
|
1303
|
-
|
|
1304
|
-
|
|
1336
|
+
const fromMatches = router.matchRoutes(
|
|
1337
|
+
router.state.latestLocation.pathname,
|
|
1338
|
+
{
|
|
1339
|
+
strictParseParams: true,
|
|
1340
|
+
},
|
|
1341
|
+
)
|
|
1305
1342
|
|
|
1306
1343
|
const toMatches = router.matchRoutes(pathname)
|
|
1307
1344
|
|
|
@@ -1327,9 +1364,9 @@ export function createRouter<
|
|
|
1327
1364
|
const preFilteredSearch = dest.__preSearchFilters?.length
|
|
1328
1365
|
? dest.__preSearchFilters.reduce(
|
|
1329
1366
|
(prev, next) => next(prev),
|
|
1330
|
-
router.
|
|
1367
|
+
router.state.latestLocation.search,
|
|
1331
1368
|
)
|
|
1332
|
-
: router.
|
|
1369
|
+
: router.state.latestLocation.search
|
|
1333
1370
|
|
|
1334
1371
|
// Then the link/navigate function
|
|
1335
1372
|
const destSearch =
|
|
@@ -1350,22 +1387,22 @@ export function createRouter<
|
|
|
1350
1387
|
: destSearch
|
|
1351
1388
|
|
|
1352
1389
|
const search = replaceEqualDeep(
|
|
1353
|
-
router.
|
|
1390
|
+
router.state.latestLocation.search,
|
|
1354
1391
|
postFilteredSearch,
|
|
1355
1392
|
)
|
|
1356
1393
|
|
|
1357
1394
|
const searchStr = router.options.stringifySearch(search)
|
|
1358
1395
|
let hash =
|
|
1359
1396
|
dest.hash === true
|
|
1360
|
-
? router.
|
|
1361
|
-
: functionalUpdate(dest.hash!, router.
|
|
1397
|
+
? router.state.latestLocation.hash
|
|
1398
|
+
: functionalUpdate(dest.hash!, router.state.latestLocation.hash)
|
|
1362
1399
|
hash = hash ? `#${hash}` : ''
|
|
1363
1400
|
|
|
1364
1401
|
return {
|
|
1365
1402
|
pathname,
|
|
1366
1403
|
search,
|
|
1367
1404
|
searchStr,
|
|
1368
|
-
state: router.
|
|
1405
|
+
state: router.state.latestLocation.state,
|
|
1369
1406
|
hash,
|
|
1370
1407
|
href: `${pathname}${searchStr}${hash}`,
|
|
1371
1408
|
key: dest.key,
|