@tanstack/react-router 1.63.5 → 1.64.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/react-router",
3
- "version": "1.63.5",
3
+ "version": "1.64.1",
4
4
  "description": "Modern and scalable routing for React applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -66,7 +66,7 @@
66
66
  "peerDependencies": {
67
67
  "react": ">=18",
68
68
  "react-dom": ">=18",
69
- "@tanstack/router-generator": "1.63.5"
69
+ "@tanstack/router-generator": "1.64.0"
70
70
  },
71
71
  "peerDependenciesMeta": {
72
72
  "@tanstack/router-generator": {
package/src/router.ts CHANGED
@@ -495,6 +495,11 @@ export interface BuildNextOptions {
495
495
  _fromLocation?: ParsedLocation
496
496
  }
497
497
 
498
+ export interface MatchedRoutesResult {
499
+ matchedRoutes: Array<AnyRoute>
500
+ routeParams: Record<string, string>
501
+ }
502
+
498
503
  export interface DehydratedRouterState {
499
504
  dehydratedMatches: Array<DehydratedRouteMatch>
500
505
  }
@@ -602,6 +607,7 @@ type MatchRoutesOpts = {
602
607
  preload?: boolean
603
608
  throwOnError?: boolean
604
609
  _buildLocation?: boolean
610
+ dest?: BuildNextOptions
605
611
  }
606
612
 
607
613
  export class Router<
@@ -1013,33 +1019,10 @@ export class Router<
1013
1019
  next: ParsedLocation,
1014
1020
  opts?: MatchRoutesOpts,
1015
1021
  ): Array<AnyRouteMatch> {
1016
- let routeParams: Record<string, string> = {}
1017
-
1018
- const foundRoute = this.flatRoutes.find((route) => {
1019
- const matchedParams = matchPathname(
1020
- this.basepath,
1021
- trimPathRight(next.pathname),
1022
- {
1023
- to: route.fullPath,
1024
- caseSensitive:
1025
- route.options.caseSensitive ?? this.options.caseSensitive,
1026
- fuzzy: true,
1027
- },
1028
- )
1029
-
1030
- if (matchedParams) {
1031
- routeParams = matchedParams
1032
- return true
1033
- }
1034
-
1035
- return false
1036
- })
1037
-
1038
- let routeCursor: AnyRoute =
1039
- foundRoute || (this.routesById as any)[rootRouteId]
1040
-
1041
- const matchedRoutes: Array<AnyRoute> = [routeCursor]
1042
-
1022
+ const { foundRoute, matchedRoutes, routeParams } = this.getMatchedRoutes(
1023
+ next,
1024
+ opts?.dest,
1025
+ )
1043
1026
  let isGlobalNotFound = false
1044
1027
 
1045
1028
  // Check to see if the route needs a 404 entry
@@ -1059,11 +1042,6 @@ export class Router<
1059
1042
  }
1060
1043
  }
1061
1044
 
