@tanstack/react-router 1.97.26 → 1.98.1
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/cjs/Match.cjs +78 -28
- package/dist/cjs/Match.cjs.map +1 -1
- package/dist/cjs/Matches.cjs +4 -1
- package/dist/cjs/Matches.cjs.map +1 -1
- package/dist/cjs/Matches.d.cts +2 -0
- package/dist/cjs/ScriptOnce.cjs +1 -1
- package/dist/cjs/ScriptOnce.cjs.map +1 -1
- package/dist/cjs/ScrollRestoration.cjs +39 -0
- package/dist/cjs/ScrollRestoration.cjs.map +1 -0
- package/dist/cjs/ScrollRestoration.d.cts +15 -0
- package/dist/cjs/Transitioner.cjs +3 -33
- package/dist/cjs/Transitioner.cjs.map +1 -1
- package/dist/cjs/index.cjs +3 -4
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +2 -3
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/route.d.cts +10 -2
- package/dist/cjs/router.cjs +37 -23
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +28 -27
- package/dist/cjs/scroll-restoration.cjs +168 -165
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/cjs/scroll-restoration.d.cts +25 -15
- package/dist/esm/Match.js +80 -30
- package/dist/esm/Match.js.map +1 -1
- package/dist/esm/Matches.d.ts +2 -0
- package/dist/esm/Matches.js +4 -1
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/ScriptOnce.js +1 -1
- package/dist/esm/ScriptOnce.js.map +1 -1
- package/dist/esm/ScrollRestoration.d.ts +15 -0
- package/dist/esm/ScrollRestoration.js +39 -0
- package/dist/esm/ScrollRestoration.js.map +1 -0
- package/dist/esm/Transitioner.js +4 -34
- package/dist/esm/Transitioner.js.map +1 -1
- package/dist/esm/index.d.ts +2 -3
- package/dist/esm/index.js +1 -2
- package/dist/esm/route.d.ts +10 -2
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/router.d.ts +28 -27
- package/dist/esm/router.js +38 -24
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration.d.ts +25 -15
- package/dist/esm/scroll-restoration.js +168 -148
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/package.json +3 -3
- package/src/Match.tsx +101 -54
- package/src/Matches.tsx +3 -1
- package/src/ScriptOnce.tsx +1 -1
- package/src/ScrollRestoration.tsx +65 -0
- package/src/Transitioner.tsx +4 -40
- package/src/index.tsx +3 -3
- package/src/route.ts +38 -1
- package/src/router.ts +75 -49
- package/src/scroll-restoration.tsx +271 -183
package/src/router.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
defaultParseSearch,
|
|
13
13
|
defaultStringifySearch,
|
|
14
14
|
functionalUpdate,
|
|
15
|
+
getLocationChangeInfo,
|
|
15
16
|
interpolatePath,
|
|
16
17
|
joinPaths,
|
|
17
18
|
last,
|
|
@@ -27,6 +28,8 @@ import {
|
|
|
27
28
|
} from '@tanstack/router-core'
|
|
28
29
|
import { isRedirect, isResolvedRedirect } from './redirects'
|
|
29
30
|
import { isNotFound } from './not-found'
|
|
31
|
+
|
|
32
|
+
import { setupScrollRestoration } from './scroll-restoration'
|
|
30
33
|
import type * as React from 'react'
|
|
31
34
|
import type {
|
|
32
35
|
HistoryLocation,
|
|
@@ -61,6 +64,7 @@ import type {
|
|
|
61
64
|
BeforeLoadContextOptions,
|
|
62
65
|
ErrorRouteComponent,
|
|
63
66
|
LoaderFnContext,
|
|
67
|
+
MakeRemountDepsOptionsUnion,
|
|
64
68
|
NotFoundRouteComponent,
|
|
65
69
|
RootRoute,
|
|
66
70
|
RouteComponent,
|
|
@@ -451,6 +455,17 @@ export interface RouterOptions<
|
|
|
451
455
|
pathParamsAllowedCharacters?: Array<
|
|
452
456
|
';' | ':' | '@' | '&' | '=' | '+' | '$' | ','
|
|
453
457
|
>
|
|
458
|
+
|
|
459
|
+
defaultRemountDeps?: (opts: MakeRemountDepsOptionsUnion<TRouteTree>) => any
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* If `false`, scroll restoration will be disabled
|
|
463
|
+
*
|
|
464
|
+
* @default true
|
|
465
|
+
*/
|
|
466
|
+
scrollRestoration?: boolean
|
|
467
|
+
getScrollRestorationKey?: (location: ParsedLocation) => string
|
|
468
|
+
scrollRestorationBehavior?: ScrollBehavior
|
|
454
469
|
}
|
|
455
470
|
|
|
456
471
|
export interface RouterErrorSerializer<TSerializedError> {
|
|
@@ -470,7 +485,7 @@ export interface RouterState<
|
|
|
470
485
|
pendingMatches?: Array<TRouteMatch>
|
|
471
486
|
cachedMatches: Array<TRouteMatch>
|
|
472
487
|
location: ParsedLocation<FullSearchSchema<TRouteTree>>
|
|
473
|
-
resolvedLocation
|
|
488
|
+
resolvedLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>
|
|
474
489
|
statusCode: number
|
|
475
490
|
redirect?: ResolvedRedirect
|
|
476
491
|
}
|
|
@@ -563,46 +578,37 @@ function validateSearch(validateSearch: AnyValidator, input: unknown): unknown {
|
|
|
563
578
|
return {}
|
|
564
579
|
}
|
|
565
580
|
|
|
581
|
+
type NavigationEventInfo = {
|
|
582
|
+
fromLocation?: ParsedLocation
|
|
583
|
+
toLocation: ParsedLocation
|
|
584
|
+
pathChanged: boolean
|
|
585
|
+
hrefChanged: boolean
|
|
586
|
+
hashChanged: boolean
|
|
587
|
+
}
|
|
588
|
+
|
|
566
589
|
export type RouterEvents = {
|
|
567
590
|
onBeforeNavigate: {
|
|
568
591
|
type: 'onBeforeNavigate'
|
|
569
|
-
|
|
570
|
-
toLocation: ParsedLocation
|
|
571
|
-
pathChanged: boolean
|
|
572
|
-
hrefChanged: boolean
|
|
573
|
-
}
|
|
592
|
+
} & NavigationEventInfo
|
|
574
593
|
onBeforeLoad: {
|
|
575
594
|
type: 'onBeforeLoad'
|
|
576
|
-
|
|
577
|
-
toLocation: ParsedLocation
|
|
578
|
-
pathChanged: boolean
|
|
579
|
-
hrefChanged: boolean
|
|
580
|
-
}
|
|
595
|
+
} & NavigationEventInfo
|
|
581
596
|
onLoad: {
|
|
582
597
|
type: 'onLoad'
|
|
583
|
-
|
|
584
|
-
toLocation: ParsedLocation
|
|
585
|
-
pathChanged: boolean
|
|
586
|
-
hrefChanged: boolean
|
|
587
|
-
}
|
|
598
|
+
} & NavigationEventInfo
|
|
588
599
|
onResolved: {
|
|
589
600
|
type: 'onResolved'
|
|
590
|
-
|
|
591
|
-
toLocation: ParsedLocation
|
|
592
|
-
pathChanged: boolean
|
|
593
|
-
hrefChanged: boolean
|
|
594
|
-
}
|
|
601
|
+
} & NavigationEventInfo
|
|
595
602
|
onBeforeRouteMount: {
|
|
596
603
|
type: 'onBeforeRouteMount'
|
|
597
|
-
|
|
598
|
-
toLocation: ParsedLocation
|
|
599
|
-
pathChanged: boolean
|
|
600
|
-
hrefChanged: boolean
|
|
601
|
-
}
|
|
604
|
+
} & NavigationEventInfo
|
|
602
605
|
onInjectedHtml: {
|
|
603
606
|
type: 'onInjectedHtml'
|
|
604
607
|
promise: Promise<string>
|
|
605
608
|
}
|
|
609
|
+
onRendered: {
|
|
610
|
+
type: 'onRendered'
|
|
611
|
+
} & NavigationEventInfo
|
|
606
612
|
}
|
|
607
613
|
|
|
608
614
|
export type RouterEvent = RouterEvents[keyof RouterEvents]
|
|
@@ -664,6 +670,8 @@ export class Router<
|
|
|
664
670
|
isViewTransitionTypesSupported?: boolean = undefined
|
|
665
671
|
subscribers = new Set<RouterListener<RouterEvent>>()
|
|
666
672
|
viewTransitionPromise?: ControlledPromise<true>
|
|
673
|
+
isScrollRestoring = false
|
|
674
|
+
isScrollRestorationSetup = false
|
|
667
675
|
|
|
668
676
|
// Must build in constructor
|
|
669
677
|
__store!: Store<RouterState<TRouteTree>>
|
|
@@ -800,6 +808,8 @@ export class Router<
|
|
|
800
808
|
}
|
|
801
809
|
},
|
|
802
810
|
})
|
|
811
|
+
|
|
812
|
+
setupScrollRestoration(this)
|
|
803
813
|
}
|
|
804
814
|
|
|
805
815
|
if (
|
|
@@ -1151,19 +1161,26 @@ export class Router<
|
|
|
1151
1161
|
|
|
1152
1162
|
const parentMatch = matches[index - 1]
|
|
1153
1163
|
|
|
1154
|
-
const [preMatchSearch, searchError]: [
|
|
1164
|
+
const [preMatchSearch, strictMatchSearch, searchError]: [
|
|
1165
|
+
Record<string, any>,
|
|
1166
|
+
Record<string, any>,
|
|
1167
|
+
any,
|
|
1168
|
+
] = (() => {
|
|
1155
1169
|
// Validate the search params and stabilize them
|
|
1156
1170
|
const parentSearch = parentMatch?.search ?? next.search
|
|
1171
|
+
const parentStrictSearch = parentMatch?._strictSearch ?? {}
|
|
1157
1172
|
|
|
1158
1173
|
try {
|
|
1159
|
-
const
|
|
1160
|
-
validateSearch(route.options.validateSearch, parentSearch) ??
|
|
1174
|
+
const strictSearch =
|
|
1175
|
+
validateSearch(route.options.validateSearch, { ...parentSearch }) ??
|
|
1176
|
+
{}
|
|
1161
1177
|
|
|
1162
1178
|
return [
|
|
1163
1179
|
{
|
|
1164
1180
|
...parentSearch,
|
|
1165
|
-
...
|
|
1181
|
+
...strictSearch,
|
|
1166
1182
|
},
|
|
1183
|
+
{ ...parentStrictSearch, ...strictSearch },
|
|
1167
1184
|
undefined,
|
|
1168
1185
|
]
|
|
1169
1186
|
} catch (err: any) {
|
|
@@ -1178,7 +1195,7 @@ export class Router<
|
|
|
1178
1195
|
throw searchParamError
|
|
1179
1196
|
}
|
|
1180
1197
|
|
|
1181
|
-
return [parentSearch, searchParamError]
|
|
1198
|
+
return [parentSearch, {}, searchParamError]
|
|
1182
1199
|
}
|
|
1183
1200
|
})()
|
|
1184
1201
|
|
|
@@ -1194,7 +1211,7 @@ export class Router<
|
|
|
1194
1211
|
|
|
1195
1212
|
const loaderDepsHash = loaderDeps ? JSON.stringify(loaderDeps) : ''
|
|
1196
1213
|
|
|
1197
|
-
const interpolatedPath = interpolatePath({
|
|
1214
|
+
const { usedParams, interpolatedPath } = interpolatePath({
|
|
1198
1215
|
path: route.fullPath,
|
|
1199
1216
|
params: routeParams,
|
|
1200
1217
|
decodeCharMap: this.pathParamsDecodeCharMap,
|
|
@@ -1206,7 +1223,7 @@ export class Router<
|
|
|
1206
1223
|
params: routeParams,
|
|
1207
1224
|
leaveWildcards: true,
|
|
1208
1225
|
decodeCharMap: this.pathParamsDecodeCharMap,
|
|
1209
|
-
}) + loaderDepsHash
|
|
1226
|
+
}).interpolatedPath + loaderDepsHash
|
|
1210
1227
|
|
|
1211
1228
|
// Waste not, want not. If we already have a match for this route,
|
|
1212
1229
|
// reuse it. This is important for layout routes, which might stick
|
|
@@ -1231,9 +1248,11 @@ export class Router<
|
|
|
1231
1248
|
params: previousMatch
|
|
1232
1249
|
? replaceEqualDeep(previousMatch.params, routeParams)
|
|
1233
1250
|
: routeParams,
|
|
1251
|
+
_strictParams: usedParams,
|
|
1234
1252
|
search: previousMatch
|
|
1235
1253
|
? replaceEqualDeep(previousMatch.search, preMatchSearch)
|
|
1236
1254
|
: replaceEqualDeep(existingMatch.search, preMatchSearch),
|
|
1255
|
+
_strictSearch: strictMatchSearch,
|
|
1237
1256
|
}
|
|
1238
1257
|
} else {
|
|
1239
1258
|
const status =
|
|
@@ -1251,11 +1270,13 @@ export class Router<
|
|
|
1251
1270
|
params: previousMatch
|
|
1252
1271
|
? replaceEqualDeep(previousMatch.params, routeParams)
|
|
1253
1272
|
: routeParams,
|
|
1273
|
+
_strictParams: usedParams,
|
|
1254
1274
|
pathname: joinPaths([this.basepath, interpolatedPath]),
|
|
1255
1275
|
updatedAt: Date.now(),
|
|
1256
1276
|
search: previousMatch
|
|
1257
1277
|
? replaceEqualDeep(previousMatch.search, preMatchSearch)
|
|
1258
1278
|
: preMatchSearch,
|
|
1279
|
+
_strictSearch: strictMatchSearch,
|
|
1259
1280
|
searchError: undefined,
|
|
1260
1281
|
status,
|
|
1261
1282
|
isFetching: false,
|
|
@@ -1463,7 +1484,7 @@ export class Router<
|
|
|
1463
1484
|
path: route.fullPath,
|
|
1464
1485
|
params: matchedRoutesResult?.routeParams ?? {},
|
|
1465
1486
|
decodeCharMap: this.pathParamsDecodeCharMap,
|
|
1466
|
-
})
|
|
1487
|
+
}).interpolatedPath
|
|
1467
1488
|
const pathname = joinPaths([this.basepath, interpolatedPath])
|
|
1468
1489
|
return pathname === fromPath
|
|
1469
1490
|
})?.id as keyof this['routesById']
|
|
@@ -1503,7 +1524,7 @@ export class Router<
|
|
|
1503
1524
|
leaveWildcards: false,
|
|
1504
1525
|
leaveParams: opts.leaveParams,
|
|
1505
1526
|
decodeCharMap: this.pathParamsDecodeCharMap,
|
|
1506
|
-
})
|
|
1527
|
+
}).interpolatedPath
|
|
1507
1528
|
|
|
1508
1529
|
let search = fromSearch
|
|
1509
1530
|
if (opts._includeValidateSearch && this.options.search?.strict) {
|
|
@@ -1867,8 +1888,6 @@ export class Router<
|
|
|
1867
1888
|
try {
|
|
1868
1889
|
const next = this.latestLocation
|
|
1869
1890
|
const prevLocation = this.state.resolvedLocation
|
|
1870
|
-
const hrefChanged = prevLocation.href !== next.href
|
|
1871
|
-
const pathChanged = prevLocation.pathname !== next.pathname
|
|
1872
1891
|
|
|
1873
1892
|
// Cancel any pending matches
|
|
1874
1893
|
this.cancelMatches()
|
|
@@ -1900,19 +1919,19 @@ export class Router<
|
|
|
1900
1919
|
if (!this.state.redirect) {
|
|
1901
1920
|
this.emit({
|
|
1902
1921
|
type: 'onBeforeNavigate',
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1922
|
+
...getLocationChangeInfo({
|
|
1923
|
+
resolvedLocation: prevLocation,
|
|
1924
|
+
location: next,
|
|
1925
|
+
}),
|
|
1907
1926
|
})
|
|
1908
1927
|
}
|
|
1909
1928
|
|
|
1910
1929
|
this.emit({
|
|
1911
1930
|
type: 'onBeforeLoad',
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1931
|
+
...getLocationChangeInfo({
|
|
1932
|
+
resolvedLocation: prevLocation,
|
|
1933
|
+
location: next,
|
|
1934
|
+
}),
|
|
1916
1935
|
})
|
|
1917
1936
|
|
|
1918
1937
|
await this.loadMatches({
|
|
@@ -2173,6 +2192,10 @@ export class Router<
|
|
|
2173
2192
|
this._handleNotFound(matches, err, {
|
|
2174
2193
|
updateMatch,
|
|
2175
2194
|
})
|
|
2195
|
+
this.serverSsr?.onMatchSettled({
|
|
2196
|
+
router: this,
|
|
2197
|
+
match: this.getMatch(match.id)!,
|
|
2198
|
+
})
|
|
2176
2199
|
throw err
|
|
2177
2200
|
}
|
|
2178
2201
|
}
|
|
@@ -2637,6 +2660,7 @@ export class Router<
|
|
|
2637
2660
|
if (isNotFound(err) && !allPreload) {
|
|
2638
2661
|
await triggerOnReady()
|
|
2639
2662
|
}
|
|
2663
|
+
|
|
2640
2664
|
throw err
|
|
2641
2665
|
}
|
|
2642
2666
|
}
|
|
@@ -2835,8 +2859,10 @@ export class Router<
|
|
|
2835
2859
|
_fromLocation: next,
|
|
2836
2860
|
})
|
|
2837
2861
|
}
|
|
2838
|
-
|
|
2839
|
-
|
|
2862
|
+
if (!isNotFound(err)) {
|
|
2863
|
+
// Preload errors are not fatal, but we should still log them
|
|
2864
|
+
console.error(err)
|
|
2865
|
+
}
|
|
2840
2866
|
return undefined
|
|
2841
2867
|
}
|
|
2842
2868
|
}
|
|
@@ -2882,7 +2908,7 @@ export class Router<
|
|
|
2882
2908
|
|
|
2883
2909
|
const baseLocation = pending
|
|
2884
2910
|
? this.latestLocation
|
|
2885
|
-
: this.state.resolvedLocation
|
|
2911
|
+
: this.state.resolvedLocation || this.state.location
|
|
2886
2912
|
|
|
2887
2913
|
const match = matchPathname(this.basepath, baseLocation.pathname, {
|
|
2888
2914
|
...opts,
|
|
@@ -3020,7 +3046,7 @@ export function getInitialRouterState(
|
|
|
3020
3046
|
isLoading: false,
|
|
3021
3047
|
isTransitioning: false,
|
|
3022
3048
|
status: 'idle',
|
|
3023
|
-
resolvedLocation:
|
|
3049
|
+
resolvedLocation: undefined,
|
|
3024
3050
|
location,
|
|
3025
3051
|
matches: [],
|
|
3026
3052
|
pendingMatches: [],
|