#16 issue/router #18

Merged
SethTrowbridge merged 6 commits from issue/router into master 2023-04-18 19:39:56 -04:00
Showing only changes of commit 64a4a82ac8 - Show all commits

View File

@ -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]}>