@tanstack/solid-router 1.166.6 → 2.0.0-alpha.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/dist/cjs/Asset.cjs +111 -68
- package/dist/cjs/Asset.cjs.map +1 -1
- package/dist/cjs/CatchBoundary.cjs +15 -15
- package/dist/cjs/CatchBoundary.cjs.map +1 -1
- package/dist/cjs/ClientOnly.cjs +2 -2
- package/dist/cjs/ClientOnly.cjs.map +1 -1
- package/dist/cjs/HeadContent.cjs +16 -8
- package/dist/cjs/HeadContent.cjs.map +1 -1
- package/dist/cjs/HeadContent.dev.cjs +18 -10
- package/dist/cjs/HeadContent.dev.cjs.map +1 -1
- package/dist/cjs/Match.cjs +125 -81
- package/dist/cjs/Match.cjs.map +1 -1
- package/dist/cjs/Matches.cjs +23 -16
- package/dist/cjs/Matches.cjs.map +1 -1
- package/dist/cjs/RouterProvider.cjs +3 -2
- package/dist/cjs/RouterProvider.cjs.map +1 -1
- package/dist/cjs/SafeFragment.cjs +1 -1
- package/dist/cjs/ScriptOnce.cjs +4 -2
- package/dist/cjs/ScriptOnce.cjs.map +1 -1
- package/dist/cjs/Scripts.cjs +6 -2
- package/dist/cjs/Scripts.cjs.map +1 -1
- package/dist/cjs/Transitioner.cjs +11 -16
- package/dist/cjs/Transitioner.cjs.map +1 -1
- package/dist/cjs/awaited.cjs +20 -16
- package/dist/cjs/awaited.cjs.map +1 -1
- package/dist/cjs/lazyRouteComponent.cjs +3 -3
- package/dist/cjs/lazyRouteComponent.cjs.map +1 -1
- package/dist/cjs/link.cjs +40 -22
- package/dist/cjs/link.cjs.map +1 -1
- package/dist/cjs/not-found.cjs +1 -1
- package/dist/cjs/renderRouteNotFound.cjs +1 -1
- package/dist/cjs/route.cjs +1 -1
- package/dist/cjs/scroll-restoration.cjs +1 -1
- package/dist/cjs/ssr/RouterClient.cjs +4 -23
- package/dist/cjs/ssr/RouterClient.cjs.map +1 -1
- package/dist/cjs/ssr/RouterServer.cjs +4 -47
- package/dist/cjs/ssr/RouterServer.cjs.map +1 -1
- package/dist/cjs/ssr/RouterServer.d.cts +0 -1
- package/dist/cjs/ssr/defaultRenderHandler.cjs +1 -1
- package/dist/cjs/ssr/defaultStreamHandler.cjs +1 -1
- package/dist/cjs/ssr/renderRouterToStream.cjs +2 -3
- 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/useBlocker.cjs +9 -5
- package/dist/cjs/useBlocker.cjs.map +1 -1
- package/dist/cjs/useMatch.cjs +3 -6
- package/dist/cjs/useMatch.cjs.map +1 -1
- package/dist/cjs/useNavigate.cjs +1 -1
- package/dist/cjs/useNavigate.cjs.map +1 -1
- package/dist/cjs/useRouterState.cjs +15 -9
- package/dist/cjs/useRouterState.cjs.map +1 -1
- package/dist/cjs/utils.cjs +2 -4
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +1 -0
- package/dist/esm/Asset.js +111 -68
- package/dist/esm/Asset.js.map +1 -1
- package/dist/esm/CatchBoundary.js +15 -15
- package/dist/esm/CatchBoundary.js.map +1 -1
- package/dist/esm/ClientOnly.js +2 -2
- package/dist/esm/ClientOnly.js.map +1 -1
- package/dist/esm/HeadContent.dev.js +18 -10
- package/dist/esm/HeadContent.dev.js.map +1 -1
- package/dist/esm/HeadContent.js +16 -8
- package/dist/esm/HeadContent.js.map +1 -1
- package/dist/esm/Match.js +89 -45
- package/dist/esm/Match.js.map +1 -1
- package/dist/esm/Matches.js +23 -16
- package/dist/esm/Matches.js.map +1 -1
- package/dist/esm/RouterProvider.js +3 -2
- package/dist/esm/RouterProvider.js.map +1 -1
- package/dist/esm/SafeFragment.js +1 -1
- package/dist/esm/ScriptOnce.js +4 -2
- package/dist/esm/ScriptOnce.js.map +1 -1
- package/dist/esm/Scripts.js +6 -2
- package/dist/esm/Scripts.js.map +1 -1
- package/dist/esm/Transitioner.js +11 -16
- package/dist/esm/Transitioner.js.map +1 -1
- package/dist/esm/awaited.js +18 -14
- package/dist/esm/awaited.js.map +1 -1
- package/dist/esm/lazyRouteComponent.js +3 -3
- package/dist/esm/lazyRouteComponent.js.map +1 -1
- package/dist/esm/link.js +39 -21
- package/dist/esm/link.js.map +1 -1
- package/dist/esm/not-found.js +1 -1
- package/dist/esm/renderRouteNotFound.js +1 -1
- package/dist/esm/route.js +1 -1
- package/dist/esm/scroll-restoration.js +1 -1
- package/dist/esm/ssr/RouterClient.js +4 -23
- package/dist/esm/ssr/RouterClient.js.map +1 -1
- package/dist/esm/ssr/RouterServer.d.ts +0 -1
- package/dist/esm/ssr/RouterServer.js +5 -48
- package/dist/esm/ssr/RouterServer.js.map +1 -1
- package/dist/esm/ssr/defaultRenderHandler.js +1 -1
- package/dist/esm/ssr/defaultStreamHandler.js +1 -1
- package/dist/esm/ssr/renderRouterToStream.js +2 -4
- 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/useBlocker.js +9 -5
- package/dist/esm/useBlocker.js.map +1 -1
- package/dist/esm/useMatch.js +3 -6
- package/dist/esm/useMatch.js.map +1 -1
- package/dist/esm/useNavigate.js +1 -1
- package/dist/esm/useNavigate.js.map +1 -1
- package/dist/esm/useRouterState.js +15 -9
- package/dist/esm/useRouterState.js.map +1 -1
- package/dist/esm/utils.d.ts +1 -0
- package/dist/esm/utils.js +2 -4
- package/dist/esm/utils.js.map +1 -1
- package/dist/source/Asset.jsx +58 -35
- package/dist/source/Asset.jsx.map +1 -1
- package/dist/source/CatchBoundary.jsx +9 -5
- package/dist/source/CatchBoundary.jsx.map +1 -1
- package/dist/source/ClientOnly.jsx +1 -1
- package/dist/source/ClientOnly.jsx.map +1 -1
- package/dist/source/HeadContent.dev.jsx +8 -6
- package/dist/source/HeadContent.dev.jsx.map +1 -1
- package/dist/source/HeadContent.jsx +6 -4
- package/dist/source/HeadContent.jsx.map +1 -1
- package/dist/source/Match.jsx +76 -35
- package/dist/source/Match.jsx.map +1 -1
- package/dist/source/Matches.jsx +25 -17
- package/dist/source/Matches.jsx.map +1 -1
- package/dist/source/RouterProvider.jsx +2 -3
- package/dist/source/RouterProvider.jsx.map +1 -1
- package/dist/source/Scripts.jsx +4 -3
- package/dist/source/Scripts.jsx.map +1 -1
- package/dist/source/Transitioner.jsx +15 -16
- package/dist/source/Transitioner.jsx.map +1 -1
- package/dist/source/awaited.jsx +7 -8
- package/dist/source/awaited.jsx.map +1 -1
- package/dist/source/lazyRouteComponent.jsx +3 -3
- package/dist/source/lazyRouteComponent.jsx.map +1 -1
- package/dist/source/link.jsx +53 -48
- package/dist/source/link.jsx.map +1 -1
- package/dist/source/ssr/RouterClient.jsx +1 -13
- package/dist/source/ssr/RouterClient.jsx.map +1 -1
- package/dist/source/ssr/RouterServer.d.ts +0 -1
- package/dist/source/ssr/RouterServer.jsx +1 -34
- package/dist/source/ssr/RouterServer.jsx.map +1 -1
- package/dist/source/ssr/renderRouterToStream.jsx +2 -6
- 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/useBlocker.jsx +8 -4
- package/dist/source/useBlocker.jsx.map +1 -1
- package/dist/source/useMatch.jsx +3 -8
- package/dist/source/useMatch.jsx.map +1 -1
- package/dist/source/useNavigate.jsx +1 -1
- package/dist/source/useNavigate.jsx.map +1 -1
- package/dist/source/useRouterState.jsx +23 -10
- package/dist/source/useRouterState.jsx.map +1 -1
- package/dist/source/utils.d.ts +1 -0
- package/dist/source/utils.js +3 -4
- package/dist/source/utils.js.map +1 -1
- package/package.json +8 -7
- package/src/Asset.tsx +123 -95
- package/src/CatchBoundary.tsx +9 -7
- package/src/ClientOnly.tsx +8 -3
- package/src/HeadContent.dev.tsx +16 -11
- package/src/HeadContent.tsx +6 -4
- package/src/Match.tsx +112 -44
- package/src/Matches.tsx +39 -30
- package/src/RouterProvider.tsx +7 -4
- package/src/Scripts.tsx +4 -3
- package/src/Transitioner.tsx +51 -58
- package/src/awaited.tsx +11 -12
- package/src/lazyRouteComponent.tsx +3 -3
- package/src/link.tsx +68 -60
- package/src/ssr/RouterClient.tsx +1 -22
- package/src/ssr/RouterServer.tsx +1 -53
- package/src/ssr/renderRouterToStream.tsx +5 -15
- package/src/ssr/renderRouterToString.tsx +2 -2
- package/src/useBlocker.tsx +8 -4
- package/src/useMatch.tsx +6 -11
- package/src/useNavigate.tsx +1 -1
- package/src/useRouterState.tsx +34 -22
- package/src/utils.ts +5 -4
package/src/Match.tsx
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
rootRouteId,
|
|
10
10
|
} from '@tanstack/router-core'
|
|
11
11
|
import { isServer } from '@tanstack/router-core/isServer'
|
|
12
|
-
import { Dynamic } from '
|
|
12
|
+
import { Dynamic } from '@solidjs/web'
|
|
13
13
|
import { CatchBoundary, ErrorComponent } from './CatchBoundary'
|
|
14
14
|
import { useRouterState } from './useRouterState'
|
|
15
15
|
import { useRouter } from './useRouter'
|
|
@@ -20,6 +20,11 @@ import { renderRouteNotFound } from './renderRouteNotFound'
|
|
|
20
20
|
import { ScrollRestoration } from './scroll-restoration'
|
|
21
21
|
import type { AnyRoute, RootRouteOptions } from '@tanstack/router-core'
|
|
22
22
|
|
|
23
|
+
const MatchContext = matchContext as unknown as Solid.Component<{
|
|
24
|
+
value: any
|
|
25
|
+
children?: any
|
|
26
|
+
}>
|
|
27
|
+
|
|
23
28
|
export const Match = (props: { matchId: string }) => {
|
|
24
29
|
const router = useRouter()
|
|
25
30
|
const matchState = useRouterState({
|
|
@@ -41,7 +46,7 @@ export const Match = (props: { matchId: string }) => {
|
|
|
41
46
|
})
|
|
42
47
|
|
|
43
48
|
// If match doesn't exist yet, return null (component is being unmounted or not ready)
|
|
44
|
-
if (!matchState
|
|
49
|
+
if (!Solid.untrack(matchState)) return null
|
|
45
50
|
|
|
46
51
|
const route: () => AnyRoute = () => router.routesById[matchState()!.routeId]
|
|
47
52
|
|
|
@@ -61,10 +66,12 @@ export const Match = (props: { matchId: string }) => {
|
|
|
61
66
|
router.options.notFoundRoute?.options.component)
|
|
62
67
|
: route().options.notFoundComponent
|
|
63
68
|
|
|
64
|
-
const resolvedNoSsr =
|
|
65
|
-
matchState()!.ssr === false || matchState()!.ssr === 'data-only'
|
|
69
|
+
const resolvedNoSsr = Solid.createMemo(
|
|
70
|
+
() => matchState()!.ssr === false || matchState()!.ssr === 'data-only',
|
|
71
|
+
)
|
|
66
72
|
|
|
67
|
-
const ResolvedSuspenseBoundary = () =>
|
|
73
|
+
const ResolvedSuspenseBoundary = () =>
|
|
74
|
+
resolvedNoSsr() ? SafeFragment : Solid.Loading
|
|
68
75
|
|
|
69
76
|
const ResolvedCatchBoundary = () =>
|
|
70
77
|
routeErrorComponent() ? CatchBoundary : SafeFragment
|
|
@@ -83,18 +90,20 @@ export const Match = (props: { matchId: string }) => {
|
|
|
83
90
|
},
|
|
84
91
|
})
|
|
85
92
|
|
|
86
|
-
const ShellComponent =
|
|
87
|
-
|
|
88
|
-
|
|
93
|
+
const ShellComponent = Solid.createMemo(() =>
|
|
94
|
+
route().isRoot
|
|
95
|
+
? ((route().options as RootRouteOptions).shellComponent ?? SafeFragment)
|
|
96
|
+
: SafeFragment,
|
|
97
|
+
)
|
|
89
98
|
|
|
90
99
|
return (
|
|
91
|
-
<ShellComponent>
|
|
92
|
-
<
|
|
100
|
+
<Dynamic component={ShellComponent()}>
|
|
101
|
+
<MatchContext value={() => props.matchId}>
|
|
93
102
|
<Dynamic
|
|
94
103
|
component={ResolvedSuspenseBoundary()}
|
|
95
104
|
fallback={
|
|
96
105
|
// Don't show fallback on server when using no-ssr mode to avoid hydration mismatch
|
|
97
|
-
(isServer ?? router.isServer) || resolvedNoSsr ? undefined : (
|
|
106
|
+
(isServer ?? router.isServer) || resolvedNoSsr() ? undefined : (
|
|
98
107
|
<Dynamic component={resolvePendingComponent()} />
|
|
99
108
|
)
|
|
100
109
|
}
|
|
@@ -106,7 +115,10 @@ export const Match = (props: { matchId: string }) => {
|
|
|
106
115
|
onCatch={(error: Error) => {
|
|
107
116
|
// Forward not found errors (we don't want to show the error component for these)
|
|
108
117
|
if (isNotFound(error)) throw error
|
|
109
|
-
warning(
|
|
118
|
+
warning(
|
|
119
|
+
false,
|
|
120
|
+
`Error in route match: ${Solid.untrack(matchState)!.routeId}`,
|
|
121
|
+
)
|
|
110
122
|
routeOnCatch()?.(error)
|
|
111
123
|
}}
|
|
112
124
|
>
|
|
@@ -128,7 +140,7 @@ export const Match = (props: { matchId: string }) => {
|
|
|
128
140
|
}}
|
|
129
141
|
>
|
|
130
142
|
<Solid.Switch>
|
|
131
|
-
<Solid.Match when={resolvedNoSsr}>
|
|
143
|
+
<Solid.Match when={resolvedNoSsr()}>
|
|
132
144
|
<Solid.Show
|
|
133
145
|
when={!(isServer ?? router.isServer)}
|
|
134
146
|
fallback={<Dynamic component={resolvePendingComponent()} />}
|
|
@@ -136,14 +148,14 @@ export const Match = (props: { matchId: string }) => {
|
|
|
136
148
|
<MatchInner matchId={props.matchId} />
|
|
137
149
|
</Solid.Show>
|
|
138
150
|
</Solid.Match>
|
|
139
|
-
<Solid.Match when={!resolvedNoSsr}>
|
|
151
|
+
<Solid.Match when={!resolvedNoSsr()}>
|
|
140
152
|
<MatchInner matchId={props.matchId} />
|
|
141
153
|
</Solid.Match>
|
|
142
154
|
</Solid.Switch>
|
|
143
155
|
</Dynamic>
|
|
144
156
|
</Dynamic>
|
|
145
157
|
</Dynamic>
|
|
146
|
-
</
|
|
158
|
+
</MatchContext>
|
|
147
159
|
|
|
148
160
|
{parentRouteId() === rootRouteId ? (
|
|
149
161
|
<>
|
|
@@ -151,7 +163,7 @@ export const Match = (props: { matchId: string }) => {
|
|
|
151
163
|
<ScrollRestoration />
|
|
152
164
|
</>
|
|
153
165
|
) : null}
|
|
154
|
-
</
|
|
166
|
+
</Dynamic>
|
|
155
167
|
)
|
|
156
168
|
}
|
|
157
169
|
|
|
@@ -162,6 +174,14 @@ export const Match = (props: { matchId: string }) => {
|
|
|
162
174
|
// allows us to fire onRendered events even after a hydration mismatch
|
|
163
175
|
// error that occurred above the root layout (like bad head/link tags,
|
|
164
176
|
// which is common).
|
|
177
|
+
//
|
|
178
|
+
// In Solid, createEffect(source, fn) fires on initial mount as well as on
|
|
179
|
+
// reactive changes. OnRendered can also remount when the first child route
|
|
180
|
+
// changes (e.g. navigating from / to /posts). We deduplicate by tracking
|
|
181
|
+
// the last emitted resolvedLocation key per router so each unique resolved
|
|
182
|
+
// location only triggers one onRendered event regardless of remounts.
|
|
183
|
+
const lastOnRenderedKey = new WeakMap<object, string>()
|
|
184
|
+
|
|
165
185
|
function OnRendered() {
|
|
166
186
|
const router = useRouter()
|
|
167
187
|
|
|
@@ -171,12 +191,16 @@ function OnRendered() {
|
|
|
171
191
|
},
|
|
172
192
|
})
|
|
173
193
|
Solid.createEffect(
|
|
174
|
-
|
|
194
|
+
() => [location()] as const,
|
|
195
|
+
([location]) => {
|
|
196
|
+
if (!location) return
|
|
197
|
+
if (lastOnRenderedKey.get(router) === location) return
|
|
198
|
+
lastOnRenderedKey.set(router, location)
|
|
175
199
|
router.emit({
|
|
176
200
|
type: 'onRendered',
|
|
177
201
|
...getLocationChangeInfo(router.state),
|
|
178
202
|
})
|
|
179
|
-
}
|
|
203
|
+
},
|
|
180
204
|
)
|
|
181
205
|
return null
|
|
182
206
|
}
|
|
@@ -220,7 +244,7 @@ export const MatchInner = (props: { matchId: string }): any => {
|
|
|
220
244
|
},
|
|
221
245
|
})
|
|
222
246
|
|
|
223
|
-
if (!matchState
|
|
247
|
+
if (!Solid.untrack(matchState)) return null
|
|
224
248
|
|
|
225
249
|
const route = () => router.routesById[matchState()!.routeId]!
|
|
226
250
|
|
|
@@ -229,7 +253,9 @@ export const MatchInner = (props: { matchId: string }): any => {
|
|
|
229
253
|
const componentKey = () => matchState()!.key ?? matchState()!.match.id
|
|
230
254
|
|
|
231
255
|
const out = () => {
|
|
232
|
-
const
|
|
256
|
+
const currentRoute = Solid.untrack(route)
|
|
257
|
+
const Comp =
|
|
258
|
+
currentRoute.options.component ?? router.options.defaultComponent
|
|
233
259
|
if (Comp) {
|
|
234
260
|
return <Comp />
|
|
235
261
|
}
|
|
@@ -246,9 +272,9 @@ export const MatchInner = (props: { matchId: string }): any => {
|
|
|
246
272
|
<Solid.Switch>
|
|
247
273
|
<Solid.Match when={match()._displayPending}>
|
|
248
274
|
{(_) => {
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
275
|
+
const matchId = Solid.untrack(() => match().id)
|
|
276
|
+
const displayPendingResult = Solid.createMemo(
|
|
277
|
+
() => router.getMatch(matchId)?._nonReactive.displayPendingPromise,
|
|
252
278
|
)
|
|
253
279
|
|
|
254
280
|
return <>{displayPendingResult()}</>
|
|
@@ -256,8 +282,9 @@ export const MatchInner = (props: { matchId: string }): any => {
|
|
|
256
282
|
</Solid.Match>
|
|
257
283
|
<Solid.Match when={match()._forcePending}>
|
|
258
284
|
{(_) => {
|
|
259
|
-
const
|
|
260
|
-
|
|
285
|
+
const matchId = Solid.untrack(() => match().id)
|
|
286
|
+
const minPendingResult = Solid.createMemo(
|
|
287
|
+
() => router.getMatch(matchId)?._nonReactive.minPendingPromise,
|
|
261
288
|
)
|
|
262
289
|
|
|
263
290
|
return <>{minPendingResult()}</>
|
|
@@ -265,11 +292,14 @@ export const MatchInner = (props: { matchId: string }): any => {
|
|
|
265
292
|
</Solid.Match>
|
|
266
293
|
<Solid.Match when={match().status === 'pending'}>
|
|
267
294
|
{(_) => {
|
|
295
|
+
const currentMatch = Solid.untrack(match)
|
|
296
|
+
const currentRoute = Solid.untrack(route)
|
|
268
297
|
const pendingMinMs =
|
|
269
|
-
|
|
298
|
+
currentRoute.options.pendingMinMs ??
|
|
299
|
+
router.options.defaultPendingMinMs
|
|
270
300
|
|
|
271
301
|
if (pendingMinMs) {
|
|
272
|
-
const routerMatch = router.getMatch(
|
|
302
|
+
const routerMatch = router.getMatch(currentMatch.id)
|
|
273
303
|
if (routerMatch && !routerMatch._nonReactive.minPendingPromise) {
|
|
274
304
|
// Create a promise that will resolve after the minPendingMs
|
|
275
305
|
if (!(isServer ?? router.isServer)) {
|
|
@@ -286,13 +316,13 @@ export const MatchInner = (props: { matchId: string }): any => {
|
|
|
286
316
|
}
|
|
287
317
|
}
|
|
288
318
|
|
|
289
|
-
const
|
|
319
|
+
const loaderResult = Solid.createMemo(async () => {
|
|
290
320
|
await new Promise((r) => setTimeout(r, 0))
|
|
291
|
-
return router.getMatch(
|
|
321
|
+
return router.getMatch(currentMatch.id)?._nonReactive.loadPromise
|
|
292
322
|
})
|
|
293
323
|
|
|
294
324
|
const FallbackComponent =
|
|
295
|
-
|
|
325
|
+
currentRoute.options.pendingComponent ??
|
|
296
326
|
router.options.defaultPendingComponent
|
|
297
327
|
|
|
298
328
|
return (
|
|
@@ -307,13 +337,16 @@ export const MatchInner = (props: { matchId: string }): any => {
|
|
|
307
337
|
</Solid.Match>
|
|
308
338
|
<Solid.Match when={match().status === 'notFound'}>
|
|
309
339
|
{(_) => {
|
|
310
|
-
|
|
340
|
+
const currentMatch = Solid.untrack(match)
|
|
341
|
+
const currentRoute = Solid.untrack(route)
|
|
342
|
+
const currentRouteId = Solid.untrack(() => matchState()!.routeId)
|
|
343
|
+
invariant(isNotFound(currentMatch.error), 'Expected a notFound error')
|
|
311
344
|
|
|
312
345
|
// Use Show with keyed to ensure re-render when routeId changes
|
|
313
346
|
return (
|
|
314
|
-
<Solid.Show when={
|
|
347
|
+
<Solid.Show when={currentRouteId} keyed>
|
|
315
348
|
{(_routeId) =>
|
|
316
|
-
renderRouteNotFound(router,
|
|
349
|
+
renderRouteNotFound(router, currentRoute, currentMatch.error)
|
|
317
350
|
}
|
|
318
351
|
</Solid.Show>
|
|
319
352
|
)
|
|
@@ -321,11 +354,15 @@ export const MatchInner = (props: { matchId: string }): any => {
|
|
|
321
354
|
</Solid.Match>
|
|
322
355
|
<Solid.Match when={match().status === 'redirected'}>
|
|
323
356
|
{(_) => {
|
|
324
|
-
|
|
357
|
+
const matchId = Solid.untrack(() => match().id)
|
|
358
|
+
invariant(
|
|
359
|
+
isRedirect(Solid.untrack(match).error),
|
|
360
|
+
'Expected a redirect error',
|
|
361
|
+
)
|
|
325
362
|
|
|
326
|
-
const
|
|
363
|
+
const loaderResult = Solid.createMemo(async () => {
|
|
327
364
|
await new Promise((r) => setTimeout(r, 0))
|
|
328
|
-
return router.getMatch(
|
|
365
|
+
return router.getMatch(matchId)?._nonReactive.loadPromise
|
|
329
366
|
})
|
|
330
367
|
|
|
331
368
|
return <>{loaderResult()}</>
|
|
@@ -333,7 +370,24 @@ export const MatchInner = (props: { matchId: string }): any => {
|
|
|
333
370
|
</Solid.Match>
|
|
334
371
|
<Solid.Match when={match().status === 'error'}>
|
|
335
372
|
{(_) => {
|
|
336
|
-
|
|
373
|
+
if (isServer ?? router.isServer) {
|
|
374
|
+
const currentMatch = Solid.untrack(match)
|
|
375
|
+
const RouteErrorComponent =
|
|
376
|
+
(Solid.untrack(route).options.errorComponent ??
|
|
377
|
+
router.options.defaultErrorComponent) ||
|
|
378
|
+
ErrorComponent
|
|
379
|
+
|
|
380
|
+
return (
|
|
381
|
+
<RouteErrorComponent
|
|
382
|
+
error={currentMatch.error}
|
|
383
|
+
info={{
|
|
384
|
+
componentStack: '',
|
|
385
|
+
}}
|
|
386
|
+
/>
|
|
387
|
+
)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
throw Solid.untrack(match).error
|
|
337
391
|
}}
|
|
338
392
|
</Solid.Match>
|
|
339
393
|
<Solid.Match when={match().status === 'success'}>
|
|
@@ -376,6 +430,14 @@ export const Outlet = () => {
|
|
|
376
430
|
},
|
|
377
431
|
})
|
|
378
432
|
|
|
433
|
+
const childRouteId = useRouterState({
|
|
434
|
+
select: (s) => {
|
|
435
|
+
const matches = s.matches
|
|
436
|
+
const index = matches.findIndex((d) => d.id === matchId())
|
|
437
|
+
return matches[index + 1]?.routeId
|
|
438
|
+
},
|
|
439
|
+
})
|
|
440
|
+
|
|
379
441
|
const childMatchStatus = useRouterState({
|
|
380
442
|
select: (s) => {
|
|
381
443
|
const matches = s.matches
|
|
@@ -406,13 +468,19 @@ export const Outlet = () => {
|
|
|
406
468
|
when={routeId() === rootRouteId}
|
|
407
469
|
fallback={<Match matchId={currentMatchId()} />}
|
|
408
470
|
>
|
|
409
|
-
<Solid.
|
|
410
|
-
|
|
411
|
-
<
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
471
|
+
<Solid.Show when={childRouteId()} keyed>
|
|
472
|
+
{(_routeId) => (
|
|
473
|
+
<Solid.Loading
|
|
474
|
+
fallback={
|
|
475
|
+
<Dynamic
|
|
476
|
+
component={router.options.defaultPendingComponent}
|
|
477
|
+
/>
|
|
478
|
+
}
|
|
479
|
+
>
|
|
480
|
+
<Match matchId={currentMatchId()} />
|
|
481
|
+
</Solid.Loading>
|
|
482
|
+
)}
|
|
483
|
+
</Solid.Show>
|
|
416
484
|
</Solid.Show>
|
|
417
485
|
)
|
|
418
486
|
}}
|
package/src/Matches.tsx
CHANGED
|
@@ -28,6 +28,11 @@ import type {
|
|
|
28
28
|
ToSubOptionsProps,
|
|
29
29
|
} from '@tanstack/router-core'
|
|
30
30
|
|
|
31
|
+
const MatchContext = matchContext as unknown as Solid.Component<{
|
|
32
|
+
value: any
|
|
33
|
+
children: any
|
|
34
|
+
}>
|
|
35
|
+
|
|
31
36
|
declare module '@tanstack/router-core' {
|
|
32
37
|
export interface RouteMatchExtensions {
|
|
33
38
|
meta?: Array<Solid.JSX.IntrinsicElements['meta'] | undefined>
|
|
@@ -41,11 +46,15 @@ declare module '@tanstack/router-core' {
|
|
|
41
46
|
export function Matches() {
|
|
42
47
|
const router = useRouter()
|
|
43
48
|
|
|
49
|
+
// When disableGlobalCatchBoundary is true, we must NOT wrap with Solid.Loading
|
|
50
|
+
// because Solid.Loading transforms STATUS_ERROR into STATUS_PENDING, which
|
|
51
|
+
// prevents errors from propagating to an external Errored boundary.
|
|
44
52
|
const ResolvedSuspense =
|
|
53
|
+
router.options.disableGlobalCatchBoundary ||
|
|
45
54
|
(isServer ?? router.isServer) ||
|
|
46
55
|
(typeof document !== 'undefined' && router.ssr)
|
|
47
56
|
? SafeFragment
|
|
48
|
-
: Solid.
|
|
57
|
+
: Solid.Loading
|
|
49
58
|
|
|
50
59
|
const rootRoute: () => AnyRoute = () => router.routesById[rootRouteId]
|
|
51
60
|
const PendingComponent =
|
|
@@ -78,39 +87,39 @@ function MatchesInner() {
|
|
|
78
87
|
select: (s) => s.loadedAt,
|
|
79
88
|
})
|
|
80
89
|
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
90
|
+
const matchContent = () => (
|
|
91
|
+
<Solid.Show when={matchId()}>
|
|
92
|
+
<Match matchId={matchId()!} />
|
|
93
|
+
</Solid.Show>
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
if (router.options.disableGlobalCatchBoundary) {
|
|
97
|
+
// When disableGlobalCatchBoundary is true, render without any internal
|
|
98
|
+
// error boundary so errors bubble up freely to an external Errored boundary.
|
|
99
|
+
return <MatchContext value={matchId}>{matchContent()}</MatchContext>
|
|
87
100
|
}
|
|
88
101
|
|
|
89
102
|
return (
|
|
90
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
warning(
|
|
101
|
-
false,
|
|
102
|
-
`The following error wasn't caught by any route! At the very leas
|
|
103
|
+
<MatchContext value={matchId}>
|
|
104
|
+
<CatchBoundary
|
|
105
|
+
getResetKey={() => resetKey()}
|
|
106
|
+
errorComponent={ErrorComponent}
|
|
107
|
+
onCatch={
|
|
108
|
+
process.env.NODE_ENV !== 'production'
|
|
109
|
+
? (error) => {
|
|
110
|
+
warning(
|
|
111
|
+
false,
|
|
112
|
+
`The following error wasn't caught by any route! At the very leas
|
|
103
113
|
t, consider setting an 'errorComponent' in your RootRoute!`,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
</matchContext.Provider>
|
|
114
|
+
)
|
|
115
|
+
warning(false, error.message || error.toString())
|
|
116
|
+
}
|
|
117
|
+
: undefined
|
|
118
|
+
}
|
|
119
|
+
>
|
|
120
|
+
{matchContent()}
|
|
121
|
+
</CatchBoundary>
|
|
122
|
+
</MatchContext>
|
|
114
123
|
)
|
|
115
124
|
}
|
|
116
125
|
|
package/src/RouterProvider.tsx
CHANGED
|
@@ -8,6 +8,11 @@ import type {
|
|
|
8
8
|
} from '@tanstack/router-core'
|
|
9
9
|
import type * as Solid from 'solid-js'
|
|
10
10
|
|
|
11
|
+
const RouterContext = routerContext as unknown as Solid.Component<{
|
|
12
|
+
value: any
|
|
13
|
+
children: any
|
|
14
|
+
}>
|
|
15
|
+
|
|
11
16
|
export function RouterContextProvider<
|
|
12
17
|
TRouter extends AnyRouter = RegisteredRouter,
|
|
13
18
|
TDehydrated extends Record<string, any> = Record<string, any>,
|
|
@@ -26,15 +31,13 @@ export function RouterContextProvider<
|
|
|
26
31
|
...router.options.context,
|
|
27
32
|
...rest.context,
|
|
28
33
|
},
|
|
29
|
-
})
|
|
34
|
+
} as any)
|
|
30
35
|
|
|
31
36
|
const OptionalWrapper = router.options.Wrap || SafeFragment
|
|
32
37
|
|
|
33
38
|
return (
|
|
34
39
|
<OptionalWrapper>
|
|
35
|
-
<
|
|
36
|
-
{children()}
|
|
37
|
-
</routerContext.Provider>
|
|
40
|
+
<RouterContext value={router as AnyRouter}>{children()}</RouterContext>
|
|
38
41
|
</OptionalWrapper>
|
|
39
42
|
)
|
|
40
43
|
}
|
package/src/Scripts.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { NoHydration } from '@solidjs/web'
|
|
1
2
|
import { Asset } from './Asset'
|
|
2
3
|
import { useRouterState } from './useRouterState'
|
|
3
4
|
import { useRouter } from './useRouter'
|
|
@@ -67,10 +68,10 @@ export const Scripts = () => {
|
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
return (
|
|
70
|
-
|
|
71
|
-
{allScripts.map((asset,
|
|
71
|
+
<NoHydration>
|
|
72
|
+
{allScripts.map((asset, _i) => (
|
|
72
73
|
<Asset {...asset} />
|
|
73
74
|
))}
|
|
74
|
-
|
|
75
|
+
</NoHydration>
|
|
75
76
|
)
|
|
76
77
|
}
|
package/src/Transitioner.tsx
CHANGED
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
handleHashScroll,
|
|
5
5
|
trimPathRight,
|
|
6
6
|
} from '@tanstack/router-core'
|
|
7
|
-
import { isServer } from '@tanstack/router-core/isServer'
|
|
8
7
|
import { useRouter } from './useRouter'
|
|
9
8
|
import { useRouterState } from './useRouterState'
|
|
10
9
|
import { usePrevious } from './utils'
|
|
@@ -16,11 +15,7 @@ export function Transitioner() {
|
|
|
16
15
|
select: ({ isLoading }) => isLoading,
|
|
17
16
|
})
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
return null
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const [isSolidTransitioning, startSolidTransition] = Solid.useTransition()
|
|
18
|
+
const [isSolidTransitioning] = [() => false]
|
|
24
19
|
|
|
25
20
|
// Track pending state changes
|
|
26
21
|
const hasPendingMatches = useRouterState({
|
|
@@ -37,16 +32,20 @@ export function Transitioner() {
|
|
|
37
32
|
const previousIsPagePending = usePrevious(isPagePending)
|
|
38
33
|
|
|
39
34
|
router.startTransition = (fn: () => void | Promise<void>) => {
|
|
40
|
-
Solid.
|
|
41
|
-
startSolidTransition(fn)
|
|
42
|
-
})
|
|
35
|
+
Solid.runWithOwner(null, fn)
|
|
43
36
|
}
|
|
44
37
|
|
|
45
38
|
// Subscribe to location changes
|
|
46
39
|
// and try to load the new location
|
|
47
|
-
Solid.
|
|
40
|
+
Solid.onSettled(() => {
|
|
48
41
|
const unsub = router.history.subscribe(router.load)
|
|
49
42
|
|
|
43
|
+
// Refresh latestLocation from the current browser URL before comparing.
|
|
44
|
+
// The URL may have been changed synchronously (e.g. via replaceState) after
|
|
45
|
+
// render() but before this effect ran, so we must not use the stale
|
|
46
|
+
// render-time location here.
|
|
47
|
+
router.updateLatestLocation()
|
|
48
|
+
|
|
50
49
|
const nextLocation = router.buildLocation({
|
|
51
50
|
to: router.latestLocation.pathname,
|
|
52
51
|
search: true,
|
|
@@ -72,7 +71,7 @@ export function Transitioner() {
|
|
|
72
71
|
})
|
|
73
72
|
|
|
74
73
|
// Try to load the initial location
|
|
75
|
-
Solid.
|
|
74
|
+
Solid.createTrackedEffect(() => {
|
|
76
75
|
Solid.untrack(() => {
|
|
77
76
|
if (
|
|
78
77
|
// if we are hydrating from SSR, loading is triggered in ssr-client
|
|
@@ -93,58 +92,52 @@ export function Transitioner() {
|
|
|
93
92
|
})
|
|
94
93
|
})
|
|
95
94
|
|
|
96
|
-
Solid.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
},
|
|
107
|
-
),
|
|
95
|
+
Solid.createEffect(
|
|
96
|
+
() => [previousIsLoading(), isLoading()] as const,
|
|
97
|
+
([previousIsLoading, isLoading]) => {
|
|
98
|
+
if (previousIsLoading.previous && !isLoading) {
|
|
99
|
+
router.emit({
|
|
100
|
+
type: 'onLoad',
|
|
101
|
+
...getLocationChangeInfo(router.state),
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
},
|
|
108
105
|
)
|
|
109
106
|
|
|
110
|
-
Solid.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
},
|
|
122
|
-
),
|
|
107
|
+
Solid.createEffect(
|
|
108
|
+
() => [isPagePending(), previousIsPagePending()] as const,
|
|
109
|
+
([isPagePending, previousIsPagePending]) => {
|
|
110
|
+
// emit onBeforeRouteMount
|
|
111
|
+
if (previousIsPagePending.previous && !isPagePending) {
|
|
112
|
+
router.emit({
|
|
113
|
+
type: 'onBeforeRouteMount',
|
|
114
|
+
...getLocationChangeInfo(router.state),
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
},
|
|
123
118
|
)
|
|
124
119
|
|
|
125
|
-
Solid.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
handleHashScroll(router)
|
|
144
|
-
}
|
|
120
|
+
Solid.createEffect(
|
|
121
|
+
() => [isAnyPending(), previousIsAnyPending()] as const,
|
|
122
|
+
([isAnyPending, previousIsAnyPending]) => {
|
|
123
|
+
if (previousIsAnyPending.previous && !isAnyPending) {
|
|
124
|
+
const changeInfo = getLocationChangeInfo(router.state)
|
|
125
|
+
router.emit({
|
|
126
|
+
type: 'onResolved',
|
|
127
|
+
...changeInfo,
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
router.__store.setState((s) => ({
|
|
131
|
+
...s,
|
|
132
|
+
status: 'idle',
|
|
133
|
+
resolvedLocation: s.location,
|
|
134
|
+
}))
|
|
135
|
+
|
|
136
|
+
if (changeInfo.hrefChanged) {
|
|
137
|
+
handleHashScroll(router)
|
|
145
138
|
}
|
|
146
|
-
}
|
|
147
|
-
|
|
139
|
+
}
|
|
140
|
+
},
|
|
148
141
|
)
|
|
149
142
|
|
|
150
143
|
return null
|
package/src/awaited.tsx
CHANGED
|
@@ -24,24 +24,23 @@ export function useAwaited<T>({
|
|
|
24
24
|
return [promise[TSR_DEFERRED_PROMISE].data, promise]
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
function InnerAwait<T>(props: {
|
|
28
|
+
promise: Promise<T>
|
|
29
|
+
children: (res: T) => SolidNode
|
|
30
|
+
}) {
|
|
31
|
+
const [data] = useAwaited({ promise: props.promise })
|
|
32
|
+
return props.children(data) as any
|
|
33
|
+
}
|
|
34
|
+
|
|
27
35
|
export function Await<T>(
|
|
28
36
|
props: AwaitOptions<T> & {
|
|
29
37
|
fallback?: SolidNode
|
|
30
38
|
children: (result: T) => SolidNode
|
|
31
39
|
},
|
|
32
40
|
) {
|
|
33
|
-
const [resource] = Solid.createResource(
|
|
34
|
-
() => defer(props.promise),
|
|
35
|
-
// Simple passthrough - just return the promise for Solid to await
|
|
36
|
-
(p) => p,
|
|
37
|
-
{
|
|
38
|
-
deferStream: true,
|
|
39
|
-
},
|
|
40
|
-
)
|
|
41
|
-
|
|
42
41
|
return (
|
|
43
|
-
<Solid.
|
|
44
|
-
{
|
|
45
|
-
</Solid.
|
|
42
|
+
<Solid.Loading fallback={props.fallback as any}>
|
|
43
|
+
<InnerAwait promise={props.promise}>{props.children}</InnerAwait>
|
|
44
|
+
</Solid.Loading>
|
|
46
45
|
)
|
|
47
46
|
}
|