@typeroute/router 0.7.0 โ†’ 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +62 -10
  2. package/dist/index.js +1 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -9,25 +9,19 @@
9
9
  <div align="center">
10
10
  <a href="https://www.npmjs.com/package/@typeroute/router">
11
11
  <img
12
- src="https://img.shields.io/npm/v/@typeroute/router?style=flat-square&color=0B0D0F&labelColor=0B0D0F"
12
+ src="https://img.shields.io/npm/v/%40typeroute%2Frouter?style=flat-square&color=0B0D0F&labelColor=0B0D0F"
13
13
  alt="npm version"
14
14
  />
15
15
  </a>
16
16
  <a href="https://www.npmjs.com/package/@typeroute/router">
17
17
  <img
18
- src="https://img.badgesize.io/https://unpkg.com/waymark/dist/index.js?compression=gzip&label=gzip&style=flat-square&color=0B0D0F&labelColor=0B0D0F"
18
+ src="https://img.badgesize.io/https://cdn.jsdelivr.net/npm/@typeroute/router/dist/index.js?compression=gzip&label=gzip&style=flat-square&color=0B0D0F&labelColor=0B0D0F"
19
19
  alt="gzip size"
20
20
  />
21
21
  </a>
22
- <a href="https://www.npmjs.com/package/@typeroute/router">
23
- <img
24
- src="https://img.shields.io/npm/dm/@typeroute/router?style=flat-square&color=0B0D0F&labelColor=0B0D0F"
25
- alt="downloads"
26
- />
27
- </a>
28
22
  <a href="https://github.com/strblr/typeroute/blob/master/LICENSE">
29
23
  <img
30
- src="https://img.shields.io/npm/l/@typeroute/router?style=flat-square&color=0B0D0F&labelColor=0B0D0F"
24
+ src="https://img.shields.io/npm/l/%40typeroute%2Frouter?style=flat-square&color=0B0D0F&labelColor=0B0D0F"
31
25
  alt="license"
32
26
  />
33
27
  </a>
@@ -40,7 +34,7 @@
40
34
  </div>
41
35
 
42
36
  <p align="center">
43
- ๐Ÿ“– <a href="https://typeroute.com">Documentation</a> ยท ๐ŸŽฎ <a href="https://stackblitz.com/edit/typeroute-demo?file=src%2Fapp.tsx">Live playground</a>
37
+ ๐Ÿ“– <a href="https://typeroute.com">typeroute.com</a> ยท ๐ŸŽฎ <a href="https://stackblitz.com/edit/typeroute-demo?file=src%2Fapp.tsx">Live playground</a>
44
38
  </p>
45
39
 
46
40
  ---
