@tanstack/vue-router 0.0.1 → 1.140.0
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/LICENSE +21 -0
- package/README.md +66 -45
- package/dist/esm/Asset.d.ts +2 -0
- package/dist/esm/Asset.js +33 -0
- package/dist/esm/Asset.js.map +1 -0
- package/dist/esm/CatchBoundary.d.ts +19 -0
- package/dist/esm/CatchBoundary.js +135 -0
- package/dist/esm/CatchBoundary.js.map +1 -0
- package/dist/esm/ClientOnly.d.ts +67 -0
- package/dist/esm/HeadContent.d.ts +10 -0
- package/dist/esm/HeadContent.js +116 -0
- package/dist/esm/HeadContent.js.map +1 -0
- package/dist/esm/Match.d.ts +25 -0
- package/dist/esm/Match.js +262 -0
- package/dist/esm/Match.js.map +1 -0
- package/dist/esm/Matches.d.ts +39 -0
- package/dist/esm/Matches.js +186 -0
- package/dist/esm/Matches.js.map +1 -0
- package/dist/esm/RouterProvider.d.ts +33 -0
- package/dist/esm/RouterProvider.js +65 -0
- package/dist/esm/RouterProvider.js.map +1 -0
- package/dist/esm/SafeFragment.d.ts +4 -0
- package/dist/esm/ScriptOnce.d.ts +5 -0
- package/dist/esm/ScriptOnce.js +21 -0
- package/dist/esm/ScriptOnce.js.map +1 -0
- package/dist/esm/Scripts.d.ts +1 -0
- package/dist/esm/Scripts.js +46 -0
- package/dist/esm/Scripts.js.map +1 -0
- package/dist/esm/ScrollRestoration.d.ts +14 -0
- package/dist/esm/ScrollRestoration.js +36 -0
- package/dist/esm/ScrollRestoration.js.map +1 -0
- package/dist/esm/Transitioner.d.ts +2 -0
- package/dist/esm/Transitioner.js +154 -0
- package/dist/esm/Transitioner.js.map +1 -0
- package/dist/esm/awaited.d.ts +12 -0
- package/dist/esm/awaited.js +40 -0
- package/dist/esm/awaited.js.map +1 -0
- package/dist/esm/fileRoute.d.ts +54 -0
- package/dist/esm/fileRoute.js +103 -0
- package/dist/esm/fileRoute.js.map +1 -0
- package/dist/esm/history.d.ts +8 -0
- package/dist/esm/index.d.ts +51 -0
- package/dist/esm/index.js +138 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/lazyRouteComponent.d.ts +8 -0
- package/dist/esm/lazyRouteComponent.js +106 -0
- package/dist/esm/lazyRouteComponent.js.map +1 -0
- package/dist/esm/link.d.ts +61 -0
- package/dist/esm/link.js +376 -0
- package/dist/esm/link.js.map +1 -0
- package/dist/esm/matchContext.d.ts +20 -0
- package/dist/esm/matchContext.js +16 -0
- package/dist/esm/matchContext.js.map +1 -0
- package/dist/esm/not-found.d.ts +12 -0
- package/dist/esm/not-found.js +45 -0
- package/dist/esm/not-found.js.map +1 -0
- package/dist/esm/renderRouteNotFound.d.ts +11 -0
- package/dist/esm/renderRouteNotFound.js +19 -0
- package/dist/esm/renderRouteNotFound.js.map +1 -0
- package/dist/esm/route.d.ts +96 -0
- package/dist/esm/route.js +176 -0
- package/dist/esm/route.js.map +1 -0
- package/dist/esm/router.d.ts +69 -0
- package/dist/esm/router.js +14 -0
- package/dist/esm/router.js.map +1 -0
- package/dist/esm/routerContext.d.ts +21 -0
- package/dist/esm/routerContext.js +21 -0
- package/dist/esm/routerContext.js.map +1 -0
- package/dist/esm/scroll-restoration.d.ts +1 -0
- package/dist/esm/scroll-restoration.js +21 -0
- package/dist/esm/scroll-restoration.js.map +1 -0
- package/dist/esm/typePrimitives.d.ts +10 -0
- package/dist/esm/useBlocker.d.ts +66 -0
- package/dist/esm/useBlocker.js +295 -0
- package/dist/esm/useBlocker.js.map +1 -0
- package/dist/esm/useCanGoBack.d.ts +1 -0
- package/dist/esm/useCanGoBack.js +8 -0
- package/dist/esm/useCanGoBack.js.map +1 -0
- package/dist/esm/useLoaderData.d.ts +8 -0
- package/dist/esm/useLoaderData.js +14 -0
- package/dist/esm/useLoaderData.js.map +1 -0
- package/dist/esm/useLoaderDeps.d.ts +7 -0
- package/dist/esm/useLoaderDeps.js +17 -0
- package/dist/esm/useLoaderDeps.js.map +1 -0
- package/dist/esm/useLocation.d.ts +7 -0
- package/dist/esm/useLocation.js +10 -0
- package/dist/esm/useLocation.js.map +1 -0
- package/dist/esm/useMatch.d.ts +10 -0
- package/dist/esm/useMatch.js +39 -0
- package/dist/esm/useMatch.js.map +1 -0
- package/dist/esm/useNavigate.d.ts +5 -0
- package/dist/esm/useNavigate.js +29 -0
- package/dist/esm/useNavigate.js.map +1 -0
- package/dist/esm/useParams.d.ts +9 -0
- package/dist/esm/useParams.js +15 -0
- package/dist/esm/useParams.js.map +1 -0
- package/dist/esm/useRouteContext.d.ts +4 -0
- package/dist/esm/useRouteContext.js +11 -0
- package/dist/esm/useRouteContext.js.map +1 -0
- package/dist/esm/useRouter.d.ts +4 -0
- package/dist/esm/useRouter.js +12 -0
- package/dist/esm/useRouter.js.map +1 -0
- package/dist/esm/useRouterState.d.ts +8 -0
- package/dist/esm/useRouterState.js +20 -0
- package/dist/esm/useRouterState.js.map +1 -0
- package/dist/esm/useSearch.d.ts +9 -0
- package/dist/esm/useSearch.js +15 -0
- package/dist/esm/useSearch.js.map +1 -0
- package/dist/esm/utils.d.ts +40 -0
- package/dist/esm/utils.js +44 -0
- package/dist/esm/utils.js.map +1 -0
- package/dist/source/Asset.d.ts +2 -0
- package/dist/source/Asset.jsx +22 -0
- package/dist/source/Asset.jsx.map +1 -0
- package/dist/source/CatchBoundary.d.ts +19 -0
- package/dist/source/CatchBoundary.jsx +134 -0
- package/dist/source/CatchBoundary.jsx.map +1 -0
- package/dist/source/ClientOnly.d.ts +67 -0
- package/dist/source/ClientOnly.jsx +63 -0
- package/dist/source/ClientOnly.jsx.map +1 -0
- package/dist/source/HeadContent.d.ts +10 -0
- package/dist/source/HeadContent.jsx +133 -0
- package/dist/source/HeadContent.jsx.map +1 -0
- package/dist/source/Match.d.ts +25 -0
- package/dist/source/Match.jsx +316 -0
- package/dist/source/Match.jsx.map +1 -0
- package/dist/source/Matches.d.ts +39 -0
- package/dist/source/Matches.jsx +191 -0
- package/dist/source/Matches.jsx.map +1 -0
- package/dist/source/RouterProvider.d.ts +33 -0
- package/dist/source/RouterProvider.jsx +63 -0
- package/dist/source/RouterProvider.jsx.map +1 -0
- package/dist/source/SafeFragment.d.ts +4 -0
- package/dist/source/SafeFragment.jsx +10 -0
- package/dist/source/SafeFragment.jsx.map +1 -0
- package/dist/source/ScriptOnce.d.ts +5 -0
- package/dist/source/ScriptOnce.jsx +17 -0
- package/dist/source/ScriptOnce.jsx.map +1 -0
- package/dist/source/Scripts.d.ts +1 -0
- package/dist/source/Scripts.jsx +49 -0
- package/dist/source/Scripts.jsx.map +1 -0
- package/dist/source/ScrollRestoration.d.ts +14 -0
- package/dist/source/ScrollRestoration.jsx +37 -0
- package/dist/source/ScrollRestoration.jsx.map +1 -0
- package/dist/source/Transitioner.d.ts +2 -0
- package/dist/source/Transitioner.jsx +181 -0
- package/dist/source/Transitioner.jsx.map +1 -0
- package/dist/source/awaited.d.ts +12 -0
- package/dist/source/awaited.jsx +38 -0
- package/dist/source/awaited.jsx.map +1 -0
- package/dist/source/fileRoute.d.ts +54 -0
- package/dist/source/fileRoute.js +98 -0
- package/dist/source/fileRoute.js.map +1 -0
- package/dist/source/history.d.ts +8 -0
- package/dist/source/history.js +2 -0
- package/dist/source/history.js.map +1 -0
- package/dist/source/index.d.ts +51 -0
- package/dist/source/index.jsx +40 -0
- package/dist/source/index.jsx.map +1 -0
- package/dist/source/lazyRouteComponent.d.ts +8 -0
- package/dist/source/lazyRouteComponent.jsx +135 -0
- package/dist/source/lazyRouteComponent.jsx.map +1 -0
- package/dist/source/link.d.ts +61 -0
- package/dist/source/link.jsx +495 -0
- package/dist/source/link.jsx.map +1 -0
- package/dist/source/matchContext.d.ts +20 -0
- package/dist/source/matchContext.jsx +32 -0
- package/dist/source/matchContext.jsx.map +1 -0
- package/dist/source/not-found.d.ts +12 -0
- package/dist/source/not-found.jsx +48 -0
- package/dist/source/not-found.jsx.map +1 -0
- package/dist/source/renderRouteNotFound.d.ts +11 -0
- package/dist/source/renderRouteNotFound.jsx +24 -0
- package/dist/source/renderRouteNotFound.jsx.map +1 -0
- package/dist/source/route.d.ts +97 -0
- package/dist/source/route.js +167 -0
- package/dist/source/route.js.map +1 -0
- package/dist/source/router.d.ts +70 -0
- package/dist/source/router.js +10 -0
- package/dist/source/router.js.map +1 -0
- package/dist/source/routerContext.d.ts +21 -0
- package/dist/source/routerContext.jsx +37 -0
- package/dist/source/routerContext.jsx.map +1 -0
- package/dist/source/scroll-restoration.d.ts +1 -0
- package/dist/source/scroll-restoration.jsx +16 -0
- package/dist/source/scroll-restoration.jsx.map +1 -0
- package/dist/source/typePrimitives.d.ts +10 -0
- package/dist/source/typePrimitives.js +2 -0
- package/dist/source/typePrimitives.js.map +1 -0
- package/dist/source/useBlocker.d.ts +66 -0
- package/dist/source/useBlocker.jsx +308 -0
- package/dist/source/useBlocker.jsx.map +1 -0
- package/dist/source/useCanGoBack.d.ts +1 -0
- package/dist/source/useCanGoBack.js +5 -0
- package/dist/source/useCanGoBack.js.map +1 -0
- package/dist/source/useLoaderData.d.ts +8 -0
- package/dist/source/useLoaderData.jsx +11 -0
- package/dist/source/useLoaderData.jsx.map +1 -0
- package/dist/source/useLoaderDeps.d.ts +7 -0
- package/dist/source/useLoaderDeps.jsx +11 -0
- package/dist/source/useLoaderDeps.jsx.map +1 -0
- package/dist/source/useLocation.d.ts +7 -0
- package/dist/source/useLocation.jsx +7 -0
- package/dist/source/useLocation.jsx.map +1 -0
- package/dist/source/useMatch.d.ts +10 -0
- package/dist/source/useMatch.jsx +46 -0
- package/dist/source/useMatch.jsx.map +1 -0
- package/dist/source/useNavigate.d.ts +5 -0
- package/dist/source/useNavigate.jsx +18 -0
- package/dist/source/useNavigate.jsx.map +1 -0
- package/dist/source/useParams.d.ts +9 -0
- package/dist/source/useParams.jsx +12 -0
- package/dist/source/useParams.jsx.map +1 -0
- package/dist/source/useRouteContext.d.ts +4 -0
- package/dist/source/useRouteContext.js +8 -0
- package/dist/source/useRouteContext.js.map +1 -0
- package/dist/source/useRouter.d.ts +4 -0
- package/dist/source/useRouter.jsx +9 -0
- package/dist/source/useRouter.jsx.map +1 -0
- package/dist/source/useRouterState.d.ts +8 -0
- package/dist/source/useRouterState.jsx +19 -0
- package/dist/source/useRouterState.jsx.map +1 -0
- package/dist/source/useSearch.d.ts +9 -0
- package/dist/source/useSearch.jsx +12 -0
- package/dist/source/useSearch.jsx.map +1 -0
- package/dist/source/utils.d.ts +40 -0
- package/dist/source/utils.js +78 -0
- package/dist/source/utils.js.map +1 -0
- package/package.json +77 -7
- package/src/Asset.tsx +23 -0
- package/src/CatchBoundary.tsx +186 -0
- package/src/ClientOnly.tsx +75 -0
- package/src/HeadContent.tsx +159 -0
- package/src/Match.tsx +415 -0
- package/src/Matches.tsx +349 -0
- package/src/RouterProvider.tsx +117 -0
- package/src/SafeFragment.tsx +10 -0
- package/src/ScriptOnce.tsx +30 -0
- package/src/Scripts.tsx +65 -0
- package/src/ScrollRestoration.tsx +69 -0
- package/src/Transitioner.tsx +213 -0
- package/src/awaited.tsx +54 -0
- package/src/fileRoute.ts +271 -0
- package/src/history.ts +9 -0
- package/src/index.tsx +346 -0
- package/src/lazyRouteComponent.tsx +173 -0
- package/src/link.tsx +765 -0
- package/src/matchContext.tsx +41 -0
- package/src/not-found.tsx +55 -0
- package/src/renderRouteNotFound.tsx +35 -0
- package/src/route.ts +658 -0
- package/src/router.ts +103 -0
- package/src/routerContext.tsx +53 -0
- package/src/scroll-restoration.tsx +29 -0
- package/src/typePrimitives.ts +74 -0
- package/src/useBlocker.tsx +501 -0
- package/src/useCanGoBack.ts +5 -0
- package/src/useLoaderData.tsx +50 -0
- package/src/useLoaderDeps.tsx +46 -0
- package/src/useLocation.tsx +30 -0
- package/src/useMatch.tsx +127 -0
- package/src/useNavigate.tsx +40 -0
- package/src/useParams.tsx +71 -0
- package/src/useRouteContext.ts +31 -0
- package/src/useRouter.tsx +15 -0
- package/src/useRouterState.tsx +43 -0
- package/src/useSearch.tsx +71 -0
- package/src/utils.ts +111 -0
package/src/Matches.tsx
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import * as Vue from 'vue'
|
|
2
|
+
import warning from 'tiny-warning'
|
|
3
|
+
import { CatchBoundary } from './CatchBoundary'
|
|
4
|
+
import { useRouterState } from './useRouterState'
|
|
5
|
+
import { useRouter } from './useRouter'
|
|
6
|
+
import { Transitioner } from './Transitioner'
|
|
7
|
+
import { matchContext } from './matchContext'
|
|
8
|
+
import { Match } from './Match'
|
|
9
|
+
import type {
|
|
10
|
+
AnyRouter,
|
|
11
|
+
DeepPartial,
|
|
12
|
+
ErrorComponentProps,
|
|
13
|
+
MakeOptionalPathParams,
|
|
14
|
+
MakeOptionalSearchParams,
|
|
15
|
+
MakeRouteMatchUnion,
|
|
16
|
+
MaskOptions,
|
|
17
|
+
MatchRouteOptions,
|
|
18
|
+
NoInfer,
|
|
19
|
+
RegisteredRouter,
|
|
20
|
+
ResolveRelativePath,
|
|
21
|
+
ResolveRoute,
|
|
22
|
+
RouteByPath,
|
|
23
|
+
RouterState,
|
|
24
|
+
ToSubOptionsProps,
|
|
25
|
+
} from '@tanstack/router-core'
|
|
26
|
+
|
|
27
|
+
// Define a type for the error component function
|
|
28
|
+
type ErrorRouteComponentType = (props: ErrorComponentProps) => Vue.VNode
|
|
29
|
+
|
|
30
|
+
declare module '@tanstack/router-core' {
|
|
31
|
+
export interface RouteMatchExtensions {
|
|
32
|
+
meta?: Array<Vue.ComponentOptions['meta'] | undefined>
|
|
33
|
+
links?: Array<Vue.ComponentOptions['link'] | undefined>
|
|
34
|
+
scripts?: Array<Vue.ComponentOptions['script'] | undefined>
|
|
35
|
+
headScripts?: Array<Vue.ComponentOptions['script'] | undefined>
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Create a component that renders both the Transitioner and MatchesInner
|
|
40
|
+
const MatchesContent = Vue.defineComponent({
|
|
41
|
+
name: 'MatchesContent',
|
|
42
|
+
setup() {
|
|
43
|
+
return () =>
|
|
44
|
+
Vue.h(Vue.Fragment, null, [Vue.h(Transitioner), Vue.h(MatchesInner)])
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
export const Matches = Vue.defineComponent({
|
|
49
|
+
name: 'Matches',
|
|
50
|
+
setup() {
|
|
51
|
+
const router = useRouter()
|
|
52
|
+
|
|
53
|
+
return () => {
|
|
54
|
+
const pendingElement = router?.options?.defaultPendingComponent
|
|
55
|
+
? Vue.h(router.options.defaultPendingComponent)
|
|
56
|
+
: null
|
|
57
|
+
|
|
58
|
+
// Do not render a root Suspense during SSR or hydrating from SSR
|
|
59
|
+
const inner =
|
|
60
|
+
router?.isServer || (typeof document !== 'undefined' && router?.ssr)
|
|
61
|
+
? Vue.h(MatchesContent)
|
|
62
|
+
: Vue.h(
|
|
63
|
+
Vue.Suspense,
|
|
64
|
+
{ fallback: pendingElement },
|
|
65
|
+
{
|
|
66
|
+
default: () => Vue.h(MatchesContent),
|
|
67
|
+
},
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
return router?.options?.InnerWrap
|
|
71
|
+
? Vue.h(router.options.InnerWrap, null, { default: () => inner })
|
|
72
|
+
: inner
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
// Create a simple error component function that matches ErrorRouteComponent
|
|
78
|
+
const errorComponentFn: ErrorRouteComponentType = (
|
|
79
|
+
props: ErrorComponentProps,
|
|
80
|
+
) => {
|
|
81
|
+
return Vue.h('div', { class: 'error' }, [
|
|
82
|
+
Vue.h('h1', null, 'Error'),
|
|
83
|
+
Vue.h('p', null, props.error.message || String(props.error)),
|
|
84
|
+
Vue.h('button', { onClick: props.reset }, 'Try Again'),
|
|
85
|
+
])
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const MatchesInner = Vue.defineComponent({
|
|
89
|
+
name: 'MatchesInner',
|
|
90
|
+
setup() {
|
|
91
|
+
const router = useRouter()
|
|
92
|
+
|
|
93
|
+
const matchId = useRouterState({
|
|
94
|
+
select: (s) => {
|
|
95
|
+
return s.matches[0]?.id
|
|
96
|
+
},
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
const resetKey = useRouterState({
|
|
100
|
+
select: (s) => s.loadedAt,
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
// Create a ref for the match id to provide
|
|
104
|
+
const matchIdRef = Vue.computed(() => matchId.value)
|
|
105
|
+
|
|
106
|
+
// Provide the matchId for child components using the InjectionKey
|
|
107
|
+
Vue.provide(matchContext, matchIdRef)
|
|
108
|
+
|
|
109
|
+
return () => {
|
|
110
|
+
// Generate a placeholder element if matchId.value is not present
|
|
111
|
+
const childElement = matchId.value
|
|
112
|
+
? Vue.h(Match, { matchId: matchId.value })
|
|
113
|
+
: Vue.h('div')
|
|
114
|
+
|
|
115
|
+
// If disableGlobalCatchBoundary is true, don't wrap in CatchBoundary
|
|
116
|
+
if (router.options.disableGlobalCatchBoundary) {
|
|
117
|
+
return childElement
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return Vue.h(CatchBoundary, {
|
|
121
|
+
getResetKey: () => resetKey.value,
|
|
122
|
+
errorComponent: errorComponentFn,
|
|
123
|
+
onCatch: (error: Error) => {
|
|
124
|
+
warning(
|
|
125
|
+
false,
|
|
126
|
+
`The following error wasn't caught by any route! At the very least, consider setting an 'errorComponent' in your RootRoute!`,
|
|
127
|
+
)
|
|
128
|
+
warning(false, error.message || error.toString())
|
|
129
|
+
},
|
|
130
|
+
children: childElement,
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
export type UseMatchRouteOptions<
|
|
137
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
138
|
+
TFrom extends string = string,
|
|
139
|
+
TTo extends string | undefined = undefined,
|
|
140
|
+
TMaskFrom extends string = TFrom,
|
|
141
|
+
TMaskTo extends string = '',
|
|
142
|
+
> = ToSubOptionsProps<TRouter, TFrom, TTo> &
|
|
143
|
+
DeepPartial<MakeOptionalSearchParams<TRouter, TFrom, TTo>> &
|
|
144
|
+
DeepPartial<MakeOptionalPathParams<TRouter, TFrom, TTo>> &
|
|
145
|
+
MaskOptions<TRouter, TMaskFrom, TMaskTo> &
|
|
146
|
+
MatchRouteOptions
|
|
147
|
+
|
|
148
|
+
export function useMatchRoute<TRouter extends AnyRouter = RegisteredRouter>() {
|
|
149
|
+
const router = useRouter()
|
|
150
|
+
|
|
151
|
+
// Track state changes to trigger re-computation
|
|
152
|
+
// Use multiple state values like React does for complete reactivity
|
|
153
|
+
const routerState = useRouterState({
|
|
154
|
+
select: (s) => ({
|
|
155
|
+
locationHref: s.location.href,
|
|
156
|
+
resolvedLocationHref: s.resolvedLocation?.href,
|
|
157
|
+
status: s.status,
|
|
158
|
+
}),
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
return <
|
|
162
|
+
const TFrom extends string = string,
|
|
163
|
+
const TTo extends string | undefined = undefined,
|
|
164
|
+
const TMaskFrom extends string = TFrom,
|
|
165
|
+
const TMaskTo extends string = '',
|
|
166
|
+
>(
|
|
167
|
+
opts: UseMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,
|
|
168
|
+
): Vue.Ref<
|
|
169
|
+
false | ResolveRoute<TRouter, TFrom, TTo>['types']['allParams']
|
|
170
|
+
> => {
|
|
171
|
+
const { pending, caseSensitive, fuzzy, includeSearch, ...rest } = opts
|
|
172
|
+
|
|
173
|
+
const matchRoute = Vue.computed(() => {
|
|
174
|
+
// Access routerState to establish dependency
|
|
175
|
+
|
|
176
|
+
routerState.value
|
|
177
|
+
return router.matchRoute(rest as any, {
|
|
178
|
+
pending,
|
|
179
|
+
caseSensitive,
|
|
180
|
+
fuzzy,
|
|
181
|
+
includeSearch,
|
|
182
|
+
})
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
return matchRoute
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export type MakeMatchRouteOptions<
|
|
190
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
191
|
+
TFrom extends string = string,
|
|
192
|
+
TTo extends string | undefined = undefined,
|
|
193
|
+
TMaskFrom extends string = TFrom,
|
|
194
|
+
TMaskTo extends string = '',
|
|
195
|
+
> = UseMatchRouteOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo> & {
|
|
196
|
+
// If a function is passed as a child, it will be given the `isActive` boolean to aid in further styling on the element it returns
|
|
197
|
+
children?:
|
|
198
|
+
| ((
|
|
199
|
+
params?: RouteByPath<
|
|
200
|
+
TRouter['routeTree'],
|
|
201
|
+
ResolveRelativePath<TFrom, NoInfer<TTo>>
|
|
202
|
+
>['types']['allParams'],
|
|
203
|
+
) => Vue.VNode)
|
|
204
|
+
| Vue.VNode
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Create a type for the MatchRoute component that includes the generics
|
|
208
|
+
export interface MatchRouteComponentType {
|
|
209
|
+
<
|
|
210
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
211
|
+
TFrom extends string = string,
|
|
212
|
+
TTo extends string | undefined = undefined,
|
|
213
|
+
>(
|
|
214
|
+
props: MakeMatchRouteOptions<TRouter, TFrom, TTo>,
|
|
215
|
+
): Vue.VNode
|
|
216
|
+
new (): {
|
|
217
|
+
$props: {
|
|
218
|
+
from?: string
|
|
219
|
+
to?: string
|
|
220
|
+
fuzzy?: boolean
|
|
221
|
+
caseSensitive?: boolean
|
|
222
|
+
includeSearch?: boolean
|
|
223
|
+
pending?: boolean
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export const MatchRoute = Vue.defineComponent({
|
|
229
|
+
name: 'MatchRoute',
|
|
230
|
+
props: {
|
|
231
|
+
// Define props to match MakeMatchRouteOptions
|
|
232
|
+
from: {
|
|
233
|
+
type: String,
|
|
234
|
+
required: false,
|
|
235
|
+
},
|
|
236
|
+
to: {
|
|
237
|
+
type: String,
|
|
238
|
+
required: false,
|
|
239
|
+
},
|
|
240
|
+
fuzzy: {
|
|
241
|
+
type: Boolean,
|
|
242
|
+
required: false,
|
|
243
|
+
},
|
|
244
|
+
caseSensitive: {
|
|
245
|
+
type: Boolean,
|
|
246
|
+
required: false,
|
|
247
|
+
},
|
|
248
|
+
includeSearch: {
|
|
249
|
+
type: Boolean,
|
|
250
|
+
required: false,
|
|
251
|
+
},
|
|
252
|
+
pending: {
|
|
253
|
+
type: Boolean,
|
|
254
|
+
required: false,
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
setup(props, { slots }) {
|
|
258
|
+
const status = useRouterState({
|
|
259
|
+
select: (s) => s.status,
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
return () => {
|
|
263
|
+
if (!status.value) return null
|
|
264
|
+
|
|
265
|
+
const matchRoute = useMatchRoute()
|
|
266
|
+
const params = matchRoute(props as any).value as boolean
|
|
267
|
+
|
|
268
|
+
// Create a component that renders the slot in a reactive manner
|
|
269
|
+
if (!params || !slots.default) {
|
|
270
|
+
return null
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// For function slots, pass the params
|
|
274
|
+
if (typeof slots.default === 'function') {
|
|
275
|
+
// Use h to create a wrapper component that will call the slot function
|
|
276
|
+
return Vue.h(Vue.Fragment, null, slots.default(params))
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// For normal slots, just render them
|
|
280
|
+
return Vue.h(Vue.Fragment, null, slots.default)
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
}) as unknown as MatchRouteComponentType
|
|
284
|
+
|
|
285
|
+
export interface UseMatchesBaseOptions<TRouter extends AnyRouter, TSelected> {
|
|
286
|
+
select?: (matches: Array<MakeRouteMatchUnion<TRouter>>) => TSelected
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export type UseMatchesResult<
|
|
290
|
+
TRouter extends AnyRouter,
|
|
291
|
+
TSelected,
|
|
292
|
+
> = unknown extends TSelected ? Array<MakeRouteMatchUnion<TRouter>> : TSelected
|
|
293
|
+
|
|
294
|
+
export function useMatches<
|
|
295
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
296
|
+
TSelected = unknown,
|
|
297
|
+
>(
|
|
298
|
+
opts?: UseMatchesBaseOptions<TRouter, TSelected>,
|
|
299
|
+
): Vue.Ref<UseMatchesResult<TRouter, TSelected>> {
|
|
300
|
+
return useRouterState({
|
|
301
|
+
select: (state: RouterState<TRouter['routeTree']>) => {
|
|
302
|
+
const matches = state?.matches || []
|
|
303
|
+
return opts?.select
|
|
304
|
+
? opts.select(matches as Array<MakeRouteMatchUnion<TRouter>>)
|
|
305
|
+
: matches
|
|
306
|
+
},
|
|
307
|
+
} as any) as Vue.Ref<UseMatchesResult<TRouter, TSelected>>
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export function useParentMatches<
|
|
311
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
312
|
+
TSelected = unknown,
|
|
313
|
+
>(
|
|
314
|
+
opts?: UseMatchesBaseOptions<TRouter, TSelected>,
|
|
315
|
+
): Vue.Ref<UseMatchesResult<TRouter, TSelected>> {
|
|
316
|
+
// Use matchContext with proper type
|
|
317
|
+
const contextMatchId = Vue.inject<Vue.Ref<string | undefined>>(matchContext)
|
|
318
|
+
const safeMatchId = Vue.computed(() => contextMatchId?.value || '')
|
|
319
|
+
|
|
320
|
+
return useMatches({
|
|
321
|
+
select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {
|
|
322
|
+
matches = matches.slice(
|
|
323
|
+
0,
|
|
324
|
+
matches.findIndex((d) => d.id === safeMatchId.value),
|
|
325
|
+
)
|
|
326
|
+
return opts?.select ? opts.select(matches) : matches
|
|
327
|
+
},
|
|
328
|
+
} as any)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export function useChildMatches<
|
|
332
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
333
|
+
TSelected = unknown,
|
|
334
|
+
>(
|
|
335
|
+
opts?: UseMatchesBaseOptions<TRouter, TSelected>,
|
|
336
|
+
): Vue.Ref<UseMatchesResult<TRouter, TSelected>> {
|
|
337
|
+
// Use matchContext with proper type
|
|
338
|
+
const contextMatchId = Vue.inject<Vue.Ref<string | undefined>>(matchContext)
|
|
339
|
+
const safeMatchId = Vue.computed(() => contextMatchId?.value || '')
|
|
340
|
+
|
|
341
|
+
return useMatches({
|
|
342
|
+
select: (matches: Array<MakeRouteMatchUnion<TRouter>>) => {
|
|
343
|
+
matches = matches.slice(
|
|
344
|
+
matches.findIndex((d) => d.id === safeMatchId.value) + 1,
|
|
345
|
+
)
|
|
346
|
+
return opts?.select ? opts.select(matches) : matches
|
|
347
|
+
},
|
|
348
|
+
} as any)
|
|
349
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import * as Vue from 'vue'
|
|
2
|
+
import { Matches } from './Matches'
|
|
3
|
+
import { provideRouter } from './routerContext'
|
|
4
|
+
import type {
|
|
5
|
+
AnyRouter,
|
|
6
|
+
RegisteredRouter,
|
|
7
|
+
RouterOptions,
|
|
8
|
+
} from '@tanstack/router-core'
|
|
9
|
+
|
|
10
|
+
// Component that provides router context and renders children
|
|
11
|
+
export const RouterContextProvider = Vue.defineComponent({
|
|
12
|
+
name: 'RouterContextProvider',
|
|
13
|
+
props: {
|
|
14
|
+
router: {
|
|
15
|
+
type: Object,
|
|
16
|
+
required: true,
|
|
17
|
+
},
|
|
18
|
+
// Rest of router options will be passed as attrs
|
|
19
|
+
},
|
|
20
|
+
setup(props, { attrs, slots }) {
|
|
21
|
+
const router = props.router as AnyRouter
|
|
22
|
+
const restAttrs = attrs as Record<string, any>
|
|
23
|
+
|
|
24
|
+
// Allow the router to update options on the router instance
|
|
25
|
+
router.update({
|
|
26
|
+
...router.options,
|
|
27
|
+
...restAttrs,
|
|
28
|
+
context: {
|
|
29
|
+
...router.options.context,
|
|
30
|
+
...((restAttrs.context as Record<string, any>) || {}),
|
|
31
|
+
},
|
|
32
|
+
} as any)
|
|
33
|
+
|
|
34
|
+
// Provide router to all child components
|
|
35
|
+
provideRouter(router)
|
|
36
|
+
|
|
37
|
+
return () => {
|
|
38
|
+
// Get child content
|
|
39
|
+
const childContent = slots.default?.()
|
|
40
|
+
|
|
41
|
+
// If a Wrap component is specified in router options, use it
|
|
42
|
+
if (router.options.Wrap) {
|
|
43
|
+
const WrapComponent = router.options.Wrap
|
|
44
|
+
return Vue.h(WrapComponent, null, () => childContent)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Otherwise just return the child content
|
|
48
|
+
return childContent
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
// The main router provider component that includes matches
|
|
54
|
+
export const RouterProvider = Vue.defineComponent({
|
|
55
|
+
name: 'RouterProvider',
|
|
56
|
+
props: {
|
|
57
|
+
router: {
|
|
58
|
+
type: Object,
|
|
59
|
+
required: true,
|
|
60
|
+
},
|
|
61
|
+
// Rest of router options will be passed as attrs
|
|
62
|
+
},
|
|
63
|
+
setup(props, { attrs }) {
|
|
64
|
+
const restAttrs = attrs as Record<string, any>
|
|
65
|
+
|
|
66
|
+
return () => {
|
|
67
|
+
return Vue.h(
|
|
68
|
+
RouterContextProvider,
|
|
69
|
+
{
|
|
70
|
+
router: props.router,
|
|
71
|
+
...restAttrs,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
default: () => Vue.h(Matches),
|
|
75
|
+
},
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
}) as unknown as {
|
|
80
|
+
<TRouter extends AnyRouter = RegisteredRouter>(
|
|
81
|
+
props: {
|
|
82
|
+
router: TRouter
|
|
83
|
+
routeTree?: TRouter['routeTree']
|
|
84
|
+
} & Record<string, any>,
|
|
85
|
+
): Vue.VNode
|
|
86
|
+
new (): {
|
|
87
|
+
$props: {
|
|
88
|
+
router: AnyRouter
|
|
89
|
+
routeTree?: AnyRouter['routeTree']
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export type RouterProps<
|
|
95
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
96
|
+
TDehydrated extends Record<string, any> = Record<string, any>,
|
|
97
|
+
> = Omit<
|
|
98
|
+
RouterOptions<
|
|
99
|
+
TRouter['routeTree'],
|
|
100
|
+
NonNullable<TRouter['options']['trailingSlash']>,
|
|
101
|
+
false,
|
|
102
|
+
TRouter['history'],
|
|
103
|
+
TDehydrated
|
|
104
|
+
>,
|
|
105
|
+
'context'
|
|
106
|
+
> & {
|
|
107
|
+
router: TRouter
|
|
108
|
+
context?: Partial<
|
|
109
|
+
RouterOptions<
|
|
110
|
+
TRouter['routeTree'],
|
|
111
|
+
NonNullable<TRouter['options']['trailingSlash']>,
|
|
112
|
+
false,
|
|
113
|
+
TRouter['history'],
|
|
114
|
+
TDehydrated
|
|
115
|
+
>['context']
|
|
116
|
+
>
|
|
117
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import jsesc from 'jsesc'
|
|
2
|
+
|
|
3
|
+
export function ScriptOnce({
|
|
4
|
+
children,
|
|
5
|
+
log,
|
|
6
|
+
}: {
|
|
7
|
+
children: string
|
|
8
|
+
log?: boolean
|
|
9
|
+
sync?: boolean
|
|
10
|
+
}) {
|
|
11
|
+
if (typeof document !== 'undefined') {
|
|
12
|
+
return null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<script
|
|
17
|
+
class="tsr-once"
|
|
18
|
+
innerHTML={[
|
|
19
|
+
children,
|
|
20
|
+
(log ?? true) && process.env.NODE_ENV === 'development'
|
|
21
|
+
? `console.info(\`Injected From Server:
|
|
22
|
+
${jsesc(children.toString(), { quotes: 'backtick' })}\`)`
|
|
23
|
+
: '',
|
|
24
|
+
'if (typeof __TSR_SSR__ !== "undefined") __TSR_SSR__.cleanScripts()',
|
|
25
|
+
]
|
|
26
|
+
.filter(Boolean)
|
|
27
|
+
.join('\n')}
|
|
28
|
+
/>
|
|
29
|
+
)
|
|
30
|
+
}
|
package/src/Scripts.tsx
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
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
|
+
})
|
|
35
|
+
|
|
36
|
+
const scripts = useRouterState({
|
|
37
|
+
select: (state) => ({
|
|
38
|
+
scripts: (
|
|
39
|
+
state.matches
|
|
40
|
+
.map((match) => match.scripts!)
|
|
41
|
+
.flat(1)
|
|
42
|
+
.filter(Boolean) as Array<RouterManagedTag>
|
|
43
|
+
).map(({ children, ...script }) => ({
|
|
44
|
+
tag: 'script',
|
|
45
|
+
attrs: {
|
|
46
|
+
...script,
|
|
47
|
+
},
|
|
48
|
+
children,
|
|
49
|
+
})),
|
|
50
|
+
}),
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const allScripts = [
|
|
54
|
+
...scripts.value.scripts,
|
|
55
|
+
...assetScripts.value,
|
|
56
|
+
] as Array<RouterManagedTag>
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<>
|
|
60
|
+
{allScripts.map((asset, i) => (
|
|
61
|
+
<Asset {...asset} key={i} />
|
|
62
|
+
))}
|
|
63
|
+
</>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultGetScrollRestorationKey,
|
|
3
|
+
getCssSelector,
|
|
4
|
+
scrollRestorationCache,
|
|
5
|
+
setupScrollRestoration,
|
|
6
|
+
} from '@tanstack/router-core'
|
|
7
|
+
import { useRouter } from './useRouter'
|
|
8
|
+
import type {
|
|
9
|
+
ParsedLocation,
|
|
10
|
+
ScrollRestorationEntry,
|
|
11
|
+
ScrollRestorationOptions,
|
|
12
|
+
} from '@tanstack/router-core'
|
|
13
|
+
|
|
14
|
+
function useScrollRestoration() {
|
|
15
|
+
const router = useRouter()
|
|
16
|
+
setupScrollRestoration(router, true)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @deprecated use createRouter's `scrollRestoration` option instead
|
|
21
|
+
*/
|
|
22
|
+
export function ScrollRestoration(_props: ScrollRestorationOptions) {
|
|
23
|
+
useScrollRestoration()
|
|
24
|
+
|
|
25
|
+
if (process.env.NODE_ENV === 'development') {
|
|
26
|
+
console.warn(
|
|
27
|
+
"The ScrollRestoration component is deprecated. Use createRouter's `scrollRestoration` option instead.",
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function useElementScrollRestoration(
|
|
35
|
+
options: (
|
|
36
|
+
| {
|
|
37
|
+
id: string
|
|
38
|
+
getElement?: () => Window | Element | undefined | null
|
|
39
|
+
}
|
|
40
|
+
| {
|
|
41
|
+
id?: string
|
|
42
|
+
getElement: () => Window | Element | undefined | null
|
|
43
|
+
}
|
|
44
|
+
) & {
|
|
45
|
+
getKey?: (location: ParsedLocation) => string
|
|
46
|
+
},
|
|
47
|
+
): ScrollRestorationEntry | undefined {
|
|
48
|
+
useScrollRestoration()
|
|
49
|
+
|
|
50
|
+
const router = useRouter()
|
|
51
|
+
const getKey = options.getKey || defaultGetScrollRestorationKey
|
|
52
|
+
|
|
53
|
+
let elementSelector = ''
|
|
54
|
+
|
|
55
|
+
if (options.id) {
|
|
56
|
+
elementSelector = `[data-scroll-restoration-id="${options.id}"]`
|
|
57
|
+
} else {
|
|
58
|
+
const element = options.getElement?.()
|
|
59
|
+
if (!element) {
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
elementSelector =
|
|
63
|
+
element instanceof Window ? 'window' : getCssSelector(element)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const restoreKey = getKey(router.latestLocation)
|
|
67
|
+
const byKey = scrollRestorationCache?.state[restoreKey]
|
|
68
|
+
return byKey?.[elementSelector]
|
|
69
|
+
}
|