@tanstack/react-router 1.30.1 → 1.31.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.
Files changed (58) hide show
  1. package/dist/cjs/Matches.cjs.map +1 -1
  2. package/dist/cjs/Matches.d.cts +10 -10
  3. package/dist/cjs/RouterProvider.cjs.map +1 -1
  4. package/dist/cjs/RouterProvider.d.cts +7 -7
  5. package/dist/cjs/fileRoute.d.cts +1 -1
  6. package/dist/cjs/link.cjs.map +1 -1
  7. package/dist/cjs/link.d.cts +42 -42
  8. package/dist/cjs/redirects.cjs.map +1 -1
  9. package/dist/cjs/redirects.d.cts +5 -6
  10. package/dist/cjs/route.cjs.map +1 -1
  11. package/dist/cjs/route.d.cts +6 -6
  12. package/dist/cjs/routeInfo.d.cts +19 -2
  13. package/dist/cjs/router.cjs +69 -52
  14. package/dist/cjs/router.cjs.map +1 -1
  15. package/dist/cjs/router.d.cts +15 -15
  16. package/dist/cjs/routerContext.cjs.map +1 -1
  17. package/dist/cjs/routerContext.d.cts +1 -1
  18. package/dist/cjs/useNavigate.cjs.map +1 -1
  19. package/dist/cjs/useNavigate.d.cts +3 -4
  20. package/dist/cjs/useRouter.cjs.map +1 -1
  21. package/dist/cjs/useRouter.d.cts +3 -4
  22. package/dist/cjs/useRouterState.cjs.map +1 -1
  23. package/dist/cjs/useRouterState.d.cts +3 -4
  24. package/dist/esm/Matches.d.ts +10 -10
  25. package/dist/esm/Matches.js.map +1 -1
  26. package/dist/esm/RouterProvider.d.ts +7 -7
  27. package/dist/esm/RouterProvider.js.map +1 -1
  28. package/dist/esm/fileRoute.d.ts +1 -1
  29. package/dist/esm/link.d.ts +42 -42
  30. package/dist/esm/link.js.map +1 -1
  31. package/dist/esm/redirects.d.ts +5 -6
  32. package/dist/esm/redirects.js.map +1 -1
  33. package/dist/esm/route.d.ts +6 -6
  34. package/dist/esm/route.js.map +1 -1
  35. package/dist/esm/routeInfo.d.ts +19 -2
  36. package/dist/esm/router.d.ts +15 -15
  37. package/dist/esm/router.js +69 -52
  38. package/dist/esm/router.js.map +1 -1
  39. package/dist/esm/routerContext.d.ts +1 -1
  40. package/dist/esm/routerContext.js.map +1 -1
  41. package/dist/esm/useNavigate.d.ts +3 -4
  42. package/dist/esm/useNavigate.js.map +1 -1
  43. package/dist/esm/useRouter.d.ts +3 -4
  44. package/dist/esm/useRouter.js.map +1 -1
  45. package/dist/esm/useRouterState.d.ts +3 -4
  46. package/dist/esm/useRouterState.js.map +1 -1
  47. package/package.json +1 -1
  48. package/src/Matches.tsx +40 -22
  49. package/src/RouterProvider.tsx +34 -11
  50. package/src/link.tsx +124 -139
  51. package/src/redirects.ts +14 -14
  52. package/src/route.ts +3 -3
  53. package/src/routeInfo.ts +72 -4
  54. package/src/router.ts +132 -68
  55. package/src/routerContext.tsx +1 -1
  56. package/src/useNavigate.tsx +9 -10
  57. package/src/useRouter.tsx +4 -5
  58. package/src/useRouterState.tsx +5 -6
package/src/routeInfo.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { AnyRoute } from './route'
2
+ import type { AnyRouter, Router, TrailingSlashOption } from './router'
2
3
  import type { UnionToIntersection, UnionToTuple } from './utils'
3
4
 
