#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 RouteParams = Record<string, string>;
|
||||
type RouteState = {URL:URL, Path:string[]};
|
||||
type RouteContext = [Route:RouteState, Update:(inPath?:RoutePath, inParams?:RouteParams)=>void];
|
||||
type RouteParams = Record<string, string|number|boolean>;
|
||||
type RouteState = {URL:URL, Path:RoutePath, Params:RouteParams, Anchor:string};
|
||||
type RouteContext = [Route:RouteState, Update:(inPath?:RoutePath, inParams?:RouteParams, inAnchor?:string)=>void];
|
||||
type RouteProps = {children:typeof React.Children, url?:URL };
|
||||
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)
|
||||
{
|
||||
const url = props.url || new URL(document.location.href);
|
||||
const path = Router.Path(url);
|
||||
const [routeGet, routeSet] = React.useState(Router.Parse(props.url || new URL(document.location.href)));
|
||||
const [dirtyGet, dirtySet] = React.useState(false);
|
||||
|
||||
const [routeGet, routeSet] = React.useState({URL:url, Path:path} as RouteState);
|
||||
//const routeUpdate:RouteContext[1] =(inURL:URL)=>routeSet({URL:inURL, Path:Router.Path(inURL)});
|
||||
const routeUpdate:RouteContext[1] =(inPath?:RoutePath, inParams?:RouteParams)=>
|
||||
const routeUpdate:RouteContext[1] =(inPath, inParams, inAnchor)=>
|
||||
{
|
||||
const clone = new URL(routeGet.URL.href);
|
||||
inPath && (clone.pathname = `/${inPath.join("/")}`);
|
||||
inParams && (clone.search = new URLSearchParams(inParams).toString());
|
||||
const clone = new URL(routeGet.URL);
|
||||
inPath && (clone.pathname = inPath.join("/"));
|
||||
inParams && (clone.search = new URLSearchParams(inParams as Record<string, string>).toString());
|
||||
routeSet({
|
||||
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(()=>{
|
||||
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]}>
|
||||
|
Loading…
Reference in New Issue
Block a user