@tanstack/router-core 1.154.13 → 1.154.14
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/index.d.cts +1 -1
- package/dist/cjs/location.d.cts +0 -27
- package/dist/cjs/router.cjs +69 -205
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +5 -37
- package/dist/cjs/scroll-restoration.cjs +2 -2
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/location.d.ts +0 -27
- package/dist/esm/router.d.ts +5 -37
- package/dist/esm/router.js +69 -205
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration.js +2 -2
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -5
- package/src/location.ts +0 -35
- package/src/router.ts +83 -330
- package/src/scroll-restoration.ts +2 -2
package/src/router.ts
CHANGED
|
@@ -56,7 +56,7 @@ import type {
|
|
|
56
56
|
PickAsRequired,
|
|
57
57
|
Updater,
|
|
58
58
|
} from './utils'
|
|
59
|
-
import type {
|
|
59
|
+
import type { ParsedLocation } from './location'
|
|
60
60
|
import type {
|
|
61
61
|
AnyContext,
|
|
62
62
|
AnyRoute,
|
|
@@ -590,14 +590,6 @@ export interface MatchRoutesOpts {
|
|
|
590
590
|
throwOnError?: boolean
|
|
591
591
|
_buildLocation?: boolean
|
|
592
592
|
dest?: BuildNextOptions
|
|
593
|
-
/** Optional match snapshot hint for fast-path (skips path matching) */
|
|
594
|
-
snapshot?: MatchSnapshot
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
export interface MatchRoutesResult {
|
|
598
|
-
matches: Array<AnyRouteMatch>
|
|
599
|
-
/** Raw string params extracted from path (before parsing) */
|
|
600
|
-
rawParams: Record<string, string>
|
|
601
593
|
}
|
|
602
594
|
|
|
603
595
|
export type InferRouterContext<TRouteTree extends AnyRoute> =
|
|
@@ -710,17 +702,14 @@ export type GetMatchRoutesFn = (pathname: string) => {
|
|
|
710
702
|
/** exhaustive params, still in their string form */
|
|
711
703
|
routeParams: Record<string, string>
|
|
712
704
|
/** partial params, parsed from routeParams during matching */
|
|
713
|
-
parsedParams: Record<string, unknown>
|
|
705
|
+
parsedParams: Record<string, unknown> | undefined
|
|
714
706
|
foundRoute: AnyRoute | undefined
|
|
715
707
|
parseError?: unknown
|
|
716
708
|
}
|
|
717
709
|
|
|
718
710
|
export type EmitFn = (routerEvent: RouterEvent) => void
|
|
719
711
|
|
|
720
|
-
export type LoadFn = (opts?: {
|
|
721
|
-
sync?: boolean
|
|
722
|
-
_skipUpdateLatestLocation?: boolean
|
|
723
|
-
}) => Promise<void>
|
|
712
|
+
export type LoadFn = (opts?: { sync?: boolean }) => Promise<void>
|
|
724
713
|
|
|
725
714
|
export type CommitLocationFn = ({
|
|
726
715
|
viewTransition,
|
|
@@ -903,6 +892,7 @@ export class RouterCore<
|
|
|
903
892
|
tempLocationKey: string | undefined = `${Math.round(
|
|
904
893
|
Math.random() * 10000000,
|
|
905
894
|
)}`
|
|
895
|
+
resetNextScroll = true
|
|
906
896
|
shouldViewTransition?: boolean | ViewTransitionOptions = undefined
|
|
907
897
|
isViewTransitionTypesSupported?: boolean = undefined
|
|
908
898
|
subscribers = new Set<RouterListener<RouterEvent>>()
|
|
@@ -927,8 +917,6 @@ export class RouterCore<
|
|
|
927
917
|
origin?: string
|
|
928
918
|
latestLocation!: ParsedLocation<FullSearchSchema<TRouteTree>>
|
|
929
919
|
pendingBuiltLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>
|
|
930
|
-
/** Session id for cached history snapshots */
|
|
931
|
-
private sessionId!: string
|
|
932
920
|
basepath!: string
|
|
933
921
|
routeTree!: TRouteTree
|
|
934
922
|
routesById!: RoutesById<TRouteTree>
|
|
@@ -949,11 +937,6 @@ export class RouterCore<
|
|
|
949
937
|
TDehydrated
|
|
950
938
|
>,
|
|
951
939
|
) {
|
|
952
|
-
this.sessionId =
|
|
953
|
-
typeof crypto !== 'undefined' && 'randomUUID' in crypto
|
|
954
|
-
? crypto.randomUUID()
|
|
955
|
-
: `${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
956
|
-
|
|
957
940
|
this.update({
|
|
958
941
|
defaultPreloadDelay: 50,
|
|
959
942
|
defaultPendingMs: 1000,
|
|
@@ -1271,70 +1254,42 @@ export class RouterCore<
|
|
|
1271
1254
|
search: locationSearchOrOpts,
|
|
1272
1255
|
} as ParsedLocation,
|
|
1273
1256
|
opts,
|
|
1274
|
-
)
|
|
1257
|
+
)
|
|
1275
1258
|
}
|
|
1276
1259
|
|
|
1277
1260
|
return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts)
|
|
1278
|
-
.matches
|
|
1279
1261
|
}
|
|
1280
1262
|
|
|
1281
1263
|
private matchRoutesInternal(
|
|
1282
1264
|
next: ParsedLocation,
|
|
1283
1265
|
opts?: MatchRoutesOpts,
|
|
1284
|
-
):
|
|
1285
|
-
|
|
1286
|
-
const
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
snapshot.routeIds.length > 0 &&
|
|
1290
|
-
snapshot.routeIds.every((id) => this.routesById[id])
|
|
1291
|
-
|
|
1292
|
-
let matchedRoutes: ReadonlyArray<AnyRoute>
|
|
1293
|
-
let routeParams: Record<string, string>
|
|
1294
|
-
let rawParams: Record<string, string>
|
|
1295
|
-
let globalNotFoundRouteId: string | undefined
|
|
1296
|
-
let parsedParams: Record<string, unknown>
|
|
1297
|
-
|
|
1298
|
-
if (snapshotValid) {
|
|
1299
|
-
// Rebuild matched routes from snapshot
|
|
1300
|
-
matchedRoutes = snapshot.routeIds.map((id) => this.routesById[id]!)
|
|
1301
|
-
routeParams = { ...snapshot.params }
|
|
1302
|
-
rawParams = { ...snapshot.params }
|
|
1303
|
-
globalNotFoundRouteId = snapshot.globalNotFoundRouteId
|
|
1304
|
-
parsedParams = snapshot.parsedParams
|
|
1305
|
-
} else {
|
|
1306
|
-
// Normal path matching
|
|
1307
|
-
const matchedRoutesResult = this.getMatchedRoutes(next.pathname)
|
|
1308
|
-
const { foundRoute, routeParams: rp } = matchedRoutesResult
|
|
1309
|
-
routeParams = rp
|
|
1310
|
-
rawParams = { ...rp } // Capture before routeParams gets modified
|
|
1311
|
-
matchedRoutes = matchedRoutesResult.matchedRoutes
|
|
1312
|
-
parsedParams = matchedRoutesResult.parsedParams
|
|
1266
|
+
): Array<AnyRouteMatch> {
|
|
1267
|
+
const matchedRoutesResult = this.getMatchedRoutes(next.pathname)
|
|
1268
|
+
const { foundRoute, routeParams, parsedParams } = matchedRoutesResult
|
|
1269
|
+
let { matchedRoutes } = matchedRoutesResult
|
|
1270
|
+
let isGlobalNotFound = false
|
|
1313
1271
|
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
//
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
) {
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
// If there is no routes found during path matching
|
|
1329
|
-
isGlobalNotFound = true
|
|
1330
|
-
}
|
|
1272
|
+
// Check to see if the route needs a 404 entry
|
|
1273
|
+
if (
|
|
1274
|
+
// If we found a route, and it's not an index route and we have left over path
|
|
1275
|
+
foundRoute
|
|
1276
|
+
? foundRoute.path !== '/' && routeParams['**']
|
|
1277
|
+
: // Or if we didn't find a route and we have left over path
|
|
1278
|
+
trimPathRight(next.pathname)
|
|
1279
|
+
) {
|
|
1280
|
+
// If the user has defined an (old) 404 route, use it
|
|
1281
|
+
if (this.options.notFoundRoute) {
|
|
1282
|
+
matchedRoutes = [...matchedRoutes, this.options.notFoundRoute]
|
|
1283
|
+
} else {
|
|
1284
|
+
// If there is no routes found during path matching
|
|
1285
|
+
isGlobalNotFound = true
|
|
1331
1286
|
}
|
|
1332
|
-
|
|
1333
|
-
globalNotFoundRouteId = isGlobalNotFound
|
|
1334
|
-
? findGlobalNotFoundRouteId(this.options.notFoundMode, matchedRoutes)
|
|
1335
|
-
: undefined
|
|
1336
1287
|
}
|
|
1337
1288
|
|
|
1289
|
+
const globalNotFoundRouteId = isGlobalNotFound
|
|
1290
|
+
? findGlobalNotFoundRouteId(this.options.notFoundMode, matchedRoutes)
|
|
1291
|
+
: undefined
|
|
1292
|
+
|
|
1338
1293
|
const matches: Array<AnyRouteMatch> = []
|
|
1339
1294
|
|
|
1340
1295
|
const getParentContext = (parentMatch?: AnyRouteMatch) => {
|
|
@@ -1347,19 +1302,6 @@ export class RouterCore<
|
|
|
1347
1302
|
return parentContext
|
|
1348
1303
|
}
|
|
1349
1304
|
|
|
1350
|
-
// Check if we can use cached validated searches from snapshot
|
|
1351
|
-
// Valid if: snapshot exists, searchStr matches, and validatedSearches has correct length
|
|
1352
|
-
const canUseCachedSearch =
|
|
1353
|
-
snapshotValid &&
|
|
1354
|
-
snapshot.searchStr === next.searchStr &&
|
|
1355
|
-
snapshot.validatedSearches?.length === matchedRoutes.length
|
|
1356
|
-
|
|
1357
|
-
// Collect validated searches to cache in snapshot (only when not using cache)
|
|
1358
|
-
const validatedSearchesToCache: Array<{
|
|
1359
|
-
search: Record<string, unknown>
|
|
1360
|
-
strictSearch: Record<string, unknown>
|
|
1361
|
-
}> = []
|
|
1362
|
-
|
|
1363
1305
|
matchedRoutes.forEach((route, index) => {
|
|
1364
1306
|
// Take each matched route and resolve + validate its search params
|
|
1365
1307
|
// This has to happen serially because each route's search params
|
|
@@ -1375,12 +1317,6 @@ export class RouterCore<
|
|
|
1375
1317
|
Record<string, any>,
|
|
1376
1318
|
any,
|
|
1377
1319
|
] = (() => {
|
|
1378
|
-
// Fast-path: use cached validated search from snapshot
|
|
1379
|
-
if (canUseCachedSearch) {
|
|
1380
|
-
const cached = snapshot.validatedSearches![index]!
|
|
1381
|
-
return [cached.search, cached.strictSearch, undefined]
|
|
1382
|
-
}
|
|
1383
|
-
|
|
1384
1320
|
// Validate the search params and stabilize them
|
|
1385
1321
|
const parentSearch = parentMatch?.search ?? next.search
|
|
1386
1322
|
const parentStrictSearch = parentMatch?._strictSearch ?? undefined
|
|
@@ -1414,14 +1350,6 @@ export class RouterCore<
|
|
|
1414
1350
|
}
|
|
1415
1351
|
})()
|
|
1416
1352
|
|
|
1417
|
-
// Cache the validated search for future pop navigations
|
|
1418
|
-
if (!canUseCachedSearch) {
|
|
1419
|
-
validatedSearchesToCache.push({
|
|
1420
|
-
search: preMatchSearch,
|
|
1421
|
-
strictSearch: strictMatchSearch,
|
|
1422
|
-
})
|
|
1423
|
-
}
|
|
1424
|
-
|
|
1425
1353
|
// This is where we need to call route.options.loaderDeps() to get any additional
|
|
1426
1354
|
// deps that the route's loader function might need to run. We need to do this
|
|
1427
1355
|
// before we create the match so that we can pass the deps to the route's
|
|
@@ -1588,18 +1516,6 @@ export class RouterCore<
|
|
|
1588
1516
|
matches.push(match)
|
|
1589
1517
|
})
|
|
1590
1518
|
|
|
1591
|
-
// Cache validated searches in snapshot for future pop navigations
|
|
1592
|
-
// Only update if we computed fresh values (not using cached)
|
|
1593
|
-
if (!canUseCachedSearch && validatedSearchesToCache.length > 0) {
|
|
1594
|
-
const existingSnapshot = next.state?.__TSR_matches as
|
|
1595
|
-
| MatchSnapshot
|
|
1596
|
-
| undefined
|
|
1597
|
-
if (existingSnapshot) {
|
|
1598
|
-
existingSnapshot.searchStr = next.searchStr
|
|
1599
|
-
existingSnapshot.validatedSearches = validatedSearchesToCache
|
|
1600
|
-
}
|
|
1601
|
-
}
|
|
1602
|
-
|
|
1603
1519
|
matches.forEach((match, index) => {
|
|
1604
1520
|
const route = this.looseRoutesById[match.routeId]!
|
|
1605
1521
|
const existingMatch = this.getMatch(match.id)
|
|
@@ -1639,7 +1555,7 @@ export class RouterCore<
|
|
|
1639
1555
|
}
|
|
1640
1556
|
})
|
|
1641
1557
|
|
|
1642
|
-
return
|
|
1558
|
+
return matches
|
|
1643
1559
|
}
|
|
1644
1560
|
|
|
1645
1561
|
getMatchedRoutes: GetMatchRoutesFn = (pathname) => {
|
|
@@ -1767,7 +1683,6 @@ export class RouterCore<
|
|
|
1767
1683
|
// which are expensive and not needed for buildLocation
|
|
1768
1684
|
const destMatchResult = this.getMatchedRoutes(interpolatedNextTo)
|
|
1769
1685
|
let destRoutes = destMatchResult.matchedRoutes
|
|
1770
|
-
const rawParams = destMatchResult.routeParams
|
|
1771
1686
|
|
|
1772
1687
|
// Compute globalNotFoundRouteId using the same logic as matchRoutesInternal
|
|
1773
1688
|
const isGlobalNotFound = destMatchResult.foundRoute
|
|
@@ -1867,20 +1782,6 @@ export class RouterCore<
|
|
|
1867
1782
|
// Replace the equal deep
|
|
1868
1783
|
nextState = replaceEqualDeep(currentLocation.state, nextState)
|
|
1869
1784
|
|
|
1870
|
-
// Build match snapshot for fast-path on back/forward navigation
|
|
1871
|
-
// Use raw params captured during matchRoutesInternal (needed for literal path navigation
|
|
1872
|
-
// where nextParams may be empty but path contains param values)
|
|
1873
|
-
const snapshotParams = {
|
|
1874
|
-
...rawParams,
|
|
1875
|
-
...nextParams,
|
|
1876
|
-
}
|
|
1877
|
-
const matchSnapshot = buildMatchSnapshotFromRoutes({
|
|
1878
|
-
routes: destRoutes,
|
|
1879
|
-
params: snapshotParams,
|
|
1880
|
-
searchStr,
|
|
1881
|
-
globalNotFoundRouteId,
|
|
1882
|
-
})
|
|
1883
|
-
|
|
1884
1785
|
// Create the full path of the location
|
|
1885
1786
|
const fullPath = `${nextPathname}${searchStr}${hashStr}`
|
|
1886
1787
|
|
|
@@ -1890,13 +1791,10 @@ export class RouterCore<
|
|
|
1890
1791
|
// If a rewrite function is provided, use it to rewrite the URL
|
|
1891
1792
|
const rewrittenUrl = executeRewriteOutput(this.rewrite, url)
|
|
1892
1793
|
|
|
1893
|
-
// Use encoded URL path for href (consistent with parseLocation)
|
|
1894
|
-
const encodedHref = url.href.replace(url.origin, '')
|
|
1895
|
-
|
|
1896
1794
|
return {
|
|
1897
1795
|
publicHref:
|
|
1898
1796
|
rewrittenUrl.pathname + rewrittenUrl.search + rewrittenUrl.hash,
|
|
1899
|
-
href:
|
|
1797
|
+
href: fullPath,
|
|
1900
1798
|
url: rewrittenUrl,
|
|
1901
1799
|
pathname: nextPathname,
|
|
1902
1800
|
search: nextSearch,
|
|
@@ -1904,7 +1802,6 @@ export class RouterCore<
|
|
|
1904
1802
|
state: nextState as any,
|
|
1905
1803
|
hash: hash ?? '',
|
|
1906
1804
|
unmaskOnReload: dest.unmaskOnReload,
|
|
1907
|
-
_matchSnapshot: matchSnapshot,
|
|
1908
1805
|
}
|
|
1909
1806
|
}
|
|
1910
1807
|
|
|
@@ -2010,105 +1907,65 @@ export class RouterCore<
|
|
|
2010
1907
|
// Don't commit to history if nothing changed
|
|
2011
1908
|
if (isSameUrl && isSameState()) {
|
|
2012
1909
|
this.load()
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
key: undefined!, // TODO: Remove in v2 - use __TSR_key instead
|
|
1910
|
+
} else {
|
|
1911
|
+
let {
|
|
1912
|
+
// eslint-disable-next-line prefer-const
|
|
1913
|
+
maskedLocation,
|
|
1914
|
+
// eslint-disable-next-line prefer-const
|
|
1915
|
+
hashScrollIntoView,
|
|
1916
|
+
// don't pass url into history since it is a URL instance that cannot be serialized
|
|
1917
|
+
// eslint-disable-next-line prefer-const
|
|
1918
|
+
url: _url,
|
|
1919
|
+
...nextHistory
|
|
1920
|
+
} = next
|
|
1921
|
+
|
|
1922
|
+
if (maskedLocation) {
|
|
1923
|
+
nextHistory = {
|
|
1924
|
+
...maskedLocation,
|
|
1925
|
+
state: {
|
|
1926
|
+
...maskedLocation.state,
|
|
1927
|
+
__tempKey: undefined,
|
|
1928
|
+
__tempLocation: {
|
|
1929
|
+
...nextHistory,
|
|
1930
|
+
search: nextHistory.searchStr,
|
|
1931
|
+
state: {
|
|
1932
|
+
...nextHistory.state,
|
|
1933
|
+
__tempKey: undefined!,
|
|
1934
|
+
__tempLocation: undefined!,
|
|
1935
|
+
__TSR_key: undefined!,
|
|
1936
|
+
key: undefined!, // TODO: Remove in v2 - use __TSR_key instead
|
|
1937
|
+
},
|
|
2042
1938
|
},
|
|
2043
1939
|
},
|
|
2044
|
-
}
|
|
2045
|
-
}
|
|
1940
|
+
}
|
|
2046
1941
|
|
|
2047
|
-
|
|
2048
|
-
|
|
1942
|
+
if (
|
|
1943
|
+
nextHistory.unmaskOnReload ??
|
|
1944
|
+
this.options.unmaskOnReload ??
|
|
1945
|
+
false
|
|
1946
|
+
) {
|
|
1947
|
+
nextHistory.state.__tempKey = this.tempLocationKey
|
|
1948
|
+
}
|
|
2049
1949
|
}
|
|
2050
|
-
}
|
|
2051
|
-
|
|
2052
|
-
nextHistory.state.__hashScrollIntoViewOptions =
|
|
2053
|
-
hashScrollIntoView ?? this.options.defaultHashScrollIntoView ?? true
|
|
2054
|
-
|
|
2055
|
-
// Store resetScroll in history state so it survives back/forward navigation
|
|
2056
|
-
nextHistory.state.__TSR_resetScroll = next.resetScroll ?? true
|
|
2057
1950
|
|
|
2058
|
-
|
|
1951
|
+
nextHistory.state.__hashScrollIntoViewOptions =
|
|
1952
|
+
hashScrollIntoView ?? this.options.defaultHashScrollIntoView ?? true
|
|
2059
1953
|
|
|
2060
|
-
|
|
2061
|
-
nextHistory.state.__TSR_sessionId = this.sessionId
|
|
1954
|
+
this.shouldViewTransition = viewTransition
|
|
2062
1955
|
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
matchResult: this.getMatchedRoutes(next.pathname),
|
|
2069
|
-
pathname: next.pathname,
|
|
2070
|
-
searchStr: next.searchStr,
|
|
2071
|
-
notFoundRoute: this.options.notFoundRoute,
|
|
2072
|
-
notFoundMode: this.options.notFoundMode,
|
|
2073
|
-
})
|
|
2074
|
-
|
|
2075
|
-
// Build the pre-computed ParsedLocation to avoid re-parsing after push
|
|
2076
|
-
// Spread next (which has href, pathname, search, etc.) and override with final state
|
|
2077
|
-
const precomputedLocation: ParsedLocation = {
|
|
2078
|
-
...next,
|
|
2079
|
-
publicHref: nextHistory.publicHref,
|
|
2080
|
-
state: nextHistory.state,
|
|
2081
|
-
maskedLocation,
|
|
1956
|
+
this.history[next.replace ? 'replace' : 'push'](
|
|
1957
|
+
nextHistory.publicHref,
|
|
1958
|
+
nextHistory.state,
|
|
1959
|
+
{ ignoreBlocker },
|
|
1960
|
+
)
|
|
2082
1961
|
}
|
|
2083
1962
|
|
|
2084
|
-
|
|
2085
|
-
// Pass skipTransitionerLoad so Transitioner doesn't call load() - we handle it below
|
|
2086
|
-
const result = await this.history[next.replace ? 'replace' : 'push'](
|
|
2087
|
-
nextHistory.publicHref,
|
|
2088
|
-
nextHistory.state,
|
|
2089
|
-
{ ignoreBlocker, skipTransitionerLoad: true },
|
|
2090
|
-
)
|
|
2091
|
-
|
|
2092
|
-
// If blocked, resolve promise and return
|
|
2093
|
-
if (result.type === 'BLOCKED') {
|
|
2094
|
-
this.commitLocationPromise?.resolve()
|
|
2095
|
-
return this.commitLocationPromise
|
|
2096
|
-
}
|
|
1963
|
+
this.resetNextScroll = next.resetScroll ?? true
|
|
2097
1964
|
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
if (this.history.location.href !== nextHistory.publicHref) {
|
|
2101
|
-
return this.commitLocationPromise
|
|
1965
|
+
if (!this.history.subscribers.size) {
|
|
1966
|
+
this.load()
|
|
2102
1967
|
}
|
|
2103
1968
|
|
|
2104
|
-
// Success: set latestLocation directly (we skip updateLatestLocation in load)
|
|
2105
|
-
this.latestLocation = precomputedLocation as unknown as ParsedLocation<
|
|
2106
|
-
FullSearchSchema<TRouteTree>
|
|
2107
|
-
>
|
|
2108
|
-
|
|
2109
|
-
// Call load() with _skipUpdateLatestLocation since we already set latestLocation
|
|
2110
|
-
this.load({ _skipUpdateLatestLocation: true })
|
|
2111
|
-
|
|
2112
1969
|
return this.commitLocationPromise
|
|
2113
1970
|
}
|
|
2114
1971
|
|
|
@@ -2260,14 +2117,10 @@ export class RouterCore<
|
|
|
2260
2117
|
|
|
2261
2118
|
latestLoadPromise: undefined | Promise<void>
|
|
2262
2119
|
|
|
2263
|
-
beforeLoad = (
|
|
2120
|
+
beforeLoad = () => {
|
|
2264
2121
|
// Cancel any pending matches
|
|
2265
2122
|
this.cancelMatches()
|
|
2266
|
-
|
|
2267
|
-
this.updateLatestLocation()
|
|
2268
|
-
} else {
|
|
2269
|
-
// Already have latestLocation from commitLocation, skip parsing
|
|
2270
|
-
}
|
|
2123
|
+
this.updateLatestLocation()
|
|
2271
2124
|
|
|
2272
2125
|
if (this.isServer) {
|
|
2273
2126
|
// for SPAs on the initial load, this is handled by the Transitioner
|
|
@@ -2291,12 +2144,7 @@ export class RouterCore<
|
|
|
2291
2144
|
}
|
|
2292
2145
|
|
|
2293
2146
|
// Match the routes
|
|
2294
|
-
|
|
2295
|
-
const snapshot =
|
|
2296
|
-
this.latestLocation.state.__TSR_sessionId === this.sessionId
|
|
2297
|
-
? this.latestLocation.state.__TSR_matches
|
|
2298
|
-
: undefined
|
|
2299
|
-
const pendingMatches = this.matchRoutes(this.latestLocation, { snapshot })
|
|
2147
|
+
const pendingMatches = this.matchRoutes(this.latestLocation)
|
|
2300
2148
|
|
|
2301
2149
|
// Ingest the new matches
|
|
2302
2150
|
this.__store.setState((s) => ({
|
|
@@ -2313,10 +2161,7 @@ export class RouterCore<
|
|
|
2313
2161
|
}))
|
|
2314
2162
|
}
|
|
2315
2163
|
|
|
2316
|
-
load: LoadFn = async (opts?: {
|
|
2317
|
-
sync?: boolean
|
|
2318
|
-
_skipUpdateLatestLocation?: boolean
|
|
2319
|
-
}): Promise<void> => {
|
|
2164
|
+
load: LoadFn = async (opts?: { sync?: boolean }): Promise<void> => {
|
|
2320
2165
|
let redirect: AnyRedirect | undefined
|
|
2321
2166
|
let notFound: NotFoundError | undefined
|
|
2322
2167
|
let loadPromise: Promise<void>
|
|
@@ -2325,9 +2170,7 @@ export class RouterCore<
|
|
|
2325
2170
|
loadPromise = new Promise<void>((resolve) => {
|
|
2326
2171
|
this.startTransition(async () => {
|
|
2327
2172
|
try {
|
|
2328
|
-
this.beforeLoad(
|
|
2329
|
-
_skipUpdateLatestLocation: opts?._skipUpdateLatestLocation,
|
|
2330
|
-
})
|
|
2173
|
+
this.beforeLoad()
|
|
2331
2174
|
const next = this.latestLocation
|
|
2332
2175
|
const prevLocation = this.state.resolvedLocation
|
|
2333
2176
|
|
|
@@ -2935,7 +2778,7 @@ export function getMatchedRoutes<TRouteLike extends RouteLike>({
|
|
|
2935
2778
|
const trimmedPath = trimPathRight(pathname)
|
|
2936
2779
|
|
|
2937
2780
|
let foundRoute: TRouteLike | undefined = undefined
|
|
2938
|
-
let parsedParams: Record<string, unknown> =
|
|
2781
|
+
let parsedParams: Record<string, unknown> | undefined = undefined
|
|
2939
2782
|
const match = findRouteMatch<TRouteLike>(trimmedPath, processedTree, true)
|
|
2940
2783
|
if (match) {
|
|
2941
2784
|
foundRoute = match.route
|
|
@@ -2948,96 +2791,6 @@ export function getMatchedRoutes<TRouteLike extends RouteLike>({
|
|
|
2948
2791
|
return { matchedRoutes, routeParams, foundRoute, parsedParams }
|
|
2949
2792
|
}
|
|
2950
2793
|
|
|
2951
|
-
/**
|
|
2952
|
-
* Build a MatchSnapshot from a getMatchedRoutes result.
|
|
2953
|
-
* Determines globalNotFoundRouteId using the same logic as matchRoutesInternal.
|
|
2954
|
-
*/
|
|
2955
|
-
export function buildMatchSnapshot({
|
|
2956
|
-
matchResult,
|
|
2957
|
-
pathname,
|
|
2958
|
-
searchStr,
|
|
2959
|
-
notFoundRoute,
|
|
2960
|
-
notFoundMode,
|
|
2961
|
-
}: {
|
|
2962
|
-
matchResult: ReturnType<typeof getMatchedRoutes>
|
|
2963
|
-
pathname: string
|
|
2964
|
-
searchStr?: string
|
|
2965
|
-
notFoundRoute?: AnyRoute
|
|
2966
|
-
notFoundMode?: 'root' | 'fuzzy'
|
|
2967
|
-
}): MatchSnapshot {
|
|
2968
|
-
const snapshot: MatchSnapshot = {
|
|
2969
|
-
routeIds: matchResult.matchedRoutes.map((r) => r.id),
|
|
2970
|
-
params: matchResult.routeParams,
|
|
2971
|
-
parsedParams: matchResult.parsedParams,
|
|
2972
|
-
searchStr,
|
|
2973
|
-
}
|
|
2974
|
-
|
|
2975
|
-
const isGlobalNotFound = matchResult.foundRoute
|
|
2976
|
-
? matchResult.foundRoute.path !== '/' && matchResult.routeParams['**']
|
|
2977
|
-
: trimPathRight(pathname)
|
|
2978
|
-
|
|
2979
|
-
if (isGlobalNotFound) {
|
|
2980
|
-
if (notFoundRoute) {
|
|
2981
|
-
// Custom notFoundRoute provided - use its id
|
|
2982
|
-
snapshot.globalNotFoundRouteId = notFoundRoute.id
|
|
2983
|
-
} else {
|
|
2984
|
-
if (notFoundMode !== 'root') {
|
|
2985
|
-
for (let i = matchResult.matchedRoutes.length - 1; i >= 0; i--) {
|
|
2986
|
-
const route = matchResult.matchedRoutes[i]!
|
|
2987
|
-
if (route.children) {
|
|
2988
|
-
snapshot.globalNotFoundRouteId = route.id
|
|
2989
|
-
break
|
|
2990
|
-
}
|
|
2991
|
-
}
|
|
2992
|
-
}
|
|
2993
|
-
if (!snapshot.globalNotFoundRouteId) {
|
|
2994
|
-
snapshot.globalNotFoundRouteId = rootRouteId
|
|
2995
|
-
}
|
|
2996
|
-
}
|
|
2997
|
-
}
|
|
2998
|
-
|
|
2999
|
-
return snapshot
|
|
3000
|
-
}
|
|
3001
|
-
|
|
3002
|
-
/**
|
|
3003
|
-
* Build a MatchSnapshot from routes and params directly.
|
|
3004
|
-
* Used by buildLocation to avoid duplicate getMatchedRoutes call.
|
|
3005
|
-
*/
|
|
3006
|
-
export function buildMatchSnapshotFromRoutes({
|
|
3007
|
-
routes,
|
|
3008
|
-
params,
|
|
3009
|
-
searchStr,
|
|
3010
|
-
globalNotFoundRouteId,
|
|
3011
|
-
}: {
|
|
3012
|
-
routes: ReadonlyArray<AnyRoute>
|
|
3013
|
-
params: Record<string, unknown>
|
|
3014
|
-
searchStr?: string
|
|
3015
|
-
globalNotFoundRouteId?: string
|
|
3016
|
-
}): MatchSnapshot {
|
|
3017
|
-
// Convert all params to strings for snapshot storage
|
|
3018
|
-
// (params from path matching are always strings)
|
|
3019
|
-
const stringParams: Record<string, string> = {}
|
|
3020
|
-
for (const key in params) {
|
|
3021
|
-
const value = params[key]
|
|
3022
|
-
if (value != null) {
|
|
3023
|
-
stringParams[key] = String(value)
|
|
3024
|
-
}
|
|
3025
|
-
}
|
|
3026
|
-
|
|
3027
|
-
const snapshot: MatchSnapshot = {
|
|
3028
|
-
routeIds: routes.map((r) => r.id),
|
|
3029
|
-
params: stringParams,
|
|
3030
|
-
parsedParams: params,
|
|
3031
|
-
searchStr,
|
|
3032
|
-
}
|
|
3033
|
-
|
|
3034
|
-
if (globalNotFoundRouteId) {
|
|
3035
|
-
snapshot.globalNotFoundRouteId = globalNotFoundRouteId
|
|
3036
|
-
}
|
|
3037
|
-
|
|
3038
|
-
return snapshot
|
|
3039
|
-
}
|
|
3040
|
-
|
|
3041
2794
|
/**
|
|
3042
2795
|
* TODO: once caches are persisted across requests on the server,
|
|
3043
2796
|
* we can cache the built middleware chain using `last(destRoutes)` as the key
|
|
@@ -340,8 +340,8 @@ export function setupScrollRestoration(router: AnyRouter, force?: boolean) {
|
|
|
340
340
|
|
|
341
341
|
// If the user doesn't want to restore the scroll position,
|
|
342
342
|
// we don't need to do anything.
|
|
343
|
-
|
|
344
|
-
|
|
343
|
+
if (!router.resetNextScroll) {
|
|
344
|
+
router.resetNextScroll = true
|
|
345
345
|
return
|
|
346
346
|
}
|
|
347
347
|
if (typeof router.options.scrollRestoration === 'function') {
|