@tanstack/react-router 0.0.1-beta.245 → 0.0.1-beta.246

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,7 +1,7 @@
1
1
  {
2
2
  "name": "@tanstack/react-router",
3
3
  "author": "Tanner Linsley",
4
- "version": "0.0.1-beta.245",
4
+ "version": "0.0.1-beta.246",
5
5
  "license": "MIT",
6
6
  "repository": "tanstack/router",
7
7
  "homepage": "https://tanstack.com/router",
@@ -44,7 +44,7 @@
44
44
  "@tanstack/store": "^0.1.3",
45
45
  "tiny-invariant": "^1.3.1",
46
46
  "tiny-warning": "^1.0.3",
47
- "@tanstack/history": "0.0.1-beta.245"
47
+ "@tanstack/history": "0.0.1-beta.246"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "rollup --config rollup.config.js"
package/src/path.ts CHANGED
@@ -161,13 +161,17 @@ export function matchPathname(
161
161
  return pathParams ?? {}
162
162
  }
163
163
 
164
+ export function removeBasepath(basepath: string, pathname: string) {
165
+ return basepath != '/' ? pathname.substring(basepath.length) : pathname
166
+ }
167
+
164
168
  export function matchByPath(
165
169
  basepath: string,
166
170
  from: string,
167
171
  matchLocation: Pick<MatchLocation, 'to' | 'caseSensitive' | 'fuzzy'>,
168
172
  ): Record<string, string> | undefined {
169
173
  // Remove the base path from the pathname
170
- from = basepath != '/' ? from.substring(basepath.length) : from
174
+ from = removeBasepath(basepath, from)
171
175
  // Default to to $ (wildcard)
172
176
  const to = `${matchLocation.to ?? '$'}`
173
177
  // Parse the from and to
@@ -245,7 +249,8 @@ export function matchByPath(
245
249
  }
246
250
 
247
251
  if (!isLastBaseSegment && isLastRouteSegment) {
248
- return !!matchLocation.fuzzy
252
+ params['**'] = joinPaths(baseSegments.slice(i + 1).map((d) => d.value))
253
+ return !!matchLocation.fuzzy && routeSegment?.value !== '/'
249
254
  }
250
255
  }
251
256
 
package/src/route.ts CHANGED
@@ -224,9 +224,6 @@ export type UpdatableRouteOptions<
224
224
  onEnter?: (match: AnyRouteMatch) => void
225
225
  onTransition?: (match: AnyRouteMatch) => void
226
226
  onLeave?: (match: AnyRouteMatch) => void
227
- // Set this to true or false to specifically set whether or not this route should be preloaded. If unset, will
228
- // default to router.options.reloadOnWindowFocus
229
- reloadOnWindowFocus?: boolean
230
227
  }
231
228
 
232
229
  export type ParseParamsOption<TPath extends string, TParams> = ParseParamsFn<
@@ -459,7 +456,6 @@ export class Route<
459
456
  ) {
460
457
  this.options = (options as any) || {}
461
458
  this.isRoot = !options?.getParentRoute as any
462
- Route.__onInit(this)
463
459
  ;(this as any).$$typeof = Symbol.for('react.memo')
464
460
  }
465
461
 
@@ -585,11 +581,6 @@ export class Route<
585
581
  return this
586
582
  }
587
583
 
