@tanstack/router-core 0.0.1-beta.35 → 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/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 -82
- package/build/cjs/router.js.map +1 -1
- package/build/esm/index.js +95 -85
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +134 -134
- package/build/types/index.d.ts +9 -12
- package/build/umd/index.development.js +95 -85
- 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/route.ts +0 -1
- package/src/routeConfig.ts +7 -2
- package/src/routeMatch.ts +4 -2
- package/src/router.ts +147 -119
package/package.json
CHANGED
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,61 +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
|
-
console.info(err)
|
|
670
|
-
invariant(false, `A route's beforeLoad middleware failed! 👆`)
|
|
671
|
-
}
|
|
672
|
-
|
|
673
650
|
router.notify()
|
|
674
651
|
|
|
675
652
|
// Load the matches
|
|
676
|
-
|
|
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
|
+
}
|
|
677
662
|
|
|
678
663
|
if (router.startedLoadingAt !== id) {
|
|
679
664
|
// Ignore side-effects of match loading
|
|
680
665
|
return router.navigationPromise
|
|
681
666
|
}
|
|
682
667
|
|
|
683
|
-
const previousMatches = router.state.
|
|
668
|
+
const previousMatches = router.state.currentMatches
|
|
684
669
|
|
|
685
670
|
const exiting: RouteMatch[] = [],
|
|
686
671
|
staying: RouteMatch[] = []
|
|
@@ -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,13 +847,13 @@ export function createRouter<
|
|
|
857
847
|
route.options.caseSensitive ?? router.options.caseSensitive,
|
|
858
848
|
})
|
|
859
849
|
|
|
860
|
-
console.log(
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
)
|
|
850
|
+
// console.log(
|
|
851
|
+
// router.basepath,
|
|
852
|
+
// route.fullPath,
|
|
853
|
+
// fuzzy,
|
|
854
|
+
// pathname,
|
|
855
|
+
// matchParams,
|
|
856
|
+
// )
|
|
867
857
|
|
|
868
858
|
if (matchParams) {
|
|
869
859
|
let parsedParams
|
|
@@ -931,10 +921,30 @@ export function createRouter<
|
|
|
931
921
|
},
|
|
932
922
|
|
|
933
923
|
loadMatches: async (resolvedMatches, loaderOpts) => {
|
|
934
|
-
|
|
924
|
+
resolvedMatches.forEach(async (match) => {
|
|
935
925
|
// Validate the match (loads search params etc)
|
|
936
926
|
match.__.validate()
|
|
927
|
+
})
|
|
937
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
|
+
)
|
|
946
|
+
|
|
947
|
+
const matchPromises = resolvedMatches.map(async (match) => {
|
|
938
948
|
const search = match.search as { __data?: any }
|
|
939
949
|
|
|
940
950
|
if (search.__data?.matchId && search.__data.matchId !== match.matchId) {
|
|
@@ -1004,8 +1014,8 @@ export function createRouter<
|
|
|
1004
1014
|
.matchRoutes(next.pathname)
|
|
1005
1015
|
.map((d) => d.matchId)
|
|
1006
1016
|
;[
|
|
1007
|
-
...router.state.
|
|
1008
|
-
...(router.state.
|
|
1017
|
+
...router.state.currentMatches,
|
|
1018
|
+
...(router.state.pendingMatches ?? []),
|
|
1009
1019
|
].forEach((match) => {
|
|
1010
1020
|
if (unloadedMatchIds.includes(match.matchId)) {
|
|
1011
1021
|
match.invalidate()
|
|
@@ -1037,13 +1047,13 @@ export function createRouter<
|
|
|
1037
1047
|
const next = router.buildNext(location)
|
|
1038
1048
|
|
|
1039
1049
|
if (opts?.pending) {
|
|
1040
|
-
if (!router.state.
|
|
1050
|
+
if (!router.state.pendingLocation) {
|
|
1041
1051
|
return false
|
|
1042
1052
|
}
|
|
1043
1053
|
|
|
1044
1054
|
return !!matchPathname(
|
|
1045
1055
|
router.basepath,
|
|
1046
|
-
router.state.
|
|
1056
|
+
router.state.pendingLocation.pathname,
|
|
1047
1057
|
{
|
|
1048
1058
|
...opts,
|
|
1049
1059
|
to: next.pathname,
|
|
@@ -1051,10 +1061,14 @@ export function createRouter<
|
|
|
1051
1061
|
)
|
|
1052
1062
|
}
|
|
1053
1063
|
|
|
1054
|
-
return !!matchPathname(
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1064
|
+
return !!matchPathname(
|
|
1065
|
+
router.basepath,
|
|
1066
|
+
router.state.currentLocation.pathname,
|
|
1067
|
+
{
|
|
1068
|
+
...opts,
|
|
1069
|
+
to: next.pathname,
|
|
1070
|
+
},
|
|
1071
|
+
)
|
|
1058
1072
|
},
|
|
1059
1073
|
|
|
1060
1074
|
navigate: async ({ from, to = '.', search, hash, replace, params }) => {
|
|
@@ -1133,13 +1147,14 @@ export function createRouter<
|
|
|
1133
1147
|
userPreloadDelay ?? router.options.defaultPreloadDelay ?? 0
|
|
1134
1148
|
|
|
1135
1149
|
// Compare path/hash for matches
|
|
1136
|
-
const pathIsEqual =
|
|
1137
|
-
|
|
1150
|
+
const pathIsEqual =
|
|
1151
|
+
router.state.currentLocation.pathname === next.pathname
|
|
1152
|
+
const currentPathSplit = router.state.currentLocation.pathname.split('/')
|
|
1138
1153
|
const nextPathSplit = next.pathname.split('/')
|
|
1139
1154
|
const pathIsFuzzyEqual = nextPathSplit.every(
|
|
1140
1155
|
(d, i) => d === currentPathSplit[i],
|
|
1141
1156
|
)
|
|
1142
|
-
const hashIsEqual = router.state.
|
|
1157
|
+
const hashIsEqual = router.state.currentLocation.hash === next.hash
|
|
1143
1158
|
// Combine the matches based on user options
|
|
1144
1159
|
const pathTest = activeOptions?.exact ? pathIsEqual : pathIsFuzzyEqual
|
|
1145
1160
|
const hashTest = activeOptions?.includeHash ? hashIsEqual : true
|
|
@@ -1169,10 +1184,15 @@ export function createRouter<
|
|
|
1169
1184
|
// The click handler
|
|
1170
1185
|
const handleFocus = (e: MouseEvent) => {
|
|
1171
1186
|
if (preload) {
|
|
1172
|
-
router
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
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
|
+
})
|
|
1176
1196
|
}
|
|
1177
1197
|
}
|
|
1178
1198
|
|
|
@@ -1186,10 +1206,15 @@ export function createRouter<
|
|
|
1186
1206
|
|
|
1187
1207
|
target.preloadTimeout = setTimeout(() => {
|
|
1188
1208
|
target.preloadTimeout = null
|
|
1189
|
-
router
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
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
|
+
})
|
|
1193
1218
|
}, preloadDelay)
|
|
1194
1219
|
}
|
|
1195
1220
|
}
|
|
@@ -1299,8 +1324,8 @@ export function createRouter<
|
|
|
1299
1324
|
|
|
1300
1325
|
buildLocation: (dest: BuildNextOptions = {}): Location => {
|
|
1301
1326
|
const fromPathname = dest.fromCurrent
|
|
1302
|
-
? router.
|
|
1303
|
-
: dest.from ?? router.
|
|
1327
|
+
? router.state.latestLocation.pathname
|
|
1328
|
+
: dest.from ?? router.state.latestLocation.pathname
|
|
1304
1329
|
|
|
1305
1330
|
let pathname = resolvePath(
|
|
1306
1331
|
router.basepath ?? '/',
|
|
@@ -1308,9 +1333,12 @@ export function createRouter<
|
|
|
1308
1333
|
`${dest.to ?? '.'}`,
|
|
1309
1334
|
)
|
|
1310
1335
|
|
|
1311
|
-
const fromMatches = router.matchRoutes(
|
|
1312
|
-
|
|
1313
|
-
|
|
1336
|
+
const fromMatches = router.matchRoutes(
|
|
1337
|
+
router.state.latestLocation.pathname,
|
|
1338
|
+
{
|
|
1339
|
+
strictParseParams: true,
|
|
1340
|
+
},
|
|
1341
|
+
)
|
|
1314
1342
|
|
|
1315
1343
|
const toMatches = router.matchRoutes(pathname)
|
|
1316
1344
|
|
|
@@ -1336,9 +1364,9 @@ export function createRouter<
|
|
|
1336
1364
|
const preFilteredSearch = dest.__preSearchFilters?.length
|
|
1337
1365
|
? dest.__preSearchFilters.reduce(
|
|
1338
1366
|
(prev, next) => next(prev),
|
|
1339
|
-
router.
|
|
1367
|
+
router.state.latestLocation.search,
|
|
1340
1368
|
)
|
|
1341
|
-
: router.
|
|
1369
|
+
: router.state.latestLocation.search
|
|
1342
1370
|
|
|
1343
1371
|
// Then the link/navigate function
|
|
1344
1372
|
const destSearch =
|
|
@@ -1359,22 +1387,22 @@ export function createRouter<
|
|
|
1359
1387
|
: destSearch
|
|
1360
1388
|
|
|
1361
1389
|
const search = replaceEqualDeep(
|
|
1362
|
-
router.
|
|
1390
|
+
router.state.latestLocation.search,
|
|
1363
1391
|
postFilteredSearch,
|
|
1364
1392
|
)
|
|
1365
1393
|
|
|
1366
1394
|
const searchStr = router.options.stringifySearch(search)
|
|
1367
1395
|
let hash =
|
|
1368
1396
|
dest.hash === true
|
|
1369
|
-
? router.
|
|
1370
|
-
: functionalUpdate(dest.hash!, router.
|
|
1397
|
+
? router.state.latestLocation.hash
|
|
1398
|
+
: functionalUpdate(dest.hash!, router.state.latestLocation.hash)
|
|
1371
1399
|
hash = hash ? `#${hash}` : ''
|
|
1372
1400
|
|
|
1373
1401
|
return {
|
|
1374
1402
|
pathname,
|
|
1375
1403
|
search,
|
|
1376
1404
|
searchStr,
|
|
1377
|
-
state: router.
|
|
1405
|
+
state: router.state.latestLocation.state,
|
|
1378
1406
|
hash,
|
|
1379
1407
|
href: `${pathname}${searchStr}${hash}`,
|
|
1380
1408
|
key: dest.key,
|