Comparing version 0.6.1 to 0.7.0
@@ -1,2 +0,2 @@ | ||
var a=class{constructor(e,{replace:n,search:s,state:r}={}){this.params=[];var t,i;if(typeof e=="string"){e.startsWith("/")||(e=`/${e}`),s||(this._h=e);let[l,v]=e.split("?");this.path=l.split("/").filter(Boolean),(t=this.search)!=null||(this.search=Object.fromEntries(new URLSearchParams(v).entries()))}else this.path=e;s!==void 0&&(this.search=s),r!==void 0&&(this.state=r),n!==void 0&&(this.replace=n),(i=this.search)!=null||(this.search={})}get href(){if(!this._h){let e=new URLSearchParams(this.search).toString(),n=`/${this.path.join("/")}`;this._h=`${n}${e?`?${e}`:""}`}return this._h}get go(){return(e,n={})=>{var s;return new a(e,{search:n.search,state:n.state,replace:(s=n.replace)!=null?s:this.replace})}}};var m=10,T=async(f,e,n)=>{var t;let s=e,r=new Array;for(;s instanceof a&&r.length<=m;){e=s,r.push(e);let i=(t=await O(f,e))!=null?t:[n];for(let l of i)if(s=await l(e,s instanceof a?void 0:s),s instanceof a)break}if(r.length>m)throw new Error(`More than ${m} redirects: ${r.map(i=>i.href).join(" -> ")}`);return{value:s,opts:e}},O=async(f,e)=>{let{path:n,params:s}=e,r=[],t=f;for(let i=0;i<n.length;i++){let l=n[i];if(!t||typeof t=="function")return null;let v=await g(t,e);if(v)return[()=>v];if(typeof t["?"]=="function"){let d=await t["?"](e);if(d instanceof a)return[()=>d]}let p=t[""];typeof p=="function"&&r.unshift(p),l in t?t=t[l]:"*"in t?(s.push(l),t=t["*"]):typeof p=="object"&&(t=p,i--)}do{if(typeof t=="function")return r.unshift(t),r;let i=await g(t,e);if(i)return[()=>i]}while(t=t[""]);return null},g=async(f,e)=>{if(typeof f["?"]=="function"){let n=await f["?"](e);if(n instanceof a)return n}};var k=({routes:f={},notFound:e=({go:r})=>r([]),noClick:n=!1,onResolve:s}={})=>{let r,t=new Set(s?[s]:[]),i,l={routes:f,get resolution(){return i},init(){window.addEventListener("popstate",p),n||document.addEventListener("click",v),p({state:history.state})},dispose(){window.removeEventListener("popstate",p),document.removeEventListener("click",v)},async go(o,c){await this.resolution;let u=o instanceof a?o:new a(o,c),h=await d(T(l.routes,u,e));y(h.opts)},onResolve(o){return t.add(o),r&&o(r),()=>t.delete(o)}},v=o=>{var u;let c=w(o.target)?o.target:(u=o.composedPath)==null?void 0:u.call(o).find(w);c&&c.origin===location.origin&&(l.go(c.pathname,{replace:"replace"in c.dataset}),o.preventDefault())},p=async({state:o})=>{let{pathname:c,search:u}=window.location,h=new a(`${c}${u}`,{state:o}),{opts:R}=await d(T(l.routes,h,e));R!==h&&y(new a(R.path,{replace:!0,search:R.search,state:R.state}))},d=async o=>(i=o,r=await o,t.forEach(c=>c(r)),o),y=({state:o,replace:c,href:u})=>{let h=window.history;c?h.replaceState(o,"",u):h.pushState(o,"",u)};return l},w=f=>f instanceof HTMLAnchorElement;export{a as NavOpts,k as createRouter,T as resolve}; | ||
var N=Object.defineProperty;var m=Object.getOwnPropertySymbols;var x=Object.prototype.hasOwnProperty,L=Object.prototype.propertyIsEnumerable;var w=(n,e,t)=>e in n?N(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t,P=(n,e)=>{for(var t in e||={})x.call(e,t)&&w(n,t,e[t]);if(m)for(var t of m(e))L.call(e,t)&&w(n,t,e[t]);return n};var l=class{constructor(e,t={}){this.params=[];var r;if(typeof e=="string"){e.startsWith("/")||(e=`/${e}`),t.search||(this._h=e);let[,a,,o,,i]=e.match(/([^?#]+)(\?([^#]+))?(#(.+))?/);this.path=a.split("/").filter(Boolean),o&&(this.search=Object.fromEntries(new URLSearchParams(o).entries())),i&&(this.hash=i)}else this.path=e;t.hash!==void 0&&(this.hash=t.hash),t.pop!==void 0&&(this.pop=t.pop),t.search!==void 0&&(this.search=t.search),t.state!==void 0&&(this.state=t.state),t.replace!==void 0&&(this.replace=t.replace),(r=this.search)!=null||(this.search={})}get href(){if(!this._h){let e=new URLSearchParams(this.search).toString(),t=`/${this.path.join("/")}`;this._h=`${t}${e?`?${e}`:""}`}return this._h}get go(){return(e,t={})=>{var r;return new l(e,{search:t.search,state:t.state,replace:(r=t.replace)!=null?r:this.replace})}}};var g=10,T=async(n,e,t)=>{var o;let r=e,a=new Array;for(;r instanceof l&&a.length<=g;){e=r,a.push(e);let i=(o=await M(n,e))!=null?o:[t];for(let h of i)if(r=await h(e,r instanceof l?void 0:r),r instanceof l)break}if(a.length>g)throw new Error(`More than ${g} redirects: ${a.map(i=>i.href).join(" -> ")}`);return{value:r,opts:e}},M=async(n,e)=>{let{path:t,params:r}=e,a=[],o=n;for(let i=0;i<t.length;i++){let h=t[i];if(!o||typeof o=="function")return null;let v=await O(o,e);if(v)return[()=>v];if(typeof o["?"]=="function"){let d=await o["?"](e);if(d instanceof l)return[()=>d]}let p=o[""];typeof p=="function"&&a.unshift(p),h in o?o=o[h]:"*"in o?(r.push(h),o=o["*"]):typeof p=="object"&&(o=p,i--)}do{if(typeof o=="function")return a.unshift(o),a;let i=await O(o,e);if(i)return[()=>i]}while(o=o[""]);return null},O=async(n,e)=>{if(typeof n["?"]=="function"){let t=await n["?"](e);if(t instanceof l)return t}};var D=({routes:n={},notFound:e=({go:a})=>a([]),noClick:t=!1,onResolve:r}={})=>{let a,o=new Set(r?[r]:[]),i,h={routes:n,get resolution(){return i},init(){window.addEventListener("popstate",p),t||document.addEventListener("click",v),p({state:history.state})},dispose(){window.removeEventListener("popstate",p),document.removeEventListener("click",v)},async go(s,c){await this.resolution;let f=s instanceof l?s:new l(s,c),u=await d(T(h.routes,f,e));y(u.opts)},onResolve(s){return o.add(s),a&&s(a),()=>o.delete(s)}},v=s=>{var f;let c=E(s.target)?s.target:(f=s.composedPath)==null?void 0:f.call(s).find(E);c&&c.origin===location.origin&&(h.go(c.pathname,{replace:"replace"in c.dataset}),s.preventDefault())},p=async s=>{let{href:c,origin:f}=window.location,u=new l(c.substring(f.length),P({state:s.state},s instanceof PopStateEvent&&{pop:!0})),{opts:R}=await d(T(h.routes,u,e));R!==u&&y(new l(R.path,{replace:!0,search:R.search,state:R.state}))},d=async s=>(i=s,a=await s,o.forEach(c=>c(a)),s),y=({state:s,replace:c,href:f})=>{let u=window.history;c?u.replaceState(s,"",f):u.pushState(s,"",f)};return h},E=n=>n instanceof HTMLAnchorElement;export{l as NavOpts,D as createRouter,T as resolve}; | ||
//# sourceMappingURL=index.js.map |
@@ -1,17 +0,26 @@ | ||
export declare type PathOrHref = string | string[]; | ||
export type PathOrHref = string | string[]; | ||
export interface NavMeta { | ||
/** The search query object. */ | ||
search?: Record<string, string>; | ||
/** The state to push. */ | ||
state?: any; | ||
/** The location hash. */ | ||
hash?: string; | ||
/** Whethe the history state shall be replaced. */ | ||
replace?: boolean; | ||
/** Whether the resolution was triggered by a popstate event. */ | ||
pop?: boolean; | ||
} | ||
export declare class NavOpts { | ||
readonly state: any; | ||
export declare class NavOpts implements NavMeta { | ||
readonly state?: any; | ||
readonly params: string[]; | ||
readonly hash?: string; | ||
readonly replace?: boolean; | ||
readonly path: string[]; | ||
readonly search?: Record<string, string>; | ||
readonly search: Record<string, string>; | ||
readonly pop?: boolean; | ||
private _h?; | ||
constructor(pathOrHref: PathOrHref, { replace, search, state }?: NavMeta); | ||
constructor(pathOrHref: PathOrHref, m?: NavMeta); | ||
get href(): string; | ||
get go(): (path: PathOrHref, opts?: NavMeta) => NavOpts; | ||
} |
import { NavOpts } from "./nav-opts"; | ||
import { Resolve, Routes } from "./routes"; | ||
export interface Resolved<T> { | ||
/** The resolved value of the route. */ | ||
value: T; | ||
/** The final navigation options after all redirecting. */ | ||
opts: NavOpts; | ||
} | ||
export declare type RouteResolver<T> = (routes: Routes<T>, opts: NavOpts, notFound: Resolve<T>) => Promise<Resolved<T>>; | ||
export type RouteResolver<T> = (routes: Routes<T>, opts: NavOpts, notFound: Resolve<T>) => Promise<Resolved<T>>; | ||
export declare const resolve: <T>(routes: Routes<T>, opts: NavOpts, notFound: Resolve<T>) => Promise<Resolved<T>>; |
import { NavMeta, PathOrHref } from "./nav-opts"; | ||
import { Resolved } from "./route-resolver"; | ||
import { Resolve, Routes } from "./routes"; | ||
export declare type OnResolveListener<T> = (resolved: Resolved<T>) => void; | ||
export type OnResolveListener<T> = (resolved: Resolved<T>) => void; | ||
export interface Router<T = any> { | ||
@@ -6,0 +6,0 @@ /** |
import { NavOpts } from "./nav-opts"; | ||
export declare type Resolve<T = any> = (navOpts: NavOpts, next?: T) => T | NavOpts | Promise<T | NavOpts>; | ||
export type Resolve<T = any> = (navOpts: NavOpts, next?: T) => T | NavOpts | Promise<T | NavOpts>; | ||
export interface Routes<T = any> { | ||
[k: string]: Routes<T> | Resolve<T>; | ||
} |
{ | ||
"name": "esroute", | ||
"version": "0.6.1", | ||
"version": "0.7.0", | ||
"description": "A small efficient framework-agnostic client-side routing library, written in TypeScript.", | ||
@@ -22,5 +22,5 @@ "types": "dist/index.d.ts", | ||
"devDependencies": { | ||
"esbuild": "^0.14.34", | ||
"typescript": "^4.8.3" | ||
"esbuild": "^0.17.8", | ||
"typescript": "^4.9.5" | ||
} | ||
} |
# esroute | ||
A small efficient framework-agnostic client-side routing library, written in TypeScript. | ||
A small efficient framework-agnostic client-side routing library, written in TypeScript.\ | ||
[![](https://flat.badgen.net/bundlephobia/minzip/esroute)](https://bundlephobia.com/result?p=esroute) | ||
It is currently under development and API might slightly change. | ||
[Demo](https://stackblitz.com/edit/esroute) | ||
## Features | ||
@@ -77,3 +80,3 @@ | ||
The route resolution is done by traversing the route spec tree and this algorithm is based on simple string comparisons (no regex matching). | ||
The route resolution is done by traversing the route spec that is used to configure the app routes (no preprocessing required). The algorithm is based on simple string comparisons (no regex matching). | ||
@@ -80,0 +83,0 @@ #### 🛡 Route guards |
Sorry, the diff of this file is not supported yet
28930
121
204