404 fallback routes
This commit is contained in:
parent
fadb797c55
commit
11359a906f
24
app.tsx
24
app.tsx
@ -2,8 +2,8 @@ import {Route, useRoute} from ">able/iso-router.tsx";
|
|||||||
|
|
||||||
const Tracer =()=>
|
const Tracer =()=>
|
||||||
{
|
{
|
||||||
const {nestedDepth, pathIndex} = useRoute();
|
const {nestedDepth, pathIndex, blocked} = useRoute();
|
||||||
return <div>Depth: {nestedDepth}, Index:{pathIndex}</div>
|
return <div>Depth: {nestedDepth}, Index:{pathIndex}, Match:{blocked.value}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ()=><div>
|
export default ()=><div>
|
||||||
@ -11,23 +11,17 @@ export default ()=><div>
|
|||||||
<nav class="flex gap-10 p-6">
|
<nav class="flex gap-10 p-6">
|
||||||
<a href="/">Home</a>
|
<a href="/">Home</a>
|
||||||
<a href="/about">About</a>
|
<a href="/about">About</a>
|
||||||
|
<a href="/404">404</a>
|
||||||
</nav>
|
</nav>
|
||||||
<Route path={[]}>
|
<Route path={[]}><p>home page!</p></Route>
|
||||||
|
|
||||||
<p>home page! <Tracer/></p>
|
|
||||||
</Route>
|
|
||||||
<Route path={["about"]}>
|
<Route path={["about"]}>
|
||||||
|
|
||||||
<nav class="flex gap-10 p-6">
|
<nav class="flex gap-10 p-6">
|
||||||
<a href="/about/more">more</a>
|
<a href="/about/more">more</a>
|
||||||
|
<a href="/about/404">more 404</a>
|
||||||
</nav>
|
</nav>
|
||||||
<Route path={[]}>
|
<Route path={[]}><p>About page!</p></Route>
|
||||||
|
<Route path={["more"]}><p>more!</p></Route>
|
||||||
<p>About page! <Tracer/></p>
|
<Route><span>couldnt find it</span></Route>
|
||||||
</Route>
|
|
||||||
<Route path={["more"]}>
|
|
||||||
|
|
||||||
<p>more!<Tracer/></p>
|
|
||||||
</Route>
|
|
||||||
</Route>
|
</Route>
|
||||||
|
<Route><p>404 :(</p></Route>
|
||||||
</div>;
|
</div>;
|
@ -22,10 +22,21 @@ export const Meta =(props:MetaFields)=> { useMeta(props); return null; }
|
|||||||
|
|
||||||
|
|
||||||
//////// Router
|
//////// Router
|
||||||
|
type RouteContextData = {
|
||||||
|
/** Current nested depth of the router */ nestedDepth:number,
|
||||||
|
/** Index into the page path to start matching routes */ pathIndex:number,
|
||||||
|
/** Collection of keys from matched routes ("page/:key/") */ keys: Record<string, string>,
|
||||||
|
blocked: Signal.Signal<string | false>
|
||||||
|
}
|
||||||
|
const context = React.createContext({nestedDepth:0, pathIndex:0, keys:{}, blocked:Signal.signal(false as false|string)} as RouteContextData);
|
||||||
//// Create Signals
|
//// Create Signals
|
||||||
export const pageURL = Signal.signal(new URL(globalThis?.location.href || ""));
|
export const pageURL = Signal.signal(new URL(globalThis?.location.href || ""));
|
||||||
export const pagePath = Signal.signal([] as string[]);
|
export const pagePath = Signal.signal([] as string[]);
|
||||||
Signal.effect(()=> pagePath.value = pageURL.value.pathname.split("/").filter(part=>part!=""));
|
Signal.effect(()=>{
|
||||||
|
//@ts-ignore 1337 hax
|
||||||
|
if(context){context.__.blocked.value = false;}
|
||||||
|
pagePath.value = pageURL.value.pathname.split("/").filter(part=>part!="");
|
||||||
|
});
|
||||||
//// Add handlers
|
//// Add handlers
|
||||||
globalThis.addEventListener("click", e=>
|
globalThis.addEventListener("click", e=>
|
||||||
{
|
{
|
||||||
@ -44,14 +55,7 @@ globalThis.addEventListener("click", e=>
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
globalThis.addEventListener("popstate", _=> pageURL.value = new URL(globalThis.location.href) );
|
globalThis.addEventListener("popstate", _=> pageURL.value = new URL(globalThis.location.href) );
|
||||||
/// Rendering context
|
//// Rendering context
|
||||||
type RouteContextData = {
|
|
||||||
/** Current nested depth of the router */ nestedDepth:number,
|
|
||||||
/** Index into the page path to start matching routes */ pathIndex:number,
|
|
||||||
/** Collection of keys from matched routes ("page/:key/") */ keys: Record<string, string>,
|
|
||||||
blocked: Signal.Signal<string | false>
|
|
||||||
}
|
|
||||||
const context = React.createContext({nestedDepth:0, pathIndex:0, keys:{}, blocked:Signal.signal(false as false|string)} as RouteContextData);
|
|
||||||
type PathFields = {pathAfter:string[], pathBefore:[], compare:typeof compare}
|
type PathFields = {pathAfter:string[], pathBefore:[], compare:typeof compare}
|
||||||
const compare =(pathA:string[], pathB:string[])=>
|
const compare =(pathA:string[], pathB:string[])=>
|
||||||
{
|
{
|
||||||
@ -88,21 +92,21 @@ export const useRoute =()=> {
|
|||||||
const pathBefore = pathFull.slice(0, Math.max(0, routeContext.pathIndex-1));
|
const pathBefore = pathFull.slice(0, Math.max(0, routeContext.pathIndex-1));
|
||||||
return { ...routeContext, pathAfter, pathBefore, compare } as PathFields&RouteContextData;
|
return { ...routeContext, pathAfter, pathBefore, compare } as PathFields&RouteContextData;
|
||||||
}
|
}
|
||||||
export const Route =(props:{path:string[], children:React.ReactNode|React.ReactNode[]}):React.JSX.Element|null=>
|
export const Route =(props:{path?:string[], children:React.ReactNode|React.ReactNode[]}):React.JSX.Element|null=>
|
||||||
{
|
{
|
||||||
const {nestedDepth, pathIndex, pathAfter, compare, keys} = useRoute();
|
const {nestedDepth, pathIndex, pathAfter, compare, keys, blocked} = useRoute();
|
||||||
|
|
||||||
|
if(blocked.peek()){ return null; }
|
||||||
|
|
||||||
|
const passOn:RouteContextData = { nestedDepth:nestedDepth+1, pathIndex, keys, blocked:Signal.signal(false) }
|
||||||
|
if(props.path)
|
||||||
|
{
|
||||||
const check = compare(props.path, pathAfter);
|
const check = compare(props.path, pathAfter);
|
||||||
if (check)
|
if (!check){ return null; }
|
||||||
{
|
|
||||||
return <context.Provider value={{
|
blocked.value = "/"+props.path.join("/");
|
||||||
nestedDepth:nestedDepth+1,
|
passOn.pathIndex += check.comparisonSize;
|
||||||
pathIndex:pathIndex+check.comparisonSize,
|
passOn.keys = {...keys, ...check.keys};
|
||||||
keys: {...keys, ...check.keys},
|
|
||||||
blocked:Signal.signal(false)
|
|
||||||
}}>{props.children}</context.Provider>;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return <context.Provider value={passOn}>{props.children}</context.Provider>;
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user