588
- static __onInit = (route: any) => {
589
- // This is a dummy static method that should get
590
- // replaced by a framework specific implementation if necessary
591
- }
592
-
593
584
  useMatch = <TSelected = TAllContext>(opts?: {
594
585
  select?: (search: TAllContext) => TSelected
595
586
  }): TSelected => {
@@ -859,3 +850,62 @@ export type ComponentPropsFromRoute<TRoute> =
859
850
  >
860
851
  ? RouteProps<TFullSearchSchema, TAllParams, TAllContext, TLoaderData>
861
852
  : {}
853
+
854
+ export class NotFoundRoute<
855
+ TParentRoute extends AnyRootRoute,
856
+ TSearchSchema extends RouteConstraints['TSearchSchema'] = {},
857
+ TFullSearchSchema extends
858
+ RouteConstraints['TFullSearchSchema'] = ResolveFullSearchSchema<
859
+ TParentRoute,
860
+ TSearchSchema
861
+ >,
862
+ TRouteContext extends RouteConstraints['TRouteContext'] = RouteContext,
863
+ TAllContext extends Expand<
864
+ Assign<IsAny<TParentRoute['types']['allContext'], {}>, TRouteContext>
865
+ > = Expand<
866
+ Assign<IsAny<TParentRoute['types']['allContext'], {}>, TRouteContext>
867
+ >,
868
+ TRouterContext extends RouteConstraints['TRouterContext'] = AnyContext,
869
+ TLoaderData extends any = unknown,
870
+ TChildren extends RouteConstraints['TChildren'] = unknown,
871
+ TRouteTree extends RouteConstraints['TRouteTree'] = AnyRoute,
872
+ > extends Route<
873
+ TParentRoute,
874
+ '/404',
875
+ '/404',
876
+ '404',
877
+ '404',
878
+ TSearchSchema,
879
+ TFullSearchSchema,
880
+ {},
881
+ {},
882
+ TRouteContext,
883
+ TAllContext,
884
+ TRouterContext,
885
+ TLoaderData,
886
+ TChildren,
887
+ TRouteTree
888
+ > {
889
+ constructor(
890
+ options: Omit<
891
+ RouteOptions<
892
+ TParentRoute,
893
+ string,
894
+ string,
895
+ TSearchSchema,
896
+ TFullSearchSchema,
897
+ {},
898
+ {},
899
+ TRouteContext,
900
+ TAllContext,
901
+ TLoaderData
902
+ >,
903
+ 'caseSensitive' | 'parseParams' | 'stringifyParams' | 'path' | 'id'
904
+ >,
905
+ ) {
906
+ super({
907
+ ...(options as any),
908
+ id: '404',
909
+ })
910
+ }
911
+ }
package/src/router.ts CHANGED
@@ -56,8 +56,10 @@ import {
56
56
  joinPaths,
57
57
  matchPathname,
58
58
  parsePathname,
59
+ removeBasepath,
59
60
  resolvePath,
60
61
  trimPath,
62
+ trimPathLeft,
61
63
  trimPathRight,
62
64
  } from './path'
63
65
  import invariant from 'tiny-invariant'
@@ -130,6 +132,7 @@ export interface RouterOptions<
130
132
  routeMasks?: RouteMask<TRouteTree>[]
131
133
  unmaskOnReload?: boolean
132
134
  Wrap?: (props: { children: any }) => JSX.Element
135
+ notFoundRoute?: AnyRoute
133
136
  }
134
137
 