1062
- while (routeCursor.parentRoute) {
1063
- routeCursor = routeCursor.parentRoute
1064
- matchedRoutes.unshift(routeCursor)
1065
- }
1066
-
1067
1045
  const globalNotFoundRouteId = (() => {
1068
1046
  if (!isGlobalNotFound) {
1069
1047
  return undefined
@@ -1307,6 +1285,49 @@ export class Router<
1307
1285
  return matches as any
1308
1286
  }
1309
1287
 
1288
+ getMatchedRoutes = (next: ParsedLocation, dest?: BuildNextOptions) => {
1289
+ let routeParams: Record<string, string> = {}
1290
+ const trimmedPath = trimPathRight(next.pathname)
1291
+ const getMatchedParams = (route: AnyRoute) => {
1292
+ const result = matchPathname(this.basepath, trimmedPath, {
1293
+ to: route.fullPath,
1294
+ caseSensitive:
1295
+ route.options.caseSensitive ?? this.options.caseSensitive,
1296
+ fuzzy: true,
1297
+ })
1298
+ return result
1299
+ }
1300
+
1301
+ let foundRoute: AnyRoute | undefined =
1302
+ dest?.to !== undefined ? this.routesByPath[dest.to!] : undefined
1303
+ if (foundRoute) {
1304
+ routeParams = getMatchedParams(foundRoute)!
1305
+ } else {
1306
+ foundRoute = this.flatRoutes.find((route) => {
1307
+ const matchedParams = getMatchedParams(route)
1308
+
1309
+ if (matchedParams) {
1310
+ routeParams = matchedParams
1311
+ return true
1312
+ }
1313
+
1314
+ return false
1315
+ })
1316
+ }
1317
+
1318
+ let routeCursor: AnyRoute =
1319
+ foundRoute || (this.routesById as any)[rootRouteId]
1320
+
1321
+ const matchedRoutes: Array<AnyRoute> = [routeCursor]
1322
+
1323
+ while (routeCursor.parentRoute) {
1324
+ routeCursor = routeCursor.parentRoute
1325
+ matchedRoutes.unshift(routeCursor)
1326
+ }
1327
+
1328
+ return { matchedRoutes, routeParams, foundRoute }
1329
+ }
1330
+
1310
1331
  cancelMatch = (id: string) => {
1311
1332
  const match = this.getMatch(id)
1312
1333
 
@@ -1327,7 +1348,7 @@ export class Router<
1327
1348
  dest: BuildNextOptions & {
1328
1349
  unmaskOnReload?: boolean
1329
1350
  } = {},
1330
- matches?: Array<MakeRouteMatch<TRouteTree>>,
1351
+ matchedRoutesResult?: MatchedRoutesResult,
1331
1352
  ): ParsedLocation => {
1332
1353
  const fromMatches = dest._fromLocation
1333
1354
  ? this.matchRoutes(dest._fromLocation, { _buildLocation: true })
@@ -1355,22 +1376,30 @@ export class Router<
1355
1376
  ? last(this.state.pendingMatches)?.search
1356
1377
  : last(fromMatches)?.search || this.latestLocation.search
1357
1378
 
1358
- const stayingMatches = matches?.filter((d) =>
1359
- fromMatches.find((e) => e.routeId === d.routeId),
1379
+ const stayingMatches = matchedRoutesResult?.matchedRoutes.filter((d) =>
1380
+ fromMatches.find((e) => e.routeId === d.id),
1360
1381
  )
1361
1382
 
1362
- const fromRouteByFromPathRouteId =
1363
- this.routesById[
1364
- stayingMatches?.find((d) => d.pathname === fromPath)
1365
- ?.routeId as keyof this['routesById']
1366
- ]
1367
-
1368
- let pathname = dest.to
1369
- ? this.resolvePathWithBase(fromPath, `${dest.to}`)
1370
- : this.resolvePathWithBase(
1371
- fromPath,
1372
- fromRouteByFromPathRouteId?.to ?? fromPath,
1373
- )
1383
+ let pathname: string
1384
+ if (dest.to) {
1385
+ pathname = this.resolvePathWithBase(fromPath, `${dest.to}`)
1386
+ } else {
1387
+ const fromRouteByFromPathRouteId =
1388
+ this.routesById[
1389
+ stayingMatches?.find((route) => {
1390
+ const interpolatedPath = interpolatePath({
1391
+ path: route.fullPath,
1392
+ params: matchedRoutesResult?.routeParams ?? {},
1393
+ })
1394
+ const pathname = joinPaths([this.basepath, interpolatedPath])
1395
+ return pathname === fromPath
1396
+ })?.id as keyof this['routesById']
1397
+ ]
1398
+ pathname = this.resolvePathWithBase(
1399
+ fromPath,
1400
+ fromRouteByFromPathRouteId?.to ?? fromPath,
1401
+ )
1402
+ }
1374
1403
 
1375
1404
  const prevParams = { ...last(fromMatches)?.params }
1376
1405
 
@@ -1380,11 +1409,10 @@ export class Router<
1380
1409
  : { ...prevParams, ...functionalUpdate(dest.params, prevParams) }
1381
1410
 
1382
1411
  if (Object.keys(nextParams).length > 0) {
1383
- matches
1384
- ?.map((d) => {
1385
- const route = this.looseRoutesById[d.routeId]
1412
+ matchedRoutesResult?.matchedRoutes
1413
+ .map((route) => {
1386
1414
  return (
1387
- route?.options.params?.stringify ?? route!.options.stringifyParams
1415
+ route.options.params?.stringify ?? route.options.stringifyParams
1388
1416
  )
1389
1417
  })
1390
1418
  .filter(Boolean)
@@ -1402,21 +1430,13 @@ export class Router<
1402
1430
 
1403
1431
  const preSearchFilters =
1404
1432
  stayingMatches
1405
- ?.map(
1406
- (match) =>
1407
- this.looseRoutesById[match.routeId]!.options.preSearchFilters ??
1408
- [],
1409
- )
1433
+ ?.map((route) => route.options.preSearchFilters ?? [])
1410
1434
  .flat()
1411
1435
  .filter(Boolean) ?? []
1412
1436
 
1413
1437
  const postSearchFilters =
1414
1438
  stayingMatches
1415
- ?.map(
1416
- (match) =>
1417
- this.looseRoutesById[match.routeId]!.options.postSearchFilters ??
1418
- [],
1419
- )
1439
+ ?.map((route) => route.options.postSearchFilters ?? [])
1420
1440
  .flat()
1421
1441
  .filter(Boolean) ?? []
1422
1442
 
@@ -1509,17 +1529,12 @@ export class Router<
1509
1529
  }
1510
1530
  }
1511
1531
 
1512
- const nextMatches = this.matchRoutes(next, { _buildLocation: true })
1513
- const maskedMatches = maskedNext
1514
- ? this.matchRoutes(maskedNext, { _buildLocation: true })
1515
- : undefined
1516
- const maskedFinal = maskedNext
1517
- ? build(maskedDest, maskedMatches)
1518
- : undefined
1519
-
1532
+ const nextMatches = this.getMatchedRoutes(next, dest)
1520
1533
  const final = build(dest, nextMatches)
1521
1534
 
1522
- if (maskedFinal) {
1535
+ if (maskedNext) {
1536
+ const maskedMatches = this.getMatchedRoutes(maskedNext, maskedDest)
1537
+ const maskedFinal = build(maskedDest, maskedMatches)
1523
1538
  final.maskedLocation = maskedFinal
1524
1539
  }
1525
1540
 
@@ -2497,6 +2512,7 @@ export class Router<
2497
2512
  let matches = this.matchRoutes(next, {
2498
2513
  throwOnError: true,
2499
2514
  preload: true,
2515
+ dest: opts,
2500
2516
  })
2501
2517
 
2502
2518
  const loadedMatchIds = Object.fromEntries(