UNPKG

@tanstack/solid-router

Version:

Modern and scalable routing for Solid applications

263 lines (262 loc) 10.1 kB
import { nonRouteComponentContext, renderInNonRouteComponentContext } from "./nonRouteComponentContext.js"; import { CatchBoundary, ErrorComponent } from "./CatchBoundary.js"; import { ClientOnly } from "./ClientOnly.js"; import { useRouter } from "./useRouter.js"; import { nearestMatchContext } from "./matchContext.js"; import { SafeFragment } from "./SafeFragment.js"; import { CatchNotFound, getNotFound } from "./not-found.js"; import { renderRouteNotFound } from "./renderRouteNotFound.js"; import { ScrollRestoration } from "./scroll-restoration.js"; import { rootRouteId } from "@tanstack/router-core"; import { Dynamic, createComponent, memo, mergeProps } from "solid-js/web"; import * as Solid from "solid-js"; import { isServer } from "@tanstack/router-core/isServer"; //#region src/Match.tsx var renderScrollRestoration = isServer === false ? void 0 : (router, route) => (isServer ?? router.isServer) && route.parentRoute?.id === rootRouteId && router.options.scrollRestoration ? createComponent(ScrollRestoration, {}) : null; var Match = (props) => { const router = useRouter(); const currentMatch = Solid.createMemo(() => router.stores.byRoute.get(props.routeId).get()); const nearestMatch = [() => props.routeId, currentMatch]; const route = router.routesById[props.routeId]; const routeOptions = isServer ?? router.isServer ? () => route.options : () => { currentMatch(); return route.options; }; const resolvePendingComponent = () => routeOptions().pendingComponent ?? router.options.defaultPendingComponent; const routeErrorComponent = () => routeOptions().errorComponent ?? router.options.defaultErrorComponent; const routeNotFoundComponent = () => route.isRoot ? routeOptions().notFoundComponent ?? router.options.notFoundRoute?.options.component : routeOptions().notFoundComponent; const resolvedNoSsr = () => currentMatch().ssr === false || currentMatch().ssr === "data-only"; const shouldSkipSuspenseFallback = () => isServer ?? router.isServer ? resolvedNoSsr() : currentMatch().ssr === "data-only"; const ShellComponent = route.isRoot ? route.options.shellComponent ?? SafeFragment : SafeFragment; const MatchContent = () => createComponent(Solid.Show, { get when() { return currentMatch().status !== "pending"; }, get fallback() { if (process.env.NODE_ENV !== "production") return renderInNonRouteComponentContext(() => createComponent(Dynamic, { get component() { return resolvePendingComponent(); } }), "pendingComponent"); return createComponent(Dynamic, { get component() { return resolvePendingComponent(); } }); }, get children() { return createComponent(MatchInner, {}); } }); return createComponent(ShellComponent, { get children() { return [createComponent(nearestMatchContext.Provider, { value: nearestMatch, get children() { return createComponent(Solid.Suspense, { get fallback() { if (shouldSkipSuspenseFallback()) return; if (process.env.NODE_ENV !== "production") return renderInNonRouteComponentContext(() => createComponent(Dynamic, { get component() { return resolvePendingComponent(); } }), "pendingComponent"); return createComponent(Dynamic, { get component() { return resolvePendingComponent(); } }); }, get children() { return createComponent(Dynamic, { get component() { return routeErrorComponent() ? CatchBoundary : SafeFragment; }, getResetKey: currentMatch, get errorComponent() { return routeErrorComponent(); }, onCatch: (error) => { const notFoundError = getNotFound(error); if (notFoundError) { notFoundError.routeId ??= currentMatch().routeId; throw notFoundError; } if (process.env.NODE_ENV !== "production") console.warn(`Warning: Error in route match: ${currentMatch().routeId}`); (route.options.onCatch ?? router.options.defaultOnCatch)?.(error); }, get children() { return createComponent(Dynamic, { get component() { return routeNotFoundComponent() ? CatchNotFound : SafeFragment; }, fallback: (error) => { const notFoundError = getNotFound(error) ?? error; notFoundError.routeId ??= currentMatch().routeId; if (notFoundError.routeId !== currentMatch().routeId) throw notFoundError; return process.env.NODE_ENV !== "production" ? renderInNonRouteComponentContext(() => createComponent(Dynamic, mergeProps({ get component() { return routeNotFoundComponent(); } }, notFoundError)), "notFoundComponent") : createComponent(Dynamic, mergeProps({ get component() { return routeNotFoundComponent(); } }, notFoundError)); }, get children() { return createComponent(Solid.Switch, { get children() { return [createComponent(Solid.Match, { get when() { return resolvedNoSsr(); }, get children() { return createComponent(ClientOnly, { get fallback() { if (process.env.NODE_ENV !== "production") return renderInNonRouteComponentContext(() => createComponent(Dynamic, { get component() { return resolvePendingComponent(); } }), "pendingComponent"); return createComponent(Dynamic, { get component() { return resolvePendingComponent(); } }); }, get children() { return createComponent(MatchContent, {}); } }); } }), createComponent(Solid.Match, { get when() { return !resolvedNoSsr(); }, get children() { return createComponent(MatchContent, {}); } })]; } }); } }); } }); } }); } }), memo(() => renderScrollRestoration?.(router, route))]; } }); }; var MatchInner = () => { const router = useRouter(); const nearestMatch = Solid.useContext(nearestMatchContext); const match = nearestMatch[1]; const routeId = nearestMatch[0]; const route = router.routesById[routeId()]; const currentMatch = () => match(); const componentKey = () => { const current = currentMatch(); const remount = route.options.remountDeps ?? router.options.defaultRemountDeps; if (!remount) return routeId(); const deps = remount({ routeId: routeId(), loaderDeps: current.loaderDeps, params: current._strictParams, search: current._strictSearch }); return JSON.stringify(deps) ?? routeId(); }; const out = () => { const Comp = route.options.component ?? router.options.defaultComponent; if (Comp) return createComponent(Comp, {}); return createComponent(Outlet, {}); }; const keyedOut = () => createComponent(Solid.Show, { get when() { return componentKey(); }, keyed: true, children: (_key) => out() }); return createComponent(Solid.Switch, { get children() { return [ createComponent(Solid.Match, { get when() { return currentMatch().status === "notFound"; }, children: (_) => renderRouteNotFound(router, route, currentMatch().error) }), createComponent(Solid.Match, { get when() { return currentMatch().status === "error"; }, children: (_) => { if (isServer ?? router.isServer) { const RouteErrorComponent = (route.options.errorComponent ?? router.options.defaultErrorComponent) || ErrorComponent; return process.env.NODE_ENV !== "production" ? renderInNonRouteComponentContext(() => createComponent(RouteErrorComponent, { get error() { return currentMatch().error; }, info: { componentStack: "" } }), "errorComponent") : createComponent(RouteErrorComponent, { get error() { return currentMatch().error; }, info: { componentStack: "" } }); } throw currentMatch().error; } }), createComponent(Solid.Match, { get when() { return currentMatch().status === "success"; }, get children() { return keyedOut(); } }) ]; } }); }; var Outlet = () => { if (process.env.NODE_ENV !== "production") { const nonRouteComponent = Solid.useContext(nonRouteComponentContext); if (nonRouteComponent) console.warn(`Warning: An <Outlet /> was rendered inside a ${nonRouteComponent}. <Outlet /> should only be rendered inside a route component.`); } const router = useRouter(); const nearestParentMatch = Solid.useContext(nearestMatchContext); const parentMatch = nearestParentMatch[1]; const routeId = nearestParentMatch[0]; const route = router.routesById[routeId()]; const childRouteId = () => { if (parentMatch()._notFound) return; const ids = router.stores.ids.get(); return ids[ids.indexOf(routeId()) + 1]; }; return createComponent(Solid.Show, { get when() { return childRouteId(); }, keyed: true, get fallback() { return memo(() => !!parentMatch()._notFound)() ? renderRouteNotFound(router, route, parentMatch().error) : void 0; }, children: (_routeKey) => { return createComponent(Solid.Show, { get when() { return routeId() === rootRouteId; }, get fallback() { return createComponent(Match, { get routeId() { return childRouteId(); } }); }, get children() { return createComponent(Solid.Suspense, { get fallback() { if (process.env.NODE_ENV !== "production") return renderInNonRouteComponentContext(() => createComponent(Dynamic, { get component() { return router.options.defaultPendingComponent; } }), "pendingComponent"); return createComponent(Dynamic, { get component() { return router.options.defaultPendingComponent; } }); }, get children() { return createComponent(Match, { get routeId() { return childRouteId(); } }); } }); } }); } }); }; //#endregion export { Match, Outlet }; //# sourceMappingURL=Match.js.map