135
138
  export interface RouterState<TRouteTree extends AnyRoute = AnyRoute> {
@@ -316,11 +319,14 @@ export class Router<
316
319
  this.routesById = {} as RoutesById<TRouteTree>
317
320
  this.routesByPath = {} as RoutesByPath<TRouteTree>
318
321
 
322
+ const notFoundRoute = this.options.notFoundRoute
323
+ if (notFoundRoute) {
324
+ notFoundRoute.init({ originalIndex: 99999999999 })
325
+ ;(this.routesById as any)[notFoundRoute.id] = notFoundRoute
326
+ }
327
+
319
328
  const recurseRoutes = (childRoutes: AnyRoute[]) => {
320
329
  childRoutes.forEach((childRoute, i) => {
321
- // if (typeof childRoute === 'function') {
322
- // childRoute = (childRoute as any)()
323
- // }
324
330
  childRoute.init({ originalIndex: i })
325
331
 
326
332
  const existingRoute = (this.routesById as any)[childRoute.id]
@@ -351,29 +357,42 @@ export class Router<
351
357
 
352
358
  recurseRoutes([this.routeTree])
353
359
 
354
- this.flatRoutes = (Object.values(this.routesByPath) as AnyRoute[])
355
- .map((d, i) => {
356
- const trimmed = trimPath(d.fullPath)
357
- const parsed = parsePathname(trimmed)
360
+ const scoredRoutes: {
361
+ child: AnyRoute
362
+ trimmed: string
363
+ parsed: ReturnType<typeof parsePathname>
364
+ index: number
365
+ score: number[]
366
+ }[] = []
367
+
368
+ ;(Object.values(this.routesById) as AnyRoute[]).forEach((d, i) => {
369
+ if (d.isRoot || !d.path) {
370
+ return
371
+ }
358
372
 
359
- while (parsed.length > 1 && parsed[0]?.value === '/') {
360
- parsed.shift()
361
- }
373
+ const trimmed = trimPathLeft(d.fullPath)
374
+ const parsed = parsePathname(trimmed)
362
375
 
363
- const score = parsed.map((d) => {
364
- if (d.type === 'param') {
365
- return 0.5
366
- }
376
+ while (parsed.length > 1 && parsed[0]?.value === '/') {
377
+ parsed.shift()
378
+ }
367
379
 
368
- if (d.type === 'wildcard') {
369
- return 0.25
370
- }
380
+ const score = parsed.map((d) => {
381
+ if (d.type === 'param') {
382
+ return 0.5
383
+ }
371
384
 
372
- return 1
373
- })
385
+ if (d.type === 'wildcard') {
386
+ return 0.25
387
+ }
374
388
 
375
- return { child: d, trimmed, parsed, index: i, score }
389
+ return 1
376
390
  })
391
+
392
+ scoredRoutes.push({ child: d, trimmed, parsed, index: i, score })
393
+ })
394
+
395
+ this.flatRoutes = scoredRoutes
377
396
  .sort((a, b) => {
378
397
  let isIndex = a.trimmed === '/' ? 1 : b.trimmed === '/' ? -1 : 0
379
398
 
@@ -498,7 +517,7 @@ export class Router<
498
517
  locationSearch: AnySearchSchema,
499
518
  opts?: { throwOnError?: boolean; debug?: boolean },
500
519
  ): RouteMatch<TRouteTree>[] => {
501
- let routeParams: AnyPathParams = {}
520
+ let routeParams: Record<string, string> = {}
502
521
 
503
522
  let foundRoute = this.flatRoutes.find((route) => {
504
523
  const matchedParams = matchPathname(
@@ -508,7 +527,7 @@ export class Router<
508
527
  to: route.fullPath,
509
528
  caseSensitive:
510
529
  route.options.caseSensitive ?? this.options.caseSensitive,
511
- fuzzy: false,
530
+ fuzzy: true,
512
531
  },
513
532
  )
514
533
 
@@ -524,7 +543,20 @@ export class Router<
524
543
  foundRoute || (this.routesById as any)['__root__']
525
544
 
526
545
  let matchedRoutes: AnyRoute[] = [routeCursor]
527
- // let includingLayouts = true
546
+
547
+ // Check to see if the route needs a 404 entry
548
+ if (
549
+ // If we found a route, and it's not an index route and we have left over path
550
+ (foundRoute
551
+ ? foundRoute.path !== '/' && routeParams['**']
552
+ : // Or if we didn't find a route and we have left over path
553
+ trimPathRight(pathname)) &&
554
+ // And we have a 404 route configured
555
+ this.options.notFoundRoute
556
+ ) {
557
+ matchedRoutes.push(this.options.notFoundRoute)
558
+ }
559
+
528
560
  while (routeCursor?.parentRoute) {
529
561
  routeCursor = routeCursor.parentRoute
530
562
  if (routeCursor) matchedRoutes.unshift(routeCursor)
@@ -1380,13 +1412,13 @@ export class Router<
1380
1412
  throwOnError: true,
1381
1413
  })
1382
1414
 
1383
- await this.loadMatches({
1415
+ matches = await this.loadMatches({
1384
1416
  matches,
1385
1417
  preload: true,
1386
1418
  checkLatest: () => undefined,
1387
1419
  })
1388
1420
 
1389
- return [last(matches)!, matches] as const
1421
+ return matches
1390
1422
  }
1391
1423
 
1392
1424
  buildLink: BuildLinkFn<TRouteTree> = (dest) => {
@@ -10,15 +10,7 @@ export function useBlocker(
10
10
 
11
11
  React.useEffect(() => {
12
12
  if (!condition) return
13
-
14
- let unblock = history.block((retry, cancel) => {
15
- if (window.confirm(message)) {
16
- unblock()
17
- retry()
18
- }
19
- })
20
-
21
- return unblock
13
+ return history.block(message)
22
14
  })
23
15
  }
24
16