@bleedingdev/modern-js-renderer-solid 0.0.0-stage → 3.9.3-ultramodern.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/esm/actions.js +283 -0
- package/dist/esm/application-router.js +25 -0
- package/dist/esm/client.js +49 -0
- package/dist/esm/entry-application.js +60 -0
- package/dist/esm/entry-client.js +23 -0
- package/dist/esm/federation-context.js +25 -0
- package/dist/esm/federation-ssr.js +84 -0
- package/dist/esm/federation.js +83 -0
- package/dist/esm/i18n/I18nProvider.js +33 -0
- package/dist/esm/i18n/LocalizedLink.js +74 -0
- package/dist/esm/i18n/context.js +3 -0
- package/dist/esm/i18n/index.js +8 -0
- package/dist/esm/i18n/languageSync.js +50 -0
- package/dist/esm/i18n/types.js +0 -0
- package/dist/esm/i18n/useI18n.js +74 -0
- package/dist/esm/index.js +58 -0
- package/dist/esm/manifest.js +150 -0
- package/dist/esm/route-completion.js +150 -0
- package/dist/esm/route-data-error.js +108 -0
- package/dist/esm/router-binding/Asset.js +201 -0
- package/dist/esm/router-binding/CatchBoundary.js +94 -0
- package/dist/esm/router-binding/ClientOnly.js +26 -0
- package/dist/esm/router-binding/HeadContent.js +8 -0
- package/dist/esm/router-binding/LICENSE +21 -0
- package/dist/esm/router-binding/Match.js +319 -0
- package/dist/esm/router-binding/Matches.js +117 -0
- package/dist/esm/router-binding/PROVENANCE.json +94 -0
- package/dist/esm/router-binding/RouterProvider.js +51 -0
- package/dist/esm/router-binding/SafeFragment.js +5 -0
- package/dist/esm/router-binding/ScriptOnce.js +15 -0
- package/dist/esm/router-binding/Scripts.js +30 -0
- package/dist/esm/router-binding/ScrollRestoration.js +16 -0
- package/dist/esm/router-binding/Transitioner.js +103 -0
- package/dist/esm/router-binding/awaited.js +48 -0
- package/dist/esm/router-binding/fileRoute.js +83 -0
- package/dist/esm/router-binding/flightData.js +23 -0
- package/dist/esm/router-binding/headContentUtils.js +162 -0
- package/dist/esm/router-binding/history.js +0 -0
- package/dist/esm/router-binding/index.js +35 -0
- package/dist/esm/router-binding/lazyRouteComponent.js +30 -0
- package/dist/esm/router-binding/link.js +389 -0
- package/dist/esm/router-binding/matchContext.js +7 -0
- package/dist/esm/router-binding/nonRouteComponentContext.js +13 -0
- package/dist/esm/router-binding/not-found.js +35 -0
- package/dist/esm/router-binding/publicMatchData.js +447 -0
- package/dist/esm/router-binding/registryTransfer.js +210 -0
- package/dist/esm/router-binding/renderRouteNotFound.js +23 -0
- package/dist/esm/router-binding/route.js +143 -0
- package/dist/esm/router-binding/router.js +13 -0
- package/dist/esm/router-binding/routerContext.js +3 -0
- package/dist/esm/router-binding/routerStores.js +50 -0
- package/dist/esm/router-binding/scroll-restoration.js +13 -0
- package/dist/esm/router-binding/typePrimitives.js +0 -0
- package/dist/esm/router-binding/useBlocker.js +152 -0
- package/dist/esm/router-binding/useCanGoBack.js +7 -0
- package/dist/esm/router-binding/useLoaderData.js +9 -0
- package/dist/esm/router-binding/useLoaderDeps.js +8 -0
- package/dist/esm/router-binding/useLocation.js +14 -0
- package/dist/esm/router-binding/useMatch.js +28 -0
- package/dist/esm/router-binding/useNavigate.js +19 -0
- package/dist/esm/router-binding/useParams.js +13 -0
- package/dist/esm/router-binding/useRouteContext.js +8 -0
- package/dist/esm/router-binding/useRouter.js +10 -0
- package/dist/esm/router-binding/useRouterState.js +19 -0
- package/dist/esm/router-binding/useSearch.js +13 -0
- package/dist/esm/router-binding/utils.js +23 -0
- package/dist/esm/router.js +187 -0
- package/dist/esm-node/actions.js +263 -0
- package/dist/esm-node/application-router.js +25 -0
- package/dist/esm-node/client.js +49 -0
- package/dist/esm-node/entry-application.js +110 -0
- package/dist/esm-node/entry-client.js +23 -0
- package/dist/esm-node/entry-server.js +47 -0
- package/dist/esm-node/federation-context.js +25 -0
- package/dist/esm-node/federation-ssr.js +84 -0
- package/dist/esm-node/federation.js +83 -0
- package/dist/esm-node/i18n/I18nProvider.js +42 -0
- package/dist/esm-node/i18n/LocalizedLink.js +142 -0
- package/dist/esm-node/i18n/context.js +3 -0
- package/dist/esm-node/i18n/index.js +8 -0
- package/dist/esm-node/i18n/languageSync.js +50 -0
- package/dist/esm-node/i18n/types.js +1 -0
- package/dist/esm-node/i18n/useI18n.js +74 -0
- package/dist/esm-node/index.js +58 -0
- package/dist/esm-node/manifest.js +150 -0
- package/dist/esm-node/native-promise-serialization.js +113 -0
- package/dist/esm-node/plugin/compiler.js +209 -0
- package/dist/esm-node/plugin/create.js +235 -0
- package/dist/esm-node/plugin/index.js +73 -0
- package/dist/esm-node/plugin/profile.js +52 -0
- package/dist/esm-node/route-completion.js +160 -0
- package/dist/esm-node/route-data-error.js +108 -0
- package/dist/esm-node/router-binding/Asset.js +171 -0
- package/dist/esm-node/router-binding/CatchBoundary.js +136 -0
- package/dist/esm-node/router-binding/ClientOnly.js +46 -0
- package/dist/esm-node/router-binding/HeadContent.js +8 -0
- package/dist/esm-node/router-binding/LICENSE +21 -0
- package/dist/esm-node/router-binding/Match.js +660 -0
- package/dist/esm-node/router-binding/Matches.js +161 -0
- package/dist/esm-node/router-binding/PROVENANCE.json +94 -0
- package/dist/esm-node/router-binding/RouterProvider.js +87 -0
- package/dist/esm-node/router-binding/SafeFragment.js +5 -0
- package/dist/esm-node/router-binding/ScriptOnce.js +16 -0
- package/dist/esm-node/router-binding/Scripts.js +49 -0
- package/dist/esm-node/router-binding/ScrollRestoration.js +16 -0
- package/dist/esm-node/router-binding/Transitioner.js +103 -0
- package/dist/esm-node/router-binding/awaited.js +75 -0
- package/dist/esm-node/router-binding/fileRoute.js +83 -0
- package/dist/esm-node/router-binding/flightData.js +23 -0
- package/dist/esm-node/router-binding/headContentUtils.js +162 -0
- package/dist/esm-node/router-binding/history.js +1 -0
- package/dist/esm-node/router-binding/index.js +35 -0
- package/dist/esm-node/router-binding/lazyRouteComponent.js +30 -0
- package/dist/esm-node/router-binding/link.js +399 -0
- package/dist/esm-node/router-binding/matchContext.js +7 -0
- package/dist/esm-node/router-binding/nonRouteComponentContext.js +22 -0
- package/dist/esm-node/router-binding/not-found.js +49 -0
- package/dist/esm-node/router-binding/publicMatchData.js +447 -0
- package/dist/esm-node/router-binding/registryTransfer.js +210 -0
- package/dist/esm-node/router-binding/renderRouteNotFound.js +22 -0
- package/dist/esm-node/router-binding/route.js +162 -0
- package/dist/esm-node/router-binding/router.js +13 -0
- package/dist/esm-node/router-binding/routerContext.js +3 -0
- package/dist/esm-node/router-binding/routerStores.js +50 -0
- package/dist/esm-node/router-binding/scroll-restoration.js +12 -0
- package/dist/esm-node/router-binding/typePrimitives.js +1 -0
- package/dist/esm-node/router-binding/useBlocker.js +152 -0
- package/dist/esm-node/router-binding/useCanGoBack.js +7 -0
- package/dist/esm-node/router-binding/useLoaderData.js +9 -0
- package/dist/esm-node/router-binding/useLoaderDeps.js +8 -0
- package/dist/esm-node/router-binding/useLocation.js +14 -0
- package/dist/esm-node/router-binding/useMatch.js +28 -0
- package/dist/esm-node/router-binding/useNavigate.js +19 -0
- package/dist/esm-node/router-binding/useParams.js +13 -0
- package/dist/esm-node/router-binding/useRouteContext.js +8 -0
- package/dist/esm-node/router-binding/useRouter.js +10 -0
- package/dist/esm-node/router-binding/useRouterState.js +19 -0
- package/dist/esm-node/router-binding/useSearch.js +13 -0
- package/dist/esm-node/router-binding/utils.js +23 -0
- package/dist/esm-node/router.js +187 -0
- package/dist/esm-node/server.js +396 -0
- package/dist/types/actions.d.ts +45 -0
- package/dist/types/application-router.d.ts +5 -0
- package/dist/types/client.d.ts +23 -0
- package/dist/types/entry-application.d.ts +10 -0
- package/dist/types/entry-client.d.ts +5 -0
- package/dist/types/entry-server.d.ts +5 -0
- package/dist/types/federation-context.d.ts +16 -0
- package/dist/types/federation-ssr.d.ts +21 -0
- package/dist/types/federation.d.ts +30 -0
- package/dist/types/i18n/I18nProvider.d.ts +21 -0
- package/dist/types/i18n/LocalizedLink.d.ts +43 -0
- package/dist/types/i18n/context.d.ts +11 -0
- package/dist/types/i18n/index.d.ts +9 -0
- package/dist/types/i18n/languageSync.d.ts +31 -0
- package/dist/types/i18n/types.d.ts +33 -0
- package/dist/types/i18n/useI18n.d.ts +24 -0
- package/dist/types/index.d.ts +41 -0
- package/dist/types/manifest.d.ts +55 -0
- package/dist/types/native-promise-serialization.d.ts +9 -0
- package/dist/types/plugin/compiler.d.ts +6 -0
- package/dist/types/plugin/create.d.ts +21 -0
- package/dist/types/plugin/index.d.ts +3 -0
- package/dist/types/plugin/lazy-modules.d.cts +15 -0
- package/dist/types/plugin/preserve-import-loader.d.cts +3 -0
- package/dist/types/plugin/profile.d.ts +2 -0
- package/dist/types/plugin/solid-loader.d.cts +2 -0
- package/dist/types/plugin/svg-component-template.d.cts +6 -0
- package/dist/types/route-completion.d.ts +21 -0
- package/dist/types/route-data-error.d.ts +17 -0
- package/dist/types/router-binding/Asset.d.ts +3 -0
- package/dist/types/router-binding/CatchBoundary.d.ts +13 -0
- package/dist/types/router-binding/ClientOnly.d.ts +31 -0
- package/dist/types/router-binding/HeadContent.d.ts +13 -0
- package/dist/types/router-binding/Match.d.ts +6 -0
- package/dist/types/router-binding/Matches.d.ts +26 -0
- package/dist/types/router-binding/RouterProvider.d.ts +10 -0
- package/dist/types/router-binding/SafeFragment.d.ts +2 -0
- package/dist/types/router-binding/ScriptOnce.d.ts +6 -0
- package/dist/types/router-binding/Scripts.d.ts +2 -0
- package/dist/types/router-binding/ScrollRestoration.d.ts +14 -0
- package/dist/types/router-binding/Transitioner.d.ts +2 -0
- package/dist/types/router-binding/awaited.d.ts +11 -0
- package/dist/types/router-binding/fileRoute.d.ts +54 -0
- package/dist/types/router-binding/flightData.d.ts +38 -0
- package/dist/types/router-binding/headContentUtils.d.ts +15 -0
- package/dist/types/router-binding/history.d.ts +8 -0
- package/dist/types/router-binding/index.d.ts +45 -0
- package/dist/types/router-binding/lazyRouteComponent.d.ts +2 -0
- package/dist/types/router-binding/link.d.ts +43 -0
- package/dist/types/router-binding/matchContext.d.ts +7 -0
- package/dist/types/router-binding/nonRouteComponentContext.d.ts +5 -0
- package/dist/types/router-binding/not-found.d.ts +11 -0
- package/dist/types/router-binding/publicMatchData.d.ts +19 -0
- package/dist/types/router-binding/registryTransfer.d.ts +47 -0
- package/dist/types/router-binding/renderRouteNotFound.d.ts +11 -0
- package/dist/types/router-binding/route.d.ts +105 -0
- package/dist/types/router-binding/router.d.ts +70 -0
- package/dist/types/router-binding/routerContext.d.ts +3 -0
- package/dist/types/router-binding/routerStores.d.ts +2 -0
- package/dist/types/router-binding/scroll-restoration.d.ts +2 -0
- package/dist/types/router-binding/typePrimitives.d.ts +10 -0
- package/dist/types/router-binding/useBlocker.d.ts +70 -0
- package/dist/types/router-binding/useCanGoBack.d.ts +2 -0
- package/dist/types/router-binding/useLoaderData.d.ts +8 -0
- package/dist/types/router-binding/useLoaderDeps.d.ts +8 -0
- package/dist/types/router-binding/useLocation.d.ts +7 -0
- package/dist/types/router-binding/useMatch.d.ts +10 -0
- package/dist/types/router-binding/useNavigate.d.ts +5 -0
- package/dist/types/router-binding/useParams.d.ts +9 -0
- package/dist/types/router-binding/useRouteContext.d.ts +4 -0
- package/dist/types/router-binding/useRouter.d.ts +4 -0
- package/dist/types/router-binding/useRouterState.d.ts +8 -0
- package/dist/types/router-binding/useSearch.d.ts +9 -0
- package/dist/types/router-binding/utils.d.ts +25 -0
- package/dist/types/router.d.ts +31 -0
- package/dist/types/server.d.ts +47 -0
- package/package.json +123 -4
- package/src/actions.tsx +437 -0
- package/src/application-router.tsx +41 -0
- package/src/client.ts +106 -0
- package/src/entry-application.tsx +73 -0
- package/src/entry-client.tsx +48 -0
- package/src/entry-server.tsx +85 -0
- package/src/federation-context.ts +47 -0
- package/src/federation-ssr.ts +117 -0
- package/src/federation.tsx +193 -0
- package/src/i18n/I18nProvider.tsx +54 -0
- package/src/i18n/LocalizedLink.tsx +122 -0
- package/src/i18n/context.ts +13 -0
- package/src/i18n/index.ts +35 -0
- package/src/i18n/languageSync.ts +113 -0
- package/src/i18n/types.ts +35 -0
- package/src/i18n/useI18n.ts +121 -0
- package/src/index.ts +41 -0
- package/src/manifest.ts +337 -0
- package/src/native-promise-serialization.ts +167 -0
- package/src/plugin/compiler.ts +320 -0
- package/src/plugin/create.ts +270 -0
- package/src/plugin/index.ts +72 -0
- package/src/plugin/lazy-modules.cjs +146 -0
- package/src/plugin/preserve-import-loader.cjs +46 -0
- package/src/plugin/profile.ts +42 -0
- package/src/plugin/solid-loader.cjs +83 -0
- package/src/plugin/svg-component-template.cjs +19 -0
- package/src/route-completion.tsx +222 -0
- package/src/route-data-error.ts +175 -0
- package/src/router-binding/Asset.tsx +283 -0
- package/src/router-binding/CatchBoundary.tsx +130 -0
- package/src/router-binding/ClientOnly.tsx +76 -0
- package/src/router-binding/HeadContent.tsx +23 -0
- package/src/router-binding/LICENSE +21 -0
- package/src/router-binding/Match.tsx +397 -0
- package/src/router-binding/Matches.tsx +242 -0
- package/src/router-binding/PROVENANCE.json +94 -0
- package/src/router-binding/RouterProvider.tsx +129 -0
- package/src/router-binding/SafeFragment.tsx +5 -0
- package/src/router-binding/ScriptOnce.tsx +23 -0
- package/src/router-binding/Scripts.tsx +44 -0
- package/src/router-binding/ScrollRestoration.tsx +49 -0
- package/src/router-binding/Transitioner.tsx +172 -0
- package/src/router-binding/awaited.tsx +71 -0
- package/src/router-binding/fileRoute.ts +268 -0
- package/src/router-binding/flightData.ts +90 -0
- package/src/router-binding/headContentUtils.tsx +290 -0
- package/src/router-binding/history.ts +9 -0
- package/src/router-binding/index.tsx +318 -0
- package/src/router-binding/lazyRouteComponent.tsx +70 -0
- package/src/router-binding/link.tsx +865 -0
- package/src/router-binding/matchContext.tsx +15 -0
- package/src/router-binding/nonRouteComponentContext.tsx +23 -0
- package/src/router-binding/not-found.tsx +65 -0
- package/src/router-binding/publicMatchData.ts +674 -0
- package/src/router-binding/registryTransfer.ts +383 -0
- package/src/router-binding/renderRouteNotFound.tsx +53 -0
- package/src/router-binding/route.tsx +665 -0
- package/src/router-binding/router.ts +121 -0
- package/src/router-binding/routerContext.tsx +6 -0
- package/src/router-binding/routerStores.ts +85 -0
- package/src/router-binding/scroll-restoration.tsx +15 -0
- package/src/router-binding/typePrimitives.ts +74 -0
- package/src/router-binding/useBlocker.tsx +359 -0
- package/src/router-binding/useCanGoBack.ts +9 -0
- package/src/router-binding/useLoaderData.tsx +50 -0
- package/src/router-binding/useLoaderDeps.tsx +46 -0
- package/src/router-binding/useLocation.tsx +43 -0
- package/src/router-binding/useMatch.tsx +111 -0
- package/src/router-binding/useNavigate.tsx +43 -0
- package/src/router-binding/useParams.tsx +72 -0
- package/src/router-binding/useRouteContext.ts +30 -0
- package/src/router-binding/useRouter.tsx +17 -0
- package/src/router-binding/useRouterState.tsx +50 -0
- package/src/router-binding/useSearch.tsx +72 -0
- package/src/router-binding/utils.ts +59 -0
- package/src/router.ts +376 -0
- package/src/server.ts +645 -0
- package/README.md +0 -3
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import type { AnyRouteMatch } from '@tanstack/router-core';
|
|
2
|
+
import { getLocationChangeInfo, trimPathRight } from '@tanstack/router-core';
|
|
3
|
+
import { isServer } from '@tanstack/router-core/isServer';
|
|
4
|
+
import type { NavigationRef } from 'solid-js';
|
|
5
|
+
import * as Solid from 'solid-js';
|
|
6
|
+
import { useRouter } from './useRouter';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Solid's observe tier (`OBSERVE` is defined on the dev and observe builds,
|
|
10
|
+
* undefined in production) attributes what the user waited on to the
|
|
11
|
+
* navigation that caused it. The rule for every router is the same: wrap the
|
|
12
|
+
* write whose landing is the destination showing, and pass `at` when the
|
|
13
|
+
* request predates that write. Here that write is the match publish inside
|
|
14
|
+
* `startTransition` — the loaders were awaited in router-core before it —
|
|
15
|
+
* so the ref names the destination route from the expected matches and
|
|
16
|
+
* dates from the history change that started the load. The pending offer
|
|
17
|
+
* (`offerPending`, a match with `status: 'pending'`) is not the destination
|
|
18
|
+
* and is published undeclared; the initial load and a same-location reload
|
|
19
|
+
* are not navigations.
|
|
20
|
+
*/
|
|
21
|
+
function describeNavigation(
|
|
22
|
+
router: ReturnType<typeof useRouter>,
|
|
23
|
+
expected: Array<AnyRouteMatch>,
|
|
24
|
+
at: number | undefined,
|
|
25
|
+
): NavigationRef | undefined {
|
|
26
|
+
if (expected.some(match => match.status === 'pending')) return;
|
|
27
|
+
const to = router.latestLocation;
|
|
28
|
+
const from = router.stores.resolvedLocation.get();
|
|
29
|
+
// Nothing shown yet (the initial load), or a reload of what is shown.
|
|
30
|
+
if (!from || from.href === to.href) return;
|
|
31
|
+
const leaf = expected[expected.length - 1];
|
|
32
|
+
const ref: NavigationRef = {
|
|
33
|
+
kind: 'navigation',
|
|
34
|
+
name: leaf?.fullPath || to.pathname,
|
|
35
|
+
to: to.pathname,
|
|
36
|
+
from: from.pathname,
|
|
37
|
+
};
|
|
38
|
+
if (leaf && Object.keys(leaf.params).length) ref.params = leaf.params;
|
|
39
|
+
if (at !== undefined) ref.at = at;
|
|
40
|
+
return ref;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getResolvedLocation(router: ReturnType<typeof useRouter>) {
|
|
44
|
+
const resolvedLocation = router.stores.resolvedLocation.get();
|
|
45
|
+
if (
|
|
46
|
+
resolvedLocation?.href === router.latestLocation.href &&
|
|
47
|
+
resolvedLocation.state.__TSR_key === router.latestLocation.state.__TSR_key
|
|
48
|
+
) {
|
|
49
|
+
return resolvedLocation;
|
|
50
|
+
}
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function Transitioner() {
|
|
55
|
+
const router = useRouter();
|
|
56
|
+
|
|
57
|
+
type Ack = [
|
|
58
|
+
expected: Array<AnyRouteMatch>,
|
|
59
|
+
resolve: (rendered: boolean) => void,
|
|
60
|
+
];
|
|
61
|
+
const acks: Array<Ack> = [];
|
|
62
|
+
let committed: Array<AnyRouteMatch> | undefined;
|
|
63
|
+
|
|
64
|
+
const isCommitted = (expected: Array<AnyRouteMatch>) =>
|
|
65
|
+
!!committed &&
|
|
66
|
+
committed.length === expected.length &&
|
|
67
|
+
expected.every((match, index) => committed![index] === match);
|
|
68
|
+
|
|
69
|
+
// When the history changed since the last declared publish: the moment
|
|
70
|
+
// the user asked, which is where the navigation's wait starts.
|
|
71
|
+
let requestedAt: number | undefined;
|
|
72
|
+
|
|
73
|
+
// Ack when the commit's transition settles (the atomic swap), not when the
|
|
74
|
+
// flush parks it; superseded or rolled-back commits resolve false.
|
|
75
|
+
router.startTransition = (fn, expectedMatches) => {
|
|
76
|
+
if (isServer ?? router.isServer) {
|
|
77
|
+
fn();
|
|
78
|
+
return Promise.resolve(true);
|
|
79
|
+
}
|
|
80
|
+
return new Promise(resolve => {
|
|
81
|
+
const ack: Ack = [expectedMatches, resolve];
|
|
82
|
+
acks.push(ack);
|
|
83
|
+
let publish = fn;
|
|
84
|
+
if (Solid.OBSERVE !== undefined) {
|
|
85
|
+
const ref = describeNavigation(router, expectedMatches, requestedAt);
|
|
86
|
+
if (ref !== undefined) {
|
|
87
|
+
requestedAt = undefined;
|
|
88
|
+
const observe = Solid.OBSERVE;
|
|
89
|
+
publish = () => observe.attribution.withOrigin(ref, fn);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
Solid.runWithOwner(null, publish);
|
|
93
|
+
try {
|
|
94
|
+
Solid.flush();
|
|
95
|
+
} catch {
|
|
96
|
+
// Solid auto-flushes when this is called from a reactive context.
|
|
97
|
+
}
|
|
98
|
+
// A commit that changed nothing produces no settlement to observe.
|
|
99
|
+
if (acks.includes(ack) && isCommitted(expectedMatches)) {
|
|
100
|
+
acks.splice(acks.indexOf(ack), 1);
|
|
101
|
+
resolve(true);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// No server early-return here or below: Solid 2 derives hydration keys
|
|
107
|
+
// from the reactive owner tree, so the server must register the same slots
|
|
108
|
+
// as the client. The callbacks themselves never run on the server.
|
|
109
|
+
Solid.createEffect(
|
|
110
|
+
() => router.stores.matches.get(),
|
|
111
|
+
current => {
|
|
112
|
+
committed = current;
|
|
113
|
+
if (acks.length) {
|
|
114
|
+
for (const [expected, resolve] of acks.splice(0)) {
|
|
115
|
+
resolve(isCommitted(expected));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
Solid.onSettled(() => {
|
|
122
|
+
const unsub = router.history.subscribe(() => {
|
|
123
|
+
requestedAt ??= performance.now();
|
|
124
|
+
queueMicrotask(() => router.load().catch(console.error));
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// The URL may have changed synchronously between render and settlement.
|
|
128
|
+
router.updateLatestLocation();
|
|
129
|
+
const nextLocation = router.buildLocation({
|
|
130
|
+
to: router.latestLocation.pathname,
|
|
131
|
+
search: true,
|
|
132
|
+
params: true,
|
|
133
|
+
hash: true,
|
|
134
|
+
state: true,
|
|
135
|
+
_includeValidateSearch: true,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
if (
|
|
139
|
+
trimPathRight(router.latestLocation.publicHref) !==
|
|
140
|
+
trimPathRight(nextLocation.publicHref)
|
|
141
|
+
) {
|
|
142
|
+
router.commitLocation({
|
|
143
|
+
...nextLocation,
|
|
144
|
+
replace: true,
|
|
145
|
+
ignoreBlocker: true,
|
|
146
|
+
});
|
|
147
|
+
return unsub;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!getResolvedLocation(router) && !router._tx) {
|
|
151
|
+
queueMicrotask(() => router.load().catch(console.error));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return unsub;
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function Rendered() {
|
|
161
|
+
const router = useRouter();
|
|
162
|
+
Solid.onSettled(() => {
|
|
163
|
+
const resolvedLocation = getResolvedLocation(router);
|
|
164
|
+
if (resolvedLocation) {
|
|
165
|
+
router.emit({
|
|
166
|
+
type: 'onRendered',
|
|
167
|
+
...getLocationChangeInfo(resolvedLocation, resolvedLocation),
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { JSX } from '@solidjs/web';
|
|
2
|
+
import type { DeferredPromise } from '@tanstack/router-core';
|
|
3
|
+
import { defer, TSR_DEFERRED_PROMISE } from '@tanstack/router-core';
|
|
4
|
+
import * as Solid from 'solid-js';
|
|
5
|
+
import type { SolidNode } from './route';
|
|
6
|
+
|
|
7
|
+
export type AwaitOptions<T> = {
|
|
8
|
+
promise: Promise<T>;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Native loader data is frozen, and defer() tags the promise it tracks, so a
|
|
13
|
+
* frozen promise is tracked through a follower that settles the same way.
|
|
14
|
+
*/
|
|
15
|
+
function track<T>(promise: Promise<T>): DeferredPromise<T> {
|
|
16
|
+
return defer(Object.isExtensible(promise) ? promise : promise.then(v => v));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function useAwaited<T>({
|
|
20
|
+
promise: _promise,
|
|
21
|
+
}: AwaitOptions<T>): [data: T, promise: DeferredPromise<T>] {
|
|
22
|
+
const promise = track(_promise);
|
|
23
|
+
const data = Solid.createMemo(async () => await promise);
|
|
24
|
+
|
|
25
|
+
return [data(), promise];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function InnerAwait<T>(props: {
|
|
29
|
+
deferred: DeferredPromise<T>;
|
|
30
|
+
ready: Solid.Accessor<unknown>;
|
|
31
|
+
children: (res: T) => SolidNode;
|
|
32
|
+
}) {
|
|
33
|
+
return (
|
|
34
|
+
<Solid.Show when={props.ready()}>
|
|
35
|
+
{_ => {
|
|
36
|
+
const state = props.deferred[TSR_DEFERRED_PROMISE];
|
|
37
|
+
if (state.status === 'error') {
|
|
38
|
+
throw state.error;
|
|
39
|
+
}
|
|
40
|
+
return props.children(state.data as T) as any;
|
|
41
|
+
}}
|
|
42
|
+
</Solid.Show>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function Await<T>(
|
|
47
|
+
props: AwaitOptions<T> & {
|
|
48
|
+
fallback?: SolidNode;
|
|
49
|
+
children: (result: T) => SolidNode;
|
|
50
|
+
},
|
|
51
|
+
): JSX.Element {
|
|
52
|
+
const deferred = track(props.promise);
|
|
53
|
+
const ready = Solid.createMemo(async () => {
|
|
54
|
+
await deferred;
|
|
55
|
+
return true;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const inner = (
|
|
59
|
+
<InnerAwait deferred={deferred} ready={ready}>
|
|
60
|
+
{props.children}
|
|
61
|
+
</InnerAwait>
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (props.fallback === undefined) {
|
|
65
|
+
return inner;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<Solid.Loading fallback={props.fallback as any}>{inner}</Solid.Loading>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AnyContext,
|
|
3
|
+
AnyRoute,
|
|
4
|
+
AnyRouter,
|
|
5
|
+
Constrain,
|
|
6
|
+
ConstrainLiteral,
|
|
7
|
+
FileBaseRouteOptions,
|
|
8
|
+
FileRoutesByPath,
|
|
9
|
+
LazyRouteOptions,
|
|
10
|
+
Register,
|
|
11
|
+
RegisteredRouter,
|
|
12
|
+
ResolveParams,
|
|
13
|
+
Route,
|
|
14
|
+
RouteById,
|
|
15
|
+
RouteConstraints,
|
|
16
|
+
RouteIds,
|
|
17
|
+
RouteLoaderEntry,
|
|
18
|
+
UpdatableRouteOptions,
|
|
19
|
+
UseNavigateResult,
|
|
20
|
+
} from '@tanstack/router-core';
|
|
21
|
+
import { createRoute } from './route';
|
|
22
|
+
import type { UseLoaderDataRoute } from './useLoaderData';
|
|
23
|
+
import { useLoaderData } from './useLoaderData';
|
|
24
|
+
import type { UseLoaderDepsRoute } from './useLoaderDeps';
|
|
25
|
+
import { useLoaderDeps } from './useLoaderDeps';
|
|
26
|
+
import type { UseMatchRoute } from './useMatch';
|
|
27
|
+
import { useMatch } from './useMatch';
|
|
28
|
+
import { useNavigate } from './useNavigate';
|
|
29
|
+
import type { UseParamsRoute } from './useParams';
|
|
30
|
+
import { useParams } from './useParams';
|
|
31
|
+
import type { UseRouteContextRoute } from './useRouteContext';
|
|
32
|
+
import { useRouteContext } from './useRouteContext';
|
|
33
|
+
import { useRouter } from './useRouter';
|
|
34
|
+
import type { UseSearchRoute } from './useSearch';
|
|
35
|
+
import { useSearch } from './useSearch';
|
|
36
|
+
|
|
37
|
+
export function createFileRoute<
|
|
38
|
+
TFilePath extends keyof FileRoutesByPath,
|
|
39
|
+
TParentRoute extends AnyRoute = FileRoutesByPath[TFilePath]['parentRoute'],
|
|
40
|
+
TId extends RouteConstraints['TId'] = FileRoutesByPath[TFilePath]['id'],
|
|
41
|
+
TPath extends RouteConstraints['TPath'] = FileRoutesByPath[TFilePath]['path'],
|
|
42
|
+
TFullPath extends
|
|
43
|
+
RouteConstraints['TFullPath'] = FileRoutesByPath[TFilePath]['fullPath'],
|
|
44
|
+
>(
|
|
45
|
+
_path?: TFilePath,
|
|
46
|
+
): FileRoute<TFilePath, TParentRoute, TId, TPath, TFullPath>['createRoute'] {
|
|
47
|
+
return options => {
|
|
48
|
+
const route = createRoute(options as any);
|
|
49
|
+
(route as any).isRoot = false;
|
|
50
|
+
return route as any;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
@deprecated It's no longer recommended to use the `FileRoute` class directly.
|
|
56
|
+
Instead, use `createFileRoute('/path/to/file')(options)` to create a file route.
|
|
57
|
+
*/
|
|
58
|
+
export class FileRoute<
|
|
59
|
+
TFilePath extends keyof FileRoutesByPath,
|
|
60
|
+
TParentRoute extends AnyRoute = FileRoutesByPath[TFilePath]['parentRoute'],
|
|
61
|
+
TId extends RouteConstraints['TId'] = FileRoutesByPath[TFilePath]['id'],
|
|
62
|
+
TPath extends RouteConstraints['TPath'] = FileRoutesByPath[TFilePath]['path'],
|
|
63
|
+
TFullPath extends
|
|
64
|
+
RouteConstraints['TFullPath'] = FileRoutesByPath[TFilePath]['fullPath'],
|
|
65
|
+
> {
|
|
66
|
+
silent?: boolean;
|
|
67
|
+
|
|
68
|
+
constructor(
|
|
69
|
+
public path?: TFilePath,
|
|
70
|
+
_opts?: { silent: boolean },
|
|
71
|
+
) {
|
|
72
|
+
this.silent = _opts?.silent;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
createRoute = <
|
|
76
|
+
TRegister = Register,
|
|
77
|
+
TSearchValidator = undefined,
|
|
78
|
+
TParams = ResolveParams<TPath>,
|
|
79
|
+
TRouteContextFn = AnyContext,
|
|
80
|
+
TBeforeLoadFn = AnyContext,
|
|
81
|
+
TLoaderDeps extends Record<string, any> = {},
|
|
82
|
+
TLoaderFn = undefined,
|
|
83
|
+
TChildren = unknown,
|
|
84
|
+
TSSR = unknown,
|
|
85
|
+
const TMiddlewares = unknown,
|
|
86
|
+
THandlers = undefined,
|
|
87
|
+
>(
|
|
88
|
+
options?: FileBaseRouteOptions<
|
|
89
|
+
TRegister,
|
|
90
|
+
TParentRoute,
|
|
91
|
+
TId,
|
|
92
|
+
TPath,
|
|
93
|
+
TSearchValidator,
|
|
94
|
+
TParams,
|
|
95
|
+
TLoaderDeps,
|
|
96
|
+
TLoaderFn,
|
|
97
|
+
AnyContext,
|
|
98
|
+
TRouteContextFn,
|
|
99
|
+
TBeforeLoadFn,
|
|
100
|
+
AnyContext,
|
|
101
|
+
TSSR,
|
|
102
|
+
TMiddlewares,
|
|
103
|
+
THandlers
|
|
104
|
+
> &
|
|
105
|
+
UpdatableRouteOptions<
|
|
106
|
+
TParentRoute,
|
|
107
|
+
TId,
|
|
108
|
+
TFullPath,
|
|
109
|
+
TParams,
|
|
110
|
+
TSearchValidator,
|
|
111
|
+
TLoaderFn,
|
|
112
|
+
TLoaderDeps,
|
|
113
|
+
AnyContext,
|
|
114
|
+
TRouteContextFn,
|
|
115
|
+
TBeforeLoadFn
|
|
116
|
+
>,
|
|
117
|
+
): Route<
|
|
118
|
+
TRegister,
|
|
119
|
+
TParentRoute,
|
|
120
|
+
TPath,
|
|
121
|
+
TFullPath,
|
|
122
|
+
TFilePath,
|
|
123
|
+
TId,
|
|
124
|
+
TSearchValidator,
|
|
125
|
+
TParams,
|
|
126
|
+
AnyContext,
|
|
127
|
+
TRouteContextFn,
|
|
128
|
+
TBeforeLoadFn,
|
|
129
|
+
TLoaderDeps,
|
|
130
|
+
TLoaderFn,
|
|
131
|
+
TChildren,
|
|
132
|
+
unknown,
|
|
133
|
+
TSSR,
|
|
134
|
+
TMiddlewares,
|
|
135
|
+
THandlers
|
|
136
|
+
> => {
|
|
137
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
138
|
+
if (!this.silent) {
|
|
139
|
+
console.warn(
|
|
140
|
+
'Warning: FileRoute is deprecated and will be removed in the next major version. Use the createFileRoute(path)(options) function instead.',
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const route = createRoute(options as any);
|
|
145
|
+
(route as any).isRoot = false;
|
|
146
|
+
return route as any;
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
@deprecated It's recommended not to split loaders into separate files.
|
|
152
|
+
Instead, place the loader function in the main route file, inside the
|
|
153
|
+
`createFileRoute('/path/to/file)(options)` options.
|
|
154
|
+
*/
|
|
155
|
+
export function FileRouteLoader<
|
|
156
|
+
TFilePath extends keyof FileRoutesByPath,
|
|
157
|
+
TRoute extends FileRoutesByPath[TFilePath]['preLoaderRoute'],
|
|
158
|
+
>(
|
|
159
|
+
_path: TFilePath,
|
|
160
|
+
): <TLoaderFn>(
|
|
161
|
+
loaderFn: Constrain<
|
|
162
|
+
TLoaderFn,
|
|
163
|
+
RouteLoaderEntry<
|
|
164
|
+
Register,
|
|
165
|
+
TRoute['parentRoute'],
|
|
166
|
+
TRoute['types']['id'],
|
|
167
|
+
TRoute['types']['params'],
|
|
168
|
+
TRoute['types']['loaderDeps'],
|
|
169
|
+
TRoute['types']['routerContext'],
|
|
170
|
+
TRoute['types']['routeContextFn'],
|
|
171
|
+
TRoute['types']['beforeLoadFn']
|
|
172
|
+
>
|
|
173
|
+
>,
|
|
174
|
+
) => TLoaderFn {
|
|
175
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
176
|
+
console.warn(
|
|
177
|
+
`Warning: FileRouteLoader is deprecated and will be removed in the next major version. Please place the loader function in the main route file, inside the \`createFileRoute('/path/to/file')(options)\` options`,
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
return loaderFn => loaderFn as any;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
declare module '@tanstack/router-core' {
|
|
184
|
+
export interface LazyRoute<in out TRoute extends AnyRoute> {
|
|
185
|
+
useMatch: UseMatchRoute<TRoute['id']>;
|
|
186
|
+
useRouteContext: UseRouteContextRoute<TRoute['id']>;
|
|
187
|
+
useSearch: UseSearchRoute<TRoute['id']>;
|
|
188
|
+
useParams: UseParamsRoute<TRoute['id']>;
|
|
189
|
+
useLoaderDeps: UseLoaderDepsRoute<TRoute['id']>;
|
|
190
|
+
useLoaderData: UseLoaderDataRoute<TRoute['id']>;
|
|
191
|
+
useNavigate: () => UseNavigateResult<TRoute['fullPath']>;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export class LazyRoute<TRoute extends AnyRoute> {
|
|
196
|
+
options: {
|
|
197
|
+
id: string;
|
|
198
|
+
} & LazyRouteOptions;
|
|
199
|
+
|
|
200
|
+
constructor(
|
|
201
|
+
opts: {
|
|
202
|
+
id: string;
|
|
203
|
+
} & LazyRouteOptions,
|
|
204
|
+
) {
|
|
205
|
+
this.options = opts;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
useMatch: UseMatchRoute<TRoute['id']> = opts => {
|
|
209
|
+
return useMatch({
|
|
210
|
+
select: opts?.select,
|
|
211
|
+
from: this.options.id,
|
|
212
|
+
} as any) as any;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
useRouteContext: UseRouteContextRoute<TRoute['id']> = opts => {
|
|
216
|
+
return useRouteContext({ ...(opts as any), from: this.options.id });
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
useSearch: UseSearchRoute<TRoute['id']> = opts => {
|
|
220
|
+
return useSearch({
|
|
221
|
+
select: opts?.select,
|
|
222
|
+
from: this.options.id,
|
|
223
|
+
} as any) as any;
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
useParams: UseParamsRoute<TRoute['id']> = opts => {
|
|
227
|
+
return useParams({
|
|
228
|
+
select: opts?.select,
|
|
229
|
+
from: this.options.id,
|
|
230
|
+
} as any) as any;
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
useLoaderDeps: UseLoaderDepsRoute<TRoute['id']> = opts => {
|
|
234
|
+
return useLoaderDeps({ ...opts, from: this.options.id } as any);
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
useLoaderData: UseLoaderDataRoute<TRoute['id']> = opts => {
|
|
238
|
+
return useLoaderData({ ...opts, from: this.options.id } as any);
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
useNavigate = (): UseNavigateResult<TRoute['fullPath']> => {
|
|
242
|
+
const router = useRouter();
|
|
243
|
+
return useNavigate({ from: router.routesById[this.options.id].fullPath });
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export function createLazyRoute<
|
|
248
|
+
TRouter extends AnyRouter = RegisteredRouter,
|
|
249
|
+
TId extends string = string,
|
|
250
|
+
TRoute extends AnyRoute = RouteById<TRouter['routeTree'], TId>,
|
|
251
|
+
>(id: ConstrainLiteral<TId, RouteIds<TRouter['routeTree']>>) {
|
|
252
|
+
return (opts: LazyRouteOptions) => {
|
|
253
|
+
return new LazyRoute<TRoute>({
|
|
254
|
+
id: id,
|
|
255
|
+
...opts,
|
|
256
|
+
});
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
export function createLazyFileRoute<
|
|
260
|
+
TFilePath extends keyof FileRoutesByPath,
|
|
261
|
+
TRoute extends FileRoutesByPath[TFilePath]['preLoaderRoute'],
|
|
262
|
+
>(id: TFilePath): (opts: LazyRouteOptions) => LazyRoute<TRoute> {
|
|
263
|
+
if (typeof id === 'object') {
|
|
264
|
+
return new LazyRoute<TRoute>(id) as any;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return (opts: LazyRouteOptions) => new LazyRoute<TRoute>({ id, ...opts });
|
|
268
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { REVALIDATE_HEADER } from '@solidjs/web';
|
|
2
|
+
import {
|
|
3
|
+
decodeRedirectHeaderValue,
|
|
4
|
+
REDIRECT_HEADER,
|
|
5
|
+
subscribeFlightData,
|
|
6
|
+
} from '@solidjs/web/server-functions';
|
|
7
|
+
import type { AnyRouter } from '@tanstack/router-core';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Registers the router as the unnamed single-flight consumer of Solid's
|
|
11
|
+
* server-function transport, so the response helpers a mutation returns —
|
|
12
|
+
* `redirect()`, `reload()`, `respond(value, { revalidate })` — take effect
|
|
13
|
+
* on the client without the caller wrapping the call: the transport hands
|
|
14
|
+
* the caller the plain value and the router applies the metadata. Called
|
|
15
|
+
* by `RouterContextProvider` on the client; returns the unsubscribe.
|
|
16
|
+
*
|
|
17
|
+
* Subscribing is also the single-flight opt-in: while registered, the
|
|
18
|
+
* transport tags mutation calls so the server can fold fresh data for
|
|
19
|
+
* registered collectors into the same response. The router claims no
|
|
20
|
+
* slice of that data itself — route data is reloaded through `invalidate`
|
|
21
|
+
* below, and caches that want seeding (a query client) subscribe under
|
|
22
|
+
* their own source id.
|
|
23
|
+
*/
|
|
24
|
+
export function setupFlightDataConsumer(router: AnyRouter): () => void {
|
|
25
|
+
return subscribeFlightData((_data, { response }) =>
|
|
26
|
+
applyResponseMetadata(router, response),
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Applies a server-function response's integration metadata to the
|
|
32
|
+
* router. A mutation is a write, so a response carrying metadata reloads
|
|
33
|
+
* the route data the page is built on: committed and cached matches are
|
|
34
|
+
* invalidated the way `router.invalidate()` does after a mutation.
|
|
35
|
+
*
|
|
36
|
+
* `X-Revalidate` names entries in caches the router does not own, so the
|
|
37
|
+
* keys themselves are left to those caches' consumers; the router reads
|
|
38
|
+
* only the declaration's shape. Absent (a bare `redirect()`/`reload()`),
|
|
39
|
+
* named keys, or the reserved `*` all say a write happened — route data
|
|
40
|
+
* reloads. An EMPTY declaration (`revalidate: []`) is the author narrowing
|
|
41
|
+
* the scope to nothing, and the router honors that too: a redirect still
|
|
42
|
+
* navigates, but nothing is reloaded on the way.
|
|
43
|
+
*
|
|
44
|
+
* The redirect carrier delivers the target RESOLVED to an absolute url, so
|
|
45
|
+
* the soft/hard split is a real origin comparison: a same-origin target
|
|
46
|
+
* navigates under the router (`replace`, matching what HTTP gives a form
|
|
47
|
+
* post — the destination takes the submission's place in history), and any
|
|
48
|
+
* other origin leaves the app through a document navigation.
|
|
49
|
+
*/
|
|
50
|
+
export function applyResponseMetadata(
|
|
51
|
+
router: AnyRouter,
|
|
52
|
+
response: Response,
|
|
53
|
+
): void {
|
|
54
|
+
const carried = decodeRedirectHeaderValue(
|
|
55
|
+
response.headers.get(REDIRECT_HEADER),
|
|
56
|
+
);
|
|
57
|
+
const declared = response.headers.get(REVALIDATE_HEADER);
|
|
58
|
+
if (!carried && declared === null) return;
|
|
59
|
+
const reload = declared === null || declared.split(',').some(Boolean);
|
|
60
|
+
|
|
61
|
+
const target = carried ? new URL(carried.url) : undefined;
|
|
62
|
+
const origin = router.options.origin ?? window.location.origin;
|
|
63
|
+
if (target && target.origin !== origin) {
|
|
64
|
+
// A full url makes `navigate` reload the document (through the
|
|
65
|
+
// router, so protocol allowlisting and blockers still apply).
|
|
66
|
+
router.navigate({ href: target.href, replace: true });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Navigate, then invalidate — in this order so the write costs one load.
|
|
71
|
+
// `navigate` commits the destination to history synchronously (the
|
|
72
|
+
// adapter's own load follows in a microtask); `invalidate` then marks the
|
|
73
|
+
// committed matches — the layouts the destination shares with the page
|
|
74
|
+
// the mutation ran on, whose data is what just changed — and starts a
|
|
75
|
+
// load that already reads the destination as the latest location. The
|
|
76
|
+
// adapter's load adopts the loader generations that load started for
|
|
77
|
+
// the same match ids rather than restarting them, so the destination
|
|
78
|
+
// commits with the layouts reloaded, and the page being left never has
|
|
79
|
+
// its own loaders rerun. The other order would reload the abandoned
|
|
80
|
+
// page first.
|
|
81
|
+
if (target) {
|
|
82
|
+
router
|
|
83
|
+
.navigate({
|
|
84
|
+
href: target.pathname + target.search + target.hash,
|
|
85
|
+
replace: true,
|
|
86
|
+
})
|
|
87
|
+
.catch(console.error);
|
|
88
|
+
}
|
|
89
|
+
if (reload) router.invalidate().catch(console.error);
|
|
90
|
+
}
|