@tanstack/solid-router
Version:
Modern and scalable routing for Solid applications
396 lines (395 loc) • 15.4 kB
JavaScript
import { CatchBoundary, ErrorComponent } from "./CatchBoundary.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 { createControlledPromise, getLocationChangeInfo, invariant, isNotFound, isRedirect, rootRouteId } from "@tanstack/router-core";
import { Dynamic, createComponent, memo, mergeProps } from "@solidjs/web";
import * as Solid from "solid-js";
import { isServer as isServer$1 } from "@tanstack/router-core/isServer";
//#region src/Match.tsx
var NearestMatchContext = nearestMatchContext;
var Match = (props) => {
const router = useRouter();
const match = Solid.createMemo(() => {
const id = props.matchId;
if (!id) return void 0;
return router.stores.activeMatchStoresById.get(id)?.state;
});
const rawMatchState = Solid.createMemo(() => {
const currentMatch = match();
if (!currentMatch) return null;
const routeId = currentMatch.routeId;
const parentRouteId = router.routesById[routeId]?.parentRoute?.id;
return {
matchId: currentMatch.id,
routeId,
ssr: currentMatch.ssr,
_displayPending: currentMatch._displayPending,
parentRouteId
};
});
const nearestMatch = {
matchId: () => rawMatchState()?.matchId,
routeId: () => rawMatchState()?.routeId,
match,
hasPending: Solid.createMemo(() => {
const currentRouteId = rawMatchState()?.routeId;
return currentRouteId ? Boolean(router.stores.pendingRouteIds.state[currentRouteId]) : false;
})
};
return createComponent(Solid.Show, {
get when() {
return rawMatchState();
},
children: (currentMatchState) => {
const route = Solid.createMemo(() => router.routesById[currentMatchState().routeId]);
const resolvePendingComponent = Solid.createMemo(() => route().options.pendingComponent ?? router.options.defaultPendingComponent);
const routeErrorComponent = Solid.createMemo(() => route().options.errorComponent ?? router.options.defaultErrorComponent);
const routeOnCatch = Solid.createMemo(() => route().options.onCatch ?? router.options.defaultOnCatch);
const routeNotFoundComponent = Solid.createMemo(() => route().isRoot ? route().options.notFoundComponent ?? router.options.notFoundRoute?.options.component : route().options.notFoundComponent);
const resolvedNoSsr = Solid.createMemo(() => currentMatchState().ssr === false || currentMatchState().ssr === "data-only");
const ResolvedSuspenseBoundary = Solid.createMemo(() => resolvedNoSsr() ? SafeFragment : Solid.Loading);
const ResolvedCatchBoundary = Solid.createMemo(() => routeErrorComponent() ? CatchBoundary : SafeFragment);
const ResolvedNotFoundBoundary = Solid.createMemo(() => routeNotFoundComponent() ? CatchNotFound : SafeFragment);
const ShellComponent = Solid.createMemo(() => route().isRoot ? route().options.shellComponent ?? SafeFragment : SafeFragment);
return createComponent(Dynamic, {
get component() {
return ShellComponent();
},
get children() {
return [createComponent(NearestMatchContext, {
value: nearestMatch,
get children() {
return createComponent(Dynamic, {
get component() {
return ResolvedSuspenseBoundary();
},
get fallback() {
return memo(() => !!((isServer$1 ?? router.isServer) && resolvedNoSsr()))() ? void 0 : createComponent(Dynamic, { get component() {
return resolvePendingComponent();
} });
},
get children() {
return createComponent(Dynamic, {
get component() {
return ResolvedCatchBoundary();
},
getResetKey: () => router.stores.loadedAt.state,
get errorComponent() {
return routeErrorComponent() || ErrorComponent;
},
onCatch: (error) => {
const notFoundError = getNotFound(error);
if (notFoundError) {
notFoundError.routeId ??= currentMatchState().routeId;
throw notFoundError;
}
if (process.env.NODE_ENV !== "production") console.warn(`Warning: Error in route match: ${currentMatchState().routeId}`);
routeOnCatch()?.(error);
},
get children() {
return createComponent(Dynamic, {
get component() {
return ResolvedNotFoundBoundary();
},
fallback: (error) => {
const notFoundError = getNotFound(error) ?? error;
notFoundError.routeId ??= currentMatchState().routeId;
if (!routeNotFoundComponent() || notFoundError.routeId && notFoundError.routeId !== currentMatchState().routeId || !notFoundError.routeId && !route().isRoot) throw notFoundError;
return 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(Solid.Show, {
get when() {
return !(isServer$1 ?? router.isServer);
},
get fallback() {
return createComponent(Dynamic, { get component() {
return resolvePendingComponent();
} });
},
get children() {
return createComponent(MatchInner, {});
}
});
}
}), createComponent(Solid.Match, {
get when() {
return !resolvedNoSsr();
},
get children() {
return createComponent(MatchInner, {});
}
})];
} });
}
});
}
});
}
});
}
}), memo(() => memo(() => currentMatchState().parentRouteId === rootRouteId)() ? [createComponent(OnRendered, {}), memo(() => memo(() => !!(router.options.scrollRestoration && (isServer$1 ?? router.isServer)))() ? createComponent(ScrollRestoration, {}) : null)] : null)];
}
});
}
});
};
var lastOnRenderedKey = /* @__PURE__ */ new WeakMap();
function OnRendered() {
const router = useRouter();
const location = Solid.createMemo(() => router.stores.resolvedLocation.state?.state.__TSR_key);
const locationState = Solid.createMemo(() => router.stores.location.state);
const resolvedLocationState = Solid.createMemo(() => router.stores.resolvedLocation.state);
Solid.createEffect(() => [
location(),
locationState(),
resolvedLocationState()
], ([location, currentLocationState, currentResolvedLocationState]) => {
if (!location) return;
if (lastOnRenderedKey.get(router) === location) return;
lastOnRenderedKey.set(router, location);
router.emit({
type: "onRendered",
...getLocationChangeInfo(currentLocationState, currentResolvedLocationState)
});
});
return null;
}
var MatchInner = () => {
const router = useRouter();
const match = Solid.useContext(nearestMatchContext).match;
const rawMatchState = Solid.createMemo(() => {
const currentMatch = match();
if (!currentMatch) return null;
const routeId = currentMatch.routeId;
const remountDeps = (router.routesById[routeId].options.remountDeps ?? router.options.defaultRemountDeps)?.({
routeId,
loaderDeps: currentMatch.loaderDeps,
params: currentMatch._strictParams,
search: currentMatch._strictSearch
});
return {
key: remountDeps ? JSON.stringify(remountDeps) : void 0,
routeId,
match: {
id: currentMatch.id,
status: currentMatch.status,
error: currentMatch.error,
_forcePending: currentMatch._forcePending ?? false,
_displayPending: currentMatch._displayPending ?? false
}
};
});
return createComponent(Solid.Show, {
get when() {
return rawMatchState();
},
children: (currentMatchState) => {
const route = Solid.createMemo(() => router.routesById[currentMatchState().routeId]);
const currentMatch = Solid.createMemo(() => currentMatchState().match);
const componentKey = Solid.createMemo(() => currentMatchState().key ?? currentMatchState().match.id);
const Comp = Solid.createMemo(() => route().options.component ?? router.options.defaultComponent);
const OutComponent = Solid.createMemo(() => {
return Comp() || Outlet;
});
const RenderOut = () => createComponent(Dynamic, { get component() {
return OutComponent();
} });
const keyedOut = () => createComponent(Solid.Show, {
get when() {
return componentKey();
},
keyed: true,
children: (_key) => createComponent(RenderOut, {})
});
return createComponent(Solid.Switch, { get children() {
return [
createComponent(Solid.Match, {
get when() {
return currentMatch()._displayPending;
},
children: (_) => {
return memo(Solid.createMemo(() => router.getMatch(currentMatch().id)?._nonReactive.displayPendingPromise));
}
}),
createComponent(Solid.Match, {
get when() {
return currentMatch()._forcePending;
},
children: (_) => {
return memo(Solid.createMemo(() => router.getMatch(currentMatch().id)?._nonReactive.minPendingPromise));
}
}),
createComponent(Solid.Match, {
get when() {
return currentMatch().status === "pending";
},
children: (_) => {
const pendingMinMs = Solid.untrack(() => route().options.pendingMinMs ?? router.options.defaultPendingMinMs);
if (pendingMinMs) {
const routerMatch = Solid.untrack(() => router.getMatch(currentMatch().id));
if (routerMatch && !routerMatch._nonReactive.minPendingPromise) {
if (!(isServer$1 ?? router.isServer)) {
const minPendingPromise = createControlledPromise();
routerMatch._nonReactive.minPendingPromise = minPendingPromise;
setTimeout(() => {
minPendingPromise.resolve();
routerMatch._nonReactive.minPendingPromise = void 0;
}, pendingMinMs);
}
}
}
const loaderResult = Solid.createMemo(async () => {
await new Promise((r) => setTimeout(r, 0));
return router.getMatch(currentMatch().id)?._nonReactive.loadPromise;
});
const FallbackComponent = Solid.untrack(() => route().options.pendingComponent ?? router.options.defaultPendingComponent);
return [FallbackComponent && pendingMinMs > 0 ? createComponent(Dynamic, { component: FallbackComponent }) : null, memo(loaderResult)];
}
}),
createComponent(Solid.Match, {
get when() {
return currentMatch().status === "notFound";
},
children: (_) => {
const matchError = Solid.untrack(() => currentMatch().error);
if (!isNotFound(matchError)) {
if (process.env.NODE_ENV !== "production") throw new Error("Invariant failed: Expected a notFound error");
invariant();
}
return createComponent(Solid.Show, {
get when() {
return currentMatchState().routeId;
},
keyed: true,
children: (_routeId) => Solid.untrack(() => renderRouteNotFound(router, route(), matchError))
});
}
}),
createComponent(Solid.Match, {
get when() {
return currentMatch().status === "redirected";
},
children: (_) => {
if (!isRedirect(Solid.untrack(() => currentMatch().error))) {
if (process.env.NODE_ENV !== "production") throw new Error("Invariant failed: Expected a redirect error");
invariant();
}
return null;
}
}),
createComponent(Solid.Match, {
get when() {
return currentMatch().status === "error";
},
children: (_) => {
const matchError = Solid.untrack(() => currentMatch().error);
if (isServer$1 ?? router.isServer) return createComponent((route().options.errorComponent ?? router.options.defaultErrorComponent) || ErrorComponent, {
error: matchError,
info: { componentStack: "" }
});
throw matchError;
}
}),
createComponent(Solid.Match, {
get when() {
return currentMatch().status === "success";
},
get children() {
return keyedOut();
}
})
];
} });
}
});
};
var Outlet = () => {
const router = useRouter();
const nearestParentMatch = Solid.useContext(nearestMatchContext);
const parentMatch = nearestParentMatch.match;
const routeId = nearestParentMatch.routeId;
const route = Solid.createMemo(() => routeId() ? router.routesById[routeId()] : void 0);
const parentGlobalNotFound = Solid.createMemo(() => parentMatch()?.globalNotFound ?? false);
const childMatchId = Solid.createMemo(() => {
const currentRouteId = routeId();
return currentRouteId ? router.stores.childMatchIdByRouteId.state[currentRouteId] : void 0;
});
const childRouteId = Solid.createMemo(() => {
const id = childMatchId();
if (!id) return void 0;
return router.stores.activeMatchStoresById.get(id)?.state.routeId;
});
const childRoute = Solid.createMemo(() => {
const id = childRouteId();
return id ? router.routesById[id] : void 0;
});
const childPendingComponent = Solid.createMemo(() => childRoute()?.options.pendingComponent ?? router.options.defaultPendingComponent);
const childMatchStatus = Solid.createMemo(() => {
const id = childMatchId();
if (!id) return void 0;
return router.stores.activeMatchStoresById.get(id)?.state.status;
});
const shouldShowNotFound = () => childMatchStatus() !== "redirected" && parentGlobalNotFound();
return createComponent(Solid.Show, {
get when() {
return memo(() => !!!shouldShowNotFound())() && childMatchId();
},
get fallback() {
return createComponent(Solid.Show, {
get when() {
return memo(() => !!shouldShowNotFound())() && route();
},
children: (resolvedRoute) => Solid.untrack(() => renderRouteNotFound(router, resolvedRoute(), void 0))
});
},
children: (childMatchIdAccessor) => {
const currentMatchId = Solid.createMemo(() => childMatchIdAccessor());
return createComponent(Solid.Show, {
get when() {
return routeId() === rootRouteId;
},
get fallback() {
return createComponent(Match, { get matchId() {
return currentMatchId();
} });
},
get children() {
return createComponent(Solid.Show, {
get when() {
return childRouteId();
},
keyed: true,
children: (_routeId) => createComponent(Solid.Loading, {
get fallback() {
return memo(() => !!childPendingComponent())() ? createComponent(Dynamic, { get component() {
return childPendingComponent();
} }) : null;
},
get children() {
return createComponent(Match, { get matchId() {
return currentMatchId();
} });
}
})
});
}
});
}
});
};
//#endregion
export { Match, Outlet };
//# sourceMappingURL=Match.js.map