@tanstack/solid-router 1.167.4 → 1.168.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/dist/cjs/Match.cjs +244 -223
- package/dist/cjs/Match.cjs.map +1 -1
- package/dist/cjs/Match.d.cts +1 -3
- package/dist/cjs/Matches.cjs +32 -31
- package/dist/cjs/Matches.cjs.map +1 -1
- package/dist/cjs/Scripts.cjs +10 -8
- package/dist/cjs/Scripts.cjs.map +1 -1
- package/dist/cjs/Scripts.d.cts +2 -1
- package/dist/cjs/Transitioner.cjs +26 -26
- package/dist/cjs/Transitioner.cjs.map +1 -1
- package/dist/cjs/headContentUtils.cjs +15 -15
- package/dist/cjs/headContentUtils.cjs.map +1 -1
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/index.dev.cjs +1 -1
- package/dist/cjs/link.cjs +119 -84
- package/dist/cjs/link.cjs.map +1 -1
- package/dist/cjs/matchContext.cjs +7 -5
- package/dist/cjs/matchContext.cjs.map +1 -1
- package/dist/cjs/matchContext.d.cts +8 -2
- package/dist/cjs/not-found.cjs +8 -4
- package/dist/cjs/not-found.cjs.map +1 -1
- package/dist/cjs/not-found.d.cts +1 -1
- package/dist/cjs/router.cjs +2 -1
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/routerStores.cjs +67 -0
- package/dist/cjs/routerStores.cjs.map +1 -0
- package/dist/cjs/routerStores.d.cts +10 -0
- package/dist/cjs/ssr/RouterClient.cjs +1 -1
- package/dist/cjs/ssr/RouterClient.cjs.map +1 -1
- package/dist/cjs/ssr/renderRouterToStream.cjs +1 -1
- package/dist/cjs/ssr/renderRouterToStream.cjs.map +1 -1
- package/dist/cjs/ssr/renderRouterToString.cjs +2 -2
- package/dist/cjs/ssr/renderRouterToString.cjs.map +1 -1
- package/dist/cjs/ssr/renderRouterToString.d.cts +1 -1
- package/dist/cjs/useCanGoBack.cjs +6 -2
- package/dist/cjs/useCanGoBack.cjs.map +1 -1
- package/dist/cjs/useCanGoBack.d.cts +2 -1
- package/dist/cjs/useLoaderDeps.cjs +2 -3
- package/dist/cjs/useLoaderDeps.cjs.map +1 -1
- package/dist/cjs/useLocation.cjs +13 -2
- package/dist/cjs/useLocation.cjs.map +1 -1
- package/dist/cjs/useMatch.cjs +17 -15
- package/dist/cjs/useMatch.cjs.map +1 -1
- package/dist/cjs/useParams.cjs +1 -1
- package/dist/cjs/useParams.cjs.map +1 -1
- package/dist/cjs/useRouterState.cjs +12 -19
- package/dist/cjs/useRouterState.cjs.map +1 -1
- package/dist/cjs/useSearch.cjs +2 -1
- package/dist/cjs/useSearch.cjs.map +1 -1
- package/dist/cjs/utils.cjs +0 -14
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +0 -4
- package/dist/esm/Match.d.ts +1 -3
- package/dist/esm/Match.js +245 -224
- package/dist/esm/Match.js.map +1 -1
- package/dist/esm/Matches.js +34 -33
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/Scripts.d.ts +2 -1
- package/dist/esm/Scripts.js +8 -7
- package/dist/esm/Scripts.js.map +1 -1
- package/dist/esm/Transitioner.js +26 -26
- package/dist/esm/Transitioner.js.map +1 -1
- package/dist/esm/headContentUtils.js +15 -15
- package/dist/esm/headContentUtils.js.map +1 -1
- package/dist/esm/index.dev.js +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/link.js +120 -85
- package/dist/esm/link.js.map +1 -1
- package/dist/esm/matchContext.d.ts +8 -2
- package/dist/esm/matchContext.js +7 -4
- package/dist/esm/matchContext.js.map +1 -1
- package/dist/esm/not-found.d.ts +1 -1
- package/dist/esm/not-found.js +6 -3
- package/dist/esm/not-found.js.map +1 -1
- package/dist/esm/router.js +2 -1
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/routerStores.d.ts +10 -0
- package/dist/esm/routerStores.js +65 -0
- package/dist/esm/routerStores.js.map +1 -0
- package/dist/esm/ssr/RouterClient.js +1 -1
- package/dist/esm/ssr/RouterClient.js.map +1 -1
- package/dist/esm/ssr/renderRouterToStream.js +1 -1
- package/dist/esm/ssr/renderRouterToStream.js.map +1 -1
- package/dist/esm/ssr/renderRouterToString.d.ts +1 -1
- package/dist/esm/ssr/renderRouterToString.js +2 -2
- package/dist/esm/ssr/renderRouterToString.js.map +1 -1
- package/dist/esm/useCanGoBack.d.ts +2 -1
- package/dist/esm/useCanGoBack.js +4 -2
- package/dist/esm/useCanGoBack.js.map +1 -1
- package/dist/esm/useLoaderDeps.js +2 -3
- package/dist/esm/useLoaderDeps.js.map +1 -1
- package/dist/esm/useLocation.js +11 -2
- package/dist/esm/useLocation.js.map +1 -1
- package/dist/esm/useMatch.js +18 -16
- package/dist/esm/useMatch.js.map +1 -1
- package/dist/esm/useParams.js +1 -1
- package/dist/esm/useParams.js.map +1 -1
- package/dist/esm/useRouterState.js +10 -18
- package/dist/esm/useRouterState.js.map +1 -1
- package/dist/esm/useSearch.js +2 -1
- package/dist/esm/useSearch.js.map +1 -1
- package/dist/esm/utils.d.ts +0 -4
- package/dist/esm/utils.js +1 -14
- package/dist/esm/utils.js.map +1 -1
- package/dist/source/Match.d.ts +1 -3
- package/dist/source/Match.jsx +246 -237
- package/dist/source/Match.jsx.map +1 -1
- package/dist/source/Matches.jsx +42 -44
- package/dist/source/Matches.jsx.map +1 -1
- package/dist/source/Scripts.d.ts +2 -1
- package/dist/source/Scripts.jsx +31 -36
- package/dist/source/Scripts.jsx.map +1 -1
- package/dist/source/Transitioner.jsx +26 -31
- package/dist/source/Transitioner.jsx.map +1 -1
- package/dist/source/headContentUtils.jsx +64 -72
- package/dist/source/headContentUtils.jsx.map +1 -1
- package/dist/source/link.jsx +136 -107
- package/dist/source/link.jsx.map +1 -1
- package/dist/source/matchContext.d.ts +8 -2
- package/dist/source/matchContext.jsx +7 -3
- package/dist/source/matchContext.jsx.map +1 -1
- package/dist/source/not-found.d.ts +1 -1
- package/dist/source/not-found.jsx +6 -5
- package/dist/source/not-found.jsx.map +1 -1
- package/dist/source/router.js +2 -1
- package/dist/source/router.js.map +1 -1
- package/dist/source/routerStores.d.ts +10 -0
- package/dist/source/routerStores.js +71 -0
- package/dist/source/routerStores.js.map +1 -0
- package/dist/source/ssr/RouterClient.jsx +1 -1
- package/dist/source/ssr/RouterClient.jsx.map +1 -1
- package/dist/source/ssr/renderRouterToStream.jsx +1 -1
- package/dist/source/ssr/renderRouterToStream.jsx.map +1 -1
- package/dist/source/ssr/renderRouterToString.d.ts +1 -1
- package/dist/source/ssr/renderRouterToString.jsx +2 -2
- package/dist/source/ssr/renderRouterToString.jsx.map +1 -1
- package/dist/source/useCanGoBack.d.ts +2 -1
- package/dist/source/useCanGoBack.js +4 -2
- package/dist/source/useCanGoBack.js.map +1 -1
- package/dist/source/useLoaderDeps.jsx +2 -3
- package/dist/source/useLoaderDeps.jsx.map +1 -1
- package/dist/source/useLocation.jsx +13 -3
- package/dist/source/useLocation.jsx.map +1 -1
- package/dist/source/useMatch.jsx +30 -27
- package/dist/source/useMatch.jsx.map +1 -1
- package/dist/source/useParams.jsx +1 -1
- package/dist/source/useParams.jsx.map +1 -1
- package/dist/source/useRouterState.jsx +12 -33
- package/dist/source/useRouterState.jsx.map +1 -1
- package/dist/source/useSearch.jsx +2 -1
- package/dist/source/useSearch.jsx.map +1 -1
- package/dist/source/utils.d.ts +0 -4
- package/dist/source/utils.js +0 -13
- package/dist/source/utils.js.map +1 -1
- package/package.json +2 -3
- package/skills/solid-router/SKILL.md +2 -0
- package/src/Match.tsx +351 -304
- package/src/Matches.tsx +49 -52
- package/src/Scripts.tsx +40 -41
- package/src/Transitioner.tsx +67 -66
- package/src/headContentUtils.tsx +89 -91
- package/src/link.tsx +179 -141
- package/src/matchContext.tsx +16 -7
- package/src/not-found.tsx +6 -6
- package/src/router.ts +2 -1
- package/src/routerStores.ts +107 -0
- package/src/ssr/RouterClient.tsx +1 -1
- package/src/ssr/renderRouterToStream.tsx +1 -1
- package/src/ssr/renderRouterToString.tsx +2 -2
- package/src/useCanGoBack.ts +6 -2
- package/src/useLoaderDeps.tsx +2 -3
- package/src/useLocation.tsx +18 -5
- package/src/useMatch.tsx +36 -43
- package/src/useParams.tsx +2 -3
- package/src/useRouterState.tsx +17 -41
- package/src/useSearch.tsx +2 -1
- package/src/utils.ts +0 -20
package/src/Match.tsx
CHANGED
|
@@ -11,10 +11,9 @@ import {
|
|
|
11
11
|
import { isServer } from '@tanstack/router-core/isServer'
|
|
12
12
|
import { Dynamic } from 'solid-js/web'
|
|
13
13
|
import { CatchBoundary, ErrorComponent } from './CatchBoundary'
|
|
14
|
-
import { useRouterState } from './useRouterState'
|
|
15
14
|
import { useRouter } from './useRouter'
|
|
16
15
|
import { CatchNotFound } from './not-found'
|
|
17
|
-
import {
|
|
16
|
+
import { nearestMatchContext } from './matchContext'
|
|
18
17
|
import { SafeFragment } from './SafeFragment'
|
|
19
18
|
import { renderRouteNotFound } from './renderRouteNotFound'
|
|
20
19
|
import { ScrollRestoration } from './scroll-restoration'
|
|
@@ -22,136 +21,162 @@ import type { AnyRoute, RootRouteOptions } from '@tanstack/router-core'
|
|
|
22
21
|
|
|
23
22
|
export const Match = (props: { matchId: string }) => {
|
|
24
23
|
const router = useRouter()
|
|
25
|
-
const matchState = useRouterState({
|
|
26
|
-
select: (s) => {
|
|
27
|
-
const match = s.matches.find((d) => d.id === props.matchId)
|
|
28
|
-
|
|
29
|
-
// During navigation transitions, matches can be temporarily removed
|
|
30
|
-
// Return null to avoid errors - the component will handle this gracefully
|
|
31
|
-
if (!match) {
|
|
32
|
-
return null
|
|
33
|
-
}
|
|
34
24
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
},
|
|
25
|
+
const match = Solid.createMemo(() => {
|
|
26
|
+
const id = props.matchId
|
|
27
|
+
if (!id) return undefined
|
|
28
|
+
return router.stores.activeMatchStoresById.get(id)?.state
|
|
41
29
|
})
|
|
42
30
|
|
|
43
|
-
|
|
44
|
-
|
|
31
|
+
const rawMatchState = Solid.createMemo(() => {
|
|
32
|
+
const currentMatch = match()
|
|
33
|
+
if (!currentMatch) {
|
|
34
|
+
return null
|
|
35
|
+
}
|
|
45
36
|
|
|
46
|
-
|
|
37
|
+
const routeId = currentMatch.routeId as string
|
|
38
|
+
const parentRouteId = (router.routesById[routeId] as AnyRoute)?.parentRoute
|
|
39
|
+
?.id
|
|
47
40
|
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
return {
|
|
42
|
+
matchId: currentMatch.id,
|
|
43
|
+
routeId,
|
|
44
|
+
ssr: currentMatch.ssr,
|
|
45
|
+
_displayPending: currentMatch._displayPending,
|
|
46
|
+
parentRouteId: parentRouteId as string | undefined,
|
|
47
|
+
}
|
|
48
|
+
})
|
|
50
49
|
|
|
51
|
-
const
|
|
52
|
-
|
|
50
|
+
const hasPendingMatch = Solid.createMemo(() => {
|
|
51
|
+
const currentRouteId = rawMatchState()?.routeId
|
|
52
|
+
return currentRouteId
|
|
53
|
+
? Boolean(router.stores.pendingRouteIds.state[currentRouteId])
|
|
54
|
+
: false
|
|
55
|
+
})
|
|
56
|
+
const nearestMatch = {
|
|
57
|
+
matchId: () => rawMatchState()?.matchId,
|
|
58
|
+
routeId: () => rawMatchState()?.routeId,
|
|
59
|
+
match,
|
|
60
|
+
hasPending: hasPendingMatch,
|
|
61
|
+
}
|
|
53
62
|
|
|
54
|
-
|
|
55
|
-
|
|
63
|
+
return (
|
|
64
|
+
<Solid.Show when={rawMatchState()}>
|
|
65
|
+
{(currentMatchState) => {
|
|
66
|
+
const route: () => AnyRoute = () =>
|
|
67
|
+
router.routesById[currentMatchState().routeId]
|
|
56
68
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
(route().options.notFoundComponent ??
|
|
61
|
-
router.options.notFoundRoute?.options.component)
|
|
62
|
-
: route().options.notFoundComponent
|
|
69
|
+
const resolvePendingComponent = () =>
|
|
70
|
+
route().options.pendingComponent ??
|
|
71
|
+
router.options.defaultPendingComponent
|
|
63
72
|
|
|
64
|
-
|
|
65
|
-
|
|
73
|
+
const routeErrorComponent = () =>
|
|
74
|
+
route().options.errorComponent ?? router.options.defaultErrorComponent
|
|
66
75
|
|
|
67
|
-
|
|
76
|
+
const routeOnCatch = () =>
|
|
77
|
+
route().options.onCatch ?? router.options.defaultOnCatch
|
|
68
78
|
|
|
69
|
-
|
|
70
|
-
|
|
79
|
+
const routeNotFoundComponent = () =>
|
|
80
|
+
route().isRoot
|
|
81
|
+
? // If it's the root route, use the globalNotFound option, with fallback to the notFoundRoute's component
|
|
82
|
+
(route().options.notFoundComponent ??
|
|
83
|
+
router.options.notFoundRoute?.options.component)
|
|
84
|
+
: route().options.notFoundComponent
|
|
71
85
|
|
|
72
|
-
|
|
73
|
-
|
|
86
|
+
const resolvedNoSsr =
|
|
87
|
+
currentMatchState().ssr === false ||
|
|
88
|
+
currentMatchState().ssr === 'data-only'
|
|
74
89
|
|
|
75
|
-
|
|
76
|
-
select: (s) => s.loadedAt,
|
|
77
|
-
})
|
|
90
|
+
const ResolvedSuspenseBoundary = () => Solid.Suspense
|
|
78
91
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const index = s.matches.findIndex((d) => d.id === props.matchId)
|
|
82
|
-
return s.matches[index - 1]?.routeId as string
|
|
83
|
-
},
|
|
84
|
-
})
|
|
92
|
+
const ResolvedCatchBoundary = () =>
|
|
93
|
+
routeErrorComponent() ? CatchBoundary : SafeFragment
|
|
85
94
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
: SafeFragment
|
|
95
|
+
const ResolvedNotFoundBoundary = () =>
|
|
96
|
+
routeNotFoundComponent() ? CatchNotFound : SafeFragment
|
|
89
97
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
component={ResolvedSuspenseBoundary()}
|
|
95
|
-
fallback={
|
|
96
|
-
// Don't show fallback on server when using no-ssr mode to avoid hydration mismatch
|
|
97
|
-
(isServer ?? router.isServer) || resolvedNoSsr ? undefined : (
|
|
98
|
-
<Dynamic component={resolvePendingComponent()} />
|
|
99
|
-
)
|
|
100
|
-
}
|
|
101
|
-
>
|
|
102
|
-
<Dynamic
|
|
103
|
-
component={ResolvedCatchBoundary()}
|
|
104
|
-
getResetKey={() => resetKey()}
|
|
105
|
-
errorComponent={routeErrorComponent() || ErrorComponent}
|
|
106
|
-
onCatch={(error: Error) => {
|
|
107
|
-
// Forward not found errors (we don't want to show the error component for these)
|
|
108
|
-
if (isNotFound(error)) throw error
|
|
109
|
-
warning(false, `Error in route match: ${matchState()!.routeId}`)
|
|
110
|
-
routeOnCatch()?.(error)
|
|
111
|
-
}}
|
|
112
|
-
>
|
|
113
|
-
<Dynamic
|
|
114
|
-
component={ResolvedNotFoundBoundary()}
|
|
115
|
-
fallback={(error: any) => {
|
|
116
|
-
// If the current not found handler doesn't exist or it has a
|
|
117
|
-
// route ID which doesn't match the current route, rethrow the error
|
|
118
|
-
if (
|
|
119
|
-
!routeNotFoundComponent() ||
|
|
120
|
-
(error.routeId && error.routeId !== matchState()!.routeId) ||
|
|
121
|
-
(!error.routeId && !route().isRoot)
|
|
122
|
-
)
|
|
123
|
-
throw error
|
|
98
|
+
const ShellComponent = route().isRoot
|
|
99
|
+
? ((route().options as RootRouteOptions).shellComponent ??
|
|
100
|
+
SafeFragment)
|
|
101
|
+
: SafeFragment
|
|
124
102
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
103
|
+
return (
|
|
104
|
+
<ShellComponent>
|
|
105
|
+
<nearestMatchContext.Provider value={nearestMatch}>
|
|
106
|
+
<Dynamic
|
|
107
|
+
component={ResolvedSuspenseBoundary()}
|
|
108
|
+
fallback={
|
|
109
|
+
// Don't show fallback on server when using no-ssr mode to avoid hydration mismatch
|
|
110
|
+
(isServer ?? router.isServer) && resolvedNoSsr ? undefined : (
|
|
111
|
+
<Dynamic component={resolvePendingComponent()} />
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
>
|
|
115
|
+
<Dynamic
|
|
116
|
+
component={ResolvedCatchBoundary()}
|
|
117
|
+
getResetKey={() => router.stores.loadedAt.state}
|
|
118
|
+
errorComponent={routeErrorComponent() || ErrorComponent}
|
|
119
|
+
onCatch={(error: Error) => {
|
|
120
|
+
// Forward not found errors (we don't want to show the error component for these)
|
|
121
|
+
if (isNotFound(error)) throw error
|
|
122
|
+
warning(
|
|
123
|
+
false,
|
|
124
|
+
`Error in route match: ${currentMatchState().routeId}`,
|
|
125
|
+
)
|
|
126
|
+
routeOnCatch()?.(error)
|
|
127
|
+
}}
|
|
128
|
+
>
|
|
129
|
+
<Dynamic
|
|
130
|
+
component={ResolvedNotFoundBoundary()}
|
|
131
|
+
fallback={(error: any) => {
|
|
132
|
+
// If the current not found handler doesn't exist or it has a
|
|
133
|
+
// route ID which doesn't match the current route, rethrow the error
|
|
134
|
+
if (
|
|
135
|
+
!routeNotFoundComponent() ||
|
|
136
|
+
(error.routeId &&
|
|
137
|
+
error.routeId !== currentMatchState().routeId) ||
|
|
138
|
+
(!error.routeId && !route().isRoot)
|
|
139
|
+
)
|
|
140
|
+
throw error
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<Dynamic
|
|
144
|
+
component={routeNotFoundComponent()}
|
|
145
|
+
{...error}
|
|
146
|
+
/>
|
|
147
|
+
)
|
|
148
|
+
}}
|
|
135
149
|
>
|
|
136
|
-
<
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
150
|
+
<Solid.Switch>
|
|
151
|
+
<Solid.Match when={resolvedNoSsr}>
|
|
152
|
+
<Solid.Show
|
|
153
|
+
when={!(isServer ?? router.isServer)}
|
|
154
|
+
fallback={
|
|
155
|
+
<Dynamic component={resolvePendingComponent()} />
|
|
156
|
+
}
|
|
157
|
+
>
|
|
158
|
+
<MatchInner />
|
|
159
|
+
</Solid.Show>
|
|
160
|
+
</Solid.Match>
|
|
161
|
+
<Solid.Match when={!resolvedNoSsr}>
|
|
162
|
+
<MatchInner />
|
|
163
|
+
</Solid.Match>
|
|
164
|
+
</Solid.Switch>
|
|
165
|
+
</Dynamic>
|
|
166
|
+
</Dynamic>
|
|
167
|
+
</Dynamic>
|
|
168
|
+
</nearestMatchContext.Provider>
|
|
169
|
+
|
|
170
|
+
{currentMatchState().parentRouteId === rootRouteId ? (
|
|
171
|
+
<>
|
|
172
|
+
<OnRendered />
|
|
173
|
+
<ScrollRestoration />
|
|
174
|
+
</>
|
|
175
|
+
) : null}
|
|
176
|
+
</ShellComponent>
|
|
177
|
+
)
|
|
178
|
+
}}
|
|
179
|
+
</Solid.Show>
|
|
155
180
|
)
|
|
156
181
|
}
|
|
157
182
|
|
|
@@ -165,223 +190,244 @@ export const Match = (props: { matchId: string }) => {
|
|
|
165
190
|
function OnRendered() {
|
|
166
191
|
const router = useRouter()
|
|
167
192
|
|
|
168
|
-
const location =
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
},
|
|
172
|
-
})
|
|
193
|
+
const location = Solid.createMemo(
|
|
194
|
+
() => router.stores.resolvedLocation.state?.state.__TSR_key,
|
|
195
|
+
)
|
|
173
196
|
Solid.createEffect(
|
|
174
197
|
Solid.on([location], () => {
|
|
175
198
|
router.emit({
|
|
176
199
|
type: 'onRendered',
|
|
177
|
-
...getLocationChangeInfo(
|
|
200
|
+
...getLocationChangeInfo(
|
|
201
|
+
router.stores.location.state,
|
|
202
|
+
router.stores.resolvedLocation.state,
|
|
203
|
+
),
|
|
178
204
|
})
|
|
179
205
|
}),
|
|
180
206
|
)
|
|
181
207
|
return null
|
|
182
208
|
}
|
|
183
209
|
|
|
184
|
-
export const MatchInner = (
|
|
210
|
+
export const MatchInner = (): any => {
|
|
185
211
|
const router = useRouter()
|
|
212
|
+
const match = Solid.useContext(nearestMatchContext).match
|
|
186
213
|
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
214
|
+
const rawMatchState = Solid.createMemo(() => {
|
|
215
|
+
const currentMatch = match()
|
|
216
|
+
if (!currentMatch) {
|
|
217
|
+
return null
|
|
218
|
+
}
|
|
190
219
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
220
|
+
const routeId = currentMatch.routeId as string
|
|
221
|
+
|
|
222
|
+
const remountFn =
|
|
223
|
+
(router.routesById[routeId] as AnyRoute).options.remountDeps ??
|
|
224
|
+
router.options.defaultRemountDeps
|
|
225
|
+
const remountDeps = remountFn?.({
|
|
226
|
+
routeId,
|
|
227
|
+
loaderDeps: currentMatch.loaderDeps,
|
|
228
|
+
params: currentMatch._strictParams,
|
|
229
|
+
search: currentMatch._strictSearch,
|
|
230
|
+
})
|
|
231
|
+
const key = remountDeps ? JSON.stringify(remountDeps) : undefined
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
key,
|
|
235
|
+
routeId,
|
|
236
|
+
match: {
|
|
237
|
+
id: currentMatch.id,
|
|
238
|
+
status: currentMatch.status,
|
|
239
|
+
error: currentMatch.error,
|
|
240
|
+
_forcePending: currentMatch._forcePending ?? false,
|
|
241
|
+
_displayPending: currentMatch._displayPending ?? false,
|
|
242
|
+
},
|
|
243
|
+
}
|
|
244
|
+
})
|
|
195
245
|
|
|
196
|
-
|
|
246
|
+
return (
|
|
247
|
+
<Solid.Show when={rawMatchState()}>
|
|
248
|
+
{(currentMatchState) => {
|
|
249
|
+
const route = () => router.routesById[currentMatchState().routeId]!
|
|
197
250
|
|
|
198
|
-
|
|
199
|
-
(router.routesById[routeId] as AnyRoute).options.remountDeps ??
|
|
200
|
-
router.options.defaultRemountDeps
|
|
201
|
-
const remountDeps = remountFn?.({
|
|
202
|
-
routeId,
|
|
203
|
-
loaderDeps: match.loaderDeps,
|
|
204
|
-
params: match._strictParams,
|
|
205
|
-
search: match._strictSearch,
|
|
206
|
-
})
|
|
207
|
-
const key = remountDeps ? JSON.stringify(remountDeps) : undefined
|
|
208
|
-
|
|
209
|
-
return {
|
|
210
|
-
key,
|
|
211
|
-
routeId,
|
|
212
|
-
match: {
|
|
213
|
-
id: match.id,
|
|
214
|
-
status: match.status,
|
|
215
|
-
error: match.error,
|
|
216
|
-
_forcePending: match._forcePending,
|
|
217
|
-
_displayPending: match._displayPending,
|
|
218
|
-
},
|
|
219
|
-
}
|
|
220
|
-
},
|
|
221
|
-
})
|
|
251
|
+
const currentMatch = () => currentMatchState().match
|
|
222
252
|
|
|
223
|
-
|
|
253
|
+
const componentKey = () =>
|
|
254
|
+
currentMatchState().key ?? currentMatchState().match.id
|
|
255
|
+
|
|
256
|
+
const out = () => {
|
|
257
|
+
const Comp =
|
|
258
|
+
route().options.component ?? router.options.defaultComponent
|
|
259
|
+
if (Comp) {
|
|
260
|
+
return <Comp />
|
|
261
|
+
}
|
|
262
|
+
return <Outlet />
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const keyedOut = () => (
|
|
266
|
+
<Solid.Show when={componentKey()} keyed>
|
|
267
|
+
{(_key) => out()}
|
|
268
|
+
</Solid.Show>
|
|
269
|
+
)
|
|
224
270
|
|
|
225
|
-
|
|
271
|
+
return (
|
|
272
|
+
<Solid.Switch>
|
|
273
|
+
<Solid.Match when={currentMatch()._displayPending}>
|
|
274
|
+
{(_) => {
|
|
275
|
+
const [displayPendingResult] = Solid.createResource(
|
|
276
|
+
() =>
|
|
277
|
+
router.getMatch(currentMatch().id)?._nonReactive
|
|
278
|
+
.displayPendingPromise,
|
|
279
|
+
)
|
|
226
280
|
|
|
227
|
-
|
|
281
|
+
return <>{displayPendingResult()}</>
|
|
282
|
+
}}
|
|
283
|
+
</Solid.Match>
|
|
284
|
+
<Solid.Match when={currentMatch()._forcePending}>
|
|
285
|
+
{(_) => {
|
|
286
|
+
const [minPendingResult] = Solid.createResource(
|
|
287
|
+
() =>
|
|
288
|
+
router.getMatch(currentMatch().id)?._nonReactive
|
|
289
|
+
.minPendingPromise,
|
|
290
|
+
)
|
|
228
291
|
|
|
229
|
-
|
|
292
|
+
return <>{minPendingResult()}</>
|
|
293
|
+
}}
|
|
294
|
+
</Solid.Match>
|
|
295
|
+
<Solid.Match when={currentMatch().status === 'pending'}>
|
|
296
|
+
{(_) => {
|
|
297
|
+
const pendingMinMs =
|
|
298
|
+
route().options.pendingMinMs ??
|
|
299
|
+
router.options.defaultPendingMinMs
|
|
300
|
+
|
|
301
|
+
if (pendingMinMs) {
|
|
302
|
+
const routerMatch = router.getMatch(currentMatch().id)
|
|
303
|
+
if (
|
|
304
|
+
routerMatch &&
|
|
305
|
+
!routerMatch._nonReactive.minPendingPromise
|
|
306
|
+
) {
|
|
307
|
+
// Create a promise that will resolve after the minPendingMs
|
|
308
|
+
if (!(isServer ?? router.isServer)) {
|
|
309
|
+
const minPendingPromise = createControlledPromise<void>()
|
|
310
|
+
|
|
311
|
+
routerMatch._nonReactive.minPendingPromise =
|
|
312
|
+
minPendingPromise
|
|
313
|
+
|
|
314
|
+
setTimeout(() => {
|
|
315
|
+
minPendingPromise.resolve()
|
|
316
|
+
// We've handled the minPendingPromise, so we can delete it
|
|
317
|
+
routerMatch._nonReactive.minPendingPromise = undefined
|
|
318
|
+
}, pendingMinMs)
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const [loaderResult] = Solid.createResource(async () => {
|
|
324
|
+
await new Promise((r) => setTimeout(r, 0))
|
|
325
|
+
return router.getMatch(currentMatch().id)?._nonReactive
|
|
326
|
+
.loadPromise
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
const FallbackComponent =
|
|
330
|
+
route().options.pendingComponent ??
|
|
331
|
+
router.options.defaultPendingComponent
|
|
230
332
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
333
|
+
return (
|
|
334
|
+
<>
|
|
335
|
+
{FallbackComponent && pendingMinMs > 0 ? (
|
|
336
|
+
<Dynamic component={FallbackComponent} />
|
|
337
|
+
) : null}
|
|
338
|
+
{loaderResult()}
|
|
339
|
+
</>
|
|
340
|
+
)
|
|
341
|
+
}}
|
|
342
|
+
</Solid.Match>
|
|
343
|
+
<Solid.Match when={currentMatch().status === 'notFound'}>
|
|
344
|
+
{(_) => {
|
|
345
|
+
invariant(
|
|
346
|
+
isNotFound(currentMatch().error),
|
|
347
|
+
'Expected a notFound error',
|
|
348
|
+
)
|
|
238
349
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
350
|
+
// Use Show with keyed to ensure re-render when routeId changes
|
|
351
|
+
return (
|
|
352
|
+
<Solid.Show when={currentMatchState().routeId} keyed>
|
|
353
|
+
{(_routeId) =>
|
|
354
|
+
renderRouteNotFound(router, route(), currentMatch().error)
|
|
355
|
+
}
|
|
356
|
+
</Solid.Show>
|
|
357
|
+
)
|
|
358
|
+
}}
|
|
359
|
+
</Solid.Match>
|
|
360
|
+
<Solid.Match when={currentMatch().status === 'redirected'}>
|
|
361
|
+
{(_) => {
|
|
362
|
+
invariant(
|
|
363
|
+
isRedirect(currentMatch().error),
|
|
364
|
+
'Expected a redirect error',
|
|
365
|
+
)
|
|
244
366
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
() =>
|
|
251
|
-
router.getMatch(match().id)?._nonReactive.displayPendingPromise,
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
return <>{displayPendingResult()}</>
|
|
255
|
-
}}
|
|
256
|
-
</Solid.Match>
|
|
257
|
-
<Solid.Match when={match()._forcePending}>
|
|
258
|
-
{(_) => {
|
|
259
|
-
const [minPendingResult] = Solid.createResource(
|
|
260
|
-
() => router.getMatch(match().id)?._nonReactive.minPendingPromise,
|
|
261
|
-
)
|
|
262
|
-
|
|
263
|
-
return <>{minPendingResult()}</>
|
|
264
|
-
}}
|
|
265
|
-
</Solid.Match>
|
|
266
|
-
<Solid.Match when={match().status === 'pending'}>
|
|
267
|
-
{(_) => {
|
|
268
|
-
const pendingMinMs =
|
|
269
|
-
route().options.pendingMinMs ?? router.options.defaultPendingMinMs
|
|
270
|
-
|
|
271
|
-
if (pendingMinMs) {
|
|
272
|
-
const routerMatch = router.getMatch(match().id)
|
|
273
|
-
if (routerMatch && !routerMatch._nonReactive.minPendingPromise) {
|
|
274
|
-
// Create a promise that will resolve after the minPendingMs
|
|
275
|
-
if (!(isServer ?? router.isServer)) {
|
|
276
|
-
const minPendingPromise = createControlledPromise<void>()
|
|
277
|
-
|
|
278
|
-
routerMatch._nonReactive.minPendingPromise = minPendingPromise
|
|
279
|
-
|
|
280
|
-
setTimeout(() => {
|
|
281
|
-
minPendingPromise.resolve()
|
|
282
|
-
// We've handled the minPendingPromise, so we can delete it
|
|
283
|
-
routerMatch._nonReactive.minPendingPromise = undefined
|
|
284
|
-
}, pendingMinMs)
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
367
|
+
const [loaderResult] = Solid.createResource(async () => {
|
|
368
|
+
await new Promise((r) => setTimeout(r, 0))
|
|
369
|
+
return router.getMatch(currentMatch().id)?._nonReactive
|
|
370
|
+
.loadPromise
|
|
371
|
+
})
|
|
288
372
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}}
|
|
321
|
-
</Solid.Match>
|
|
322
|
-
<Solid.Match when={match().status === 'redirected'}>
|
|
323
|
-
{(_) => {
|
|
324
|
-
invariant(isRedirect(match().error), 'Expected a redirect error')
|
|
325
|
-
|
|
326
|
-
const [loaderResult] = Solid.createResource(async () => {
|
|
327
|
-
await new Promise((r) => setTimeout(r, 0))
|
|
328
|
-
return router.getMatch(match().id)?._nonReactive.loadPromise
|
|
329
|
-
})
|
|
330
|
-
|
|
331
|
-
return <>{loaderResult()}</>
|
|
332
|
-
}}
|
|
333
|
-
</Solid.Match>
|
|
334
|
-
<Solid.Match when={match().status === 'error'}>
|
|
335
|
-
{(_) => {
|
|
336
|
-
throw match().error
|
|
337
|
-
}}
|
|
338
|
-
</Solid.Match>
|
|
339
|
-
<Solid.Match when={match().status === 'success'}>
|
|
340
|
-
{keyedOut()}
|
|
341
|
-
</Solid.Match>
|
|
342
|
-
</Solid.Switch>
|
|
373
|
+
return <>{loaderResult()}</>
|
|
374
|
+
}}
|
|
375
|
+
</Solid.Match>
|
|
376
|
+
<Solid.Match when={currentMatch().status === 'error'}>
|
|
377
|
+
{(_) => {
|
|
378
|
+
if (isServer ?? router.isServer) {
|
|
379
|
+
const RouteErrorComponent =
|
|
380
|
+
(route().options.errorComponent ??
|
|
381
|
+
router.options.defaultErrorComponent) ||
|
|
382
|
+
ErrorComponent
|
|
383
|
+
|
|
384
|
+
return (
|
|
385
|
+
<RouteErrorComponent
|
|
386
|
+
error={currentMatch().error}
|
|
387
|
+
info={{
|
|
388
|
+
componentStack: '',
|
|
389
|
+
}}
|
|
390
|
+
/>
|
|
391
|
+
)
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
throw currentMatch().error
|
|
395
|
+
}}
|
|
396
|
+
</Solid.Match>
|
|
397
|
+
<Solid.Match when={currentMatch().status === 'success'}>
|
|
398
|
+
{keyedOut()}
|
|
399
|
+
</Solid.Match>
|
|
400
|
+
</Solid.Switch>
|
|
401
|
+
)
|
|
402
|
+
}}
|
|
403
|
+
</Solid.Show>
|
|
343
404
|
)
|
|
344
405
|
}
|
|
345
406
|
|
|
346
407
|
export const Outlet = () => {
|
|
347
408
|
const router = useRouter()
|
|
348
|
-
const
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
const parentGlobalNotFound = useRouterState({
|
|
356
|
-
select: (s) => {
|
|
357
|
-
const matches = s.matches
|
|
358
|
-
const parentMatch = matches.find((d) => d.id === matchId())
|
|
359
|
-
|
|
360
|
-
// During navigation transitions, parent match can be temporarily removed
|
|
361
|
-
// Return false to avoid errors - the component will handle this gracefully
|
|
362
|
-
if (!parentMatch) {
|
|
363
|
-
return false
|
|
364
|
-
}
|
|
409
|
+
const nearestParentMatch = Solid.useContext(nearestMatchContext)
|
|
410
|
+
const parentMatch = nearestParentMatch.match
|
|
411
|
+
const routeId = nearestParentMatch.routeId
|
|
412
|
+
const route = Solid.createMemo(() =>
|
|
413
|
+
routeId() ? router.routesById[routeId()!] : undefined,
|
|
414
|
+
)
|
|
365
415
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
416
|
+
const parentGlobalNotFound = Solid.createMemo(
|
|
417
|
+
() => parentMatch()?.globalNotFound ?? false,
|
|
418
|
+
)
|
|
369
419
|
|
|
370
|
-
const childMatchId =
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
return v
|
|
376
|
-
},
|
|
420
|
+
const childMatchId = Solid.createMemo(() => {
|
|
421
|
+
const currentRouteId = routeId()
|
|
422
|
+
return currentRouteId
|
|
423
|
+
? router.stores.childMatchIdByRouteId.state[currentRouteId]
|
|
424
|
+
: undefined
|
|
377
425
|
})
|
|
378
426
|
|
|
379
|
-
const childMatchStatus =
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
return matches[index + 1]?.status
|
|
384
|
-
},
|
|
427
|
+
const childMatchStatus = Solid.createMemo(() => {
|
|
428
|
+
const id = childMatchId()
|
|
429
|
+
if (!id) return undefined
|
|
430
|
+
return router.stores.activeMatchStoresById.get(id)?.state.status
|
|
385
431
|
})
|
|
386
432
|
|
|
387
433
|
// Only show not-found if we're not in a redirected state
|
|
@@ -392,14 +438,15 @@ export const Outlet = () => {
|
|
|
392
438
|
<Solid.Show
|
|
393
439
|
when={!shouldShowNotFound() && childMatchId()}
|
|
394
440
|
fallback={
|
|
395
|
-
<Solid.Show when={shouldShowNotFound()}>
|
|
396
|
-
{
|
|
441
|
+
<Solid.Show when={shouldShowNotFound() && route()}>
|
|
442
|
+
{(resolvedRoute) =>
|
|
443
|
+
renderRouteNotFound(router, resolvedRoute(), undefined)
|
|
444
|
+
}
|
|
397
445
|
</Solid.Show>
|
|
398
446
|
}
|
|
399
447
|
>
|
|
400
|
-
{(
|
|
401
|
-
|
|
402
|
-
const currentMatchId = Solid.createMemo(() => matchIdAccessor())
|
|
448
|
+
{(childMatchIdAccessor) => {
|
|
449
|
+
const currentMatchId = Solid.createMemo(() => childMatchIdAccessor())
|
|
403
450
|
|
|
404
451
|
return (
|
|
405
452
|
<Solid.Show
|