@tanstack/router-core 0.0.1-beta.185 → 0.0.1-beta.186
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/fileRoute.js.map +1 -1
- package/build/cjs/history.js +20 -18
- package/build/cjs/history.js.map +1 -1
- package/build/cjs/index.js +1 -0
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/route.js +4 -0
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/router.js +205 -101
- package/build/cjs/router.js.map +1 -1
- package/build/cjs/scroll-restoration.js +1 -1
- package/build/cjs/scroll-restoration.js.map +1 -1
- package/build/cjs/utils.js +15 -0
- package/build/cjs/utils.js.map +1 -1
- package/build/esm/index.js +246 -122
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +132 -132
- package/build/types/fileRoute.d.ts +1 -0
- package/build/types/history.d.ts +8 -3
- package/build/types/link.d.ts +23 -18
- package/build/types/route.d.ts +23 -7
- package/build/types/routeInfo.d.ts +3 -3
- package/build/types/router.d.ts +30 -20
- package/build/types/utils.d.ts +2 -11
- package/build/umd/index.development.js +246 -121
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +2 -2
- package/build/umd/index.production.js.map +1 -1
- package/package.json +1 -1
- package/src/fileRoute.ts +3 -3
- package/src/history.ts +33 -25
- package/src/link.ts +66 -51
- package/src/route.ts +61 -16
- package/src/routeInfo.ts +3 -3
- package/src/router.ts +324 -177
- package/src/scroll-restoration.ts +1 -1
- package/src/utils.ts +21 -17
package/src/router.ts
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
RegisteredRouteComponent,
|
|
30
30
|
RegisteredErrorRouteComponent,
|
|
31
31
|
RegisteredPendingRouteComponent,
|
|
32
|
+
RouteMask,
|
|
32
33
|
} from './route'
|
|
33
34
|
import {
|
|
34
35
|
RoutesById,
|
|
@@ -50,13 +51,15 @@ import {
|
|
|
50
51
|
Updater,
|
|
51
52
|
replaceEqualDeep,
|
|
52
53
|
partialDeepEqual,
|
|
54
|
+
NonNullableUpdater,
|
|
53
55
|
} from './utils'
|
|
54
56
|
import {
|
|
55
57
|
createBrowserHistory,
|
|
56
58
|
createMemoryHistory,
|
|
59
|
+
HistoryLocation,
|
|
60
|
+
LocationState,
|
|
57
61
|
RouterHistory,
|
|
58
62
|
} from './history'
|
|
59
|
-
import warning from 'tiny-warning'
|
|
60
63
|
|
|
61
64
|
//
|
|
62
65
|
|
|
@@ -78,25 +81,20 @@ export type RegisteredRouter = Register extends {
|
|
|
78
81
|
? TRouter
|
|
79
82
|
: AnyRouter
|
|
80
83
|
|
|
81
|
-
export interface
|
|
82
|
-
|
|
83
|
-
export interface ParsedLocation<
|
|
84
|
-
TSearchObj extends AnySearchSchema = {},
|
|
85
|
-
// TState extends LocationState = LocationState,
|
|
86
|
-
> {
|
|
84
|
+
export interface ParsedLocation<TSearchObj extends AnySearchSchema = {}> {
|
|
87
85
|
href: string
|
|
88
86
|
pathname: string
|
|
89
87
|
search: TSearchObj
|
|
90
88
|
searchStr: string
|
|
91
89
|
state: LocationState
|
|
92
90
|
hash: string
|
|
93
|
-
|
|
91
|
+
maskedLocation?: ParsedLocation<TSearchObj>
|
|
92
|
+
unmaskOnReload?: boolean
|
|
94
93
|
}
|
|
95
94
|
|
|
96
95
|
export interface FromLocation {
|
|
97
96
|
pathname: string
|
|
98
97
|
search?: unknown
|
|
99
|
-
key?: string
|
|
100
98
|
hash?: string
|
|
101
99
|
}
|
|
102
100
|
|
|
@@ -158,7 +156,7 @@ export interface RouterOptions<
|
|
|
158
156
|
parseSearch?: SearchParser
|
|
159
157
|
defaultPreload?: false | 'intent'
|
|
160
158
|
defaultPreloadDelay?: number
|
|
161
|
-
|
|
159
|
+
reloadOnWindowFocus?: boolean
|
|
162
160
|
defaultComponent?: RegisteredRouteComponent<
|
|
163
161
|
unknown,
|
|
164
162
|
AnySearchSchema,
|
|
@@ -192,6 +190,8 @@ export interface RouterOptions<
|
|
|
192
190
|
}>
|
|
193
191
|
dehydrate?: () => TDehydrated
|
|
194
192
|
hydrate?: (dehydrated: TDehydrated) => void
|
|
193
|
+
routeMasks?: RouteMask<TRouteTree>[]
|
|
194
|
+
unmaskOnReload?: boolean
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
export interface RouterState<TRouteTree extends AnyRoute = AnyRoute> {
|
|
@@ -216,11 +216,21 @@ export interface BuildNextOptions {
|
|
|
216
216
|
params?: true | Updater<unknown>
|
|
217
217
|
search?: true | Updater<unknown>
|
|
218
218
|
hash?: true | Updater<string>
|
|
219
|
-
state?: LocationState
|
|
220
|
-
|
|
219
|
+
state?: true | NonNullableUpdater<LocationState>
|
|
220
|
+
mask?: {
|
|
221
|
+
to?: string | number | null
|
|
222
|
+
params?: true | Updater<unknown>
|
|
223
|
+
search?: true | Updater<unknown>
|
|
224
|
+
hash?: true | Updater<string>
|
|
225
|
+
state?: true | NonNullableUpdater<LocationState>
|
|
226
|
+
unmaskOnReload?: boolean
|
|
227
|
+
}
|
|
221
228
|
from?: string
|
|
222
|
-
|
|
223
|
-
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export interface CommitLocationOptions {
|
|
232
|
+
replace?: boolean
|
|
233
|
+
resetScroll?: boolean
|
|
224
234
|
}
|
|
225
235
|
|
|
226
236
|
export interface MatchLocation {
|
|
@@ -228,7 +238,6 @@ export interface MatchLocation {
|
|
|
228
238
|
fuzzy?: boolean
|
|
229
239
|
caseSensitive?: boolean
|
|
230
240
|
from?: string
|
|
231
|
-
fromCurrent?: boolean
|
|
232
241
|
}
|
|
233
242
|
|
|
234
243
|
export interface MatchRouteOptions {
|
|
@@ -328,6 +337,8 @@ export class Router<
|
|
|
328
337
|
state: RouterState<TRouteTree>
|
|
329
338
|
dehydratedData?: TDehydrated
|
|
330
339
|
resetNextScroll = false
|
|
340
|
+
tempLocationKey = `${Math.round(Math.random() * 10000000)}`
|
|
341
|
+
// nextTemporaryLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>
|
|
331
342
|
|
|
332
343
|
constructor(options: RouterConstructorOptions<TRouteTree, TDehydrated>) {
|
|
333
344
|
this.options = {
|
|
@@ -399,15 +410,15 @@ export class Router<
|
|
|
399
410
|
|
|
400
411
|
this.update(options)
|
|
401
412
|
|
|
402
|
-
const
|
|
403
|
-
hash: true,
|
|
404
|
-
fromCurrent: true,
|
|
413
|
+
const nextLocation = this.buildLocation({
|
|
405
414
|
search: true,
|
|
415
|
+
params: true,
|
|
416
|
+
hash: true,
|
|
406
417
|
state: true,
|
|
407
418
|
})
|
|
408
419
|
|
|
409
|
-
if (this.state.location.href !==
|
|
410
|
-
this.#commitLocation({ ...
|
|
420
|
+
if (this.state.location.href !== nextLocation.href) {
|
|
421
|
+
this.#commitLocation({ ...nextLocation, replace: true })
|
|
411
422
|
}
|
|
412
423
|
}
|
|
413
424
|
|
|
@@ -461,8 +472,10 @@ export class Router<
|
|
|
461
472
|
}
|
|
462
473
|
|
|
463
474
|
#onFocus = () => {
|
|
464
|
-
if (this.options.
|
|
465
|
-
this.invalidate(
|
|
475
|
+
if (this.options.reloadOnWindowFocus ?? true) {
|
|
476
|
+
this.invalidate({
|
|
477
|
+
__fromFocus: true,
|
|
478
|
+
})
|
|
466
479
|
}
|
|
467
480
|
}
|
|
468
481
|
|
|
@@ -514,17 +527,6 @@ export class Router<
|
|
|
514
527
|
return this
|
|
515
528
|
}
|
|
516
529
|
|
|
517
|
-
buildNext = (opts: BuildNextOptions): ParsedLocation => {
|
|
518
|
-
const next = this.#buildLocation(opts)
|
|
519
|
-
|
|
520
|
-
const __matches = this.matchRoutes(next.pathname, next.search)
|
|
521
|
-
|
|
522
|
-
return this.#buildLocation({
|
|
523
|
-
...opts,
|
|
524
|
-
__matches,
|
|
525
|
-
})
|
|
526
|
-
}
|
|
527
|
-
|
|
528
530
|
cancelMatches = () => {
|
|
529
531
|
this.state.matches.forEach((match) => {
|
|
530
532
|
this.cancelMatch(match.id)
|
|
@@ -605,7 +607,7 @@ export class Router<
|
|
|
605
607
|
try {
|
|
606
608
|
// Load the matches
|
|
607
609
|
try {
|
|
608
|
-
await this.loadMatches(pendingMatches)
|
|
610
|
+
await this.loadMatches(pendingMatches.map((d) => d.id))
|
|
609
611
|
} catch (err) {
|
|
610
612
|
// swallow this error, since we'll display the
|
|
611
613
|
// errors on the route components
|
|
@@ -680,10 +682,20 @@ export class Router<
|
|
|
680
682
|
prevMatchesById: Record<string, RouteMatch<TRouteTree>>,
|
|
681
683
|
nextMatches: AnyRouteMatch[],
|
|
682
684
|
): Record<string, RouteMatch<TRouteTree>> => {
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
685
|
+
let matchesById = { ...prevMatchesById }
|
|
686
|
+
|
|
687
|
+
nextMatches.forEach((match) => {
|
|
688
|
+
if (!matchesById[match.id]) {
|
|
689
|
+
matchesById[match.id] = match
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
matchesById[match.id] = {
|
|
693
|
+
...matchesById[match.id],
|
|
694
|
+
...match,
|
|
695
|
+
}
|
|
696
|
+
})
|
|
697
|
+
|
|
698
|
+
return matchesById
|
|
687
699
|
}
|
|
688
700
|
|
|
689
701
|
getRoute = (id: string): Route => {
|
|
@@ -699,7 +711,8 @@ export class Router<
|
|
|
699
711
|
maxAge?: number
|
|
700
712
|
} = this.state.location,
|
|
701
713
|
) => {
|
|
702
|
-
|
|
714
|
+
let next = this.buildLocation(navigateOpts)
|
|
715
|
+
|
|
703
716
|
const matches = this.matchRoutes(next.pathname, next.search, {
|
|
704
717
|
throwOnError: true,
|
|
705
718
|
})
|
|
@@ -711,12 +724,15 @@ export class Router<
|
|
|
711
724
|
}
|
|
712
725
|
})
|
|
713
726
|
|
|
714
|
-
await this.loadMatches(
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
727
|
+
await this.loadMatches(
|
|
728
|
+
matches.map((d) => d.id),
|
|
729
|
+
{
|
|
730
|
+
preload: true,
|
|
731
|
+
maxAge: navigateOpts.maxAge,
|
|
732
|
+
},
|
|
733
|
+
)
|
|
718
734
|
|
|
719
|
-
return matches
|
|
735
|
+
return [last(matches)!, matches] as const
|
|
720
736
|
}
|
|
721
737
|
|
|
722
738
|
cleanMatches = () => {
|
|
@@ -928,14 +944,13 @@ export class Router<
|
|
|
928
944
|
}
|
|
929
945
|
|
|
930
946
|
loadMatches = async (
|
|
931
|
-
|
|
947
|
+
matchIds: string[],
|
|
932
948
|
opts?: {
|
|
933
949
|
preload?: boolean
|
|
934
950
|
maxAge?: number
|
|
935
951
|
},
|
|
936
952
|
) => {
|
|
937
|
-
const getFreshMatches = () =>
|
|
938
|
-
_resolvedMatches.map((d) => this.getRouteMatch(d.id)!)
|
|
953
|
+
const getFreshMatches = () => matchIds.map((d) => this.getRouteMatch(d)!)
|
|
939
954
|
|
|
940
955
|
if (!opts?.preload) {
|
|
941
956
|
getFreshMatches().forEach((match) => {
|
|
@@ -1029,8 +1044,9 @@ export class Router<
|
|
|
1029
1044
|
}
|
|
1030
1045
|
}
|
|
1031
1046
|
} catch (err) {
|
|
1032
|
-
if (
|
|
1033
|
-
this.navigate(err as any)
|
|
1047
|
+
if (isRedirect(err)) {
|
|
1048
|
+
if (!opts?.preload) this.navigate(err as any)
|
|
1049
|
+
return
|
|
1034
1050
|
}
|
|
1035
1051
|
|
|
1036
1052
|
throw err
|
|
@@ -1155,6 +1171,8 @@ export class Router<
|
|
|
1155
1171
|
navigate = async <
|
|
1156
1172
|
TFrom extends RoutePaths<TRouteTree> = '/',
|
|
1157
1173
|
TTo extends string = '',
|
|
1174
|
+
TMaskFrom extends RoutePaths<TRouteTree> = TFrom,
|
|
1175
|
+
TMaskTo extends string = '',
|
|
1158
1176
|
>({
|
|
1159
1177
|
from,
|
|
1160
1178
|
to = '' as any,
|
|
@@ -1163,7 +1181,7 @@ export class Router<
|
|
|
1163
1181
|
replace,
|
|
1164
1182
|
params,
|
|
1165
1183
|
resetScroll,
|
|
1166
|
-
}: NavigateOptions<TRouteTree, TFrom, TTo>) => {
|
|
1184
|
+
}: NavigateOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo>) => {
|
|
1167
1185
|
// If this link simply reloads the current route,
|
|
1168
1186
|
// make sure it has a new key so it will trigger a data refresh
|
|
1169
1187
|
|
|
@@ -1183,21 +1201,22 @@ export class Router<
|
|
|
1183
1201
|
'Attempting to navigate to external url with this.navigate!',
|
|
1184
1202
|
)
|
|
1185
1203
|
|
|
1186
|
-
return this.#
|
|
1204
|
+
return this.#buildAndCommitLocation({
|
|
1187
1205
|
from: fromString,
|
|
1188
1206
|
to: toString,
|
|
1189
1207
|
search,
|
|
1190
1208
|
hash,
|
|
1191
|
-
replace,
|
|
1192
1209
|
params,
|
|
1210
|
+
replace,
|
|
1193
1211
|
resetScroll,
|
|
1194
1212
|
})
|
|
1195
1213
|
}
|
|
1196
1214
|
|
|
1197
1215
|
matchRoute = <
|
|
1216
|
+
TRouteTree extends AnyRoute = AnyRoute,
|
|
1198
1217
|
TFrom extends RoutePaths<TRouteTree> = '/',
|
|
1199
1218
|
TTo extends string = '',
|
|
1200
|
-
TResolved
|
|
1219
|
+
TResolved = ResolveRelativePath<TFrom, NoInfer<TTo>>,
|
|
1201
1220
|
>(
|
|
1202
1221
|
location: ToOptions<TRouteTree, TFrom, TTo>,
|
|
1203
1222
|
opts?: MatchRouteOptions,
|
|
@@ -1209,7 +1228,7 @@ export class Router<
|
|
|
1209
1228
|
: undefined,
|
|
1210
1229
|
} as any
|
|
1211
1230
|
|
|
1212
|
-
const next = this.
|
|
1231
|
+
const next = this.buildLocation(location)
|
|
1213
1232
|
if (opts?.pending && this.state.status !== 'pending') {
|
|
1214
1233
|
return false
|
|
1215
1234
|
}
|
|
@@ -1254,6 +1273,7 @@ export class Router<
|
|
|
1254
1273
|
preloadDelay: userPreloadDelay,
|
|
1255
1274
|
disabled,
|
|
1256
1275
|
state,
|
|
1276
|
+
mask,
|
|
1257
1277
|
resetScroll,
|
|
1258
1278
|
}: LinkOptions<TRouteTree, TFrom, TTo>): LinkInfo => {
|
|
1259
1279
|
// If this link simply reloads the current route,
|
|
@@ -1278,10 +1298,11 @@ export class Router<
|
|
|
1278
1298
|
hash,
|
|
1279
1299
|
replace,
|
|
1280
1300
|
state,
|
|
1301
|
+
mask,
|
|
1281
1302
|
resetScroll,
|
|
1282
1303
|
}
|
|
1283
1304
|
|
|
1284
|
-
const next = this.
|
|
1305
|
+
const next = this.buildLocation(nextOpts)
|
|
1285
1306
|
|
|
1286
1307
|
preload = preload ?? this.options.defaultPreload
|
|
1287
1308
|
const preloadDelay =
|
|
@@ -1320,7 +1341,7 @@ export class Router<
|
|
|
1320
1341
|
e.preventDefault()
|
|
1321
1342
|
|
|
1322
1343
|
// All is well? Navigate!
|
|
1323
|
-
this.#commitLocation(
|
|
1344
|
+
this.#commitLocation({ ...next, replace, resetScroll })
|
|
1324
1345
|
}
|
|
1325
1346
|
}
|
|
1326
1347
|
|
|
@@ -1600,154 +1621,269 @@ export class Router<
|
|
|
1600
1621
|
#parseLocation = (
|
|
1601
1622
|
previousLocation?: ParsedLocation,
|
|
1602
1623
|
): ParsedLocation<FullSearchSchema<TRouteTree>> => {
|
|
1603
|
-
|
|
1624
|
+
const parse = ({
|
|
1625
|
+
pathname,
|
|
1626
|
+
search,
|
|
1627
|
+
hash,
|
|
1628
|
+
state,
|
|
1629
|
+
}: HistoryLocation): ParsedLocation<FullSearchSchema<TRouteTree>> => {
|
|
1630
|
+
const parsedSearch = this.options.parseSearch(search)
|
|
1631
|
+
|
|
1632
|
+
return {
|
|
1633
|
+
pathname: pathname,
|
|
1634
|
+
searchStr: search,
|
|
1635
|
+
search: replaceEqualDeep(previousLocation?.search, parsedSearch) as any,
|
|
1636
|
+
hash: hash.split('#').reverse()[0] ?? '',
|
|
1637
|
+
href: `${pathname}${search}${hash}`,
|
|
1638
|
+
state: replaceEqualDeep(
|
|
1639
|
+
previousLocation?.state,
|
|
1640
|
+
state,
|
|
1641
|
+
) as LocationState,
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1604
1644
|
|
|
1605
|
-
const
|
|
1645
|
+
const location = parse(this.history.location)
|
|
1606
1646
|
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1647
|
+
let { __tempLocation, __tempKey } = location.state
|
|
1648
|
+
|
|
1649
|
+
if (__tempLocation && (!__tempKey || __tempKey === this.tempLocationKey)) {
|
|
1650
|
+
// Sync up the location keys
|
|
1651
|
+
const parsedTempLocation = parse(__tempLocation) as any
|
|
1652
|
+
parsedTempLocation.state.key = location.state.key
|
|
1653
|
+
|
|
1654
|
+
delete parsedTempLocation.state.__tempLocation
|
|
1655
|
+
|
|
1656
|
+
return {
|
|
1657
|
+
...parsedTempLocation,
|
|
1658
|
+
maskedLocation: location,
|
|
1659
|
+
}
|
|
1615
1660
|
}
|
|
1661
|
+
|
|
1662
|
+
return location
|
|
1616
1663
|
}
|
|
1617
1664
|
|
|
1618
|
-
|
|
1619
|
-
|
|
1665
|
+
buildLocation = (opts: BuildNextOptions = {}): ParsedLocation => {
|
|
1666
|
+
const build = (
|
|
1667
|
+
dest: BuildNextOptions & {
|
|
1668
|
+
unmaskOnReload?: boolean
|
|
1669
|
+
} = {},
|
|
1670
|
+
matches?: AnyRouteMatch[],
|
|
1671
|
+
): ParsedLocation => {
|
|
1672
|
+
const from = this.state.location
|
|
1673
|
+
|
|
1674
|
+
const fromPathname = dest.from ?? from.pathname
|
|
1675
|
+
|
|
1676
|
+
let pathname = resolvePath(
|
|
1677
|
+
this.basepath ?? '/',
|
|
1678
|
+
fromPathname,
|
|
1679
|
+
`${dest.to ?? ''}`,
|
|
1680
|
+
)
|
|
1620
1681
|
|
|
1621
|
-
|
|
1622
|
-
? this.state.location.pathname
|
|
1623
|
-
: dest.from ?? this.state.location.pathname
|
|
1682
|
+
const fromMatches = this.matchRoutes(from.pathname, from.search)
|
|
1624
1683
|
|
|
1625
|
-
|
|
1626
|
-
this.basepath ?? '/',
|
|
1627
|
-
fromPathname,
|
|
1628
|
-
`${dest.to ?? ''}`,
|
|
1629
|
-
)
|
|
1684
|
+
const prevParams = { ...last(fromMatches)?.params }
|
|
1630
1685
|
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1686
|
+
let nextParams =
|
|
1687
|
+
(dest.params ?? true) === true
|
|
1688
|
+
? prevParams
|
|
1689
|
+
: functionalUpdate(dest.params!, prevParams)
|
|
1635
1690
|
|
|
1636
|
-
|
|
1691
|
+
if (nextParams) {
|
|
1692
|
+
matches
|
|
1693
|
+
?.map((d) => this.getRoute(d.routeId).options.stringifyParams)
|
|
1694
|
+
.filter(Boolean)
|
|
1695
|
+
.forEach((fn) => {
|
|
1696
|
+
nextParams = { ...nextParams!, ...fn!(nextParams!) }
|
|
1697
|
+
})
|
|
1698
|
+
}
|
|
1637
1699
|
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1700
|
+
pathname = interpolatePath(pathname, nextParams ?? {})
|
|
1701
|
+
|
|
1702
|
+
const preSearchFilters =
|
|
1703
|
+
matches
|
|
1704
|
+
?.map(
|
|
1705
|
+
(match) =>
|
|
1706
|
+
this.getRoute(match.routeId).options.preSearchFilters ?? [],
|
|
1707
|
+
)
|
|
1708
|
+
.flat()
|
|
1709
|
+
.filter(Boolean) ?? []
|
|
1710
|
+
|
|
1711
|
+
const postSearchFilters =
|
|
1712
|
+
matches
|
|
1713
|
+
?.map(
|
|
1714
|
+
(match) =>
|
|
1715
|
+
this.getRoute(match.routeId).options.postSearchFilters ?? [],
|
|
1716
|
+
)
|
|
1717
|
+
.flat()
|
|
1718
|
+
.filter(Boolean) ?? []
|
|
1719
|
+
|
|
1720
|
+
// Pre filters first
|
|
1721
|
+
const preFilteredSearch = preSearchFilters?.length
|
|
1722
|
+
? preSearchFilters?.reduce((prev, next) => next(prev), from.search)
|
|
1723
|
+
: from.search
|
|
1724
|
+
|
|
1725
|
+
// Then the link/navigate function
|
|
1726
|
+
const destSearch =
|
|
1727
|
+
dest.search === true
|
|
1728
|
+
? preFilteredSearch // Preserve resolvedFrom true
|
|
1729
|
+
: dest.search
|
|
1730
|
+
? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
|
|
1731
|
+
: preSearchFilters?.length
|
|
1732
|
+
? preFilteredSearch // Preserve resolvedFrom filters
|
|
1733
|
+
: {}
|
|
1734
|
+
|
|
1735
|
+
// Then post filters
|
|
1736
|
+
const postFilteredSearch = postSearchFilters?.length
|
|
1737
|
+
? postSearchFilters.reduce((prev, next) => next(prev), destSearch)
|
|
1738
|
+
: destSearch
|
|
1739
|
+
|
|
1740
|
+
const search = replaceEqualDeep(from.search, postFilteredSearch)
|
|
1741
|
+
|
|
1742
|
+
const searchStr = this.options.stringifySearch(search)
|
|
1743
|
+
|
|
1744
|
+
const hash =
|
|
1745
|
+
dest.hash === true
|
|
1746
|
+
? from.hash
|
|
1747
|
+
: dest.hash
|
|
1748
|
+
? functionalUpdate(dest.hash!, from.hash)
|
|
1749
|
+
: from.hash
|
|
1750
|
+
|
|
1751
|
+
const hashStr = hash ? `#${hash}` : ''
|
|
1752
|
+
|
|
1753
|
+
let nextState =
|
|
1754
|
+
dest.state === true
|
|
1755
|
+
? from.state
|
|
1756
|
+
: dest.state
|
|
1757
|
+
? functionalUpdate(dest.state, from.state)
|
|
1758
|
+
: from.state
|
|
1759
|
+
|
|
1760
|
+
nextState = replaceEqualDeep(from.state, nextState)
|
|
1642
1761
|
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
})
|
|
1762
|
+
return {
|
|
1763
|
+
pathname,
|
|
1764
|
+
search,
|
|
1765
|
+
searchStr,
|
|
1766
|
+
state: nextState,
|
|
1767
|
+
hash,
|
|
1768
|
+
href: this.history.createHref(`${pathname}${searchStr}${hashStr}`),
|
|
1769
|
+
unmaskOnReload: dest.unmaskOnReload,
|
|
1770
|
+
}
|
|
1650
1771
|
}
|
|
1651
1772
|
|
|
1652
|
-
|
|
1773
|
+
const buildWithMatches = (
|
|
1774
|
+
dest: BuildNextOptions = {},
|
|
1775
|
+
maskedDest?: BuildNextOptions,
|
|
1776
|
+
) => {
|
|
1777
|
+
let next = build(dest)
|
|
1778
|
+
let maskedNext = maskedDest ? build(maskedDest) : undefined
|
|
1779
|
+
|
|
1780
|
+
if (!maskedNext) {
|
|
1781
|
+
const foundMask = this.options.routeMasks?.find((d) => {
|
|
1782
|
+
const match = matchPathname(this.basepath, next.pathname, {
|
|
1783
|
+
to: d.from,
|
|
1784
|
+
fuzzy: false,
|
|
1785
|
+
})
|
|
1653
1786
|
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
(match) =>
|
|
1658
|
-
this.getRoute(match.routeId).options.preSearchFilters ?? [],
|
|
1659
|
-
)
|
|
1660
|
-
.flat()
|
|
1661
|
-
.filter(Boolean) ?? []
|
|
1662
|
-
|
|
1663
|
-
const postSearchFilters =
|
|
1664
|
-
dest.__matches
|
|
1665
|
-
?.map(
|
|
1666
|
-
(match) =>
|
|
1667
|
-
this.getRoute(match.routeId).options.postSearchFilters ?? [],
|
|
1668
|
-
)
|
|
1669
|
-
.flat()
|
|
1670
|
-
.filter(Boolean) ?? []
|
|
1787
|
+
if (match) {
|
|
1788
|
+
return match
|
|
1789
|
+
}
|
|
1671
1790
|
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
? preSearchFilters?.reduce(
|
|
1675
|
-
(prev, next) => next(prev),
|
|
1676
|
-
this.state.location.search,
|
|
1677
|
-
)
|
|
1678
|
-
: this.state.location.search
|
|
1679
|
-
|
|
1680
|
-
// Then the link/navigate function
|
|
1681
|
-
const destSearch =
|
|
1682
|
-
dest.search === true
|
|
1683
|
-
? preFilteredSearch // Preserve resolvedFrom true
|
|
1684
|
-
: dest.search
|
|
1685
|
-
? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
|
|
1686
|
-
: preSearchFilters?.length
|
|
1687
|
-
? preFilteredSearch // Preserve resolvedFrom filters
|
|
1688
|
-
: {}
|
|
1689
|
-
|
|
1690
|
-
// Then post filters
|
|
1691
|
-
const postFilteredSearch = postSearchFilters?.length
|
|
1692
|
-
? postSearchFilters.reduce((prev, next) => next(prev), destSearch)
|
|
1693
|
-
: destSearch
|
|
1694
|
-
|
|
1695
|
-
const search = replaceEqualDeep(
|
|
1696
|
-
this.state.location.search,
|
|
1697
|
-
postFilteredSearch,
|
|
1698
|
-
)
|
|
1791
|
+
return false
|
|
1792
|
+
})
|
|
1699
1793
|
|
|
1700
|
-
|
|
1794
|
+
if (foundMask) {
|
|
1795
|
+
maskedDest = foundMask
|
|
1796
|
+
maskedNext = build(maskedDest)
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1701
1799
|
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
? this.
|
|
1705
|
-
:
|
|
1800
|
+
const nextMatches = this.matchRoutes(next.pathname, next.search)
|
|
1801
|
+
const maskedMatches = maskedNext
|
|
1802
|
+
? this.matchRoutes(maskedNext.pathname, maskedNext.search)
|
|
1803
|
+
: undefined
|
|
1804
|
+
const maskedFinal = maskedNext
|
|
1805
|
+
? build(maskedDest, maskedMatches)
|
|
1806
|
+
: undefined
|
|
1706
1807
|
|
|
1707
|
-
|
|
1808
|
+
const final = build(dest, nextMatches)
|
|
1708
1809
|
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
: functionalUpdate(dest.state, this.state.location.state)!
|
|
1810
|
+
if (maskedFinal) {
|
|
1811
|
+
final.maskedLocation = maskedFinal
|
|
1812
|
+
}
|
|
1713
1813
|
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1814
|
+
return final
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
if (opts.mask) {
|
|
1818
|
+
return buildWithMatches(opts, {
|
|
1819
|
+
...pick(opts, ['from']),
|
|
1820
|
+
...opts.mask,
|
|
1821
|
+
})
|
|
1722
1822
|
}
|
|
1823
|
+
|
|
1824
|
+
return buildWithMatches(opts)
|
|
1723
1825
|
}
|
|
1724
1826
|
|
|
1725
|
-
#
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1827
|
+
#buildAndCommitLocation = ({
|
|
1828
|
+
replace,
|
|
1829
|
+
resetScroll,
|
|
1830
|
+
...rest
|
|
1831
|
+
}: BuildNextOptions & CommitLocationOptions = {}) => {
|
|
1832
|
+
const location = this.buildLocation(rest)
|
|
1833
|
+
return this.#commitLocation({
|
|
1834
|
+
...location,
|
|
1835
|
+
replace,
|
|
1836
|
+
resetScroll,
|
|
1837
|
+
})
|
|
1838
|
+
}
|
|
1729
1839
|
|
|
1840
|
+
#commitLocation = async (next: ParsedLocation & CommitLocationOptions) => {
|
|
1730
1841
|
if (this.navigateTimeout) clearTimeout(this.navigateTimeout)
|
|
1731
1842
|
|
|
1732
1843
|
let nextAction: 'push' | 'replace' = 'replace'
|
|
1733
1844
|
|
|
1734
|
-
if (!
|
|
1845
|
+
if (!next.replace) {
|
|
1735
1846
|
nextAction = 'push'
|
|
1736
1847
|
}
|
|
1737
1848
|
|
|
1738
1849
|
const isSameUrl = this.state.location.href === next.href
|
|
1739
1850
|
|
|
1740
|
-
if (isSameUrl
|
|
1851
|
+
if (isSameUrl) {
|
|
1741
1852
|
nextAction = 'replace'
|
|
1742
1853
|
}
|
|
1743
1854
|
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1855
|
+
let { maskedLocation, ...nextHistory } = next
|
|
1856
|
+
|
|
1857
|
+
if (maskedLocation) {
|
|
1858
|
+
nextHistory = {
|
|
1859
|
+
...maskedLocation,
|
|
1860
|
+
state: {
|
|
1861
|
+
...maskedLocation.state,
|
|
1862
|
+
__tempKey: undefined,
|
|
1863
|
+
__tempLocation: {
|
|
1864
|
+
...nextHistory,
|
|
1865
|
+
search: nextHistory.searchStr,
|
|
1866
|
+
state: {
|
|
1867
|
+
...nextHistory.state,
|
|
1868
|
+
__tempKey: undefined!,
|
|
1869
|
+
__tempLocation: undefined!,
|
|
1870
|
+
key: undefined!,
|
|
1871
|
+
},
|
|
1872
|
+
},
|
|
1873
|
+
},
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
if (nextHistory.unmaskOnReload ?? this.options.unmaskOnReload ?? false) {
|
|
1877
|
+
nextHistory.state.__tempKey = this.tempLocationKey
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1747
1880
|
|
|
1748
|
-
this.history[nextAction === 'push' ? 'push' : 'replace'](
|
|
1881
|
+
this.history[nextAction === 'push' ? 'push' : 'replace'](
|
|
1882
|
+
nextHistory.href,
|
|
1883
|
+
nextHistory.state,
|
|
1884
|
+
)
|
|
1749
1885
|
|
|
1750
|
-
this.resetNextScroll =
|
|
1886
|
+
this.resetNextScroll = next.resetScroll ?? true
|
|
1751
1887
|
|
|
1752
1888
|
return this.latestLoadPromise
|
|
1753
1889
|
}
|
|
@@ -1814,37 +1950,46 @@ export class Router<
|
|
|
1814
1950
|
invalidate = async (opts?: {
|
|
1815
1951
|
matchId?: string
|
|
1816
1952
|
reload?: boolean
|
|
1953
|
+
__fromFocus?: boolean
|
|
1817
1954
|
}): Promise<void> => {
|
|
1818
1955
|
if (opts?.matchId) {
|
|
1819
1956
|
this.setRouteMatch(opts.matchId, (s) => ({
|
|
1820
1957
|
...s,
|
|
1821
1958
|
invalid: true,
|
|
1822
1959
|
}))
|
|
1960
|
+
|
|
1823
1961
|
const matchIndex = this.state.matches.findIndex(
|
|
1824
1962
|
(d) => d.id === opts.matchId,
|
|
1825
1963
|
)
|
|
1826
1964
|
const childMatch = this.state.matches[matchIndex + 1]
|
|
1827
1965
|
|
|
1828
1966
|
if (childMatch) {
|
|
1829
|
-
return this.invalidate({
|
|
1967
|
+
return this.invalidate({
|
|
1968
|
+
matchId: childMatch.id,
|
|
1969
|
+
reload: false,
|
|
1970
|
+
__fromFocus: opts.__fromFocus,
|
|
1971
|
+
})
|
|
1830
1972
|
}
|
|
1831
1973
|
} else {
|
|
1832
1974
|
this.__store.batch(() => {
|
|
1833
1975
|
Object.values(this.state.matchesById).forEach((match) => {
|
|
1834
|
-
this.
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1976
|
+
const route = this.getRoute(match.routeId)
|
|
1977
|
+
const shouldInvalidate = opts?.__fromFocus
|
|
1978
|
+
? route.options.reloadOnWindowFocus ?? true
|
|
1979
|
+
: true
|
|
1980
|
+
|
|
1981
|
+
if (shouldInvalidate) {
|
|
1982
|
+
this.setRouteMatch(match.id, (s) => ({
|
|
1983
|
+
...s,
|
|
1984
|
+
invalid: true,
|
|
1985
|
+
}))
|
|
1986
|
+
}
|
|
1838
1987
|
})
|
|
1839
1988
|
})
|
|
1840
1989
|
}
|
|
1841
1990
|
|
|
1842
1991
|
if (opts?.reload ?? true) {
|
|
1843
|
-
return this.
|
|
1844
|
-
fromCurrent: true,
|
|
1845
|
-
replace: true,
|
|
1846
|
-
search: true,
|
|
1847
|
-
} as any)
|
|
1992
|
+
return this.load()
|
|
1848
1993
|
}
|
|
1849
1994
|
}
|
|
1850
1995
|
}
|
|
@@ -1879,7 +2024,9 @@ export type Redirect<
|
|
|
1879
2024
|
TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
|
|
1880
2025
|
TFrom extends RoutePaths<TRouteTree> = '/',
|
|
1881
2026
|
TTo extends string = '',
|
|
1882
|
-
|
|
2027
|
+
TMaskFrom extends RoutePaths<TRouteTree> = TFrom,
|
|
2028
|
+
TMaskTo extends string = '',
|
|
2029
|
+
> = NavigateOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo> & {
|
|
1883
2030
|
code?: number
|
|
1884
2031
|
}
|
|
1885
2032
|
|