@tanstack/react-router 1.121.0-alpha.22 → 1.121.0-alpha.28
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/Asset.cjs +83 -16
- package/dist/cjs/Asset.cjs.map +1 -1
- package/dist/cjs/Asset.d.cts +2 -1
- package/dist/cjs/CatchBoundary.cjs.map +1 -1
- package/dist/cjs/ClientOnly.cjs.map +1 -1
- package/dist/cjs/ClientOnly.d.cts +1 -1
- package/dist/cjs/HeadContent.cjs +19 -17
- package/dist/cjs/HeadContent.cjs.map +1 -1
- package/dist/cjs/Match.cjs +61 -57
- package/dist/cjs/Match.cjs.map +1 -1
- package/dist/cjs/Matches.cjs +14 -16
- package/dist/cjs/Matches.cjs.map +1 -1
- package/dist/cjs/Matches.d.cts +2 -2
- package/dist/cjs/RouterProvider.cjs.map +1 -1
- package/dist/cjs/SafeFragment.cjs.map +1 -1
- package/dist/cjs/ScriptOnce.cjs +3 -10
- package/dist/cjs/ScriptOnce.cjs.map +1 -1
- package/dist/cjs/ScriptOnce.d.cts +1 -1
- package/dist/cjs/Scripts.cjs +7 -11
- package/dist/cjs/Scripts.cjs.map +1 -1
- package/dist/cjs/ScrollRestoration.cjs +3 -4
- package/dist/cjs/ScrollRestoration.cjs.map +1 -1
- package/dist/cjs/Transitioner.cjs +16 -15
- package/dist/cjs/Transitioner.cjs.map +1 -1
- package/dist/cjs/awaited.cjs.map +1 -1
- package/dist/cjs/fileRoute.cjs +8 -8
- package/dist/cjs/fileRoute.cjs.map +1 -1
- package/dist/cjs/index.cjs +0 -12
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +4 -8
- package/dist/cjs/lazyRouteComponent.cjs +3 -16
- package/dist/cjs/lazyRouteComponent.cjs.map +1 -1
- package/dist/cjs/lazyRouteComponent.d.cts +1 -1
- package/dist/cjs/link.cjs +106 -74
- package/dist/cjs/link.cjs.map +1 -1
- package/dist/cjs/link.d.cts +1 -5
- package/dist/cjs/matchContext.cjs.map +1 -1
- package/dist/cjs/not-found.cjs +2 -4
- package/dist/cjs/not-found.cjs.map +1 -1
- package/dist/cjs/renderRouteNotFound.cjs.map +1 -1
- package/dist/cjs/route.cjs +21 -21
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/route.d.cts +14 -6
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/routerContext.cjs.map +1 -1
- package/dist/cjs/scroll-restoration.cjs +9 -3
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/cjs/ssr/RouterClient.cjs +25 -0
- package/dist/cjs/ssr/RouterClient.cjs.map +1 -0
- package/dist/cjs/ssr/RouterClient.d.cts +4 -0
- package/dist/cjs/ssr/RouterServer.cjs +9 -0
- package/dist/cjs/ssr/RouterServer.cjs.map +1 -0
- package/dist/cjs/ssr/RouterServer.d.cts +4 -0
- package/dist/cjs/ssr/client.cjs +12 -0
- package/dist/cjs/ssr/client.cjs.map +1 -0
- package/dist/cjs/ssr/client.d.cts +2 -0
- package/dist/cjs/ssr/defaultRenderHandler.cjs +15 -0
- package/dist/cjs/ssr/defaultRenderHandler.cjs.map +1 -0
- package/dist/cjs/ssr/defaultRenderHandler.d.cts +1 -0
- package/dist/cjs/ssr/defaultStreamHandler.cjs +16 -0
- package/dist/cjs/ssr/defaultStreamHandler.cjs.map +1 -0
- package/dist/cjs/ssr/defaultStreamHandler.d.cts +1 -0
- package/dist/cjs/ssr/renderRouterToStream.cjs +63 -0
- package/dist/cjs/ssr/renderRouterToStream.cjs.map +1 -0
- package/dist/cjs/ssr/renderRouterToStream.d.cts +8 -0
- package/dist/cjs/ssr/renderRouterToString.cjs +28 -0
- package/dist/cjs/ssr/renderRouterToString.cjs.map +1 -0
- package/dist/cjs/ssr/renderRouterToString.d.cts +7 -0
- package/dist/cjs/ssr/server.cjs +20 -0
- package/dist/cjs/ssr/server.cjs.map +1 -0
- package/dist/cjs/ssr/server.d.cts +6 -0
- package/dist/cjs/useBlocker.cjs.map +1 -1
- package/dist/cjs/useCanGoBack.cjs.map +1 -1
- package/dist/cjs/useLoaderData.cjs.map +1 -1
- package/dist/cjs/useLoaderDeps.cjs.map +1 -1
- package/dist/cjs/useLocation.cjs +1 -1
- package/dist/cjs/useLocation.cjs.map +1 -1
- package/dist/cjs/useMatch.cjs.map +1 -1
- package/dist/cjs/useNavigate.cjs +2 -2
- package/dist/cjs/useNavigate.cjs.map +1 -1
- package/dist/cjs/useParams.cjs.map +1 -1
- package/dist/cjs/useRouter.cjs +1 -1
- package/dist/cjs/useRouter.cjs.map +1 -1
- package/dist/cjs/useRouterState.cjs +3 -3
- package/dist/cjs/useRouterState.cjs.map +1 -1
- package/dist/cjs/useSearch.cjs.map +1 -1
- package/dist/cjs/utils.cjs +4 -10
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +1 -1
- package/dist/esm/Asset.d.ts +2 -1
- package/dist/esm/Asset.js +66 -16
- package/dist/esm/Asset.js.map +1 -1
- package/dist/esm/CatchBoundary.js.map +1 -1
- package/dist/esm/ClientOnly.d.ts +1 -1
- package/dist/esm/ClientOnly.js.map +1 -1
- package/dist/esm/HeadContent.js +19 -17
- package/dist/esm/HeadContent.js.map +1 -1
- package/dist/esm/Match.js +63 -59
- package/dist/esm/Match.js.map +1 -1
- package/dist/esm/Matches.d.ts +2 -2
- package/dist/esm/Matches.js +14 -16
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/RouterProvider.js.map +1 -1
- package/dist/esm/SafeFragment.js.map +1 -1
- package/dist/esm/ScriptOnce.d.ts +1 -1
- package/dist/esm/ScriptOnce.js +3 -10
- package/dist/esm/ScriptOnce.js.map +1 -1
- package/dist/esm/Scripts.js +7 -11
- package/dist/esm/Scripts.js.map +1 -1
- package/dist/esm/ScrollRestoration.js +3 -4
- package/dist/esm/ScrollRestoration.js.map +1 -1
- package/dist/esm/Transitioner.js +16 -15
- package/dist/esm/Transitioner.js.map +1 -1
- package/dist/esm/awaited.js.map +1 -1
- package/dist/esm/fileRoute.js +8 -8
- package/dist/esm/fileRoute.js.map +1 -1
- package/dist/esm/index.d.ts +4 -8
- package/dist/esm/index.js +2 -8
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lazyRouteComponent.d.ts +1 -1
- package/dist/esm/lazyRouteComponent.js +2 -15
- package/dist/esm/lazyRouteComponent.js.map +1 -1
- package/dist/esm/link.d.ts +1 -5
- package/dist/esm/link.js +107 -75
- package/dist/esm/link.js.map +1 -1
- package/dist/esm/matchContext.js.map +1 -1
- package/dist/esm/not-found.js +2 -4
- package/dist/esm/not-found.js.map +1 -1
- package/dist/esm/renderRouteNotFound.js.map +1 -1
- package/dist/esm/route.d.ts +14 -6
- package/dist/esm/route.js +21 -21
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/routerContext.js.map +1 -1
- package/dist/esm/scroll-restoration.js +9 -3
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/dist/esm/ssr/RouterClient.d.ts +4 -0
- package/dist/esm/ssr/RouterClient.js +25 -0
- package/dist/esm/ssr/RouterClient.js.map +1 -0
- package/dist/esm/ssr/RouterServer.d.ts +4 -0
- package/dist/esm/ssr/RouterServer.js +9 -0
- package/dist/esm/ssr/RouterServer.js.map +1 -0
- package/dist/esm/ssr/client.d.ts +2 -0
- package/dist/esm/ssr/client.js +6 -0
- package/dist/esm/ssr/client.js.map +1 -0
- package/dist/esm/ssr/defaultRenderHandler.d.ts +1 -0
- package/dist/esm/ssr/defaultRenderHandler.js +15 -0
- package/dist/esm/ssr/defaultRenderHandler.js.map +1 -0
- package/dist/esm/ssr/defaultStreamHandler.d.ts +1 -0
- package/dist/esm/ssr/defaultStreamHandler.js +16 -0
- package/dist/esm/ssr/defaultStreamHandler.js.map +1 -0
- package/dist/esm/ssr/renderRouterToStream.d.ts +8 -0
- package/dist/esm/ssr/renderRouterToStream.js +63 -0
- package/dist/esm/ssr/renderRouterToStream.js.map +1 -0
- package/dist/esm/ssr/renderRouterToString.d.ts +7 -0
- package/dist/esm/ssr/renderRouterToString.js +28 -0
- package/dist/esm/ssr/renderRouterToString.js.map +1 -0
- package/dist/esm/ssr/server.d.ts +6 -0
- package/dist/esm/ssr/server.js +14 -0
- package/dist/esm/ssr/server.js.map +1 -0
- package/dist/esm/useBlocker.js.map +1 -1
- package/dist/esm/useCanGoBack.js.map +1 -1
- package/dist/esm/useLoaderData.js.map +1 -1
- package/dist/esm/useLoaderDeps.js.map +1 -1
- package/dist/esm/useLocation.js +1 -1
- package/dist/esm/useLocation.js.map +1 -1
- package/dist/esm/useMatch.js.map +1 -1
- package/dist/esm/useNavigate.js +2 -2
- package/dist/esm/useNavigate.js.map +1 -1
- package/dist/esm/useParams.js.map +1 -1
- package/dist/esm/useRouter.js +1 -1
- package/dist/esm/useRouter.js.map +1 -1
- package/dist/esm/useRouterState.js +3 -3
- package/dist/esm/useRouterState.js.map +1 -1
- package/dist/esm/useSearch.js.map +1 -1
- package/dist/esm/utils.d.ts +1 -1
- package/dist/esm/utils.js +4 -10
- package/dist/esm/utils.js.map +1 -1
- package/dist/llms/index.d.ts +3 -0
- package/dist/llms/index.js +35 -0
- package/dist/llms/rules/api.d.ts +2 -0
- package/dist/llms/rules/api.js +4326 -0
- package/dist/llms/rules/guide.d.ts +2 -0
- package/dist/llms/rules/guide.js +7096 -0
- package/dist/llms/rules/routing.d.ts +2 -0
- package/dist/llms/rules/routing.js +1981 -0
- package/dist/llms/rules/setup-and-architecture.d.ts +2 -0
- package/dist/llms/rules/setup-and-architecture.js +945 -0
- package/package.json +32 -6
- package/src/Asset.tsx +95 -16
- package/src/ClientOnly.tsx +1 -1
- package/src/HeadContent.tsx +16 -0
- package/src/Match.tsx +86 -63
- package/src/Matches.tsx +24 -17
- package/src/ScriptOnce.tsx +2 -14
- package/src/Transitioner.tsx +13 -14
- package/src/index.tsx +3 -21
- package/src/lazyRouteComponent.tsx +6 -31
- package/src/link.tsx +130 -99
- package/src/not-found.tsx +1 -1
- package/src/route.tsx +18 -9
- package/src/scroll-restoration.tsx +10 -3
- package/src/ssr/RouterClient.tsx +22 -0
- package/src/ssr/RouterServer.tsx +9 -0
- package/src/ssr/client.ts +2 -0
- package/src/ssr/defaultRenderHandler.tsx +12 -0
- package/src/ssr/defaultStreamHandler.tsx +13 -0
- package/src/ssr/renderRouterToStream.tsx +79 -0
- package/src/ssr/renderRouterToString.tsx +31 -0
- package/src/ssr/server.ts +6 -0
- package/src/utils.ts +6 -14
- package/dist/cjs/serializer.d.cts +0 -6
- package/dist/esm/serializer.d.ts +0 -6
- package/src/serializer.ts +0 -7
package/src/index.tsx
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
export { default as invariant } from 'tiny-invariant'
|
|
2
|
-
export { default as warning } from 'tiny-warning'
|
|
3
|
-
|
|
4
1
|
export {
|
|
5
2
|
defer,
|
|
6
3
|
TSR_DEFERRED_PROMISE,
|
|
@@ -24,14 +21,12 @@ export {
|
|
|
24
21
|
defaultStringifySearch,
|
|
25
22
|
parseSearchWith,
|
|
26
23
|
stringifySearchWith,
|
|
27
|
-
escapeJSON, // SSR
|
|
28
24
|
pick,
|
|
29
25
|
functionalUpdate,
|
|
30
26
|
replaceEqualDeep,
|
|
31
27
|
isPlainObject,
|
|
32
28
|
isPlainArray,
|
|
33
29
|
deepEqual,
|
|
34
|
-
shallow,
|
|
35
30
|
createControlledPromise,
|
|
36
31
|
retainSearchParams,
|
|
37
32
|
stripSearchParams,
|
|
@@ -39,12 +34,6 @@ export {
|
|
|
39
34
|
|
|
40
35
|
export type {
|
|
41
36
|
AnyRoute,
|
|
42
|
-
StartSerializer,
|
|
43
|
-
Serializable,
|
|
44
|
-
SerializerParse,
|
|
45
|
-
SerializerParseBy,
|
|
46
|
-
SerializerStringify,
|
|
47
|
-
SerializerStringifyBy,
|
|
48
37
|
DeferredPromiseState,
|
|
49
38
|
DeferredPromise,
|
|
50
39
|
ParsedLocation,
|
|
@@ -92,10 +81,6 @@ export type {
|
|
|
92
81
|
SearchSerializer,
|
|
93
82
|
SearchParser,
|
|
94
83
|
TrailingSlashOption,
|
|
95
|
-
ExtractedEntry,
|
|
96
|
-
ExtractedStream,
|
|
97
|
-
ExtractedPromise,
|
|
98
|
-
StreamState,
|
|
99
84
|
Manifest,
|
|
100
85
|
RouterManagedTag,
|
|
101
86
|
ControlledPromise,
|
|
@@ -124,12 +109,9 @@ export type {
|
|
|
124
109
|
FileRoutesByPath,
|
|
125
110
|
RouteById,
|
|
126
111
|
RootRouteOptions,
|
|
127
|
-
SerializerExtensions,
|
|
128
112
|
CreateFileRoute,
|
|
129
113
|
} from '@tanstack/router-core'
|
|
130
114
|
|
|
131
|
-
export type * from './serializer'
|
|
132
|
-
|
|
133
115
|
export {
|
|
134
116
|
createHistory,
|
|
135
117
|
createBrowserHistory,
|
|
@@ -203,6 +185,7 @@ export type {
|
|
|
203
185
|
UseNavigateResult,
|
|
204
186
|
AnyRedirect,
|
|
205
187
|
Redirect,
|
|
188
|
+
RedirectOptions,
|
|
206
189
|
ResolvedRedirect,
|
|
207
190
|
MakeRouteMatch,
|
|
208
191
|
MakeRouteMatchUnion,
|
|
@@ -226,7 +209,6 @@ export type {
|
|
|
226
209
|
ControllablePromise,
|
|
227
210
|
InjectedHtmlEntry,
|
|
228
211
|
RouterOptions,
|
|
229
|
-
RouterErrorSerializer,
|
|
230
212
|
RouterState,
|
|
231
213
|
ListenerFn,
|
|
232
214
|
BuildNextOptions,
|
|
@@ -282,12 +264,12 @@ export {
|
|
|
282
264
|
} from './route'
|
|
283
265
|
export type {
|
|
284
266
|
AnyRootRoute,
|
|
285
|
-
ReactNode,
|
|
286
|
-
SyncRouteComponent,
|
|
287
267
|
AsyncRouteComponent,
|
|
288
268
|
RouteComponent,
|
|
289
269
|
ErrorRouteComponent,
|
|
290
270
|
NotFoundRouteComponent,
|
|
271
|
+
DefaultRouteTypes,
|
|
272
|
+
RouteTypes,
|
|
291
273
|
} from './route'
|
|
292
274
|
|
|
293
275
|
export { createRouter, Router } from './router'
|
|
@@ -1,32 +1,13 @@
|
|
|
1
1
|
import * as React from 'react'
|
|
2
|
-
import {
|
|
3
|
-
import { ClientOnly } from './ClientOnly'
|
|
2
|
+
import { isModuleNotFoundError } from '@tanstack/router-core'
|
|
4
3
|
import type { AsyncRouteComponent } from './route'
|
|
5
4
|
|
|
6
|
-
// If the load fails due to module not found, it may mean a new version of
|
|
7
|
-
// the build was deployed and the user's browser is still using an old version.
|
|
8
|
-
// If this happens, the old version in the user's browser would have an outdated
|
|
9
|
-
// URL to the lazy module.
|
|
10
|
-
// In that case, we want to attempt one window refresh to get the latest.
|
|
11
|
-
function isModuleNotFoundError(error: any): boolean {
|
|
12
|
-
// chrome: "Failed to fetch dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split"
|
|
13
|
-
// firefox: "error loading dynamically imported module: http://localhost:5173/src/routes/posts.index.tsx?tsr-split"
|
|
14
|
-
// safari: "Importing a module script failed."
|
|
15
|
-
if (typeof error?.message !== 'string') return false
|
|
16
|
-
return (
|
|
17
|
-
error.message.startsWith('Failed to fetch dynamically imported module') ||
|
|
18
|
-
error.message.startsWith('error loading dynamically imported module') ||
|
|
19
|
-
error.message.startsWith('Importing a module script failed')
|
|
20
|
-
)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
5
|
export function lazyRouteComponent<
|
|
24
6
|
T extends Record<string, any>,
|
|
25
7
|
TKey extends keyof T = 'default',
|
|
26
8
|
>(
|
|
27
9
|
importer: () => Promise<T>,
|
|
28
10
|
exportName?: TKey,
|
|
29
|
-
ssr?: () => boolean,
|
|
30
11
|
): T[TKey] extends (props: infer TProps) => any
|
|
31
12
|
? AsyncRouteComponent<TProps>
|
|
32
13
|
: never {
|
|
@@ -36,10 +17,6 @@ export function lazyRouteComponent<
|
|
|
36
17
|
let reload: boolean
|
|
37
18
|
|
|
38
19
|
const load = () => {
|
|
39
|
-
if (typeof document === 'undefined' && ssr?.() === false) {
|
|
40
|
-
comp = (() => null) as any
|
|
41
|
-
return Promise.resolve()
|
|
42
|
-
}
|
|
43
20
|
if (!loadPromise) {
|
|
44
21
|
loadPromise = importer()
|
|
45
22
|
.then((res) => {
|
|
@@ -51,6 +28,11 @@ export function lazyRouteComponent<
|
|
|
51
28
|
// there's nothing we want to do about module not found during preload.
|
|
52
29
|
// Record the error, the rest is handled during the render path.
|
|
53
30
|
error = err
|
|
31
|
+
// If the load fails due to module not found, it may mean a new version of
|
|
32
|
+
// the build was deployed and the user's browser is still using an old version.
|
|
33
|
+
// If this happens, the old version in the user's browser would have an outdated
|
|
34
|
+
// URL to the lazy module.
|
|
35
|
+
// In that case, we want to attempt one window refresh to get the latest.
|
|
54
36
|
if (isModuleNotFoundError(error)) {
|
|
55
37
|
if (
|
|
56
38
|
error instanceof Error &&
|
|
@@ -91,13 +73,6 @@ export function lazyRouteComponent<
|
|
|
91
73
|
throw load()
|
|
92
74
|
}
|
|
93
75
|
|
|
94
|
-
if (ssr?.() === false) {
|
|
95
|
-
return (
|
|
96
|
-
<ClientOnly fallback={<Outlet />}>
|
|
97
|
-
{React.createElement(comp, props)}
|
|
98
|
-
</ClientOnly>
|
|
99
|
-
)
|
|
100
|
-
}
|
|
101
76
|
return React.createElement(comp, props)
|
|
102
77
|
}
|
|
103
78
|
|
package/src/link.tsx
CHANGED
|
@@ -10,17 +10,12 @@ import {
|
|
|
10
10
|
import { useRouterState } from './useRouterState'
|
|
11
11
|
import { useRouter } from './useRouter'
|
|
12
12
|
|
|
13
|
-
import {
|
|
14
|
-
useForwardedRef,
|
|
15
|
-
useIntersectionObserver,
|
|
16
|
-
useLayoutEffect,
|
|
17
|
-
} from './utils'
|
|
13
|
+
import { useForwardedRef, useIntersectionObserver } from './utils'
|
|
18
14
|
|
|
19
15
|
import { useMatch } from './useMatch'
|
|
20
16
|
import type {
|
|
21
17
|
AnyRouter,
|
|
22
18
|
Constrain,
|
|
23
|
-
LinkCurrentTargetElement,
|
|
24
19
|
LinkOptions,
|
|
25
20
|
RegisteredRouter,
|
|
26
21
|
RoutePaths,
|
|
@@ -48,8 +43,8 @@ export function useLinkProps<
|
|
|
48
43
|
|
|
49
44
|
const {
|
|
50
45
|
// custom props
|
|
51
|
-
activeProps
|
|
52
|
-
inactiveProps
|
|
46
|
+
activeProps,
|
|
47
|
+
inactiveProps,
|
|
53
48
|
activeOptions,
|
|
54
49
|
to,
|
|
55
50
|
preload: userPreload,
|
|
@@ -71,10 +66,6 @@ export function useLinkProps<
|
|
|
71
66
|
onMouseLeave,
|
|
72
67
|
onTouchStart,
|
|
73
68
|
ignoreBlocker,
|
|
74
|
-
...rest
|
|
75
|
-
} = options
|
|
76
|
-
|
|
77
|
-
const {
|
|
78
69
|
// prevent these from being returned
|
|
79
70
|
params: _params,
|
|
80
71
|
search: _search,
|
|
@@ -82,8 +73,11 @@ export function useLinkProps<
|
|
|
82
73
|
state: _state,
|
|
83
74
|
mask: _mask,
|
|
84
75
|
reloadDocument: _reloadDocument,
|
|
76
|
+
unsafeRelative: _unsafeRelative,
|
|
77
|
+
from: _from,
|
|
78
|
+
_fromLocation,
|
|
85
79
|
...propsSafeToSpread
|
|
86
|
-
} =
|
|
80
|
+
} = options
|
|
87
81
|
|
|
88
82
|
// If this link simply reloads the current route,
|
|
89
83
|
// make sure it has a new key so it will trigger a data refresh
|
|
@@ -93,7 +87,7 @@ export function useLinkProps<
|
|
|
93
87
|
|
|
94
88
|
const type: 'internal' | 'external' = React.useMemo(() => {
|
|
95
89
|
try {
|
|
96
|
-
new URL(
|
|
90
|
+
new URL(to as any)
|
|
97
91
|
return 'external'
|
|
98
92
|
} catch {}
|
|
99
93
|
return 'internal'
|
|
@@ -105,33 +99,41 @@ export function useLinkProps<
|
|
|
105
99
|
structuralSharing: true as any,
|
|
106
100
|
})
|
|
107
101
|
|
|
108
|
-
const
|
|
102
|
+
const from = useMatch({
|
|
109
103
|
strict: false,
|
|
110
|
-
select: (match) => match.fullPath,
|
|
104
|
+
select: (match) => options.from ?? match.fullPath,
|
|
111
105
|
})
|
|
112
106
|
|
|
113
|
-
const from = options.from ?? nearestFrom
|
|
114
|
-
|
|
115
|
-
// Use it as the default `from` location
|
|
116
|
-
options = { ...options, from }
|
|
117
|
-
|
|
118
107
|
const next = React.useMemo(
|
|
119
|
-
() => router.buildLocation(options as any),
|
|
108
|
+
() => router.buildLocation({ ...options, from } as any),
|
|
120
109
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
121
|
-
[
|
|
110
|
+
[
|
|
111
|
+
router,
|
|
112
|
+
currentSearch,
|
|
113
|
+
options._fromLocation,
|
|
114
|
+
from,
|
|
115
|
+
options.hash,
|
|
116
|
+
options.to,
|
|
117
|
+
options.search,
|
|
118
|
+
options.params,
|
|
119
|
+
options.state,
|
|
120
|
+
options.mask,
|
|
121
|
+
options.unsafeRelative,
|
|
122
|
+
],
|
|
122
123
|
)
|
|
123
124
|
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
125
|
+
const isExternal = type === 'external'
|
|
126
|
+
|
|
127
|
+
const preload =
|
|
128
|
+
options.reloadDocument || isExternal
|
|
129
|
+
? false
|
|
130
|
+
: (userPreload ?? router.options.defaultPreload)
|
|
130
131
|
const preloadDelay =
|
|
131
132
|
userPreloadDelay ?? router.options.defaultPreloadDelay ?? 0
|
|
132
133
|
|
|
133
134
|
const isActive = useRouterState({
|
|
134
135
|
select: (s) => {
|
|
136
|
+
if (isExternal) return false
|
|
135
137
|
if (activeOptions?.exact) {
|
|
136
138
|
const testExact = exactPathTest(
|
|
137
139
|
s.location.pathname,
|
|
@@ -145,15 +147,17 @@ export function useLinkProps<
|
|
|
145
147
|
const currentPathSplit = removeTrailingSlash(
|
|
146
148
|
s.location.pathname,
|
|
147
149
|
router.basepath,
|
|
148
|
-
)
|
|
150
|
+
)
|
|
149
151
|
const nextPathSplit = removeTrailingSlash(
|
|
150
152
|
next.pathname,
|
|
151
153
|
router.basepath,
|
|
152
|
-
).split('/')
|
|
153
|
-
|
|
154
|
-
const pathIsFuzzyEqual = nextPathSplit.every(
|
|
155
|
-
(d, i) => d === currentPathSplit[i],
|
|
156
154
|
)
|
|
155
|
+
|
|
156
|
+
const pathIsFuzzyEqual =
|
|
157
|
+
currentPathSplit.startsWith(nextPathSplit) &&
|
|
158
|
+
(currentPathSplit.length === nextPathSplit.length ||
|
|
159
|
+
currentPathSplit[nextPathSplit.length] === '/')
|
|
160
|
+
|
|
157
161
|
if (!pathIsFuzzyEqual) {
|
|
158
162
|
return false
|
|
159
163
|
}
|
|
@@ -176,12 +180,34 @@ export function useLinkProps<
|
|
|
176
180
|
},
|
|
177
181
|
})
|
|
178
182
|
|
|
179
|
-
const doPreload = React.useCallback(
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
183
|
+
const doPreload = React.useCallback(
|
|
184
|
+
() => {
|
|
185
|
+
router.preloadRoute({ ...options, from } as any).catch((err) => {
|
|
186
|
+
console.warn(err)
|
|
187
|
+
console.warn(preloadWarning)
|
|
188
|
+
})
|
|
189
|
+
},
|
|
190
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
191
|
+
[
|
|
192
|
+
router,
|
|
193
|
+
options.to,
|
|
194
|
+
options._fromLocation,
|
|
195
|
+
from,
|
|
196
|
+
options.search,
|
|
197
|
+
options.hash,
|
|
198
|
+
options.params,
|
|
199
|
+
options.state,
|
|
200
|
+
options.mask,
|
|
201
|
+
options.unsafeRelative,
|
|
202
|
+
options.hashScrollIntoView,
|
|
203
|
+
options.href,
|
|
204
|
+
options.ignoreBlocker,
|
|
205
|
+
options.reloadDocument,
|
|
206
|
+
options.replace,
|
|
207
|
+
options.resetScroll,
|
|
208
|
+
options.viewTransition,
|
|
209
|
+
],
|
|
210
|
+
)
|
|
185
211
|
|
|
186
212
|
const preloadViewportIoCallback = React.useCallback(
|
|
187
213
|
(entry: IntersectionObserverEntry | undefined) => {
|
|
@@ -195,11 +221,11 @@ export function useLinkProps<
|
|
|
195
221
|
useIntersectionObserver(
|
|
196
222
|
innerRef,
|
|
197
223
|
preloadViewportIoCallback,
|
|
198
|
-
|
|
224
|
+
intersectionObserverOptions,
|
|
199
225
|
{ disabled: !!disabled || !(preload === 'viewport') },
|
|
200
226
|
)
|
|
201
227
|
|
|
202
|
-
|
|
228
|
+
React.useEffect(() => {
|
|
203
229
|
if (hasRenderFetched.current) {
|
|
204
230
|
return
|
|
205
231
|
}
|
|
@@ -209,7 +235,7 @@ export function useLinkProps<
|
|
|
209
235
|
}
|
|
210
236
|
}, [disabled, doPreload, preload])
|
|
211
237
|
|
|
212
|
-
if (
|
|
238
|
+
if (isExternal) {
|
|
213
239
|
return {
|
|
214
240
|
...propsSafeToSpread,
|
|
215
241
|
ref: innerRef as React.ComponentPropsWithRef<'a'>['ref'],
|
|
@@ -229,7 +255,7 @@ export function useLinkProps<
|
|
|
229
255
|
}
|
|
230
256
|
|
|
231
257
|
// The click handler
|
|
232
|
-
const handleClick = (e: MouseEvent) => {
|
|
258
|
+
const handleClick = (e: React.MouseEvent) => {
|
|
233
259
|
if (
|
|
234
260
|
!disabled &&
|
|
235
261
|
!isCtrlEvent(e) &&
|
|
@@ -250,8 +276,9 @@ export function useLinkProps<
|
|
|
250
276
|
|
|
251
277
|
// All is well? Navigate!
|
|
252
278
|
// N.B. we don't call `router.commitLocation(next) here because we want to run `validateSearch` before committing
|
|
253
|
-
|
|
279
|
+
router.navigate({
|
|
254
280
|
...options,
|
|
281
|
+
from,
|
|
255
282
|
replace,
|
|
256
283
|
resetScroll,
|
|
257
284
|
hashScrollIntoView,
|
|
@@ -263,7 +290,7 @@ export function useLinkProps<
|
|
|
263
290
|
}
|
|
264
291
|
|
|
265
292
|
// The click handler
|
|
266
|
-
const handleFocus = (_: MouseEvent) => {
|
|
293
|
+
const handleFocus = (_: React.MouseEvent) => {
|
|
267
294
|
if (disabled) return
|
|
268
295
|
if (preload) {
|
|
269
296
|
doPreload()
|
|
@@ -272,54 +299,44 @@ export function useLinkProps<
|
|
|
272
299
|
|
|
273
300
|
const handleTouchStart = handleFocus
|
|
274
301
|
|
|
275
|
-
const handleEnter = (e: MouseEvent) => {
|
|
276
|
-
if (disabled) return
|
|
277
|
-
const eventTarget = (e.target || {}) as LinkCurrentTargetElement
|
|
302
|
+
const handleEnter = (e: React.MouseEvent) => {
|
|
303
|
+
if (disabled || !preload) return
|
|
278
304
|
|
|
279
|
-
if (
|
|
280
|
-
|
|
305
|
+
if (!preloadDelay) {
|
|
306
|
+
doPreload()
|
|
307
|
+
} else {
|
|
308
|
+
const eventTarget = e.target
|
|
309
|
+
if (timeoutMap.has(eventTarget)) {
|
|
281
310
|
return
|
|
282
311
|
}
|
|
283
|
-
|
|
284
|
-
|
|
312
|
+
const id = setTimeout(() => {
|
|
313
|
+
timeoutMap.delete(eventTarget)
|
|
285
314
|
doPreload()
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
eventTarget.preloadTimeout = null
|
|
289
|
-
doPreload()
|
|
290
|
-
}, preloadDelay)
|
|
291
|
-
}
|
|
315
|
+
}, preloadDelay)
|
|
316
|
+
timeoutMap.set(eventTarget, id)
|
|
292
317
|
}
|
|
293
318
|
}
|
|
294
319
|
|
|
295
|
-
const handleLeave = (e: MouseEvent) => {
|
|
296
|
-
if (disabled) return
|
|
297
|
-
const eventTarget =
|
|
298
|
-
|
|
299
|
-
if (
|
|
300
|
-
clearTimeout(
|
|
301
|
-
eventTarget
|
|
320
|
+
const handleLeave = (e: React.MouseEvent) => {
|
|
321
|
+
if (disabled || !preload || !preloadDelay) return
|
|
322
|
+
const eventTarget = e.target
|
|
323
|
+
const id = timeoutMap.get(eventTarget)
|
|
324
|
+
if (id) {
|
|
325
|
+
clearTimeout(id)
|
|
326
|
+
timeoutMap.delete(eventTarget)
|
|
302
327
|
}
|
|
303
328
|
}
|
|
304
329
|
|
|
305
|
-
const composeHandlers =
|
|
306
|
-
(handlers: Array<undefined | ((e: any) => void)>) =>
|
|
307
|
-
(e: { persist?: () => void; defaultPrevented: boolean }) => {
|
|
308
|
-
e.persist?.()
|
|
309
|
-
handlers.filter(Boolean).forEach((handler) => {
|
|
310
|
-
if (e.defaultPrevented) return
|
|
311
|
-
handler!(e)
|
|
312
|
-
})
|
|
313
|
-
}
|
|
314
|
-
|
|
315
330
|
// Get the active props
|
|
316
331
|
const resolvedActiveProps: React.HTMLAttributes<HTMLAnchorElement> = isActive
|
|
317
|
-
? (functionalUpdate(activeProps as any, {}) ??
|
|
318
|
-
:
|
|
332
|
+
? (functionalUpdate(activeProps as any, {}) ?? STATIC_ACTIVE_OBJECT)
|
|
333
|
+
: STATIC_EMPTY_OBJECT
|
|
319
334
|
|
|
320
335
|
// Get the inactive props
|
|
321
336
|
const resolvedInactiveProps: React.HTMLAttributes<HTMLAnchorElement> =
|
|
322
|
-
isActive
|
|
337
|
+
isActive
|
|
338
|
+
? STATIC_EMPTY_OBJECT
|
|
339
|
+
: (functionalUpdate(inactiveProps, {}) ?? STATIC_EMPTY_OBJECT)
|
|
323
340
|
|
|
324
341
|
const resolvedClassName = [
|
|
325
342
|
className,
|
|
@@ -329,7 +346,9 @@ export function useLinkProps<
|
|
|
329
346
|
.filter(Boolean)
|
|
330
347
|
.join(' ')
|
|
331
348
|
|
|
332
|
-
const resolvedStyle =
|
|
349
|
+
const resolvedStyle = (style ||
|
|
350
|
+
resolvedActiveProps.style ||
|
|
351
|
+
resolvedInactiveProps.style) && {
|
|
333
352
|
...style,
|
|
334
353
|
...resolvedActiveProps.style,
|
|
335
354
|
...resolvedInactiveProps.style,
|
|
@@ -352,29 +371,41 @@ export function useLinkProps<
|
|
|
352
371
|
onTouchStart: composeHandlers([onTouchStart, handleTouchStart]),
|
|
353
372
|
disabled: !!disabled,
|
|
354
373
|
target,
|
|
355
|
-
...(
|
|
374
|
+
...(resolvedStyle && { style: resolvedStyle }),
|
|
356
375
|
...(resolvedClassName && { className: resolvedClassName }),
|
|
357
|
-
...(disabled &&
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}),
|
|
361
|
-
...(isActive && { 'data-status': 'active', 'aria-current': 'page' }),
|
|
362
|
-
...(isTransitioning && { 'data-transitioning': 'transitioning' }),
|
|
376
|
+
...(disabled && STATIC_DISABLED_PROPS),
|
|
377
|
+
...(isActive && STATIC_ACTIVE_PROPS),
|
|
378
|
+
...(isTransitioning && STATIC_TRANSITIONING_PROPS),
|
|
363
379
|
}
|
|
364
380
|
}
|
|
365
381
|
|
|
382
|
+
const STATIC_EMPTY_OBJECT = {}
|
|
383
|
+
const STATIC_ACTIVE_OBJECT = { className: 'active' }
|
|
384
|
+
const STATIC_DISABLED_PROPS = { role: 'link', 'aria-disabled': true }
|
|
385
|
+
const STATIC_ACTIVE_PROPS = { 'data-status': 'active', 'aria-current': 'page' }
|
|
386
|
+
const STATIC_TRANSITIONING_PROPS = { 'data-transitioning': 'transitioning' }
|
|
387
|
+
|
|
388
|
+
const timeoutMap = new WeakMap<EventTarget, ReturnType<typeof setTimeout>>()
|
|
389
|
+
|
|
390
|
+
const intersectionObserverOptions: IntersectionObserverInit = {
|
|
391
|
+
rootMargin: '100px',
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const composeHandlers =
|
|
395
|
+
(handlers: Array<undefined | React.EventHandler<any>>) =>
|
|
396
|
+
(e: React.SyntheticEvent) => {
|
|
397
|
+
handlers.filter(Boolean).forEach((handler) => {
|
|
398
|
+
if (e.defaultPrevented) return
|
|
399
|
+
handler!(e)
|
|
400
|
+
})
|
|
401
|
+
}
|
|
402
|
+
|
|
366
403
|
type UseLinkReactProps<TComp> = TComp extends keyof React.JSX.IntrinsicElements
|
|
367
404
|
? React.JSX.IntrinsicElements[TComp]
|
|
368
|
-
: React.
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
TComp extends
|
|
373
|
-
| React.FC<{ ref: React.Ref<infer TRef> }>
|
|
374
|
-
| React.Component<{ ref: React.Ref<infer TRef> }>
|
|
375
|
-
? TRef
|
|
376
|
-
: never
|
|
377
|
-
>
|
|
405
|
+
: TComp extends React.ComponentType<any>
|
|
406
|
+
? React.ComponentPropsWithoutRef<TComp> &
|
|
407
|
+
React.RefAttributes<React.ComponentRef<TComp>>
|
|
408
|
+
: never
|
|
378
409
|
|
|
379
410
|
export type UseLinkPropsOptions<
|
|
380
411
|
TRouter extends AnyRouter = RegisteredRouter,
|
|
@@ -515,7 +546,7 @@ export const Link: LinkComponent<'a'> = React.forwardRef<Element, any>(
|
|
|
515
546
|
})
|
|
516
547
|
: rest.children
|
|
517
548
|
|
|
518
|
-
if (
|
|
549
|
+
if (_asChild === undefined) {
|
|
519
550
|
// the ReturnType of useLinkProps returns the correct type for a <a> element, not a general component that has a disabled prop
|
|
520
551
|
// @ts-expect-error
|
|
521
552
|
delete linkProps.disabled
|
|
@@ -532,7 +563,7 @@ export const Link: LinkComponent<'a'> = React.forwardRef<Element, any>(
|
|
|
532
563
|
},
|
|
533
564
|
) as any
|
|
534
565
|
|
|
535
|
-
function isCtrlEvent(e: MouseEvent) {
|
|
566
|
+
function isCtrlEvent(e: React.MouseEvent) {
|
|
536
567
|
return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey)
|
|
537
568
|
}
|
|
538
569
|
|
package/src/not-found.tsx
CHANGED
package/src/route.tsx
CHANGED
|
@@ -54,6 +54,14 @@ declare module '@tanstack/router-core' {
|
|
|
54
54
|
pendingComponent?: RouteComponent
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
export interface RootRouteOptionsExtensions {
|
|
58
|
+
shellComponent?: ({
|
|
59
|
+
children,
|
|
60
|
+
}: {
|
|
61
|
+
children: React.ReactNode
|
|
62
|
+
}) => React.ReactNode
|
|
63
|
+
}
|
|
64
|
+
|
|
57
65
|
export interface RouteExtensions<
|
|
58
66
|
in out TId extends string,
|
|
59
67
|
in out TFullPath extends string,
|
|
@@ -534,21 +542,22 @@ export function createRouteMask<
|
|
|
534
542
|
return opts as any
|
|
535
543
|
}
|
|
536
544
|
|
|
537
|
-
export
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
545
|
+
export interface DefaultRouteTypes<TProps> {
|
|
546
|
+
component:
|
|
547
|
+
| ((props: TProps) => any)
|
|
548
|
+
| React.LazyExoticComponent<(props: TProps) => any>
|
|
549
|
+
}
|
|
550
|
+
export interface RouteTypes<TProps> extends DefaultRouteTypes<TProps> {}
|
|
542
551
|
|
|
543
|
-
export type AsyncRouteComponent<TProps> =
|
|
552
|
+
export type AsyncRouteComponent<TProps> = RouteTypes<TProps>['component'] & {
|
|
544
553
|
preload?: () => Promise<void>
|
|
545
554
|
}
|
|
546
555
|
|
|
547
|
-
export type RouteComponent
|
|
556
|
+
export type RouteComponent = AsyncRouteComponent<{}>
|
|
548
557
|
|
|
549
|
-
export type ErrorRouteComponent =
|
|
558
|
+
export type ErrorRouteComponent = AsyncRouteComponent<ErrorComponentProps>
|
|
550
559
|
|
|
551
|
-
export type NotFoundRouteComponent =
|
|
560
|
+
export type NotFoundRouteComponent = RouteTypes<NotFoundRouteProps>['component']
|
|
552
561
|
|
|
553
562
|
export class NotFoundRoute<
|
|
554
563
|
TParentRoute extends AnyRootRoute,
|
|
@@ -14,16 +14,23 @@ export function ScrollRestoration() {
|
|
|
14
14
|
const resolvedKey =
|
|
15
15
|
userKey !== defaultGetScrollRestorationKey(router.latestLocation)
|
|
16
16
|
? userKey
|
|
17
|
-
:
|
|
17
|
+
: undefined
|
|
18
18
|
|
|
19
19
|
if (!router.isScrollRestoring || !router.isServer) {
|
|
20
20
|
return null
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
const restoreScrollOptions: Parameters<typeof restoreScroll>[0] = {
|
|
24
|
+
storageKey,
|
|
25
|
+
shouldScrollRestoration: true,
|
|
26
|
+
}
|
|
27
|
+
if (resolvedKey) {
|
|
28
|
+
restoreScrollOptions.key = resolvedKey
|
|
29
|
+
}
|
|
30
|
+
|
|
23
31
|
return (
|
|
24
32
|
<ScriptOnce
|
|
25
|
-
children={`(${restoreScroll.toString()})(${JSON.stringify(
|
|
26
|
-
log={false}
|
|
33
|
+
children={`(${restoreScroll.toString()})(${JSON.stringify(restoreScrollOptions)})`}
|
|
27
34
|
/>
|
|
28
35
|
)
|
|
29
36
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { hydrate } from '@tanstack/router-core/ssr/client'
|
|
2
|
+
import { Await } from '../awaited'
|
|
3
|
+
import { RouterProvider } from '../RouterProvider'
|
|
4
|
+
import type { AnyRouter } from '@tanstack/router-core'
|
|
5
|
+
|
|
6
|
+
let hydrationPromise: Promise<void | Array<Array<void>>> | undefined
|
|
7
|
+
|
|
8
|
+
export function RouterClient(props: { router: AnyRouter }) {
|
|
9
|
+
if (!hydrationPromise) {
|
|
10
|
+
if (!props.router.state.matches.length) {
|
|
11
|
+
hydrationPromise = hydrate(props.router)
|
|
12
|
+
} else {
|
|
13
|
+
hydrationPromise = Promise.resolve()
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return (
|
|
17
|
+
<Await
|
|
18
|
+
promise={hydrationPromise}
|
|
19
|
+
children={() => <RouterProvider router={props.router} />}
|
|
20
|
+
/>
|
|
21
|
+
)
|
|
22
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { RouterProvider } from '../RouterProvider'
|
|
3
|
+
import type { AnyRouter } from '@tanstack/router-core'
|
|
4
|
+
|
|
5
|
+
export function RouterServer<TRouter extends AnyRouter>(props: {
|
|
6
|
+
router: TRouter
|
|
7
|
+
}) {
|
|
8
|
+
return <RouterProvider router={props.router} />
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { defineHandlerCallback } from '@tanstack/router-core/ssr/server'
|
|
2
|
+
import { renderRouterToString } from './renderRouterToString'
|
|
3
|
+
import { RouterServer } from './RouterServer'
|
|
4
|
+
|
|
5
|
+
export const defaultRenderHandler = defineHandlerCallback(
|
|
6
|
+
({ router, responseHeaders }) =>
|
|
7
|
+
renderRouterToString({
|
|
8
|
+
router,
|
|
9
|
+
responseHeaders,
|
|
10
|
+
children: <RouterServer router={router} />,
|
|
11
|
+
}),
|
|
12
|
+
)
|