@tanstack/react-router 1.120.5 → 1.121.0-alpha.3
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/HeadContent.cjs +23 -6
- package/dist/cjs/HeadContent.cjs.map +1 -1
- package/dist/cjs/Match.cjs +6 -1
- package/dist/cjs/Match.cjs.map +1 -1
- package/dist/cjs/Matches.cjs.map +1 -1
- package/dist/cjs/Matches.d.cts +2 -2
- package/dist/cjs/RouterProvider.cjs +10 -8
- package/dist/cjs/RouterProvider.cjs.map +1 -1
- package/dist/cjs/Scripts.cjs +2 -1
- package/dist/cjs/Scripts.cjs.map +1 -1
- package/dist/cjs/fileRoute.cjs +8 -0
- package/dist/cjs/fileRoute.cjs.map +1 -1
- package/dist/cjs/fileRoute.d.cts +16 -5
- package/dist/cjs/index.d.cts +2 -2
- package/dist/cjs/link.cjs +9 -5
- package/dist/cjs/link.cjs.map +1 -1
- package/dist/cjs/router.cjs +8 -0
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/useBlocker.cjs +4 -1
- package/dist/cjs/useBlocker.cjs.map +1 -1
- package/dist/cjs/useNavigate.cjs +14 -7
- package/dist/cjs/useNavigate.cjs.map +1 -1
- package/dist/esm/HeadContent.js +23 -6
- package/dist/esm/HeadContent.js.map +1 -1
- package/dist/esm/Match.js +6 -1
- package/dist/esm/Match.js.map +1 -1
- package/dist/esm/Matches.d.ts +2 -2
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/RouterProvider.js +10 -8
- package/dist/esm/RouterProvider.js.map +1 -1
- package/dist/esm/Scripts.js +2 -1
- package/dist/esm/Scripts.js.map +1 -1
- package/dist/esm/fileRoute.d.ts +16 -5
- package/dist/esm/fileRoute.js +8 -0
- package/dist/esm/fileRoute.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/link.js +9 -5
- package/dist/esm/link.js.map +1 -1
- package/dist/esm/router.js +8 -0
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/useBlocker.js +4 -1
- package/dist/esm/useBlocker.js.map +1 -1
- package/dist/esm/useNavigate.js +14 -7
- package/dist/esm/useNavigate.js.map +1 -1
- package/package.json +3 -3
- package/src/HeadContent.tsx +26 -3
- package/src/Match.tsx +15 -4
- package/src/Matches.tsx +4 -1
- package/src/RouterProvider.tsx +11 -9
- package/src/Scripts.tsx +1 -0
- package/src/fileRoute.ts +26 -4
- package/src/index.tsx +4 -3
- package/src/link.tsx +18 -4
- package/src/router.ts +9 -0
- package/src/useBlocker.tsx +4 -1
- package/src/useNavigate.tsx +23 -6
package/src/Matches.tsx
CHANGED
|
@@ -15,6 +15,7 @@ import type { ReactNode } from './route'
|
|
|
15
15
|
import type {
|
|
16
16
|
AnyRouter,
|
|
17
17
|
DeepPartial,
|
|
18
|
+
Expand,
|
|
18
19
|
MakeOptionalPathParams,
|
|
19
20
|
MakeOptionalSearchParams,
|
|
20
21
|
MakeRouteMatchUnion,
|
|
@@ -123,7 +124,9 @@ export function useMatchRoute<TRouter extends AnyRouter = RegisteredRouter>() {
|
|
|
123
124
|
const TMaskTo extends string = '',
|
|
124
125
|
>(
|
|
125
126
|
opts: UseMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,
|
|
126
|
-
):
|
|
127
|
+
):
|
|
128
|
+
| false
|
|
129
|
+
| Expand<ResolveRoute<TRouter, TFrom, TTo>['types']['allParams']> => {
|
|
127
130
|
const { pending, caseSensitive, fuzzy, includeSearch, ...rest } = opts
|
|
128
131
|
|
|
129
132
|
return router.matchRoute(rest as any, {
|
package/src/RouterProvider.tsx
CHANGED
|
@@ -17,15 +17,17 @@ export function RouterContextProvider<
|
|
|
17
17
|
}: RouterProps<TRouter, TDehydrated> & {
|
|
18
18
|
children: React.ReactNode
|
|
19
19
|
}) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
if (Object.keys(rest).length > 0) {
|
|
21
|
+
// Allow the router to update options on the router instance
|
|
22
|
+
router.update({
|
|
23
|
+
...router.options,
|
|
24
|
+
...rest,
|
|
25
|
+
context: {
|
|
26
|
+
...router.options.context,
|
|
27
|
+
...rest.context,
|
|
28
|
+
},
|
|
29
|
+
} as any)
|
|
30
|
+
}
|
|
29
31
|
|
|
30
32
|
const routerContext = getRouterContext()
|
|
31
33
|
|
package/src/Scripts.tsx
CHANGED
package/src/fileRoute.ts
CHANGED
|
@@ -28,6 +28,7 @@ import type {
|
|
|
28
28
|
RouteIds,
|
|
29
29
|
RouteLoaderFn,
|
|
30
30
|
UpdatableRouteOptions,
|
|
31
|
+
UseNavigateResult,
|
|
31
32
|
} from '@tanstack/router-core'
|
|
32
33
|
import type { UseLoaderDepsRoute } from './useLoaderDeps'
|
|
33
34
|
import type { UseLoaderDataRoute } from './useLoaderData'
|
|
@@ -41,8 +42,13 @@ export function createFileRoute<
|
|
|
41
42
|
TFullPath extends
|
|
42
43
|
RouteConstraints['TFullPath'] = FileRoutesByPath[TFilePath]['fullPath'],
|
|
43
44
|
>(
|
|
44
|
-
path
|
|
45
|
+
path?: TFilePath,
|
|
45
46
|
): FileRoute<TFilePath, TParentRoute, TId, TPath, TFullPath>['createRoute'] {
|
|
47
|
+
if (typeof path === 'object') {
|
|
48
|
+
return new FileRoute<TFilePath, TParentRoute, TId, TPath, TFullPath>(path, {
|
|
49
|
+
silent: true,
|
|
50
|
+
}).createRoute(path) as any
|
|
51
|
+
}
|
|
46
52
|
return new FileRoute<TFilePath, TParentRoute, TId, TPath, TFullPath>(path, {
|
|
47
53
|
silent: true,
|
|
48
54
|
}).createRoute
|
|
@@ -63,7 +69,7 @@ export class FileRoute<
|
|
|
63
69
|
silent?: boolean
|
|
64
70
|
|
|
65
71
|
constructor(
|
|
66
|
-
public path
|
|
72
|
+
public path?: TFilePath,
|
|
67
73
|
_opts?: { silent: boolean },
|
|
68
74
|
) {
|
|
69
75
|
this.silent = _opts?.silent
|
|
@@ -159,6 +165,18 @@ export function FileRouteLoader<
|
|
|
159
165
|
return (loaderFn) => loaderFn as any
|
|
160
166
|
}
|
|
161
167
|
|
|
168
|
+
declare module '@tanstack/router-core' {
|
|
169
|
+
export interface LazyRoute<in out TRoute extends AnyRoute> {
|
|
170
|
+
useMatch: UseMatchRoute<TRoute['id']>
|
|
171
|
+
useRouteContext: UseRouteContextRoute<TRoute['id']>
|
|
172
|
+
useSearch: UseSearchRoute<TRoute['id']>
|
|
173
|
+
useParams: UseParamsRoute<TRoute['id']>
|
|
174
|
+
useLoaderDeps: UseLoaderDepsRoute<TRoute['id']>
|
|
175
|
+
useLoaderData: UseLoaderDataRoute<TRoute['id']>
|
|
176
|
+
useNavigate: () => UseNavigateResult<TRoute['fullPath']>
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
162
180
|
export class LazyRoute<TRoute extends AnyRoute> {
|
|
163
181
|
options: {
|
|
164
182
|
id: string
|
|
@@ -214,7 +232,7 @@ export class LazyRoute<TRoute extends AnyRoute> {
|
|
|
214
232
|
return useLoaderData({ ...opts, from: this.options.id } as any)
|
|
215
233
|
}
|
|
216
234
|
|
|
217
|
-
useNavigate = () => {
|
|
235
|
+
useNavigate = (): UseNavigateResult<TRoute['fullPath']> => {
|
|
218
236
|
const router = useRouter()
|
|
219
237
|
return useNavigate({ from: router.routesById[this.options.id].fullPath })
|
|
220
238
|
}
|
|
@@ -236,6 +254,10 @@ export function createLazyRoute<
|
|
|
236
254
|
export function createLazyFileRoute<
|
|
237
255
|
TFilePath extends keyof FileRoutesByPath,
|
|
238
256
|
TRoute extends FileRoutesByPath[TFilePath]['preLoaderRoute'],
|
|
239
|
-
>(id: TFilePath) {
|
|
257
|
+
>(id: TFilePath): (opts: LazyRouteOptions) => LazyRoute<TRoute> {
|
|
258
|
+
if (typeof id === 'object') {
|
|
259
|
+
return new LazyRoute<TRoute>(id) as any
|
|
260
|
+
}
|
|
261
|
+
|
|
240
262
|
return (opts: LazyRouteOptions) => new LazyRoute<TRoute>({ id, ...opts })
|
|
241
263
|
}
|
package/src/index.tsx
CHANGED
|
@@ -48,7 +48,6 @@ export type {
|
|
|
48
48
|
DeferredPromiseState,
|
|
49
49
|
DeferredPromise,
|
|
50
50
|
ParsedLocation,
|
|
51
|
-
ParsePathParams,
|
|
52
51
|
RemoveTrailingSlashes,
|
|
53
52
|
RemoveLeadingSlashes,
|
|
54
53
|
ActiveOptions,
|
|
@@ -57,6 +56,8 @@ export type {
|
|
|
57
56
|
RootRouteId,
|
|
58
57
|
AnyPathParams,
|
|
59
58
|
ResolveParams,
|
|
59
|
+
ResolveOptionalParams,
|
|
60
|
+
ResolveRequiredParams,
|
|
60
61
|
SearchSchemaInput,
|
|
61
62
|
AnyContext,
|
|
62
63
|
RouteContext,
|
|
@@ -78,8 +79,6 @@ export type {
|
|
|
78
79
|
TrimPath,
|
|
79
80
|
TrimPathLeft,
|
|
80
81
|
TrimPathRight,
|
|
81
|
-
ParseSplatParams,
|
|
82
|
-
SplatParams,
|
|
83
82
|
StringifyParamsFn,
|
|
84
83
|
ParamsOptions,
|
|
85
84
|
InferAllParams,
|
|
@@ -126,6 +125,7 @@ export type {
|
|
|
126
125
|
RouteById,
|
|
127
126
|
RootRouteOptions,
|
|
128
127
|
SerializerExtensions,
|
|
128
|
+
CreateFileRoute,
|
|
129
129
|
} from '@tanstack/router-core'
|
|
130
130
|
|
|
131
131
|
export type * from './serializer'
|
|
@@ -237,6 +237,7 @@ export type {
|
|
|
237
237
|
RouteConstraints,
|
|
238
238
|
RouteMask,
|
|
239
239
|
MatchRouteOptions,
|
|
240
|
+
CreateLazyFileRoute,
|
|
240
241
|
} from '@tanstack/router-core'
|
|
241
242
|
export type {
|
|
242
243
|
UseLinkPropsOptions,
|
package/src/link.tsx
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
useLayoutEffect,
|
|
17
17
|
} from './utils'
|
|
18
18
|
|
|
19
|
+
import { useMatch } from './useMatch'
|
|
19
20
|
import { useMatches } from './Matches'
|
|
20
21
|
import type {
|
|
21
22
|
AnyRouter,
|
|
@@ -105,11 +106,24 @@ export function useLinkProps<
|
|
|
105
106
|
structuralSharing: true as any,
|
|
106
107
|
})
|
|
107
108
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
const isRelativeFromPath = options.relative === 'path'
|
|
110
|
+
|
|
111
|
+
// when `from` is not supplied, use the nearest parent match's full path as the `from` location
|
|
112
|
+
// so relative routing works as expected. Try to stay out of rerenders as much as possible.
|
|
113
|
+
const nearestFrom = useMatch({
|
|
114
|
+
strict: false,
|
|
115
|
+
select: (match) => (isRelativeFromPath ? undefined : match.fullPath),
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
// When no from and relative is path, use the leaf match as the from location
|
|
119
|
+
// Avoid rerenders as much as possible.
|
|
120
|
+
const leafFrom = useMatches({
|
|
121
|
+
select: (matches) =>
|
|
122
|
+
isRelativeFromPath ? matches[matches.length - 1]!.fullPath : undefined,
|
|
112
123
|
})
|
|
124
|
+
|
|
125
|
+
const from = options.from ?? (isRelativeFromPath ? leafFrom : nearestFrom)
|
|
126
|
+
|
|
113
127
|
// Use it as the default `from` location
|
|
114
128
|
const _options = React.useMemo(() => ({ ...options, from }), [options, from])
|
|
115
129
|
|
package/src/router.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RouterCore } from '@tanstack/router-core'
|
|
2
|
+
import { createFileRoute, createLazyFileRoute } from './fileRoute'
|
|
2
3
|
import type { RouterHistory } from '@tanstack/history'
|
|
3
4
|
import type {
|
|
4
5
|
AnyRoute,
|
|
@@ -105,3 +106,11 @@ export class Router<
|
|
|
105
106
|
super(options)
|
|
106
107
|
}
|
|
107
108
|
}
|
|
109
|
+
|
|
110
|
+
if (typeof globalThis !== 'undefined') {
|
|
111
|
+
;(globalThis as any).createFileRoute = createFileRoute
|
|
112
|
+
;(globalThis as any).createLazyFileRoute = createLazyFileRoute
|
|
113
|
+
} else if (typeof window !== 'undefined') {
|
|
114
|
+
;(window as any).createFileRoute = createFileRoute
|
|
115
|
+
;(window as any).createFileRoute = createLazyFileRoute
|
|
116
|
+
}
|
package/src/useBlocker.tsx
CHANGED
|
@@ -177,7 +177,10 @@ export function useBlocker(
|
|
|
177
177
|
location: HistoryLocation,
|
|
178
178
|
): AnyShouldBlockFnLocation {
|
|
179
179
|
const parsedLocation = router.parseLocation(undefined, location)
|
|
180
|
-
const matchedRoutes = router.getMatchedRoutes(
|
|
180
|
+
const matchedRoutes = router.getMatchedRoutes(
|
|
181
|
+
parsedLocation.pathname,
|
|
182
|
+
undefined,
|
|
183
|
+
)
|
|
181
184
|
if (matchedRoutes.foundRoute === undefined) {
|
|
182
185
|
throw new Error(`No route found for location ${location.href}`)
|
|
183
186
|
}
|
package/src/useNavigate.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react'
|
|
2
2
|
import { useRouter } from './useRouter'
|
|
3
|
+
import { useMatch } from './useMatch'
|
|
3
4
|
import type {
|
|
4
5
|
AnyRouter,
|
|
5
6
|
FromPathOption,
|
|
@@ -14,15 +15,32 @@ export function useNavigate<
|
|
|
14
15
|
>(_defaultOpts?: {
|
|
15
16
|
from?: FromPathOption<TRouter, TDefaultFrom>
|
|
16
17
|
}): UseNavigateResult<TDefaultFrom> {
|
|
17
|
-
const { navigate } = useRouter()
|
|
18
|
+
const { navigate, state } = useRouter()
|
|
19
|
+
|
|
20
|
+
// Just get the index of the current match to avoid rerenders
|
|
21
|
+
// as much as possible
|
|
22
|
+
const matchIndex = useMatch({
|
|
23
|
+
strict: false,
|
|
24
|
+
select: (match) => match.index,
|
|
25
|
+
})
|
|
18
26
|
|
|
19
27
|
return React.useCallback(
|
|
20
28
|
(options: NavigateOptions) => {
|
|
29
|
+
const isRelativeFromPath = options.relative === 'path'
|
|
30
|
+
|
|
31
|
+
const from =
|
|
32
|
+
options.from ??
|
|
33
|
+
_defaultOpts?.from ??
|
|
34
|
+
(isRelativeFromPath
|
|
35
|
+
? state.matches[state.matches.length - 1]!.fullPath
|
|
36
|
+
: state.matches[matchIndex]!.fullPath)
|
|
37
|
+
|
|
21
38
|
return navigate({
|
|
22
|
-
from: _defaultOpts?.from,
|
|
23
39
|
...options,
|
|
40
|
+
from: from,
|
|
24
41
|
})
|
|
25
42
|
},
|
|
43
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26
44
|
[_defaultOpts?.from, navigate],
|
|
27
45
|
) as UseNavigateResult<TDefaultFrom>
|
|
28
46
|
}
|
|
@@ -35,6 +53,7 @@ export function Navigate<
|
|
|
35
53
|
const TMaskTo extends string = '',
|
|
36
54
|
>(props: NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>): null {
|
|
37
55
|
const router = useRouter()
|
|
56
|
+
const navigate = useNavigate()
|
|
38
57
|
|
|
39
58
|
const previousPropsRef = React.useRef<NavigateOptions<
|
|
40
59
|
TRouter,
|
|
@@ -45,11 +64,9 @@ export function Navigate<
|
|
|
45
64
|
> | null>(null)
|
|
46
65
|
React.useEffect(() => {
|
|
47
66
|
if (previousPropsRef.current !== props) {
|
|
48
|
-
|
|
49
|
-
...props,
|
|
50
|
-
})
|
|
67
|
+
navigate(props)
|
|
51
68
|
previousPropsRef.current = props
|
|
52
69
|
}
|
|
53
|
-
}, [router, props])
|
|
70
|
+
}, [router, props, navigate])
|
|
54
71
|
return null
|
|
55
72
|
}
|