@tanstack/react-router 1.114.23 → 1.114.25

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/src/route.ts CHANGED
@@ -1,9 +1,8 @@
1
- import invariant from 'tiny-invariant'
2
1
  import {
3
- joinPaths,
2
+ BaseRootRoute,
3
+ BaseRoute,
4
+ BaseRouteApi,
4
5
  notFound,
5
- rootRouteId,
6
- trimPathLeft,
7
6
  } from '@tanstack/router-core'
8
7
  import { useLoaderData } from './useLoaderData'
9
8
  import { useLoaderDeps } from './useLoaderDeps'
@@ -16,10 +15,7 @@ import type {
16
15
  AnyContext,
17
16
  AnyRoute,
18
17
  AnyRouter,
19
- Constrain,
20
18
  ConstrainLiteral,
21
- LazyRoute as CoreLazyRoute,
22
- Route as CoreRoute,
23
19
  ErrorComponentProps,
24
20
  NotFoundError,
25
21
  NotFoundRouteProps,
@@ -29,22 +25,13 @@ import type {
29
25
  ResolveParams,
30
26
  RootRouteId,
31
27
  RootRouteOptions,
32
- RouteAddChildrenFn,
33
- RouteAddFileChildrenFn,
34
- RouteAddFileTypesFn,
35
28
  RouteConstraints,
36
29
  RouteIds,
37
- RouteLazyFn,
38
- RouteLoaderFn,
39
30
  RouteMask,
40
31
  RouteOptions,
41
- RoutePathOptionsIntersection,
42
- RouteTypes,
43
32
  RouteTypesById,
44
- Router,
33
+ RouterCore,
45
34
  ToMaskOptions,
46
- TrimPathRight,
47
- UpdatableRouteOptions,
48
35
  UseNavigateResult,
49
36
  } from '@tanstack/router-core'
50
37
  import type { UseLoaderDataRoute } from './useLoaderData'
@@ -84,14 +71,15 @@ export function getRouteApi<
84
71
  return new RouteApi<TId, TRouter>({ id })
85
72
  }
86
73
 