4
5
  export type ParseRoute<TRouteTree, TAcc = TRouteTree> = TRouteTree extends {
@@ -9,12 +10,14 @@ export type ParseRoute<TRouteTree, TAcc = TRouteTree> = TRouteTree extends {
9
10
  : TAcc
10
11
  : TAcc
11
12
 
12
- export type RouteLeaves<TRouteTree> =
13
+ export type ParseRouteWithoutBranches<TRouteTree> =
13
14
  ParseRoute<TRouteTree> extends infer TRoute extends AnyRoute
14
15
  ? TRoute extends any
15
16
  ? TRoute['types']['children'] extends ReadonlyArray<any>
16
- ? never
17
- : TRoute['fullPath']
17
+ ? '/' extends TRoute['types']['children'][number]['path']
18
+ ? never
19
+ : TRoute
20
+ : TRoute
18
21
  : never
19
22
  : never
20
23
 
@@ -29,9 +32,14 @@ export type RouteById<TRouteTree extends AnyRoute, TId> = Extract<
29
32
 
30
33
  export type RouteIds<TRouteTree extends AnyRoute> = ParseRoute<TRouteTree>['id']
31
34
 
35
+ export type CatchAllPaths<TRouteTree extends AnyRoute> = Record<
36
+ '.' | '..' | '',
37
+ ParseRoute<TRouteTree>
38
+ >
39
+
32
40
  export type RoutesByPath<TRouteTree extends AnyRoute> = {
33
41
  [K in ParseRoute<TRouteTree> as K['fullPath']]: K
34
- } & Record<'.' | '..', ParseRoute<TRouteTree>>
42
+ } & CatchAllPaths<TRouteTree>
35
43
 
36
44
  export type RouteByPath<TRouteTree extends AnyRoute, TPath> = Extract<
37
45
  string extends TPath
@@ -44,6 +52,66 @@ export type RoutePaths<TRouteTree extends AnyRoute> =
44
52
  | ParseRoute<TRouteTree>['fullPath']
45
53
  | '/'
46
54
 
55
+ export type RouteToPathAlwaysTrailingSlash<TRoute extends AnyRoute> =
56
+ TRoute['path'] extends '/'
57
+ ? TRoute['fullPath']
58
+ : TRoute['fullPath'] extends '/'
59
+ ? TRoute['fullPath']
60
+ : `${TRoute['fullPath']}/`
61
+
62
+ export type RouteToPathNeverTrailingSlash<TRoute extends AnyRoute> =
63
+ TRoute['path'] extends '/'
64
+ ? TRoute['fullPath'] extends '/'
65
+ ? TRoute['fullPath']
66
+ : TRoute['fullPath'] extends `${infer TRest}/`
67
+ ? TRest
68
+ : TRoute['fullPath']
69
+ : TRoute['fullPath']
70
+
71
+ export type RouteToPathPreserveTrailingSlash<TRoute extends AnyRoute> =
72
+ | RouteToPathNeverTrailingSlash<TRoute>
73
+ | RouteToPathAlwaysTrailingSlash<TRoute>
74
+
75
+ export type RouteToPathByTrailingSlashOption<TRoute extends AnyRoute> = {
76
+ always: RouteToPathAlwaysTrailingSlash<TRoute>
77
+ preserve: RouteToPathPreserveTrailingSlash<TRoute>
78
+ never: RouteToPathNeverTrailingSlash<TRoute>
79
+ }
80
+
81
+ export type TrailingSlashOptionByRouter<TRouter extends AnyRouter> =
82
+ TrailingSlashOption extends TRouter['options']['trailingSlash']
83
+ ? 'never'
84
+ : NonNullable<TRouter['options']['trailingSlash']>
85
+
86
+ export type RouteToByRouter<
87
+ TRouter extends AnyRouter,
88
+ TRoute extends AnyRoute,
89
+ > = RouteToPathByTrailingSlashOption<TRoute>[TrailingSlashOptionByRouter<TRouter>]
90
+
91
+ export type RouteToPath<
92
+ TRouter extends AnyRouter,
93
+ TRouteTree extends AnyRoute,
94
+ > =
95
+ ParseRouteWithoutBranches<TRouteTree> extends infer TRoute extends AnyRoute
96
+ ? TRoute extends any
97
+ ? RouteToByRouter<TRouter, TRoute>
98
+ : never
99
+ : never
100
+
101
+ export type RoutesByToPath<TRouter extends AnyRouter> = {
102
+ [TRoute in ParseRouteWithoutBranches<TRouter['routeTree']> as RouteToByRouter<
103
+ TRouter,
104
+ TRoute
105
+ >]: TRoute
106
+ } & CatchAllPaths<TRouter['routeTree']>
107
+
108
+ export type RouteByToPath<TRouter extends AnyRouter, TTo> = Extract<
109
+ string extends TTo
110
+ ? ParseRouteWithoutBranches<TRouter['routeTree']>
111
+ : RoutesByToPath<TRouter>[TTo],
112
+ AnyRoute
113
+ >
114
+
47
115
  export type RoutePathsAutoComplete<TRouteTree extends AnyRoute, T> =
48
116
  | (string extends T ? T & {} : T)
49
117
  | RoutePaths<TRouteTree>
package/src/router.ts CHANGED
@@ -87,7 +87,7 @@ import type { DeferredPromiseState } from './defer'
87
87
  declare global {
88
88
  interface Window {
89
89
  __TSR_DEHYDRATED__?: { data: string }
90
- __TSR_ROUTER_CONTEXT__?: React.Context<Router<any>>
90
+ __TSR_ROUTER_CONTEXT__?: React.Context<Router<any, any>>
91
91
  }
92
92
  }
93
93
 
@@ -95,7 +95,7 @@ export interface Register {
95
95
  // router: Router
96
96
  }
97
97
 
98
- export type AnyRouter = Router<AnyRoute, any, any>
98
+ export type AnyRouter = Router<any, any, any, any>
99
99
 
100
100
  export type RegisteredRouter = Register extends {
101
101
  router: infer TRouter extends AnyRouter
@@ -117,8 +117,11 @@ export type RouterContextOptions<TRouteTree extends AnyRoute> =
117
117
  context: TRouteTree['types']['routerContext']
118
118
  }
119
119
 
120
+ export type TrailingSlashOption = 'always' | 'never' | 'preserve'
121
+
120
122
  export interface RouterOptions<
121
123
  TRouteTree extends AnyRoute,
124
+ TTrailingSlashOption extends TrailingSlashOption,
122
125
  TDehydrated extends Record<string, any> = Record<string, any>,
123
126
  TSerializedError extends Record<string, any> = Record<string, any>,
124
127
  > {
@@ -157,7 +160,7 @@ export interface RouterOptions<
157
160
  defaultNotFoundComponent?: NotFoundRouteComponent
158
161
  transformer?: RouterTransformer
159
162
  errorSerializer?: RouterErrorSerializer<TSerializedError>
160
- trailingSlash?: 'always' | 'never' | 'preserve'
163
+ trailingSlash?: TTrailingSlashOption
161
164
  }
162
165
 
163
166
  export interface RouterTransformer {
@@ -202,7 +205,7 @@ export interface BuildNextOptions {
202
205
  unmaskOnReload?: boolean
203
206
  }
204
207
  from?: string
205
- _fromLocation?: ParsedLocation
208
+ fromSearch?: unknown
206
209
  }
207
210
 
208
211
  export interface DehydratedRouterState {
@@ -220,9 +223,18 @@ export interface DehydratedRouter {
220
223
 
221
224
  export type RouterConstructorOptions<
222
225
  TRouteTree extends AnyRoute,
226
+ TTrailingSlashOption extends TrailingSlashOption,
223
227
  TDehydrated extends Record<string, any>,
224
228
  TSerializedError extends Record<string, any>,
225
- > = Omit<RouterOptions<TRouteTree, TDehydrated, TSerializedError>, 'context'> &
229
+ > = Omit<
230
+ RouterOptions<
231
+ TRouteTree,
232
+ TTrailingSlashOption,
233
+ TDehydrated,
234
+ TSerializedError
235
+ >,
236
+ 'context'
237
+ > &
226
238
  RouterContextOptions<TRouteTree>
227
239
 
228
240
  export const componentTypes = [
@@ -261,17 +273,29 @@ export type RouterListener<TRouterEvent extends RouterEvent> = {
261
273
  }
262
274
 
263
275
  export function createRouter<
264
- TRouteTree extends AnyRoute = AnyRoute,
276
+ TRouteTree extends AnyRoute,
277
+ TTrailingSlashOption extends TrailingSlashOption,
265
278
  TDehydrated extends Record<string, any> = Record<string, any>,
266
279
  TSerializedError extends Record<string, any> = Record<string, any>,
267
280
  >(
268
- options: RouterConstructorOptions<TRouteTree, TDehydrated, TSerializedError>,
281
+ options: RouterConstructorOptions<
282
+ TRouteTree,
283
+ TTrailingSlashOption,
284
+ TDehydrated,
285
+ TSerializedError
286
+ >,
269
287
  ) {
270
- return new Router<TRouteTree, TDehydrated, TSerializedError>(options)
288
+ return new Router<
289
+ TRouteTree,
290
+ TTrailingSlashOption,
291
+ TDehydrated,
292
+ TSerializedError
293
+ >(options)
271
294
  }
272
295
 
273
296
  export class Router<
274
- in out TRouteTree extends AnyRoute = AnyRoute,
297
+ in out TRouteTree extends AnyRoute,
298
+ in out TTrailingSlashOption extends TrailingSlashOption,
275
299
  in out TDehydrated extends Record<string, any> = Record<string, any>,
276
300
  in out TSerializedError extends Record<string, any> = Record<string, any>,
277
301
  > {
@@ -281,7 +305,6 @@ export class Router<
281
305
  )}`
282
306
  resetNextScroll = true
283
307
  shouldViewTransition?: true = undefined
284
- navigateTimeout: Timeout | null = null
285
308
  latestLoadPromise: Promise<void> = Promise.resolve()
286
309
  subscribers = new Set<RouterListener<RouterEvent>>()
287
310
  injectedHtml: Array<InjectedHtmlEntry> = []
@@ -292,7 +315,12 @@ export class Router<
292
315
  __store!: Store<RouterState<TRouteTree>>
293
316
  options!: PickAsRequired<
294
317
  Omit<
295
- RouterOptions<TRouteTree, TDehydrated, TSerializedError>,
318
+ RouterOptions<
319
+ TRouteTree,
320
+ TTrailingSlashOption,
321
+ TDehydrated,
322
+ TSerializedError
323
+ >,
296
324
  'transformer'
297
325
  > & {
298
326
  transformer: RouterTransformer
@@ -313,6 +341,7 @@ export class Router<
313
341
  constructor(
314
342
  options: RouterConstructorOptions<
315
343
  TRouteTree,
344
+ TTrailingSlashOption,
316
345
  TDehydrated,
317
346
  TSerializedError
318
347
  >,
@@ -343,6 +372,7 @@ export class Router<
343
372
  update = (
344
373
  newOptions: RouterConstructorOptions<
345
374
  TRouteTree,
375
+ TTrailingSlashOption,
346
376
  TDehydrated,
347
377
  TSerializedError
348
378
  >,
@@ -889,25 +919,25 @@ export class Router<
889
919
  } = {},
890
920
  matches?: Array<MakeRouteMatch<TRouteTree>>,
891
921
  ): ParsedLocation => {
892
- const fromPath = dest.from || this.latestLocation.pathname
893
- let fromSearch = dest._fromLocation?.search || this.latestLocation.search
922
+ let fromPath = this.latestLocation.pathname
923
+ let fromSearch = dest.fromSearch || this.latestLocation.search
894
924
 
895
- const fromMatches = this.matchRoutes(fromPath, fromSearch)
925
+ const fromMatches = this.matchRoutes(
926
+ this.latestLocation.pathname,
927
+ fromSearch,
928
+ )
896
929
 
930
+ fromPath =
931
+ fromMatches.find((d) => d.id === dest.from)?.pathname || fromPath
897
932
  fromSearch = last(fromMatches)?.search || this.latestLocation.search
898
933
 
899
934
  const stayingMatches = matches?.filter((d) =>
900
935
  fromMatches.find((e) => e.routeId === d.routeId),
901
936
  )
902
937
 
903
- const fromRoute = this.looseRoutesById[last(fromMatches)?.routeId]
904
-
905
938
  let pathname = dest.to
906
- ? this.resolvePathWithBase(
907
- dest.from ?? this.latestLocation.pathname,
908
- `${dest.to}`,
909
- )
910
- : this.resolvePathWithBase(fromRoute?.fullPath, fromRoute?.fullPath)
939
+ ? this.resolvePathWithBase(fromPath, `${dest.to}`)
940
+ : this.resolvePathWithBase(fromPath, fromPath)
911
941
 
912
942
  const prevParams = { ...last(fromMatches)?.params }
913
943
 
@@ -1082,8 +1112,6 @@ export class Router<
1082
1112
  viewTransition,
1083
1113
  ...next
1084
1114
  }: ParsedLocation & CommitLocationOptions) => {
1085
- if (this.navigateTimeout) clearTimeout(this.navigateTimeout)
1086
-
1087
1115
  const isSameUrl = this.latestLocation.href === next.href
1088
1116
 
1089
1117
  // If the next urls are the same and we're not replacing,
@@ -1244,15 +1272,10 @@ export class Router<
1244
1272
  }
1245
1273
 
1246
1274
  if (isRedirect(err)) {
1247
- const redirect = this.resolveRedirect(err)
1248
-
1249
- if (!preload && !this.isServer) {
1250
- this.navigate({ ...(redirect as any), replace: true })
1251
- }
1252
-
1253
- throw redirect
1275
+ err = this.resolveRedirect(err)
1276
+ throw err
1254
1277
  } else if (isNotFound(err)) {
1255
- if (!preload) this.handleNotFound(matches, err)
1278
+ this.handleNotFound(matches, err)
1256
1279
  throw err
1257
1280
  }
1258
1281
  }
@@ -1264,6 +1287,25 @@ export class Router<
1264
1287
  const parentMatch = matches[index - 1]
1265
1288
  const route = this.looseRoutesById[match.routeId]!
1266
1289
  const abortController = new AbortController()
1290
+ let loadPromise = match.loadPromise
1291
+
1292
+ if (match.isFetching) {
1293
+ continue
1294
+ }
1295
+
1296
+ const previousResolve = loadPromise.resolve
1297
+ // Create a new one
1298
+ loadPromise = createControlledPromise<void>(
1299
+ // Resolve the old when we we resolve the new one
1300
+ previousResolve,
1301
+ )
1302
+
1303
+ // Otherwise, load the route
1304
+ matches[index] = match = updateMatch(match.id, (prev) => ({
1305
+ ...prev,
1306
+ isFetching: 'beforeLoad',
1307
+ loadPromise,
1308
+ }))
1267
1309
 
1268
1310
  const handleSerialError = (err: any, routerCode: string) => {
1269
1311
  err.routerCode = routerCode
@@ -1344,6 +1386,8 @@ export class Router<
1344
1386
  cause: preload ? 'preload' : match.cause,
1345
1387
  })) ?? ({} as any)
1346
1388
 
1389
+ if ((latestPromise = checkLatest())) return latestPromise
1390
+
1347
1391
  if (
1348
1392
  isRedirect(beforeLoadContext) ||
1349
1393
  isNotFound(beforeLoadContext)
@@ -1373,6 +1417,8 @@ export class Router<
1373
1417
  }
1374
1418
  }
1375
1419
 
1420
+ if ((latestPromise = checkLatest())) return latestPromise
1421
+
1376
1422
  const validResolvedMatches = matches.slice(0, firstBadMatchIndex)
1377
1423
  const matchPromises: Array<Promise<any>> = []
1378
1424
 
@@ -1400,7 +1446,6 @@ export class Router<
1400
1446
  let lazyPromise = Promise.resolve()
1401
1447
  let componentsPromise = Promise.resolve() as Promise<any>
1402
1448
  let loaderPromise = existing.loaderPromise
1403
- let loadPromise = existing.loadPromise
1404
1449
 
1405
1450
  // If the Matches component rendered
1406
1451
  // the pending component and needs to show it for
@@ -1424,7 +1469,7 @@ export class Router<
1424
1469
  }
1425
1470
 
1426
1471
  try {
1427
- if (!match.isFetching) {
1472
+ if (match.isFetching === 'beforeLoad') {
1428
1473
  // If the user doesn't want the route to reload, just
1429
1474
  // resolve with the existing loader data
1430
1475
 
@@ -1433,11 +1478,14 @@ export class Router<
1433
1478
  // }
1434
1479
 
1435
1480
  // Otherwise, load the route
1436
- matches[index] = match = {
1437
- ...match,
1438
- isFetching: true,
1439
- fetchCount: match.fetchCount + 1,
1440
- }
1481
+ matches[index] = match = updateMatch(
1482
+ match.id,
1483
+ (prev) => ({
1484
+ ...prev,
1485
+ isFetching: 'loader',
1486
+ fetchCount: match.fetchCount + 1,
1487
+ }),
1488
+ )
1441
1489
 
1442
1490
  lazyPromise =
1443
1491
  route.lazyFn?.().then((lazyRoute) => {
@@ -1470,20 +1518,15 @@ export class Router<
1470
1518
  // Kick off the loader!
1471
1519
  loaderPromise = route.options.loader?.(loaderContext)
1472
1520
 
1473
- const previousResolve = loadPromise.resolve
1474
- // Create a new one
1475
- loadPromise = createControlledPromise<void>(
1476
- // Resolve the old when we we resolve the new one
1477
- previousResolve,
1521
+ matches[index] = match = updateMatch(
1522
+ match.id,
1523
+ (prev) => ({
1524
+ ...prev,
1525
+ loaderPromise,
1526
+ }),
1478
1527
  )
1479
1528
  }
1480
1529
 
1481
- matches[index] = match = updateMatch(match.id, (prev) => ({
1482
- ...prev,
1483
- loaderPromise,
1484
- loadPromise,
1485
- }))
1486
-
1487
1530
  const loaderData = await loaderPromise
1488
1531
  if ((latestPromise = checkLatest()))
1489
1532
  return await latestPromise
@@ -1549,7 +1592,7 @@ export class Router<
1549
1592
  if ((latestPromise = checkLatest()))
1550
1593
  return await latestPromise
1551
1594
 
1552
- loadPromise.resolve()
1595
+ match.loadPromise.resolve()
1553
1596
  }
1554
1597
 
1555
1598
  // This is where all of the stale-while-revalidate magic happens
@@ -1694,27 +1737,38 @@ export class Router<
1694
1737
  let redirect: ResolvedRedirect | undefined
1695
1738
  let notFound: NotFoundError | undefined
1696
1739
 
1697
- try {
1698
- // Load the matches
1699
- const loadMatchesPromise = this.loadMatches({
1740
+ const loadMatches = () =>
1741
+ this.loadMatches({
1700
1742
  matches: pendingMatches,
1701
1743
  location: next,
1702
1744
  checkLatest: () => this.checkLatest(promise),
1703
1745
  })
1704
1746
 
1705
- if (previousMatches.length || this.isServer) {
1706
- await loadMatchesPromise
1707
- }
1708
- } catch (err) {
1709
- if (isRedirect(err)) {
1710
- redirect = err as ResolvedRedirect
1711
- } else if (isNotFound(err)) {
1712
- notFound = err
1747
+ // If we are on the server or non-first load on the client, await
1748
+ // the loadMatches before transitioning
1749
+ if (previousMatches.length || this.isServer) {
1750
+ try {
1751
+ await loadMatches()
1752
+ } catch (err) {
1753
+ if (isRedirect(err)) {
1754
+ redirect = err as ResolvedRedirect
1755
+ } else if (isNotFound(err)) {
1756
+ notFound = err
1757
+ }
1713
1758
  }
1714
-
1715
- // Swallow all other errors that happen inside
1716
- // of loadMatches. These errors will be handled
1717
- // as state on each match.
1759
+ } else {
1760
+ // For client-only first loads, we need to start the transition
1761
+ // immediately and load the matches in the background
1762
+ loadMatches().catch((err) => {
1763
+ // This also means that we need to handle any redirects
1764
+ // that might happen during the load/transition
1765
+ if (isRedirect(err)) {
1766
+ this.navigate({ ...err, replace: true })
1767
+ }
1768
+ // Because our history listener isn't guaranteed to be mounted
1769
+ // on the first load, we need to manually call load again
1770
+ this.load()
1771
+ })
1718
1772
  }
1719
1773
 
1720
1774
  // Only apply the latest transition
@@ -1848,7 +1902,13 @@ export class Router<
1848
1902
  TMaskFrom extends RoutePaths<TRouteTree> | string = TFrom,
1849
1903
  TMaskTo extends string = '',
1850
1904
  >(
1851
- opts: NavigateOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo>,
1905
+ opts: NavigateOptions<
1906
+ Router<TRouteTree, TTrailingSlashOption, TDehydrated, TSerializedError>,
1907
+ TFrom,
1908
+ TTo,
1909
+ TMaskFrom,
1910
+ TMaskTo
1911
+ >,
1852
1912
  ): Promise<Array<AnyRouteMatch> | undefined> => {
1853
1913
  const next = this.buildLocation(opts as any)
1854
1914
 
@@ -1905,7 +1965,7 @@ export class Router<
1905
1965
  } catch (err) {
1906
1966
  if (isRedirect(err)) {
1907
1967
  return await this.preloadRoute({
1908
- _fromDest: next,
1968
+ fromSearch: next.search,
1909
1969
  from: next.pathname,
1910
1970
  ...(err as any),
1911
1971
  })
@@ -1921,7 +1981,11 @@ export class Router<
1921
1981
  TTo extends string = '',
1922
1982
  TResolved = ResolveRelativePath<TFrom, NoInfer<TTo>>,
1923
1983
  >(
1924
- location: ToOptions<TRouteTree, TFrom, TTo>,
1984
+ location: ToOptions<
1985
+ Router<TRouteTree, TTrailingSlashOption, TDehydrated, TSerializedError>,
1986
+ TFrom,
1987
+ TTo
1988
+ >,
1925
1989
  opts?: MatchRouteOptions,
1926
1990
  ): false | RouteById<TRouteTree, TResolved>['types']['allParams'] => {
1927
1991
  const matchLocation = {
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react'
2
2
  import type { Router } from './router'
3
3
 
4
- const routerContext = React.createContext<Router<any>>(null!)
4
+ const routerContext = React.createContext<Router<any, any>>(null!)
5
5
 
6
6
  export function getRouterContext() {
7
7
  if (typeof document === 'undefined') {
@@ -3,20 +3,19 @@ import { useMatch } from './Matches'
3
3
  import { useRouter } from './useRouter'
4
4
 
5
5
  import type { NavigateOptions } from './link'
6
- import type { AnyRoute } from './route'
7
6
  import type { RoutePaths, RoutePathsAutoComplete } from './routeInfo'
8
- import type { RegisteredRouter } from './router'
7
+ import type { AnyRouter, RegisteredRouter } from './router'
9
8
 
10
9
  export type UseNavigateResult<TDefaultFrom extends string> = <
11
10
  TTo extends string,
12
- TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
13
- TFrom extends RoutePaths<TRouteTree> | string = TDefaultFrom,
14
- TMaskFrom extends RoutePaths<TRouteTree> | string = TFrom,
11
+ TRouter extends AnyRouter = RegisteredRouter,
12
+ TFrom extends RoutePaths<TRouter['routeTree']> | string = TDefaultFrom,
13
+ TMaskFrom extends RoutePaths<TRouter['routeTree']> | string = TFrom,
15
14
  TMaskTo extends string = '',
16
15
  >({
17
16
  from,
18
17
  ...rest
19
- }: NavigateOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo>) => Promise<void>
18
+ }: NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>) => Promise<void>
20
19
 
21
20
  export function useNavigate<
22
21
  TDefaultFrom extends string = string,
@@ -52,12 +51,12 @@ export function useNavigate<
52
51
  // } //
53
52
 
54
53
  export function Navigate<
55
- TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
56
- TFrom extends RoutePaths<TRouteTree> | string = string,
54
+ TRouter extends AnyRouter = RegisteredRouter,
55
+ TFrom extends RoutePaths<TRouter['routeTree']> | string = string,
57
56
  TTo extends string = '',
58
- TMaskFrom extends RoutePaths<TRouteTree> | string = TFrom,
57
+ TMaskFrom extends RoutePaths<TRouter['routeTree']> | string = TFrom,
59
58
  TMaskTo extends string = '',
60
- >(props: NavigateOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo>): null {
59
+ >(props: NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>): null {
61
60
  const { navigate } = useRouter()
62
61
  const match = useMatch({ strict: false })
63
62
 
package/src/useRouter.tsx CHANGED
@@ -1,12 +1,11 @@
1
1
  import * as React from 'react'
2
2
  import warning from 'tiny-warning'
3
3
  import { getRouterContext } from './routerContext'
4
- import type { AnyRoute } from './route'
5
- import type { RegisteredRouter, Router } from './router'
4
+ import type { AnyRouter, RegisteredRouter, Router } from './router'
6
5
 
7
- export function useRouter<
8
- TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
9
- >(opts?: { warn?: boolean }): Router<TRouteTree> {
6
+ export function useRouter<TRouter extends AnyRouter = RegisteredRouter>(opts?: {
7
+ warn?: boolean
8
+ }): TRouter {
10
9
  const value = React.useContext(getRouterContext())
11
10
  warning(
12
11
  !((opts?.warn ?? true) && !value),
@@ -1,16 +1,15 @@
1
1
  import { useStore } from '@tanstack/react-store'
2
2
  import { useRouter } from './useRouter'
3
- import type { AnyRoute } from './route'
4
- import type { RegisteredRouter, Router, RouterState } from './router'
3
+ import type { AnyRouter, RegisteredRouter, Router, RouterState } from './router'
5
4
 
6
5
  export function useRouterState<
7
- TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],
8
- TSelected = RouterState<TRouteTree>,
6
+ TRouter extends AnyRouter = RegisteredRouter,
7
+ TSelected = RouterState<TRouter['routeTree']>,
9
8
  >(opts?: {
10
- router?: Router<TRouteTree>
9
+ router?: TRouter
11
10
  select: (state: RouterState<RegisteredRouter['routeTree']>) => TSelected
12
11
  }): TSelected {
13
- const contextRouter = useRouter<TRouteTree>({
12
+ const contextRouter = useRouter<TRouter>({
14
13
  warn: opts?.router === undefined,
15
14
  })
16
15
  return useStore((opts?.router || contextRouter).__store, opts?.select as any)