@tanstack/react-router 1.104.1 → 1.105.5
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 +41 -0
- package/dist/cjs/Asset.cjs.map +1 -0
- package/dist/cjs/Asset.d.cts +2 -0
- package/dist/cjs/HeadContent.cjs +138 -0
- package/dist/cjs/HeadContent.cjs.map +1 -0
- package/dist/cjs/HeadContent.d.cts +7 -0
- package/dist/cjs/Matches.cjs.map +1 -1
- package/dist/cjs/Matches.d.cts +1 -0
- package/dist/cjs/Scripts.cjs +50 -0
- package/dist/cjs/Scripts.cjs.map +1 -0
- package/dist/cjs/Scripts.d.cts +1 -0
- package/dist/cjs/index.cjs +6 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +3 -0
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/route.d.cts +10 -7
- package/dist/cjs/router.cjs +19 -13
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/useNavigate.cjs +9 -5
- package/dist/cjs/useNavigate.cjs.map +1 -1
- package/dist/esm/Asset.d.ts +2 -0
- package/dist/esm/Asset.js +41 -0
- package/dist/esm/Asset.js.map +1 -0
- package/dist/esm/HeadContent.d.ts +7 -0
- package/dist/esm/HeadContent.js +122 -0
- package/dist/esm/HeadContent.js.map +1 -0
- package/dist/esm/Matches.d.ts +1 -0
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/Scripts.d.ts +1 -0
- package/dist/esm/Scripts.js +50 -0
- package/dist/esm/Scripts.js.map +1 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/route.d.ts +10 -7
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/router.js +19 -13
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/useNavigate.js +9 -5
- package/dist/esm/useNavigate.js.map +1 -1
- package/package.json +1 -1
- package/src/Asset.tsx +40 -0
- package/src/HeadContent.tsx +151 -0
- package/src/Matches.tsx +1 -0
- package/src/Scripts.tsx +64 -0
- package/src/index.tsx +4 -0
- package/src/route.ts +71 -32
- package/src/router.ts +14 -8
- package/src/useNavigate.tsx +15 -6
package/dist/esm/useNavigate.js
CHANGED
|
@@ -12,12 +12,16 @@ function useNavigate(_defaultOpts) {
|
|
|
12
12
|
);
|
|
13
13
|
}
|
|
14
14
|
function Navigate(props) {
|
|
15
|
-
const
|
|
15
|
+
const router = useRouter();
|
|
16
|
+
const previousPropsRef = React.useRef(null);
|
|
16
17
|
React.useEffect(() => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
if (previousPropsRef.current !== props) {
|
|
19
|
+
router.navigate({
|
|
20
|
+
...props
|
|
21
|
+
});
|
|
22
|
+
previousPropsRef.current = props;
|
|
23
|
+
}
|
|
24
|
+
}, [router, props]);
|
|
21
25
|
return null;
|
|
22
26
|
}
|
|
23
27
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useNavigate.js","sources":["../../src/useNavigate.tsx"],"sourcesContent":["import * as React from 'react'\nimport { useRouter } from './useRouter'\nimport type { FromPathOption, NavigateOptions } from './link'\nimport type { AnyRouter, RegisteredRouter } from './router'\n\nexport type UseNavigateResult<TDefaultFrom extends string> = <\n TRouter extends RegisteredRouter,\n TTo extends string | undefined,\n TFrom extends string = TDefaultFrom,\n TMaskFrom extends string = TFrom,\n TMaskTo extends string = '',\n>({\n from,\n ...rest\n}: NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>) => Promise<void>\n\nexport function useNavigate<\n TRouter extends AnyRouter = RegisteredRouter,\n TDefaultFrom extends string = string,\n>(_defaultOpts?: {\n from?: FromPathOption<TRouter, TDefaultFrom>\n}): UseNavigateResult<TDefaultFrom> {\n const { navigate } = useRouter()\n\n return React.useCallback(\n (options: NavigateOptions) => {\n return navigate({\n ...options,\n })\n },\n [navigate],\n ) as UseNavigateResult<TDefaultFrom>\n}\n\n// NOTE: I don't know of anyone using this. It's undocumented, so let's wait until someone needs it\n// export function typedNavigate<\n// TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],\n// TDefaultFrom extends RoutePaths<TRouteTree> = '/',\n// >(navigate: (opts: NavigateOptions<any>) => Promise<void>) {\n// return navigate as <\n// TFrom extends RoutePaths<TRouteTree> = TDefaultFrom,\n// TTo extends string = '',\n// TMaskFrom extends RoutePaths<TRouteTree> = '/',\n// TMaskTo extends string = '',\n// >(\n// opts?: NavigateOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo>,\n// ) => Promise<void>\n// } //\n\nexport function Navigate<\n TRouter extends AnyRouter = RegisteredRouter,\n const TFrom extends string = string,\n const TTo extends string | undefined = undefined,\n const TMaskFrom extends string = TFrom,\n const TMaskTo extends string = '',\n>(props: NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>): null {\n const
|
|
1
|
+
{"version":3,"file":"useNavigate.js","sources":["../../src/useNavigate.tsx"],"sourcesContent":["import * as React from 'react'\nimport { useRouter } from './useRouter'\nimport type { FromPathOption, NavigateOptions } from './link'\nimport type { AnyRouter, RegisteredRouter } from './router'\n\nexport type UseNavigateResult<TDefaultFrom extends string> = <\n TRouter extends RegisteredRouter,\n TTo extends string | undefined,\n TFrom extends string = TDefaultFrom,\n TMaskFrom extends string = TFrom,\n TMaskTo extends string = '',\n>({\n from,\n ...rest\n}: NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>) => Promise<void>\n\nexport function useNavigate<\n TRouter extends AnyRouter = RegisteredRouter,\n TDefaultFrom extends string = string,\n>(_defaultOpts?: {\n from?: FromPathOption<TRouter, TDefaultFrom>\n}): UseNavigateResult<TDefaultFrom> {\n const { navigate } = useRouter()\n\n return React.useCallback(\n (options: NavigateOptions) => {\n return navigate({\n ...options,\n })\n },\n [navigate],\n ) as UseNavigateResult<TDefaultFrom>\n}\n\n// NOTE: I don't know of anyone using this. It's undocumented, so let's wait until someone needs it\n// export function typedNavigate<\n// TRouteTree extends AnyRoute = RegisteredRouter['routeTree'],\n// TDefaultFrom extends RoutePaths<TRouteTree> = '/',\n// >(navigate: (opts: NavigateOptions<any>) => Promise<void>) {\n// return navigate as <\n// TFrom extends RoutePaths<TRouteTree> = TDefaultFrom,\n// TTo extends string = '',\n// TMaskFrom extends RoutePaths<TRouteTree> = '/',\n// TMaskTo extends string = '',\n// >(\n// opts?: NavigateOptions<TRouteTree, TFrom, TTo, TMaskFrom, TMaskTo>,\n// ) => Promise<void>\n// } //\n\nexport function Navigate<\n TRouter extends AnyRouter = RegisteredRouter,\n const TFrom extends string = string,\n const TTo extends string | undefined = undefined,\n const TMaskFrom extends string = TFrom,\n const TMaskTo extends string = '',\n>(props: NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>): null {\n const router = useRouter()\n\n const previousPropsRef = React.useRef<NavigateOptions<\n TRouter,\n TFrom,\n TTo,\n TMaskFrom,\n TMaskTo\n > | null>(null)\n React.useEffect(() => {\n if (previousPropsRef.current !== props) {\n router.navigate({\n ...props,\n })\n previousPropsRef.current = props\n }\n }, [router, props])\n return null\n}\n"],"names":[],"mappings":";;AAgBO,SAAS,YAGd,cAEkC;AAC5B,QAAA,EAAE,SAAS,IAAI,UAAU;AAE/B,SAAO,MAAM;AAAA,IACX,CAAC,YAA6B;AAC5B,aAAO,SAAS;AAAA,QACd,GAAG;AAAA,MAAA,CACJ;AAAA,IACH;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AACF;AAiBO,SAAS,SAMd,OAAuE;AACvE,QAAM,SAAS,UAAU;AAEnB,QAAA,mBAAmB,MAAM,OAMrB,IAAI;AACd,QAAM,UAAU,MAAM;AAChB,QAAA,iBAAiB,YAAY,OAAO;AACtC,aAAO,SAAS;AAAA,QACd,GAAG;AAAA,MAAA,CACJ;AACD,uBAAiB,UAAU;AAAA,IAAA;AAAA,EAC7B,GACC,CAAC,QAAQ,KAAK,CAAC;AACX,SAAA;AACT;"}
|
package/package.json
CHANGED
package/src/Asset.tsx
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { RouterManagedTag } from '@tanstack/router-core'
|
|
2
|
+
|
|
3
|
+
export function Asset({ tag, attrs, children }: RouterManagedTag): any {
|
|
4
|
+
switch (tag) {
|
|
5
|
+
case 'title':
|
|
6
|
+
return (
|
|
7
|
+
<title {...attrs} suppressHydrationWarning>
|
|
8
|
+
{children}
|
|
9
|
+
</title>
|
|
10
|
+
)
|
|
11
|
+
case 'meta':
|
|
12
|
+
return <meta {...attrs} suppressHydrationWarning />
|
|
13
|
+
case 'link':
|
|
14
|
+
return <link {...attrs} suppressHydrationWarning />
|
|
15
|
+
case 'style':
|
|
16
|
+
return (
|
|
17
|
+
<style
|
|
18
|
+
{...attrs}
|
|
19
|
+
dangerouslySetInnerHTML={{ __html: children as any }}
|
|
20
|
+
/>
|
|
21
|
+
)
|
|
22
|
+
case 'script':
|
|
23
|
+
if ((attrs as any) && (attrs as any).src) {
|
|
24
|
+
return <script {...attrs} suppressHydrationWarning />
|
|
25
|
+
}
|
|
26
|
+
if (typeof children === 'string')
|
|
27
|
+
return (
|
|
28
|
+
<script
|
|
29
|
+
{...attrs}
|
|
30
|
+
dangerouslySetInnerHTML={{
|
|
31
|
+
__html: children,
|
|
32
|
+
}}
|
|
33
|
+
suppressHydrationWarning
|
|
34
|
+
/>
|
|
35
|
+
)
|
|
36
|
+
return null
|
|
37
|
+
default:
|
|
38
|
+
return null
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { Asset } from './Asset'
|
|
3
|
+
import { useRouter } from './useRouter'
|
|
4
|
+
import { useRouterState } from './useRouterState'
|
|
5
|
+
import type { RouterManagedTag } from '@tanstack/router-core'
|
|
6
|
+
|
|
7
|
+
export const useTags = () => {
|
|
8
|
+
const router = useRouter()
|
|
9
|
+
|
|
10
|
+
const routeMeta = useRouterState({
|
|
11
|
+
select: (state) => {
|
|
12
|
+
return state.matches.map((match) => match.meta!).filter(Boolean)
|
|
13
|
+
},
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const meta: Array<RouterManagedTag> = React.useMemo(() => {
|
|
17
|
+
const resultMeta: Array<RouterManagedTag> = []
|
|
18
|
+
const metaByAttribute: Record<string, true> = {}
|
|
19
|
+
let title: RouterManagedTag | undefined
|
|
20
|
+
;[...routeMeta].reverse().forEach((metas) => {
|
|
21
|
+
;[...metas].reverse().forEach((m) => {
|
|
22
|
+
if (!m) return
|
|
23
|
+
|
|
24
|
+
if (m.title) {
|
|
25
|
+
if (!title) {
|
|
26
|
+
title = {
|
|
27
|
+
tag: 'title',
|
|
28
|
+
children: m.title,
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
} else {
|
|
32
|
+
const attribute = m.name ?? m.property
|
|
33
|
+
if (attribute) {
|
|
34
|
+
if (metaByAttribute[attribute]) {
|
|
35
|
+
return
|
|
36
|
+
} else {
|
|
37
|
+
metaByAttribute[attribute] = true
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
resultMeta.push({
|
|
42
|
+
tag: 'meta',
|
|
43
|
+
attrs: {
|
|
44
|
+
...m,
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
if (title) {
|
|
52
|
+
resultMeta.push(title)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
resultMeta.reverse()
|
|
56
|
+
|
|
57
|
+
return resultMeta
|
|
58
|
+
}, [routeMeta])
|
|
59
|
+
|
|
60
|
+
const links = useRouterState({
|
|
61
|
+
select: (state) =>
|
|
62
|
+
state.matches
|
|
63
|
+
.map((match) => match.links!)
|
|
64
|
+
.filter(Boolean)
|
|
65
|
+
.flat(1)
|
|
66
|
+
.map((link) => ({
|
|
67
|
+
tag: 'link',
|
|
68
|
+
attrs: {
|
|
69
|
+
...link,
|
|
70
|
+
},
|
|
71
|
+
})) as Array<RouterManagedTag>,
|
|
72
|
+
structuralSharing: true as any,
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const preloadMeta = useRouterState({
|
|
76
|
+
select: (state) => {
|
|
77
|
+
const preloadMeta: Array<RouterManagedTag> = []
|
|
78
|
+
|
|
79
|
+
state.matches
|
|
80
|
+
.map((match) => router.looseRoutesById[match.routeId]!)
|
|
81
|
+
.forEach((route) =>
|
|
82
|
+
router.ssr?.manifest?.routes[route.id]?.preloads
|
|
83
|
+
?.filter(Boolean)
|
|
84
|
+
.forEach((preload) => {
|
|
85
|
+
preloadMeta.push({
|
|
86
|
+
tag: 'link',
|
|
87
|
+
attrs: {
|
|
88
|
+
rel: 'modulepreload',
|
|
89
|
+
href: preload,
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
}),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
return preloadMeta
|
|
96
|
+
},
|
|
97
|
+
structuralSharing: true as any,
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
const headScripts = useRouterState({
|
|
101
|
+
select: (state) =>
|
|
102
|
+
(
|
|
103
|
+
state.matches
|
|
104
|
+
.map((match) => match.headScripts!)
|
|
105
|
+
.flat(1)
|
|
106
|
+
.filter(Boolean) as Array<RouterManagedTag>
|
|
107
|
+
).map(({ children, ...script }) => ({
|
|
108
|
+
tag: 'script',
|
|
109
|
+
attrs: {
|
|
110
|
+
...script,
|
|
111
|
+
},
|
|
112
|
+
children,
|
|
113
|
+
})),
|
|
114
|
+
structuralSharing: true as any,
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
return uniqBy(
|
|
118
|
+
[
|
|
119
|
+
...meta,
|
|
120
|
+
...preloadMeta,
|
|
121
|
+
...links,
|
|
122
|
+
...headScripts,
|
|
123
|
+
] as Array<RouterManagedTag>,
|
|
124
|
+
(d) => {
|
|
125
|
+
return JSON.stringify(d)
|
|
126
|
+
},
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @description The `HeadContent` component is used to render meta tags, links, and scripts for the current route.
|
|
132
|
+
* It should be rendered in the `<head>` of your document.
|
|
133
|
+
*/
|
|
134
|
+
export function HeadContent() {
|
|
135
|
+
const tags = useTags()
|
|
136
|
+
return tags.map((tag) => (
|
|
137
|
+
<Asset {...tag} key={`tsr-meta-${JSON.stringify(tag)}`} />
|
|
138
|
+
))
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function uniqBy<T>(arr: Array<T>, fn: (item: T) => string) {
|
|
142
|
+
const seen = new Set<string>()
|
|
143
|
+
return arr.filter((item) => {
|
|
144
|
+
const key = fn(item)
|
|
145
|
+
if (seen.has(key)) {
|
|
146
|
+
return false
|
|
147
|
+
}
|
|
148
|
+
seen.add(key)
|
|
149
|
+
return true
|
|
150
|
+
})
|
|
151
|
+
}
|
package/src/Matches.tsx
CHANGED
|
@@ -88,6 +88,7 @@ export interface RouteMatch<
|
|
|
88
88
|
meta?: Array<React.JSX.IntrinsicElements['meta'] | undefined>
|
|
89
89
|
links?: Array<React.JSX.IntrinsicElements['link'] | undefined>
|
|
90
90
|
scripts?: Array<React.JSX.IntrinsicElements['script'] | undefined>
|
|
91
|
+
headScripts?: Array<React.JSX.IntrinsicElements['script'] | undefined>
|
|
91
92
|
headers?: Record<string, string>
|
|
92
93
|
globalNotFound?: boolean
|
|
93
94
|
staticData: StaticDataRouteOption
|
package/src/Scripts.tsx
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Asset } from './Asset'
|
|
2
|
+
import { useRouterState } from './useRouterState'
|
|
3
|
+
import { useRouter } from './useRouter'
|
|
4
|
+
import type { RouterManagedTag } from '@tanstack/router-core'
|
|
5
|
+
|
|
6
|
+
export const Scripts = () => {
|
|
7
|
+
const router = useRouter()
|
|
8
|
+
|
|
9
|
+
const assetScripts = useRouterState({
|
|
10
|
+
select: (state) => {
|
|
11
|
+
const assetScripts: Array<RouterManagedTag> = []
|
|
12
|
+
const manifest = router.ssr?.manifest
|
|
13
|
+
|
|
14
|
+
if (!manifest) {
|
|
15
|
+
return []
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
state.matches
|
|
19
|
+
.map((match) => router.looseRoutesById[match.routeId]!)
|
|
20
|
+
.forEach((route) =>
|
|
21
|
+
manifest.routes[route.id]?.assets
|
|
22
|
+
?.filter((d) => d.tag === 'script')
|
|
23
|
+
.forEach((asset) => {
|
|
24
|
+
assetScripts.push({
|
|
25
|
+
tag: 'script',
|
|
26
|
+
attrs: asset.attrs,
|
|
27
|
+
children: asset.children,
|
|
28
|
+
} as any)
|
|
29
|
+
}),
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
return assetScripts
|
|
33
|
+
},
|
|
34
|
+
structuralSharing: true as any,
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
const { scripts } = useRouterState({
|
|
38
|
+
select: (state) => ({
|
|
39
|
+
scripts: (
|
|
40
|
+
state.matches
|
|
41
|
+
.map((match) => match.scripts!)
|
|
42
|
+
.flat(1)
|
|
43
|
+
.filter(Boolean) as Array<RouterManagedTag>
|
|
44
|
+
).map(({ children, ...script }) => ({
|
|
45
|
+
tag: 'script',
|
|
46
|
+
attrs: {
|
|
47
|
+
...script,
|
|
48
|
+
suppressHydrationWarning: true,
|
|
49
|
+
},
|
|
50
|
+
children,
|
|
51
|
+
})),
|
|
52
|
+
}),
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const allScripts = [...scripts, ...assetScripts] as Array<RouterManagedTag>
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<>
|
|
59
|
+
{allScripts.map((asset, i) => (
|
|
60
|
+
<Asset {...asset} key={`tsr-scripts-${asset.tag}-${i}`} />
|
|
61
|
+
))}
|
|
62
|
+
</>
|
|
63
|
+
)
|
|
64
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -356,3 +356,7 @@ export type { NotFoundError } from './not-found'
|
|
|
356
356
|
export * from './typePrimitives'
|
|
357
357
|
|
|
358
358
|
export { ScriptOnce } from './ScriptOnce'
|
|
359
|
+
|
|
360
|
+
export { Asset } from './Asset'
|
|
361
|
+
export { HeadContent } from './HeadContent'
|
|
362
|
+
export { Scripts } from './Scripts'
|
package/src/route.ts
CHANGED
|
@@ -325,6 +325,51 @@ export interface BeforeLoadContextOptions<
|
|
|
325
325
|
>
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
+
type AssetFnContextOptions<
|
|
329
|
+
in out TRouteId,
|
|
330
|
+
in out TFullPath,
|
|
331
|
+
in out TParentRoute extends AnyRoute,
|
|
332
|
+
in out TParams,
|
|
333
|
+
in out TSearchValidator,
|
|
334
|
+
in out TLoaderFn,
|
|
335
|
+
in out TRouterContext,
|
|
336
|
+
in out TRouteContextFn,
|
|
337
|
+
in out TBeforeLoadFn,
|
|
338
|
+
in out TLoaderDeps,
|
|
339
|
+
> = {
|
|
340
|
+
matches: Array<
|
|
341
|
+
RouteMatch<
|
|
342
|
+
TRouteId,
|
|
343
|
+
TFullPath,
|
|
344
|
+
ResolveAllParamsFromParent<TParentRoute, TParams>,
|
|
345
|
+
ResolveFullSearchSchema<TParentRoute, TSearchValidator>,
|
|
346
|
+
ResolveLoaderData<TLoaderFn>,
|
|
347
|
+
ResolveAllContext<
|
|
348
|
+
TParentRoute,
|
|
349
|
+
TRouterContext,
|
|
350
|
+
TRouteContextFn,
|
|
351
|
+
TBeforeLoadFn
|
|
352
|
+
>,
|
|
353
|
+
TLoaderDeps
|
|
354
|
+
>
|
|
355
|
+
>
|
|
356
|
+
match: RouteMatch<
|
|
357
|
+
TRouteId,
|
|
358
|
+
TFullPath,
|
|
359
|
+
ResolveAllParamsFromParent<TParentRoute, TParams>,
|
|
360
|
+
ResolveFullSearchSchema<TParentRoute, TSearchValidator>,
|
|
361
|
+
ResolveLoaderData<TLoaderFn>,
|
|
362
|
+
ResolveAllContext<
|
|
363
|
+
TParentRoute,
|
|
364
|
+
TRouterContext,
|
|
365
|
+
TRouteContextFn,
|
|
366
|
+
TBeforeLoadFn
|
|
367
|
+
>,
|
|
368
|
+
TLoaderDeps
|
|
369
|
+
>
|
|
370
|
+
params: ResolveAllParamsFromParent<TParentRoute, TParams>
|
|
371
|
+
loaderData: ResolveLoaderData<TLoaderFn>
|
|
372
|
+
}
|
|
328
373
|
export interface UpdatableRouteOptions<
|
|
329
374
|
in out TParentRoute extends AnyRoute,
|
|
330
375
|
in out TRouteId,
|
|
@@ -427,44 +472,38 @@ export interface UpdatableRouteOptions<
|
|
|
427
472
|
headers?: (ctx: {
|
|
428
473
|
loaderData: ResolveLoaderData<TLoaderFn>
|
|
429
474
|
}) => Record<string, string>
|
|
430
|
-
head?: (
|
|
431
|
-
|
|
432
|
-
RouteMatch<
|
|
433
|
-
TRouteId,
|
|
434
|
-
TFullPath,
|
|
435
|
-
ResolveAllParamsFromParent<TParentRoute, TParams>,
|
|
436
|
-
ResolveFullSearchSchema<TParentRoute, TSearchValidator>,
|
|
437
|
-
ResolveLoaderData<TLoaderFn>,
|
|
438
|
-
ResolveAllContext<
|
|
439
|
-
TParentRoute,
|
|
440
|
-
TRouterContext,
|
|
441
|
-
TRouteContextFn,
|
|
442
|
-
TBeforeLoadFn
|
|
443
|
-
>,
|
|
444
|
-
TLoaderDeps
|
|
445
|
-
>
|
|
446
|
-
>
|
|
447
|
-
match: RouteMatch<
|
|
475
|
+
head?: (
|
|
476
|
+
ctx: AssetFnContextOptions<
|
|
448
477
|
TRouteId,
|
|
449
478
|
TFullPath,
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
TBeforeLoadFn
|
|
458
|
-
>,
|
|
479
|
+
TParentRoute,
|
|
480
|
+
TParams,
|
|
481
|
+
TSearchValidator,
|
|
482
|
+
TLoaderFn,
|
|
483
|
+
TRouterContext,
|
|
484
|
+
TRouteContextFn,
|
|
485
|
+
TBeforeLoadFn,
|
|
459
486
|
TLoaderDeps
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
loaderData: ResolveLoaderData<TLoaderFn>
|
|
463
|
-
}) => {
|
|
487
|
+
>,
|
|
488
|
+
) => {
|
|
464
489
|
links?: AnyRouteMatch['links']
|
|
465
|
-
scripts?: AnyRouteMatch['
|
|
490
|
+
scripts?: AnyRouteMatch['headScripts']
|
|
466
491
|
meta?: AnyRouteMatch['meta']
|
|
467
492
|
}
|
|
493
|
+
scripts?: (
|
|
494
|
+
ctx: AssetFnContextOptions<
|
|
495
|
+
TRouteId,
|
|
496
|
+
TFullPath,
|
|
497
|
+
TParentRoute,
|
|
498
|
+
TParams,
|
|
499
|
+
TSearchValidator,
|
|
500
|
+
TLoaderFn,
|
|
501
|
+
TRouterContext,
|
|
502
|
+
TRouteContextFn,
|
|
503
|
+
TBeforeLoadFn,
|
|
504
|
+
TLoaderDeps
|
|
505
|
+
>,
|
|
506
|
+
) => AnyRouteMatch['scripts']
|
|
468
507
|
ssr?: boolean
|
|
469
508
|
codeSplitGroupings?: Array<
|
|
470
509
|
Array<
|
package/src/router.ts
CHANGED
|
@@ -1311,6 +1311,7 @@ export class Router<
|
|
|
1311
1311
|
preload: false,
|
|
1312
1312
|
links: undefined,
|
|
1313
1313
|
scripts: undefined,
|
|
1314
|
+
headScripts: undefined,
|
|
1314
1315
|
meta: undefined,
|
|
1315
1316
|
staticData: route.options.staticData || {},
|
|
1316
1317
|
loadPromise: createControlledPromise(),
|
|
@@ -1378,16 +1379,17 @@ export class Router<
|
|
|
1378
1379
|
match.headers = route.options.headers?.({
|
|
1379
1380
|
loaderData: match.loaderData,
|
|
1380
1381
|
})
|
|
1381
|
-
const
|
|
1382
|
+
const assetContext = {
|
|
1382
1383
|
matches,
|
|
1383
1384
|
match,
|
|
1384
1385
|
params: match.params,
|
|
1385
1386
|
loaderData: match.loaderData,
|
|
1386
|
-
}
|
|
1387
|
-
|
|
1387
|
+
}
|
|
1388
|
+
const headFnContent = route.options.head?.(assetContext)
|
|
1388
1389
|
match.links = headFnContent?.links
|
|
1389
|
-
match.
|
|
1390
|
+
match.headScripts = headFnContent?.scripts
|
|
1390
1391
|
match.meta = headFnContent?.meta
|
|
1392
|
+
match.scripts = route.options.scripts?.(assetContext)
|
|
1391
1393
|
}
|
|
1392
1394
|
})
|
|
1393
1395
|
|
|
@@ -2557,16 +2559,19 @@ export class Router<
|
|
|
2557
2559
|
|
|
2558
2560
|
await potentialPendingMinPromise()
|
|
2559
2561
|
|
|
2560
|
-
const
|
|
2562
|
+
const assetContext = {
|
|
2561
2563
|
matches,
|
|
2562
2564
|
match: this.getMatch(matchId)!,
|
|
2563
2565
|
params: this.getMatch(matchId)!.params,
|
|
2564
2566
|
loaderData,
|
|
2565
|
-
}
|
|
2567
|
+
}
|
|
2568
|
+
const headFnContent =
|
|
2569
|
+
route.options.head?.(assetContext)
|
|
2566
2570
|
const meta = headFnContent?.meta
|
|
2567
2571
|
const links = headFnContent?.links
|
|
2568
|
-
const
|
|
2572
|
+
const headScripts = headFnContent?.scripts
|
|
2569
2573
|
|
|
2574
|
+
const scripts = route.options.scripts?.(assetContext)
|
|
2570
2575
|
const headers = route.options.headers?.({
|
|
2571
2576
|
loaderData,
|
|
2572
2577
|
})
|
|
@@ -2580,8 +2585,9 @@ export class Router<
|
|
|
2580
2585
|
loaderData,
|
|
2581
2586
|
meta,
|
|
2582
2587
|
links,
|
|
2583
|
-
|
|
2588
|
+
headScripts,
|
|
2584
2589
|
headers,
|
|
2590
|
+
scripts,
|
|
2585
2591
|
}))
|
|
2586
2592
|
} catch (e) {
|
|
2587
2593
|
let error = e
|
package/src/useNavigate.tsx
CHANGED
|
@@ -54,13 +54,22 @@ export function Navigate<
|
|
|
54
54
|
const TMaskFrom extends string = TFrom,
|
|
55
55
|
const TMaskTo extends string = '',
|
|
56
56
|
>(props: NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>): null {
|
|
57
|
-
const
|
|
57
|
+
const router = useRouter()
|
|
58
58
|
|
|
59
|
+
const previousPropsRef = React.useRef<NavigateOptions<
|
|
60
|
+
TRouter,
|
|
61
|
+
TFrom,
|
|
62
|
+
TTo,
|
|
63
|
+
TMaskFrom,
|
|
64
|
+
TMaskTo
|
|
65
|
+
> | null>(null)
|
|
59
66
|
React.useEffect(() => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
if (previousPropsRef.current !== props) {
|
|
68
|
+
router.navigate({
|
|
69
|
+
...props,
|
|
70
|
+
})
|
|
71
|
+
previousPropsRef.current = props
|
|
72
|
+
}
|
|
73
|
+
}, [router, props])
|
|
65
74
|
return null
|
|
66
75
|
}
|