87
- export class RouteApi<TId, TRouter extends AnyRouter = RegisteredRouter> {
88
- id: TId
89
-
74
+ export class RouteApi<
75
+ TId,
76
+ TRouter extends AnyRouter = RegisteredRouter,
77
+ > extends BaseRouteApi<TId, TRouter> {
90
78
  /**
91
79
  * @deprecated Use the `getRouteApi` function instead.
92
80
  */
93
81
  constructor({ id }: { id: TId }) {
94
- this.id = id as any
82
+ super({ id })
95
83
  }
96
84
 
97
85
  useMatch: UseMatchRoute<TId> = (opts) => {
@@ -169,93 +157,22 @@ export class Route<
169
157
  in out TLoaderFn = undefined,
170
158
  in out TChildren = unknown,
171
159
  in out TFileRouteTypes = unknown,
172
- > implements
173
- CoreRoute<
174
- TParentRoute,
175
- TPath,
176
- TFullPath,
177
- TCustomId,
178
- TId,
179
- TSearchValidator,
180
- TParams,
181
- TRouterContext,
182
- TRouteContextFn,
183
- TBeforeLoadFn,
184
- TLoaderDeps,
185
- TLoaderFn,
186
- TChildren,
187
- TFileRouteTypes
188
- >
189
- {
190
- isRoot: TParentRoute extends AnyRoute ? true : false
191
- options: RouteOptions<
192
- TParentRoute,
193
- TId,
194
- TCustomId,
195
- TFullPath,
196
- TPath,
197
- TSearchValidator,
198
- TParams,
199
- TLoaderDeps,
200
- TLoaderFn,
201
- TRouterContext,
202
- TRouteContextFn,
203
- TBeforeLoadFn
204
- >
205
-
206
- // The following properties are set up in this.init()
207
- parentRoute!: TParentRoute
208
- private _id!: TId
209
- private _path!: TPath
210
- private _fullPath!: TFullPath
211
- private _to!: TrimPathRight<TFullPath>
212
- private _ssr!: boolean
213
-
214
- public get to() {
215
- /* invariant(
216
- this._to,
217
- `trying to access property 'to' on a route which is not initialized yet. Route properties are only available after 'createRouter' completed.`,
218
- )*/
219
- return this._to
220
- }
221
-
222
- public get id() {
223
- /* invariant(
224
- this._id,
225
- `trying to access property 'id' on a route which is not initialized yet. Route properties are only available after 'createRouter' completed.`,
226
- )*/
227
- return this._id
228
- }
229
-
230
- public get path() {
231
- /* invariant(
232
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
233
- this.isRoot || this._id || this._path,
234
- `trying to access property 'path' on a route which is not initialized yet. Route properties are only available after 'createRouter' completed.`,
235
- )*/
236
- return this._path
237
- }
238
-
239
- public get fullPath() {
240
- /* invariant(
241
- this._fullPath,
242
- `trying to access property 'fullPath' on a route which is not initialized yet. Route properties are only available after 'createRouter' completed.`,
243
- )*/
244
- return this._fullPath
245
- }
246
-
247
- public get ssr() {
248
- return this._ssr
249
- }
250
-
251
- // Optional
252
- children?: TChildren
253
- originalIndex?: number
254
- rank!: number
255
- lazyFn?: () => Promise<CoreLazyRoute>
256
- _lazyPromise?: Promise<void>
257
- _componentsPromise?: Promise<Array<void>>
258
-
160
+ > extends BaseRoute<
161
+ TParentRoute,
162
+ TPath,
163
+ TFullPath,
164
+ TCustomId,
165
+ TId,
166
+ TSearchValidator,
167
+ TParams,
168
+ TRouterContext,
169
+ TRouteContextFn,
170
+ TBeforeLoadFn,
171
+ TLoaderDeps,
172
+ TLoaderFn,
173
+ TChildren,
174
+ TFileRouteTypes
175
+ > {
259
176
  /**
260
177
  * @deprecated Use the `createRoute` function instead.
261
178
  */
@@ -275,220 +192,7 @@ export class Route<
275
192
  TBeforeLoadFn
276
193
  >,
277
194
  ) {
278
- this.options = (options as any) || {}
279
-
280
- this.isRoot = !options?.getParentRoute as any
281
- invariant(
282
- !((options as any)?.id && (options as any)?.path),
283
- `Route cannot have both an 'id' and a 'path' option.`,
284
- )
285
- ;(this as any).$$typeof = Symbol.for('react.memo')
286
- }
287
-
288
- types!: RouteTypes<
289
- TParentRoute,
290
- TPath,
291
- TFullPath,
292
- TCustomId,
293
- TId,
294
- TSearchValidator,
295
- TParams,
296
- TRouterContext,
297
- TRouteContextFn,
298
- TBeforeLoadFn,
299
- TLoaderDeps,
300
- TLoaderFn,
301
- TChildren,
302
- TFileRouteTypes
303
- >
304
-
305
- init = (opts: { originalIndex: number; defaultSsr?: boolean }): void => {
306
- this.originalIndex = opts.originalIndex
307
-
308
- const options = this.options as
309
- | (RouteOptions<
310
- TParentRoute,
311
- TId,
312
- TCustomId,
313
- TFullPath,
314
- TPath,
315
- TSearchValidator,
316
- TParams,
317
- TLoaderDeps,
318
- TLoaderFn,
319
- TRouterContext,
320
- TRouteContextFn,
321
- TBeforeLoadFn
322
- > &
323
- RoutePathOptionsIntersection<TCustomId, TPath>)
324
- | undefined
325
-
326
- const isRoot = !options?.path && !options?.id
327
-
328
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
329
- this.parentRoute = this.options.getParentRoute?.()
330
-
331
- if (isRoot) {
332
- this._path = rootRouteId as TPath
333
- } else {
334
- invariant(
335
- this.parentRoute,
336
- `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`,
337
- )
338
- }
339
-
340
- let path: undefined | string = isRoot ? rootRouteId : options.path
341
-
342
- // If the path is anything other than an index path, trim it up
343
- if (path && path !== '/') {
344
- path = trimPathLeft(path)
345
- }
346
-
347
- const customId = options?.id || path
348
-
349
- // Strip the parentId prefix from the first level of children
350
- let id = isRoot
351
- ? rootRouteId
352
- : joinPaths([
353
- this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id,
354
- customId,
355
- ])
356
-
357
- if (path === rootRouteId) {
358
- path = '/'
359
- }
360
-
361
- if (id !== rootRouteId) {
362
- id = joinPaths(['/', id])
363
- }
364
-
365
- const fullPath =
366
- id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path])
367
-
368
- this._path = path as TPath
369
- this._id = id as TId
370
- // this.customId = customId as TCustomId
371
- this._fullPath = fullPath as TFullPath
372
- this._to = fullPath as TrimPathRight<TFullPath>
373
- this._ssr = options?.ssr ?? opts.defaultSsr ?? true
374
- }
375
-
376
- addChildren: RouteAddChildrenFn<
377
- TParentRoute,
378
- TPath,
379
- TFullPath,
380
- TCustomId,
381
- TId,
382
- TSearchValidator,
383
- TParams,
384
- TRouterContext,
385
- TRouteContextFn,
386
- TBeforeLoadFn,
387
- TLoaderDeps,
388
- TLoaderFn,
389
- TFileRouteTypes
390
- > = (children) => {
391
- return this._addFileChildren(children) as any
392
- }
393
-
394
- _addFileChildren: RouteAddFileChildrenFn<
395
- TParentRoute,
396
- TPath,
397
- TFullPath,
398
- TCustomId,
399
- TId,
400
- TSearchValidator,
401
- TParams,
402
- TRouterContext,
403
- TRouteContextFn,
404
- TBeforeLoadFn,
405
- TLoaderDeps,
406
- TLoaderFn,
407
- TFileRouteTypes
408
- > = (children) => {
409
- if (Array.isArray(children)) {
410
- this.children = children as TChildren
411
- }
412
-
413
- if (typeof children === 'object' && children !== null) {
414
- this.children = Object.values(children) as TChildren
415
- }
416
-
417
- return this as any
418
- }
419
-
420
- _addFileTypes: RouteAddFileTypesFn<
421
- TParentRoute,
422
- TPath,
423
- TFullPath,
424
- TCustomId,
425
- TId,
426
- TSearchValidator,
427
- TParams,
428
- TRouterContext,
429
- TRouteContextFn,
430
- TBeforeLoadFn,
431
- TLoaderDeps,
432
- TLoaderFn,
433
- TChildren
434
- > = () => {
435
- return this as any
436
- }
437
-
438
- updateLoader = <TNewLoaderFn>(options: {
439
- loader: Constrain<
440
- TNewLoaderFn,
441
- RouteLoaderFn<
442
- TParentRoute,
443
- TCustomId,
444
- TParams,
445
- TLoaderDeps,
446
- TRouterContext,
447
- TRouteContextFn,
448
- TBeforeLoadFn
449
- >
450
- >
451
- }) => {
452
- Object.assign(this.options, options)
453
- return this as unknown as Route<
454
- TParentRoute,
455
- TPath,
456
- TFullPath,
457
- TCustomId,
458
- TId,
459
- TSearchValidator,
460
- TParams,
461
- TRouterContext,
462
- TRouteContextFn,
463
- TBeforeLoadFn,
464
- TLoaderDeps,
465
- TNewLoaderFn,
466
- TChildren,
467
- TFileRouteTypes
468
- >
469
- }
470
-
471
- update = (
472
- options: UpdatableRouteOptions<
473
- TParentRoute,
474
- TCustomId,
475
- TFullPath,
476
- TParams,
477
- TSearchValidator,
478
- TLoaderFn,
479
- TLoaderDeps,
480
- TRouterContext,
481
- TRouteContextFn,
482
- TBeforeLoadFn
483
- >,
484
- ): this => {
485
- Object.assign(this.options, options)
486
- return this
487
- }
488
-
489
- lazy: RouteLazyFn<this> = (lazyFn) => {
490
- this.lazyFn = lazyFn
491
- return this
195
+ super(options)
492
196
  }
493
197
 
494
198
  useMatch: UseMatchRoute<TId> = (opts) => {
@@ -573,7 +277,7 @@ export function createRoute<
573
277
  TRouteContextFn,
574
278
  TBeforeLoadFn
575
279
  >,
576
- ): CoreRoute<
280
+ ): Route<
577
281
  TParentRoute,
578
282
  TPath,
579
283
  TFullPath,
@@ -586,8 +290,7 @@ export function createRoute<
586
290
  TBeforeLoadFn,
587
291
  TLoaderDeps,
588
292
  TLoaderFn,
589
- TChildren,
590
- unknown
293
+ TChildren
591
294
  > {
592
295
  return new Route<
593
296
  TParentRoute,
@@ -650,20 +353,14 @@ export class RootRoute<
650
353
  in out TLoaderFn = undefined,
651
354
  in out TChildren = unknown,
652
355
  in out TFileRouteTypes = unknown,
653
- > extends Route<
654
- any, // TParentRoute
655
- '/', // TPath
656
- '/', // TFullPath
657
- string, // TCustomId
658
- RootRouteId, // TId
659
- TSearchValidator, // TSearchValidator
660
- {}, // TParams
356
+ > extends BaseRootRoute<
357
+ TSearchValidator,
661
358
  TRouterContext,
662
359
  TRouteContextFn,
663
360
  TBeforeLoadFn,
664
361
  TLoaderDeps,
665
362
  TLoaderFn,
666
- TChildren, // TChildren
363
+ TChildren,
667
364
  TFileRouteTypes
668
365
  > {
669
366
  /**
@@ -679,7 +376,53 @@ export class RootRoute<
679
376
  TLoaderFn
680
377
  >,
681
378
  ) {
682
- super(options as any)
379
+ super(options)
380
+ }
381
+
382
+ useMatch: UseMatchRoute<RootRouteId> = (opts) => {
383
+ return useMatch({
384
+ select: opts?.select,
385
+ from: this.id,
386
+ structuralSharing: opts?.structuralSharing,
387
+ } as any) as any
388
+ }
389
+
390
+ useRouteContext: UseRouteContextRoute<RootRouteId> = (opts) => {
391
+ return useMatch({
392
+ ...opts,
393
+ from: this.id,
394
+ select: (d) => (opts?.select ? opts.select(d.context) : d.context),
395
+ }) as any
396
+ }
397
+
398
+ useSearch: UseSearchRoute<RootRouteId> = (opts) => {
399
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
400
+ return useSearch({
401
+ select: opts?.select,
402
+ structuralSharing: opts?.structuralSharing,
403
+ from: this.id,
404
+ } as any) as any
405
+ }
406
+
407
+ useParams: UseParamsRoute<RootRouteId> = (opts) => {
408
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
409
+ return useParams({
410
+ select: opts?.select,
411
+ structuralSharing: opts?.structuralSharing,
412
+ from: this.id,
413
+ } as any) as any
414
+ }
415
+
416
+ useLoaderDeps: UseLoaderDepsRoute<RootRouteId> = (opts) => {
417
+ return useLoaderDeps({ ...opts, from: this.id } as any)
418
+ }
419
+
420
+ useLoaderData: UseLoaderDataRoute<RootRouteId> = (opts) => {
421
+ return useLoaderData({ ...opts, from: this.id } as any)
422
+ }
423
+
424
+ useNavigate = (): UseNavigateResult<'/'> => {
425
+ return useNavigate({ from: this.fullPath })
683
426
  }
684
427
  }
685
428
 
@@ -699,7 +442,16 @@ export function createRootRoute<
699
442
  TLoaderDeps,
700
443
  TLoaderFn
701
444
  >,
702
- ) {
445
+ ): RootRoute<
446
+ TSearchValidator,
447
+ TRouterContext,
448
+ TRouteContextFn,
449
+ TBeforeLoadFn,
450
+ TLoaderDeps,
451
+ TLoaderFn,
452
+ unknown,
453
+ unknown
454
+ > {
703
455
  return new RootRoute<
704
456
  TSearchValidator,
705
457
  TRouterContext,
@@ -717,7 +469,7 @@ export function createRouteMask<
717
469
  >(
718
470
  opts: {
719
471
  routeTree: TRouteTree
720
- } & ToMaskOptions<Router<TRouteTree, 'never', boolean>, TFrom, TTo>,
472
+ } & ToMaskOptions<RouterCore<TRouteTree, 'never', boolean>, TFrom, TTo>,
721
473
  ): RouteMask<TRouteTree> {
722
474
  return opts as any
723
475
  }