@tanstack/solid-router
Version:
Modern and scalable routing for Solid applications
263 lines (262 loc) • 10.1 kB
JavaScript
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