#16 issue/router #18
44
lib/iso.tsx
44
lib/iso.tsx
@ -34,37 +34,47 @@ export const Metas =(props:{concatListed?:boolean; dropUnlisted?:boolean}&MetasI
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RoutePath = Array<string>;
|
type RoutePath = Array<string>;
|
||||||
type RouteParams = Record<string, string>;
|
type RouteParams = Record<string, string|number|boolean>;
|
||||||
type RouteState = {URL:URL, Path:string[]};
|
type RouteState = {URL:URL, Path:RoutePath, Params:RouteParams, Anchor:string};
|
||||||
type RouteContext = [Route:RouteState, Update:(inPath?:RoutePath, inParams?:RouteParams)=>void];
|
type RouteContext = [Route:RouteState, Update:(inPath?:RoutePath, inParams?:RouteParams, inAnchor?:string)=>void];
|
||||||
type RouteProps = {children:typeof React.Children, url?:URL };
|
type RouteProps = {children:typeof React.Children, url?:URL };
|
||||||
export const Router = {
|
export const Router = {
|
||||||
Path(url:URL)
|
Parse(url:URL):RouteState
|
||||||
{
|
{
|
||||||
return url.pathname.substring(1, url.pathname.endsWith("/") ? url.pathname.length-1 : url.pathname.length).split("/");
|
const Path = url.pathname.substring(1, url.pathname.endsWith("/") ? url.pathname.length-1 : url.pathname.length).split("/");
|
||||||
|
const Params:RouteParams = {};
|
||||||
|
new URLSearchParams(url.search).forEach((k, v)=> Params[k] = v);
|
||||||
|
const Anchor = url.hash.substring(1);
|
||||||
|
return {URL:url, Path, Params, Anchor} as RouteState;
|
||||||
},
|
},
|
||||||
Context:React.createContext([{URL:new URL("https://original.route/"), Path:[]}, ()=>{}] as RouteContext),
|
Context:React.createContext([{URL:new URL("https://original.route/"), Path:[], Params:{}, Anchor:""}, ()=>{}] as RouteContext),
|
||||||
Provider(props:RouteProps)
|
Provider(props:RouteProps)
|
||||||
{
|
{
|
||||||
const url = props.url || new URL(document.location.href);
|
const [routeGet, routeSet] = React.useState(Router.Parse(props.url || new URL(document.location.href)));
|
||||||
const path = Router.Path(url);
|
const [dirtyGet, dirtySet] = React.useState(false);
|
||||||
|
|
||||||
const [routeGet, routeSet] = React.useState({URL:url, Path:path} as RouteState);
|
const routeUpdate:RouteContext[1] =(inPath, inParams, inAnchor)=>
|
||||||
//const routeUpdate:RouteContext[1] =(inURL:URL)=>routeSet({URL:inURL, Path:Router.Path(inURL)});
|
|
||||||
const routeUpdate:RouteContext[1] =(inPath?:RoutePath, inParams?:RouteParams)=>
|
|
||||||
{
|
{
|
||||||
const clone = new URL(routeGet.URL.href);
|
const clone = new URL(routeGet.URL);
|
||||||
inPath && (clone.pathname = `/${inPath.join("/")}`);
|
inPath && (clone.pathname = inPath.join("/"));
|
||||||
inParams && (clone.search = new URLSearchParams(inParams).toString());
|
inParams && (clone.search = new URLSearchParams(inParams as Record<string, string>).toString());
|
||||||
routeSet({
|
routeSet({
|
||||||
URL:clone,
|
URL:clone,
|
||||||
Path: inPath ? inPath : routeGet.Path
|
Path: inPath || routeGet.Path,
|
||||||
|
Params: inParams || routeGet.Params,
|
||||||
|
Anchor: inAnchor || routeGet.Anchor
|
||||||
});
|
});
|
||||||
|
dirtySet(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
React.useEffect(()=>history.pushState({Path:routeGet.Path, Params:routeGet.URL.search}, "", routeGet.URL), [routeGet.URL.href]);
|
// when the state changes, update the page url
|
||||||
React.useEffect(()=>{
|
React.useEffect(()=>{
|
||||||
window.addEventListener("popstate", ()=>routeUpdate());
|
history.pushState({...routeGet, URL:undefined}, "", routeGet.URL);
|
||||||
|
}, [routeGet.URL.href]);
|
||||||
|
|
||||||
|
React.useEffect(()=>{
|
||||||
|
// when the history changes, update the state
|
||||||
|
window.addEventListener("popstate", ({state})=>{routeUpdate(state.Path, state.Params, state.Anchor)});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return <Router.Context.Provider value={[routeGet, routeUpdate]}>
|
return <Router.Context.Provider value={[routeGet, routeUpdate]}>
|
||||||
|
Loading…
Reference in New Issue
Block a user