@tanstack/vue-router 0.0.1 → 1.140.1
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/Match.tsx
ADDED
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
import * as Vue from 'vue'
|
|
2
|
+
import invariant from 'tiny-invariant'
|
|
3
|
+
import warning from 'tiny-warning'
|
|
4
|
+
import {
|
|
5
|
+
createControlledPromise,
|
|
6
|
+
getLocationChangeInfo,
|
|
7
|
+
isNotFound,
|
|
8
|
+
isRedirect,
|
|
9
|
+
rootRouteId,
|
|
10
|
+
} from '@tanstack/router-core'
|
|
11
|
+
import { CatchBoundary, ErrorComponent } from './CatchBoundary'
|
|
12
|
+
import { useRouterState } from './useRouterState'
|
|
13
|
+
import { useRouter } from './useRouter'
|
|
14
|
+
import { CatchNotFound } from './not-found'
|
|
15
|
+
import { matchContext } from './matchContext'
|
|
16
|
+
import { renderRouteNotFound } from './renderRouteNotFound'
|
|
17
|
+
import { ScrollRestoration } from './scroll-restoration'
|
|
18
|
+
import type { VNode } from 'vue'
|
|
19
|
+
import type { AnyRoute } from '@tanstack/router-core'
|
|
20
|
+
|
|
21
|
+
export const Match = Vue.defineComponent({
|
|
22
|
+
name: 'Match',
|
|
23
|
+
props: {
|
|
24
|
+
matchId: {
|
|
25
|
+
type: String,
|
|
26
|
+
required: true,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
setup(props) {
|
|
30
|
+
const router = useRouter()
|
|
31
|
+
const routeId = useRouterState({
|
|
32
|
+
select: (s) => {
|
|
33
|
+
return s.matches.find((d) => d.id === props.matchId)?.routeId as string
|
|
34
|
+
},
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
invariant(
|
|
38
|
+
routeId.value,
|
|
39
|
+
`Could not find routeId for matchId "${props.matchId}". Please file an issue!`,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
const route = Vue.computed(() => router.routesById[routeId.value])
|
|
43
|
+
|
|
44
|
+
const PendingComponent = Vue.computed(
|
|
45
|
+
() =>
|
|
46
|
+
route.value?.options?.pendingComponent ??
|
|
47
|
+
router?.options?.defaultPendingComponent,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
const routeErrorComponent = Vue.computed(
|
|
51
|
+
() =>
|
|
52
|
+
route.value?.options?.errorComponent ??
|
|
53
|
+
router?.options?.defaultErrorComponent,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
const routeOnCatch = Vue.computed(
|
|
57
|
+
() => route.value?.options?.onCatch ?? router?.options?.defaultOnCatch,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
const routeNotFoundComponent = Vue.computed(() =>
|
|
61
|
+
route.value?.isRoot
|
|
62
|
+
? // If it's the root route, use the globalNotFound option, with fallback to the notFoundRoute's component
|
|
63
|
+
(route.value?.options?.notFoundComponent ??
|
|
64
|
+
router?.options?.notFoundRoute?.options?.component)
|
|
65
|
+
: route.value?.options?.notFoundComponent,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
const resetKey = useRouterState({
|
|
69
|
+
select: (s) => s.loadedAt,
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const parentRouteId = useRouterState({
|
|
73
|
+
select: (s) => {
|
|
74
|
+
const index = s.matches.findIndex((d) => d.id === props.matchId)
|
|
75
|
+
return s.matches[index - 1]?.routeId as string
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
// Create a ref for the current matchId that we can provide to child components
|
|
80
|
+
const matchIdRef = Vue.ref(props.matchId)
|
|
81
|
+
|
|
82
|
+
// When props.matchId changes, update the ref
|
|
83
|
+
Vue.watch(
|
|
84
|
+
() => props.matchId,
|
|
85
|
+
(newMatchId) => {
|
|
86
|
+
matchIdRef.value = newMatchId
|
|
87
|
+
},
|
|
88
|
+
{ immediate: true },
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
// Provide the matchId to child components
|
|
92
|
+
Vue.provide(matchContext, matchIdRef)
|
|
93
|
+
|
|
94
|
+
return (): VNode => {
|
|
95
|
+
// Determine which components to render
|
|
96
|
+
let content: VNode = Vue.h(MatchInner, { matchId: props.matchId })
|
|
97
|
+
|
|
98
|
+
// Wrap in NotFound boundary if needed
|
|
99
|
+
if (routeNotFoundComponent.value) {
|
|
100
|
+
content = Vue.h(CatchNotFound, {
|
|
101
|
+
fallback: (error: any) => {
|
|
102
|
+
// If the current not found handler doesn't exist or it has a
|
|
103
|
+
// route ID which doesn't match the current route, rethrow the error
|
|
104
|
+
if (
|
|
105
|
+
!routeNotFoundComponent.value ||
|
|
106
|
+
(error.routeId && error.routeId !== routeId.value) ||
|
|
107
|
+
(!error.routeId && route.value && !route.value.isRoot)
|
|
108
|
+
)
|
|
109
|
+
throw error
|
|
110
|
+
|
|
111
|
+
return Vue.h(routeNotFoundComponent.value, error)
|
|
112
|
+
},
|
|
113
|
+
children: content,
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Wrap in error boundary if needed
|
|
118
|
+
if (routeErrorComponent.value) {
|
|
119
|
+
content = CatchBoundary({
|
|
120
|
+
getResetKey: () => resetKey.value,
|
|
121
|
+
errorComponent: routeErrorComponent.value || ErrorComponent,
|
|
122
|
+
onCatch: (error: Error) => {
|
|
123
|
+
// Forward not found errors (we don't want to show the error component for these)
|
|
124
|
+
if (isNotFound(error)) throw error
|
|
125
|
+
warning(false, `Error in route match: ${props.matchId}`)
|
|
126
|
+
routeOnCatch.value?.(error)
|
|
127
|
+
},
|
|
128
|
+
children: content,
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Wrap in suspense if needed
|
|
133
|
+
// Root routes should also wrap in Suspense if they have a pendingComponent
|
|
134
|
+
const needsSuspense =
|
|
135
|
+
route.value &&
|
|
136
|
+
(route.value?.options?.wrapInSuspense ??
|
|
137
|
+
PendingComponent.value ??
|
|
138
|
+
false)
|
|
139
|
+
|
|
140
|
+
if (needsSuspense) {
|
|
141
|
+
content = Vue.h(
|
|
142
|
+
Vue.Suspense,
|
|
143
|
+
{
|
|
144
|
+
fallback: PendingComponent.value
|
|
145
|
+
? Vue.h(PendingComponent.value)
|
|
146
|
+
: null,
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
default: () => content,
|
|
150
|
+
},
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Add scroll restoration if needed
|
|
155
|
+
const withScrollRestoration: Array<VNode> = [
|
|
156
|
+
content,
|
|
157
|
+
parentRouteId.value === rootRouteId && router.options.scrollRestoration
|
|
158
|
+
? Vue.h(Vue.Fragment, null, [
|
|
159
|
+
Vue.h(OnRendered),
|
|
160
|
+
Vue.h(ScrollRestoration),
|
|
161
|
+
])
|
|
162
|
+
: null,
|
|
163
|
+
].filter(Boolean) as Array<VNode>
|
|
164
|
+
|
|
165
|
+
return Vue.h(Vue.Fragment, null, withScrollRestoration)
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
// On Rendered can't happen above the root layout because it actually
|
|
171
|
+
// renders a dummy dom element to track the rendered state of the app.
|
|
172
|
+
// We render a script tag with a key that changes based on the current
|
|
173
|
+
// location state.key. Also, because it's below the root layout, it
|
|
174
|
+
// allows us to fire onRendered events even after a hydration mismatch
|
|
175
|
+
// error that occurred above the root layout (like bad head/link tags,
|
|
176
|
+
// which is common).
|
|
177
|
+
const OnRendered = Vue.defineComponent({
|
|
178
|
+
name: 'OnRendered',
|
|
179
|
+
setup() {
|
|
180
|
+
const router = useRouter()
|
|
181
|
+
|
|
182
|
+
const location = useRouterState({
|
|
183
|
+
select: (s) => {
|
|
184
|
+
return s.resolvedLocation?.state.key
|
|
185
|
+
},
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
Vue.watchEffect(() => {
|
|
189
|
+
if (location.value) {
|
|
190
|
+
router.emit({
|
|
191
|
+
type: 'onRendered',
|
|
192
|
+
...getLocationChangeInfo(router.state),
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
return () => null
|
|
198
|
+
},
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
export const MatchInner = Vue.defineComponent({
|
|
202
|
+
name: 'MatchInner',
|
|
203
|
+
props: {
|
|
204
|
+
matchId: {
|
|
205
|
+
type: String,
|
|
206
|
+
required: true,
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
setup(props) {
|
|
210
|
+
const router = useRouter()
|
|
211
|
+
|
|
212
|
+
// { match, key, routeId } =
|
|
213
|
+
const matchState = useRouterState({
|
|
214
|
+
select: (s) => {
|
|
215
|
+
const match = s.matches.find((d) => d.id === props.matchId)
|
|
216
|
+
|
|
217
|
+
// During navigation transitions, matches can be temporarily removed
|
|
218
|
+
if (!match) {
|
|
219
|
+
return null
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const routeId = match.routeId as string
|
|
223
|
+
|
|
224
|
+
const remountFn =
|
|
225
|
+
(router.routesById[routeId] as AnyRoute).options.remountDeps ??
|
|
226
|
+
router.options.defaultRemountDeps
|
|
227
|
+
const remountDeps = remountFn?.({
|
|
228
|
+
routeId,
|
|
229
|
+
loaderDeps: match.loaderDeps,
|
|
230
|
+
params: match._strictParams,
|
|
231
|
+
search: match._strictSearch,
|
|
232
|
+
})
|
|
233
|
+
const key = remountDeps ? JSON.stringify(remountDeps) : undefined
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
key,
|
|
237
|
+
routeId,
|
|
238
|
+
match: {
|
|
239
|
+
id: match.id,
|
|
240
|
+
status: match.status,
|
|
241
|
+
error: match.error,
|
|
242
|
+
},
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
const route = Vue.computed(() => {
|
|
248
|
+
if (!matchState.value) return null
|
|
249
|
+
return router.routesById[matchState.value.routeId]!
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
const match = Vue.computed(() => matchState.value?.match)
|
|
253
|
+
|
|
254
|
+
const out = Vue.computed((): VNode | null => {
|
|
255
|
+
if (!route.value) return null
|
|
256
|
+
const Comp =
|
|
257
|
+
route.value.options.component ?? router.options.defaultComponent
|
|
258
|
+
if (Comp) {
|
|
259
|
+
return Vue.h(Comp)
|
|
260
|
+
}
|
|
261
|
+
return Vue.h(Outlet)
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
return (): VNode | null => {
|
|
265
|
+
// If match doesn't exist, return null (component is being unmounted or not ready)
|
|
266
|
+
if (!matchState.value || !match.value || !route.value) {
|
|
267
|
+
return null
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Handle different match statuses
|
|
271
|
+
if (match.value.status === 'notFound') {
|
|
272
|
+
invariant(isNotFound(match.value.error), 'Expected a notFound error')
|
|
273
|
+
return renderRouteNotFound(router, route.value, match.value.error)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (match.value.status === 'redirected') {
|
|
277
|
+
invariant(isRedirect(match.value.error), 'Expected a redirect error')
|
|
278
|
+
throw router.getMatch(match.value.id)?._nonReactive.loadPromise
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (match.value.status === 'error') {
|
|
282
|
+
// Check if this route or any parent has an error component
|
|
283
|
+
const RouteErrorComponent =
|
|
284
|
+
route.value.options.errorComponent ??
|
|
285
|
+
router.options.defaultErrorComponent
|
|
286
|
+
|
|
287
|
+
// If this route has an error component, render it directly
|
|
288
|
+
// This is more reliable than relying on Vue's error boundary
|
|
289
|
+
if (RouteErrorComponent) {
|
|
290
|
+
return Vue.h(RouteErrorComponent, {
|
|
291
|
+
error: match.value.error,
|
|
292
|
+
reset: () => {
|
|
293
|
+
router.invalidate()
|
|
294
|
+
},
|
|
295
|
+
info: {
|
|
296
|
+
componentStack: '',
|
|
297
|
+
},
|
|
298
|
+
})
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// If there's no error component for this route, throw the error
|
|
302
|
+
// so it can bubble up to the nearest parent with an error component
|
|
303
|
+
throw match.value.error
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (match.value.status === 'pending') {
|
|
307
|
+
const pendingMinMs =
|
|
308
|
+
route.value.options.pendingMinMs ?? router.options.defaultPendingMinMs
|
|
309
|
+
|
|
310
|
+
const routerMatch = router.getMatch(match.value.id)
|
|
311
|
+
if (
|
|
312
|
+
pendingMinMs &&
|
|
313
|
+
routerMatch &&
|
|
314
|
+
!routerMatch._nonReactive.minPendingPromise
|
|
315
|
+
) {
|
|
316
|
+
// Create a promise that will resolve after the minPendingMs
|
|
317
|
+
if (!router.isServer) {
|
|
318
|
+
const minPendingPromise = createControlledPromise<void>()
|
|
319
|
+
|
|
320
|
+
routerMatch._nonReactive.minPendingPromise = minPendingPromise
|
|
321
|
+
|
|
322
|
+
setTimeout(() => {
|
|
323
|
+
minPendingPromise.resolve()
|
|
324
|
+
// We've handled the minPendingPromise, so we can delete it
|
|
325
|
+
routerMatch._nonReactive.minPendingPromise = undefined
|
|
326
|
+
}, pendingMinMs)
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// In Vue, we render the pending component directly instead of throwing a promise
|
|
331
|
+
// because Vue's Suspense doesn't catch thrown promises like React does
|
|
332
|
+
const PendingComponent =
|
|
333
|
+
route.value.options.pendingComponent ??
|
|
334
|
+
router.options.defaultPendingComponent
|
|
335
|
+
|
|
336
|
+
if (PendingComponent) {
|
|
337
|
+
return Vue.h(PendingComponent)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// If no pending component, return null while loading
|
|
341
|
+
return null
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Success status - render the component
|
|
345
|
+
return out.value
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
export const Outlet = Vue.defineComponent({
|
|
351
|
+
name: 'Outlet',
|
|
352
|
+
setup() {
|
|
353
|
+
const router = useRouter()
|
|
354
|
+
const matchId = Vue.inject(matchContext)
|
|
355
|
+
const safeMatchId = Vue.computed(() => matchId?.value || '')
|
|
356
|
+
|
|
357
|
+
const routeId = useRouterState({
|
|
358
|
+
select: (s) =>
|
|
359
|
+
s.matches.find((d) => d.id === safeMatchId.value)?.routeId as string,
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
const route = Vue.computed(() => router.routesById[routeId.value]!)
|
|
363
|
+
|
|
364
|
+
const parentGlobalNotFound = useRouterState({
|
|
365
|
+
select: (s) => {
|
|
366
|
+
const matches = s.matches
|
|
367
|
+
const parentMatch = matches.find((d) => d.id === safeMatchId.value)
|
|
368
|
+
|
|
369
|
+
// During navigation transitions, parent match can be temporarily removed
|
|
370
|
+
// Return false to avoid errors - the component will handle this gracefully
|
|
371
|
+
if (!parentMatch) {
|
|
372
|
+
return false
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return parentMatch.globalNotFound
|
|
376
|
+
},
|
|
377
|
+
})
|
|
378
|
+
|
|
379
|
+
const childMatchId = useRouterState({
|
|
380
|
+
select: (s) => {
|
|
381
|
+
const matches = s.matches
|
|
382
|
+
const index = matches.findIndex((d) => d.id === safeMatchId.value)
|
|
383
|
+
return matches[index + 1]?.id
|
|
384
|
+
},
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
return (): VNode | null => {
|
|
388
|
+
if (parentGlobalNotFound.value) {
|
|
389
|
+
return renderRouteNotFound(router, route.value, undefined)
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (!childMatchId.value) {
|
|
393
|
+
return null
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const nextMatch = Vue.h(Match, { matchId: childMatchId.value })
|
|
397
|
+
|
|
398
|
+
if (safeMatchId.value === rootRouteId) {
|
|
399
|
+
return Vue.h(
|
|
400
|
+
Vue.Suspense,
|
|
401
|
+
{
|
|
402
|
+
fallback: router.options.defaultPendingComponent
|
|
403
|
+
? Vue.h(router.options.defaultPendingComponent)
|
|
404
|
+
: null,
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
default: () => nextMatch,
|
|
408
|
+
},
|
|
409
|
+
)
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
return nextMatch
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
})
|