@tanstack/solid-router
Version:
Modern and scalable routing for Solid applications
126 lines • 5.1 kB
JSX
import * as Solid from 'solid-js';
import { replaceEqualDeep, rootRouteId } from '@tanstack/router-core';
import { isServer } from '@tanstack/router-core/isServer';
import { CatchBoundary, ErrorComponent } from './CatchBoundary';
import { useRouter } from './useRouter';
import { Transitioner } from './Transitioner';
import { nearestMatchContext } from './matchContext';
import { SafeFragment } from './SafeFragment';
import { Match } from './Match';
const NearestMatchContext = nearestMatchContext;
export function Matches() {
const router = useRouter();
// When disableGlobalCatchBoundary is true, we must NOT wrap with Solid.Loading
// because Solid.Loading transforms STATUS_ERROR into STATUS_PENDING, which
// prevents errors from propagating to an external Errored boundary.
const ResolvedSuspense = router.options.disableGlobalCatchBoundary ||
(isServer ?? router.isServer) ||
(typeof document !== 'undefined' && router.ssr)
? SafeFragment
: Solid.Loading;
const rootRoute = () => router.routesById[rootRouteId];
const PendingComponent = rootRoute().options.pendingComponent ??
router.options.defaultPendingComponent;
const OptionalWrapper = router.options.InnerWrap || SafeFragment;
return (<OptionalWrapper>
<ResolvedSuspense fallback={PendingComponent ? <PendingComponent /> : null}>
<Transitioner />
<MatchesInner />
</ResolvedSuspense>
</OptionalWrapper>);
}
function MatchesInner() {
const router = useRouter();
const matchId = () => router.stores.firstMatchId.state;
const routeId = () => (matchId() ? rootRouteId : undefined);
const match = () => routeId()
? router.stores.getMatchStoreByRouteId(rootRouteId).state
: undefined;
const hasPendingMatch = () => routeId()
? Boolean(router.stores.pendingRouteIds.state[rootRouteId])
: false;
const resetKey = () => router.stores.loadedAt.state;
const nearestMatch = {
matchId,
routeId,
match,
hasPending: hasPendingMatch,
};
const matchContent = () => (<Solid.Show when={matchId()}>
<Match matchId={matchId()}/>
</Solid.Show>);
if (router.options.disableGlobalCatchBoundary) {
// When disableGlobalCatchBoundary is true, render without any internal
// error boundary so errors bubble up freely to an external Errored boundary.
return (<NearestMatchContext value={nearestMatch}>
{matchContent()}
</NearestMatchContext>);
}
return (<NearestMatchContext value={nearestMatch}>
<CatchBoundary getResetKey={() => resetKey()} errorComponent={ErrorComponent} onCatch={process.env.NODE_ENV !== 'production'
? (error) => {
console.warn(`Warning: The following error wasn't caught by any route! At the very least, consider setting an 'errorComponent' in your RootRoute!`);
console.warn(`Warning: ${error.message || error.toString()}`);
}
: undefined}>
{matchContent()}
</CatchBoundary>
</NearestMatchContext>);
}
export function useMatchRoute() {
const router = useRouter();
return (opts) => {
return Solid.createMemo(() => {
const { pending, caseSensitive, fuzzy, includeSearch, ...rest } = opts;
router.stores.matchRouteReactivity.state;
return router.matchRoute(rest, {
pending,
caseSensitive,
fuzzy,
includeSearch,
});
});
};
}
export function MatchRoute(props) {
const matchRoute = useMatchRoute();
const params = matchRoute(props);
const renderedChild = Solid.createMemo(() => {
const matchedParams = params();
const child = props.children;
if (typeof child === 'function') {
return child(matchedParams);
}
return matchedParams ? child : null;
});
return <>{renderedChild()}</>;
}
export function useMatches(opts) {
const router = useRouter();
return Solid.createMemo((prev) => {
const matches = router.stores.activeMatchesSnapshot.state;
const res = opts?.select ? opts.select(matches) : matches;
if (prev === undefined)
return res;
return replaceEqualDeep(prev, res);
});
}
export function useParentMatches(opts) {
const contextMatchId = Solid.useContext(nearestMatchContext).matchId;
return useMatches({
select: (matches) => {
matches = matches.slice(0, matches.findIndex((d) => d.id === contextMatchId()));
return opts?.select ? opts.select(matches) : matches;
},
});
}
export function useChildMatches(opts) {
const contextMatchId = Solid.useContext(nearestMatchContext).matchId;
return useMatches({
select: (matches) => {
matches = matches.slice(matches.findIndex((d) => d.id === contextMatchId()) + 1);
return opts?.select ? opts.select(matches) : matches;
},
});
}
//# sourceMappingURL=Matches.jsx.map