@@ -141,6 +135,7 @@ If you believe there's a mistake in the comparison table, please [open an issue]
141
135
  - [Global link configuration](#global-link-configuration)
142
136
  - [History middleware](#history-middleware)
143
137
  - [View transitions](#view-transitions)
138
+ - [Dynamic page titles](#dynamic-page-titles)
144
139
  - [API reference](#api-reference)
145
140
  - [Router class](#router-class)
146
141
  - [Route class](#route-class)
@@ -1458,6 +1453,63 @@ Add CSS to control the transition:
1458
1453
 
1459
1454
  For more advanced techniques, see the [MDN documentation on View Transitions](https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API).
1460
1455
 
1456
+ ## Dynamic page titles
1457
+
1458
+ Use [route handles](#route-handles) to define page titles and update the browser's document title dynamically as users navigate. First, attach a `title` handle to each route:
1459
+
1460
+ ```tsx
1461
+ const layout = route("/").handle({ title: "App" }).component(Layout);
1462
+ const home = layout.route("/").handle({ title: "Home" }).component(HomePage);
1463
+ const settings = layout
1464
+ .route("/settings")
1465
+ .handle({ title: "Settings" })
1466
+ .component(SettingsPage);
1467
+ ```
1468
+
1469
+ Then create a component that reads the handles and updates `document.title`:
1470
+
1471
+ ```tsx
1472
+ function DocumentTitle() {
1473
+ const handles = useHandles();
1474
+
1475
+ useEffect(() => {
1476
+ document.title = handles
1477
+ .map(h => h.title)
1478
+ .reverse()
1479
+ .join(" - ");
1480
+ }, [handles]);
1481
+
1482
+ return null;
1483
+ }
1484
+ ```
1485
+
1486
+ Place this component somewhere in your layout:
1487
+
1488
+ ```tsx
1489
+ function Layout() {
1490
+ return (
1491
+ <>
1492
+ <DocumentTitle />
1493
+ <Header />
1494
+ <Outlet />
1495
+ </>
1496
+ );
1497
+ }
1498
+ ```
1499
+
1500
+ When visiting `/settings`, the document title becomes "Settings - App". The `useHandles()` hook returns handles from all routes in the current matching chain (from root to leaf), so reversing the array puts the most specific page first.
1501
+
1502
+ For type safety, register your handle type:
1503
+
1504
+ ```tsx
1505
+ declare module "@typeroute/router" {
1506
+ interface Register {
1507
+ routes: typeof routes;
1508
+ handle: { title: string };
1509
+ }
1510
+ }
1511
+ ```
1512
+
1461
1513
  ---
1462
1514
 
1463
1515
  # API reference
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{Component as e,Suspense as t,cloneElement as n,createContext as r,isValidElement as i,lazy as a,memo as o,useCallback as s,useContext as c,useEffect as l,useInsertionEffect as u,useLayoutEffect as d,useMemo as f,useRef as p,useState as m,useSyncExternalStore as h}from"react";import{inject as g,parse as _}from"regexparam";import{jsx as v}from"react/jsx-runtime";function y(e){return`/${e}`.replaceAll(/\/+/g,`/`).replace(/(.+)\/$/,`$1`)}function b(e){let{keys:t,pattern:n}=_(e);return{pattern:e,keys:t,regex:n,loose:_(e,!0).pattern,weights:e.split(`/`).slice(1).map(e=>e.includes(`*`)?0:e.includes(`:`)?1:2)}}function x(e){return typeof e==`function`?e:t=>{let n=e[`~standard`].validate(t);if(n instanceof Promise)throw Error(`[TypeRoute] Validation can't be async`);if(n.issues)throw Error(`[TypeRoute] Validation failed`,{cause:n.issues});return n.value}}function S(e){return Object.entries(e).filter(([e,t])=>t!==void 0).map(([e,t])=>`${e}=${encodeURIComponent(w(t))}`).join(`&`)}function C(e){let t=new URLSearchParams(e);return Object.fromEntries([...t.entries()].map(([e,t])=>(t=decodeURIComponent(t),[e,T(t)?JSON.parse(t):t])))}function w(e){return typeof e==`string`&&!T(e)?e:JSON.stringify(e)}function T(e){try{return JSON.parse(e),!0}catch{return!1}}function E(e,t){return y(`${t}/${e}`)}function D(e,t){return(e===t||e.startsWith(`${t}/`))&&(e=e.slice(t.length)||`/`),e}function O(e,t){return[e,S(t)].filter(Boolean).join(`?`)}function k(e){let{pathname:t,search:n}=new URL(e,`http://w`);return{path:t,search:C(n)}}function A({keys:e,regex:t,loose:n},r,i,a){let o=(r?t:n).exec(D(i,a));if(!o)return null;let s={};return e.forEach((e,t)=>{let n=o[t+1];n&&(s[e]=n)}),s}function j(e){return[...e].sort((e,t)=>{let n=e.route._.weights,r=t.route._.weights,i=Math.max(n.length,r.length);for(let e=0;e<i;e++){let t=n[e]??-1,i=r[e]??-1;if(t!==i)return i-t}return 0})}const M=r(null),N=r(null),P=r(null),F=r(null);function I(){let e=c(M);if(e)return e;throw Error(`[TypeRoute] useRouter must be within a router context`)}function L(){let e=c(N);if(e)return e;throw Error(`[TypeRoute] useLocation must be within a router context`)}function R(e){let t=I(),{path:n}=L();return f(()=>t.match(n,e),[t,n,e.from,e.strict,e.params])}function z(){return c(F)}function B(){return I().navigate}function V(){let e=c(P);return f(()=>e?.route._.handles??[],[e])}function H(e){let t=R({from:e});if(t)return t.params;throw Error(`[TypeRoute] Can't read params for non-matching route ${e}`)}function U(e){let t=I(),{search:n,path:r}=L(),i=t.getRoute(e),a=f(()=>i._.validate(n),[i,n]);return[a,Z((e,n)=>{e=typeof e==`function`?e(a):e;let i=O(r,{...a,...e});t.navigate({url:i,replace:n})})]}var W=class{_;_loc=(e,t)=>{let{state:n}=history,[r,i]=this._??[];return i?.path===e&&r===t&&i.state===n?i:(this._=[t,{path:e,search:C(t),state:n}])[1]};constructor(){if(!window[G]){for(let e of[K,q]){let t=history[e];history[e]=function(...n){t.apply(this,n);let r=new Event(e);dispatchEvent(r)}}window[G]=1}}location=()=>this._loc(location.pathname,location.search);go=e=>history.go(e);push=e=>{let{url:t,replace:n,state:r}=e;history[n?q:K](r,``,t)};subscribe=e=>(J.forEach(t=>window.addEventListener(t,e)),()=>{J.forEach(t=>window.removeEventListener(t,e))})};const G=Symbol.for(`wmp01`),K=`pushState`,q=`replaceState`,J=[`popstate`,K,q,`hashchange`];var Y=class{routes;basePath;history;ssrContext;defaultLinkOptions;_;constructor(e){let{routes:t,basePath:n=`/`,history:r,ssrContext:i,defaultLinkOptions:a}=e;this.routes=t,this.basePath=y(n),this.history=r??new W,this.ssrContext=i,this.defaultLinkOptions=a,this._={routeMap:new Map(t.map(e=>[e._.pattern,e]))}}getRoute=e=>{if(typeof e!=`string`)return e;let t=this._.routeMap.get(e);if(!t)throw Error(`[TypeRoute] Route not found for ${e}`);return t};match=(e,t)=>{let{from:n,strict:r,params:i}=t,a=this.getRoute(n),o=A(a._,r,e,this.basePath);return o&&(!i||Object.keys(i).every(e=>i[e]===o[e]))?{route:a,params:o}:null};matchAll=e=>j(this.routes.map(t=>this.match(e,{from:t,strict:!0})).filter(e=>!!e))[0]??null;createUrl=e=>{let{to:t,params:n={},search:r={}}=e,{pattern:i}=this.getRoute(t)._;return O(E(g(i,n),this.basePath),r)};preload=async e=>{let{to:t,params:n={},search:r={}}=e,{preloads:i}=this.getRoute(t)._;await Promise.all(i.map(e=>e({params:n,search:r})))};navigate=e=>{if(typeof e==`number`)this.history.go(e);else if(`url`in e)this.history.push(e);else{let{replace:t,state:n}=e;this.history.push({url:this.createUrl(e),replace:t,state:n})}}},X=class{stack=[];index=0;listeners=new Set;constructor(e=`/`){this.stack.push({...k(e),state:void 0})}location=()=>this.stack[this.index];go=e=>{let t=this.index+e;this.stack[t]&&(this.index=t,this.listeners.forEach(e=>e()))};push=e=>{let{url:t,replace:n,state:r}=e,i={...k(t),state:r};this.stack=this.stack.slice(0,this.index+1),n?this.stack[this.index]=i:this.index=this.stack.push(i)-1,this.listeners.forEach(e=>e())};subscribe=e=>(this.listeners.add(e),()=>{this.listeners.delete(e)})},ee=class extends W{location=()=>{let{pathname:e,search:t}=new URL(location.hash.slice(1),`http://w`);return this._loc(e,t)};push=e=>{let{url:t,replace:n,state:r}=e;history[n?`replaceState`:`pushState`](r,``,`#${t}`)}};function te(e){let[t]=m(()=>`router`in e?e.router:new Y(e)),{subscribe:n,location:r}=t.history,i=h(n,r,r),a=f(()=>t.matchAll(i.path),[t,i.path]);return a||console.error(`[TypeRoute] No matching route for path`,i.path),f(()=>v(M.Provider,{value:t,children:v(N.Provider,{value:i,children:v(P.Provider,{value:a,children:a?.route._.components.reduceRight((e,t)=>v(F.Provider,{value:e,children:v(t,{})}),null)})})}),[t,i,a])}function ne(){return z()}function re(e){let t=I();return d(()=>t.navigate(e),[]),t.ssrContext&&(t.ssrContext.redirect=t.createUrl(e)),null}function ie(e){let t=I(),{to:r,replace:a,state:o,params:c,search:u,strict:d,preload:m,preloadDelay:h=50,style:g,className:_,activeStyle:y,activeClassName:b,asChild:x,children:S,...C}={...t.defaultLinkOptions,...e},w=p(null),T=p(null),E=t.createUrl(e),D=!!R({from:r,strict:d,params:c}),O=Z(()=>t.preload(e)),k=s(()=>{clearTimeout(T.current)},[]),A=s(()=>{k(),T.current=setTimeout(O,h)},[h,k]),j=f(()=>({"data-active":D,style:{...g,...D&&y},className:[_,D&&b].filter(Boolean).join(` `)||void 0}),[D,g,_,y,b]);l(()=>{if(m===`render`)A();else if(m===`viewport`&&w.current){let e=new IntersectionObserver(e=>e.forEach(e=>{e.isIntersecting?A():k()}));return e.observe(w.current),()=>{e.disconnect(),k()}}return k},[m,A,k]);let M=e=>{C.onClick?.(e),!(e.ctrlKey||e.metaKey||e.shiftKey||e.altKey||e.button!==0||e.defaultPrevented)&&(e.preventDefault(),t.navigate({url:E,replace:a,state:o}))},N=e=>{C.onFocus?.(e),m===`intent`&&!e.defaultPrevented&&A()},P=e=>{C.onBlur?.(e),m===`intent`&&k()},F=e=>{C.onPointerEnter?.(e),m===`intent`&&!e.defaultPrevented&&A()},L=e=>{C.onPointerLeave?.(e),m===`intent`&&k()},z={...C,...j,ref:ae(w,C.ref),href:E,onClick:M,onFocus:N,onBlur:P,onPointerEnter:F,onPointerLeave:L};return x&&i(S)?n(S,z):v(`a`,{...z,children:S})}function ae(e,t){return t?n=>{e.current=n;let r=typeof t==`function`?t(n):void(t.current=n);return r&&(()=>{e.current=null,r()})}:e}function Z(e){let t=p(e);return u(()=>{t.current=e},[e]),p(((...e)=>t.current(...e))).current}function oe(e){return()=>v(t,{fallback:v(e,{}),children:z()})}function se(t){class n extends e{constructor(e){super(e),this.state={children:e.children,error:null}}static getDerivedStateFromError(e){return{error:[e]}}static getDerivedStateFromProps(e,t){return e.children===t.children?t:{children:e.children,error:null}}render(){return this.state.error?v(t,{error:this.state.error[0]}):this.props.children}}return()=>v(n,{children:z()})}function Q(e){return new $({...b(y(e)),validate:e=>e,handles:[],components:[],preloads:[]})}function ce(){return Q(``)}var $=class e{_;_types;constructor(e){this._=e}route=t=>new e({...this._,...b(y(`${this._.pattern}/${t}`)),p:this});use=t=>{let{_:n}=t;return new e({...this._,handles:[...this._.handles,...n.handles],components:[...this._.components,...n.components],preloads:[...this._.preloads,...n.preloads]}).search(n.validate)};search=t=>(t=x(t),new e({...this._,validate:e=>{let n=this._.validate(e);return{...n,...t({...e,...n})}}}));handle=t=>new e({...this._,handles:[...this._.handles,t]});preload=t=>new e({...this._,preloads:[...this._.preloads,e=>t({params:e.params,search:this._.validate(e.search)})]});component=t=>new e({...this._,components:[...this._.components,o(t)]});lazy=e=>{let t=a(async()=>{let t=await e();return`default`in t?t:{default:t}});return this.preload(e).component(t)};suspense=e=>this.component(oe(e));error=e=>this.component(se(e));toString=()=>this._.pattern};export{W as BrowserHistory,ee as HashHistory,ie as Link,N as LocationContext,P as MatchContext,X as MemoryHistory,re as Navigate,ne as Outlet,F as OutletContext,$ as Route,Y as Router,M as RouterContext,te as RouterRoot,ce as middleware,Q as route,V as useHandles,L as useLocation,R as useMatch,B as useNavigate,z as useOutlet,H as useParams,I as useRouter,U as useSearch};
1
+ import{Component as e,Suspense as t,cloneElement as n,createContext as r,isValidElement as i,lazy as a,memo as o,useCallback as s,useContext as c,useEffect as l,useInsertionEffect as u,useLayoutEffect as d,useMemo as f,useRef as p,useState as m,useSyncExternalStore as h}from"react";import{inject as g,parse as _}from"regexparam";import{jsx as v}from"react/jsx-runtime";function y(e){return`/${e}`.replaceAll(/\/+/g,`/`).replace(/(.+)\/$/,`$1`)}function b(e){let{keys:t,pattern:n}=_(e);return{pattern:e,keys:t,regex:n,loose:_(e,!0).pattern,weights:e.split(`/`).slice(1).map(e=>e.includes(`*`)?0:e.includes(`:`)?1:2)}}function x(e){return typeof e==`function`?e:t=>{let n=e[`~standard`].validate(t);if(n instanceof Promise)throw Error(`[TypeRoute] Validation can't be async`);if(n.issues)throw Error(`[TypeRoute] Validation failed`,{cause:n.issues});return n.value}}function S(e){return Object.entries(e).filter(([e,t])=>t!==void 0).map(([e,t])=>`${e}=${encodeURIComponent(w(t))}`).join(`&`)}function C(e){let t=new URLSearchParams(e);return Object.fromEntries([...t.entries()].map(([e,t])=>(t=decodeURIComponent(t),[e,T(t)?JSON.parse(t):t])))}function w(e){return typeof e==`string`&&!T(e)?e:JSON.stringify(e)}function T(e){try{return JSON.parse(e),!0}catch{return!1}}function E(e,t){return y(`${t}/${e}`)}function D(e,t){return(e===t||e.startsWith(`${t}/`))&&(e=e.slice(t.length)||`/`),e}function O(e,t){return[e,S(t)].filter(Boolean).join(`?`)}function k(e){let{pathname:t,search:n}=new URL(e,`http://w`);return{path:t,search:C(n)}}function A({keys:e,regex:t,loose:n},r,i,a){let o=(r?t:n).exec(D(i,a));if(!o)return null;let s={};return e.forEach((e,t)=>{let n=o[t+1];n&&(s[e]=n)}),s}function j(e){return[...e].sort((e,t)=>{let n=e.route._.weights,r=t.route._.weights,i=Math.max(n.length,r.length);for(let e=0;e<i;e++){let t=n[e]??-1,i=r[e]??-1;if(t!==i)return i-t}return 0})}const M=r(null),N=r(null),P=r(null),F=r(null);function I(){let e=c(M);if(e)return e;throw Error(`[TypeRoute] useRouter must be within a router context`)}function L(){let e=c(N);if(e)return e;throw Error(`[TypeRoute] useLocation must be within a router context`)}function R(e){let t=I(),{path:n}=L();return f(()=>t.match(n,e),[t,n,e.from,e.strict,e.params])}function z(){return c(F)}function B(){return I().navigate}function V(){let e=c(P);return f(()=>e?.route._.handles??[],[e])}function H(e){let t=R({from:e});if(t)return t.params;throw Error(`[TypeRoute] Can't read params for non-matching route ${e}`)}function U(e){let t=I(),{search:n,path:r}=L(),i=t.getRoute(e),a=f(()=>i._.validate(n),[i,n]);return[a,Z((e,n)=>{e=typeof e==`function`?e(a):e;let i=O(r,{...a,...e});t.navigate({url:i,replace:n})})]}var W=class{_;_loc=(e,t)=>{let{state:n}=history,[r,i]=this._??[];return i?.path===e&&r===t&&i.state===n?i:(this._=[t,{path:e,search:C(t),state:n}])[1]};constructor(){if(!window[G]){for(let e of[K,q]){let t=history[e];history[e]=function(...n){t.apply(this,n),dispatchEvent(new Event(e))}}window[G]=1}}location=()=>this._loc(location.pathname,location.search);go=e=>history.go(e);push=e=>{let{url:t,replace:n,state:r}=e;history[n?q:K](r,``,t)};subscribe=e=>(J.forEach(t=>window.addEventListener(t,e)),()=>{J.forEach(t=>window.removeEventListener(t,e))})};const G=Symbol.for(`wmp01`),K=`pushState`,q=`replaceState`,J=[`popstate`,K,q,`hashchange`];var Y=class{routes;basePath;history;ssrContext;defaultLinkOptions;_;constructor(e){let{routes:t,basePath:n=`/`,history:r,ssrContext:i,defaultLinkOptions:a}=e;this.routes=t,this.basePath=y(n),this.history=r??new W,this.ssrContext=i,this.defaultLinkOptions=a,this._={routeMap:new Map(t.map(e=>[e._.pattern,e]))}}getRoute=e=>{if(typeof e!=`string`)return e;let t=this._.routeMap.get(e);if(!t)throw Error(`[TypeRoute] Route not found for ${e}`);return t};match=(e,t)=>{let{from:n,strict:r,params:i}=t,a=this.getRoute(n),o=A(a._,r,e,this.basePath);return o&&(!i||Object.keys(i).every(e=>i[e]===o[e]))?{route:a,params:o}:null};matchAll=e=>j(this.routes.map(t=>this.match(e,{from:t,strict:!0})).filter(e=>!!e))[0]??null;createUrl=e=>{let{to:t,params:n={},search:r={}}=e,{pattern:i}=this.getRoute(t)._;return O(E(g(i,n),this.basePath),r)};preload=async e=>{let{to:t,params:n={},search:r={}}=e,{preloads:i}=this.getRoute(t)._;await Promise.all(i.map(e=>e({params:n,search:r})))};navigate=e=>{if(typeof e==`number`)this.history.go(e);else if(`url`in e)this.history.push(e);else{let{replace:t,state:n}=e;this.history.push({url:this.createUrl(e),replace:t,state:n})}}},X=class{stack=[];index=0;listeners=new Set;constructor(e=`/`){this.stack.push({...k(e),state:void 0})}location=()=>this.stack[this.index];go=e=>{let t=this.index+e;this.stack[t]&&(this.index=t,this.listeners.forEach(e=>e()))};push=e=>{let{url:t,replace:n,state:r}=e,i={...k(t),state:r};this.stack=this.stack.slice(0,this.index+1),n?this.stack[this.index]=i:this.index=this.stack.push(i)-1,this.listeners.forEach(e=>e())};subscribe=e=>(this.listeners.add(e),()=>{this.listeners.delete(e)})},ee=class extends W{location=()=>{let{pathname:e,search:t}=new URL(location.hash.slice(1),`http://w`);return this._loc(e,t)};push=e=>{let{url:t,replace:n,state:r}=e;history[n?`replaceState`:`pushState`](r,``,`#${t}`)}};function te(e){let[t]=m(()=>`router`in e?e.router:new Y(e)),{subscribe:n,location:r}=t.history,i=h(n,r,r),a=f(()=>t.matchAll(i.path),[t,i.path]);return a||console.error(`[TypeRoute] No matching route for path`,i.path),f(()=>v(M.Provider,{value:t,children:v(N.Provider,{value:i,children:v(P.Provider,{value:a,children:a?.route._.components.reduceRight((e,t)=>v(F.Provider,{value:e,children:v(t,{})}),null)})})}),[t,i,a])}function ne(){return z()}function re(e){let t=I();return d(()=>t.navigate(e),[]),t.ssrContext&&(t.ssrContext.redirect=t.createUrl(e)),null}function ie(e){let t=I(),{to:r,replace:a,state:o,params:c,search:u,strict:d,preload:m,preloadDelay:h=50,style:g,className:_,activeStyle:y,activeClassName:b,asChild:x,children:S,...C}={...t.defaultLinkOptions,...e},w=p(null),T=p(null),E=t.createUrl(e),D=!!R({from:r,strict:d,params:c}),O=Z(()=>t.preload(e)),k=s(()=>{clearTimeout(T.current)},[]),A=s(()=>{k(),T.current=setTimeout(O,h)},[h,k]),j=f(()=>({"data-active":D,style:{...g,...D&&y},className:[_,D&&b].filter(Boolean).join(` `)||void 0}),[D,g,_,y,b]);l(()=>{if(m===`render`)A();else if(m===`viewport`&&w.current){let e=new IntersectionObserver(e=>e.forEach(e=>{e.isIntersecting?A():k()}));return e.observe(w.current),()=>{e.disconnect(),k()}}return k},[m,A,k]);let M=e=>{C.onClick?.(e),!(e.ctrlKey||e.metaKey||e.shiftKey||e.altKey||e.button!==0||e.defaultPrevented)&&(e.preventDefault(),t.navigate({url:E,replace:a,state:o}))},N=e=>{C.onFocus?.(e),m===`intent`&&!e.defaultPrevented&&A()},P=e=>{C.onBlur?.(e),m===`intent`&&k()},F=e=>{C.onPointerEnter?.(e),m===`intent`&&!e.defaultPrevented&&A()},L=e=>{C.onPointerLeave?.(e),m===`intent`&&k()},z={...C,...j,ref:ae(w,C.ref),href:E,onClick:M,onFocus:N,onBlur:P,onPointerEnter:F,onPointerLeave:L};return x&&i(S)?n(S,z):v(`a`,{...z,children:S})}function ae(e,t){return t?n=>{e.current=n;let r=typeof t==`function`?t(n):void(t.current=n);return r&&(()=>{e.current=null,r()})}:e}function Z(e){let t=p(e);return u(()=>{t.current=e},[e]),p(((...e)=>t.current(...e))).current}function oe(e){return()=>v(t,{fallback:v(e,{}),children:z()})}function se(t){class n extends e{constructor(e){super(e),this.state={...e}}static getDerivedStateFromError(e){return{error:[e]}}static getDerivedStateFromProps(e,t){return e.children===t.children?t:{...e,error:void 0}}render(){return this.state.error?v(t,{error:this.state.error[0]}):this.props.children}}return()=>v(n,{children:z()})}function Q(e){return new $({...b(y(e)),validate:e=>e,handles:[],components:[],preloads:[]})}function ce(){return Q(``)}var $=class e{_;_types;constructor(e){this._=e}route=t=>new e({...this._,...b(y(`${this._.pattern}/${t}`)),p:this});use=t=>{let{_:n}=t;return new e({...this._,handles:[...this._.handles,...n.handles],components:[...this._.components,...n.components],preloads:[...this._.preloads,...n.preloads]}).search(n.validate)};search=t=>(t=x(t),new e({...this._,validate:e=>{let n=this._.validate(e);return{...n,...t({...e,...n})}}}));handle=t=>new e({...this._,handles:[...this._.handles,t]});preload=t=>new e({...this._,preloads:[...this._.preloads,e=>t({params:e.params,search:this._.validate(e.search)})]});component=t=>new e({...this._,components:[...this._.components,o(t)]});lazy=e=>{let t=a(async()=>{let t=await e();return`default`in t?t:{default:t}});return this.preload(e).component(t)};suspense=e=>this.component(oe(e));error=e=>this.component(se(e));toString=()=>this._.pattern};export{W as BrowserHistory,ee as HashHistory,ie as Link,N as LocationContext,P as MatchContext,X as MemoryHistory,re as Navigate,ne as Outlet,F as OutletContext,$ as Route,Y as Router,M as RouterContext,te as RouterRoot,ce as middleware,Q as route,V as useHandles,L as useLocation,R as useMatch,B as useNavigate,z as useOutlet,H as useParams,I as useRouter,U as useSearch};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typeroute/router",
3
- "version": "0.7.0",
3
+ "version": "0.8.1",
4
4
  "license": "MIT",
5
5
  "author": "strblr",
6
6
  "description": "Type-safe React router that just works - simple setup, full autocomplete, 4kB gzipped",