UNPKG

@tanstack/vue-router

Version:

Modern and scalable routing for Vue applications

148 lines (147 loc) 6.78 kB
import { nonRouteComponentContext, renderInNonRouteComponentContext } from "./nonRouteComponentContext.js"; import { CatchBoundary } from "./CatchBoundary.js"; import { useRouter } from "./useRouter.js"; import { routeIdContext } from "./matchContext.js"; import { ClientOnly } from "./ClientOnly.js"; import { CatchNotFound } from "./not-found.js"; import { renderRouteNotFound } from "./renderRouteNotFound.js"; import { ScrollRestoration } from "./scroll-restoration.js"; import { isNotFound, rootRouteId } from "@tanstack/router-core"; import * as Vue from "vue"; import { isServer } from "@tanstack/router-core/isServer"; import { useStore } from "@tanstack/vue-store"; //#region src/Match.tsx var Match = Vue.defineComponent({ name: "Match", props: { routeId: { type: String, required: true } }, setup(props) { const router = useRouter(); const routeId = props.routeId; const activeMatch = useStore(router.stores.getMatchStore(routeId), (value) => value, { equal: Object.is }); Vue.provide(routeIdContext, routeId); return () => { const match = activeMatch.value; const route = match ? router.routesById[routeId] : void 0; const PendingComponent = route?.options.pendingComponent ?? router.options.defaultPendingComponent; const pendingElement = PendingComponent ? process.env.NODE_ENV !== "production" ? renderInNonRouteComponentContext(PendingComponent, void 0, "pendingComponent") : Vue.h(PendingComponent) : void 0; const routeErrorComponent = route?.options.errorComponent ?? router.options.defaultErrorComponent; const routeOnCatch = route?.options.onCatch ?? router.options.defaultOnCatch; const routeNotFoundComponent = route?.isRoot ? route.options.notFoundComponent ?? router.options.notFoundRoute?.options.component : route?.options.notFoundComponent; const ShellComponent = route?.isRoot ? route.options.shellComponent : void 0; const resolvedNoSsr = match?.ssr === false || match?.ssr === "data-only"; const renderMatchContent = () => { const matchInner = Vue.h(MatchInner); let content = resolvedNoSsr ? Vue.h(ClientOnly, { fallback: pendingElement }, { default: () => matchInner }) : matchInner; if (routeNotFoundComponent) content = Vue.h(CatchNotFound, { fallback: (error) => { error.routeId ??= routeId; if (error.routeId !== routeId) throw error; return process.env.NODE_ENV !== "production" ? renderInNonRouteComponentContext(routeNotFoundComponent, error, "notFoundComponent") : Vue.h(routeNotFoundComponent, error); }, children: content }); if (routeErrorComponent) content = CatchBoundary({ getResetKey: () => activeMatch.value, errorComponent: routeErrorComponent, onCatch: (error) => { if (isNotFound(error)) { error.routeId ??= routeId; throw error; } if (process.env.NODE_ENV !== "production") console.warn(`Warning: Error in route match: ${match?.id}`); routeOnCatch?.(error); }, children: content }); if (route?.parentRoute?.id !== rootRouteId) return content; return Vue.h(Vue.Fragment, null, [content, Vue.h(Vue.Fragment, null, [(isServer ?? router.isServer) && router.options.scrollRestoration ? Vue.h(ScrollRestoration) : null])]); }; if (!ShellComponent) return renderMatchContent(); return Vue.h(ShellComponent, null, { default: () => renderMatchContent() }); }; } }); var MatchInner = Vue.defineComponent({ name: "MatchInner", setup() { const router = useRouter(); const routeId = Vue.inject(routeIdContext); const activeMatch = useStore(router.stores.getMatchStore(routeId)); const combinedState = Vue.computed(() => { const match = activeMatch.value; if (!match) return null; const matchRouteId = match.routeId; const remountFn = router.routesById[matchRouteId].options.remountDeps ?? router.options.defaultRemountDeps; const remountDeps = remountFn ? remountFn({ routeId: matchRouteId, loaderDeps: match.loaderDeps, params: match._strictParams, search: match._strictSearch }) : void 0; return [match, remountDeps ? JSON.stringify(remountDeps) : void 0]; }); return () => { const state = combinedState.value; if (!state) return null; const [match, remountKey] = state; const route = router.routesById[match.routeId]; if (match.status === "notFound") return renderRouteNotFound(router, route, match.error); if (match.status === "error") { const RouteErrorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent; if (RouteErrorComponent) { const errorProps = { error: match.error, reset: () => { router.invalidate(); }, info: { componentStack: "" } }; return process.env.NODE_ENV !== "production" ? renderInNonRouteComponentContext(RouteErrorComponent, errorProps, "errorComponent") : Vue.h(RouteErrorComponent, errorProps); } throw match.error; } if (match.status === "pending") { const PendingComponent = route.options.pendingComponent ?? router.options.defaultPendingComponent; if (PendingComponent) return process.env.NODE_ENV !== "production" ? renderInNonRouteComponentContext(PendingComponent, void 0, "pendingComponent") : Vue.h(PendingComponent); return null; } const Comp = route.options.component ?? router.options.defaultComponent; if (Comp) return Vue.h(Comp, remountKey !== void 0 ? { key: remountKey } : void 0); return Vue.h(Outlet, remountKey !== void 0 ? { key: remountKey } : void 0); }; } }); var Outlet = Vue.defineComponent({ name: "Outlet", setup() { if (process.env.NODE_ENV !== "production") { const nonRouteComponent = Vue.inject(nonRouteComponentContext, void 0); if (nonRouteComponent) Vue.watch(nonRouteComponent, (component) => { console.warn(`Warning: An <Outlet /> was rendered inside a ${component}. <Outlet /> should only be rendered inside a route component.`); }, { immediate: true }); } const router = useRouter(); const parentRouteId = Vue.inject(routeIdContext); const parentMatch = useStore(router.stores.getMatchStore(parentRouteId)); const route = router.routesById[parentRouteId]; const childMatch = useStore(router.stores.matches, (matches) => { const child = matches[matches.findIndex((match) => match.routeId === parentRouteId) + 1]; return child ? [child.routeId, child.routeId + JSON.stringify(child._strictParams)] : void 0; }); return () => { if (parentMatch.value?._notFound) return renderRouteNotFound(router, route, parentMatch.value.error); const child = childMatch.value; if (!child) return null; return Vue.h(Match, { routeId: child[0], key: child[1] }); }; } }); //#endregion export { Match, Outlet }; //# sourceMappingURL=Match.js.map