UNPKG

@wbe/low-router-preact

Version:

<h1 align="center" style="text-align:center">low-router preact</h1> <p align="center"> <img alt="npm" src="https://img.shields.io/npm/v/@wbe/low-router-preact"> <img alt="npm bundle size" src="https://img.shields.io/bundlephobia/minzip/%40wbe%2Flow-router

2 lines (1 loc) 10.5 kB
import{useMemo as x,forwardRef as j,createElement as b,createContext as B,memo as ft,useEffect as U,useReducer as w,useLayoutEffect as E,useContext as M}from"preact/compat";import{useRef as y}from"preact/hooks";import z from"@wbe/debug";import{isServer as J}from"@wbe/utils";import W from"@wbe/debug";var $=W("low-router-preact:cache");function H(e,t){let o=r=>Object.keys(e).some(n=>n===r);return{get:r=>{if(o(r))return e[r]},set:(r,n)=>{if(o(r)){$(t,`"${r}"`,"already exist in cache, skip",e);return}e[r]=n,$(t,`"${r}"`,"has been cached",e)}}}function C(...e){return e.reduce((t,o)=>({...t,...o||{}}),{})}import{compilePath as q}from"@wbe/low-router";function L(e,t,o=s.routes,r=s.i18n,n=s.base){if(!e){console.error("composeUrlByRouteName > name is invalid, return",e);return}let c=(p,i,u)=>{for(let l of p){let m=i?.lang||i?.code||r?.currentLocale.code,a=l.translations?.[m]||l.path,h=q(u+a)(i);if(l?.name===e)return h;if(l.children?.length>0){let R=c(l.children,i,h);if(R)return R}}};return c(o,t,n)}function f(e,t=""){return e?.filter(Boolean).join(t).replace(/(https?:\/\/)|(\/)+/g,"$1$2")}var T=B({prevContext:void 0,currentContext:void 0,router:void 0,base:void 0,routes:void 0,options:void 0,history:void 0,counter:0,staticLocation:void 0,i18n:void 0}),s={router:void 0,base:void 0,routes:void 0,history:void 0,currentContext:void 0,staticLocation:void 0,initialStaticProps:void 0,staticPropsCache:{},isFirstRoute:!0,routeCounter:0,i18n:null},k=z("low-router-preact:Router"),N=J(),V=0;function X(e){let t=e.router.options.id,o=!!e.staticLocation||!!e.history,r=y(!0);o&&r.current&&(r.current=!1,s={router:e.router,base:e.router.options.base,routes:e.router.routes,history:e.history,currentContext:void 0,staticLocation:e.staticLocation,initialStaticProps:e.initialStaticProps,staticPropsCache:{},isFirstRoute:!0,routeCounter:0,i18n:e.i18n});let[n,c]=w((l,m)=>{switch(m.type){case"update":return{prevContext:l.currentContext,currentContext:m.currentContext,counter:l.counter+1}}},{prevContext:null,currentContext:null,counter:0});U(()=>()=>e.router?.dispose(),[]);let p=y(null),i=async({location:l})=>{o&&(s.routeCounter++,s.isFirstRoute=s.routeCounter===1);let m=e.router.matchRoute(f([l.pathname,l.search,l.hash]));if(!m){k(t,"no context found, return.");return}let a=m;for(;a.parent;)a=a.parent;if(k(t,"context",a),p.current?.relativePathname===a.relativePathname){k(t,"Same relativePathname, return.");return}let h=H(s.staticPropsCache,t),R=L(a.route?.name,a.params);a.route._props=a.route._props||a.route.props||{};let A=async(g,_,D)=>{try{let v=await g.route.getStaticProps(g,s.i18n?.currentLocale);g.route.props=C(g.route._props,v),_.set(D,v)}catch(v){console.error(t,"requestStaticProps failed",v)}};if(N)s.initialStaticProps&&(a.route.props=C(a.route.props,s.initialStaticProps?.[R]),h.set(R,a.route.props));else if(s.isFirstRoute)s.initialStaticProps?.[R]?(a.route.props=C(a.route.props,s.initialStaticProps?.[R]),h.set(R,a.route.props)):a.route.getStaticProps&&await A(a,h,R);else{let g=h.get(R);g?a.route.props=C(a.route.props,g):a.route.getStaticProps&&await A(a,h,R)}a.routeId=V++,c({type:"update",currentContext:a}),s.currentContext=a,p.current=a},u=y(!0);if(N&&s.staticLocation&&u.current){u.current=!1;let{pathname:l,search:m}=new URL(`https://a${s.staticLocation}`);i({location:{pathname:l,search:m}})}return U(()=>(i({location:window.location}),s.history?.listen(i)),[]),b(T.Provider,{children:e.children,value:{router:e.router,base:e.router.options.base,routes:e.router.routes,options:e.router.options,history:s.history,prevContext:n.prevContext,currentContext:n.currentContext,counter:n.counter,staticLocation:s.staticLocation,i18n:s.i18n}})}import{isServer as G}from"@wbe/utils";var P=()=>M(T);var K=async({prev:e,current:t,unmountPrev:o})=>{t?.root&&(t.root.style.opacity="0"),e?.playOut&&(await e.playOut?.(),o()),t?.playIn&&(await t?.playIn?.(),t?.root&&(t.root.style.opacity="1"))};function Q({transitions:e,clampRoutesRender:t=!0}){let{options:{id:o},prevContext:r,currentContext:n}=P(),c=y([]),[p,i]=w((u,l)=>{switch(l.type){case"update":return{currentContext:l.prevContext,prevContext:l.prevContext,updateId:u.updateId+1,stackRoutes:[...u.stackRoutes,l.currentContext].filter(Boolean).slice(t?-2:0)};case"unmount-prev":let a=u.stackRoutes?.filter(h=>h?.routeId!==l.routeIdToRemove);return{...u,stackRoutes:a}}},{stackRoutes:[],currentContext:n,prevContext:r,updateId:0});return x(()=>{G()&&i({type:"update",prevContext:r,currentContext:n})},[]),E(()=>{n&&i({type:"update",prevContext:r,currentContext:n})},[r,n]),E(()=>{if(p.stackRoutes?.length===0)return;let u=c.current?.[p.stackRoutes?.length-2],l=c.current?.[p.stackRoutes?.length-1];(e||K)({unmountPrev:()=>{i({type:"unmount-prev",routeIdToRemove:u?.routeId})},prev:u,current:l})},[p.updateId]),b("div",{className:"Stack"},p.stackRoutes?.map((u,l)=>{let m=u.route.action?.();if(!m)return null;let a=u.routeId;return b(m,{ref:h=>{c.current[l]={...h,routeId:a}},key:a,params:u.params,query:u.query,hash:u.hash,...u.route.props||{}})}))}import{normalizePath as F}from"@wbe/low-router";function S(e,t=s.base,o=s.i18n?.currentLocale.code,r=s.i18n?.showLocaleInUrl()){return r&&(e.startsWith(t)&&(e=e.replace(t,"")),e=f([t,`/${o}`,e==="/"?"":`/${e}`])),e}import{isServer as Y}from"@wbe/utils";function Z(e,t){let{router:o,history:r,staticLocation:n,currentContext:c,i18n:p}=P(),i=x(()=>typeof e.to=="string"?F(f([s.base,S(e.to)])):L(e.to.name,{code:p?.currentLocale?.code,...e.to.params}),[e.to,o]),u=m=>{m.preventDefault(),e.onClick?.(),r?.push(i)},l=x(()=>{let m=Y()?n:c?.pathname;return m===i||m===F(i)},[n,c,i]);return b("a",{...e,to:void 0,className:f(["Link",e.className,l&&"active"]," "),onClick:u,href:i,ref:t},e.children)}var tt=j(Z);import{LowRouter as et,normalizePath as ot}from"@wbe/low-router";var rt=({from:e,id:t})=>{let{routes:o,base:r,i18n:n}=P();return x(()=>{let c=o.find(u=>u.name===e);if(!c){console.error(`Route with name "${e}" not found. Can't create router instance.`);return}let p=c.translations?.[n?.currentLocale?.code]||c.path,i=ot(f([r,p]));return new et(c.children,{base:i,id:t})},[o,r,n])};import nt from"@wbe/debug";import{isServer as it}from"@wbe/utils";import{normalizePath as I}from"@wbe/low-router";var d=nt("low-router-preact:I18n"),O=class{locales;currentLocale;defaultLocale;browserLocale;defaultLocaleInUrl;base;staticLocation;constructor(t,o){this.locales=t,this.base=I(o.base??"/"),this.staticLocation=o.staticLocation,this.defaultLocale=this.#n(t),this.currentLocale=this.#t()||this.defaultLocale,this.browserLocale=this.#i(t),this.defaultLocaleInUrl=o.defaultLocaleInUrl??!0}setLocale(t,o=!0,r=s.currentContext){if(typeof t=="string"&&(t=this.locales.find(i=>i.code===t),!t)){d(`locale code ${t} is not available, exit.`);return}if(t.code===this.currentLocale.code){d("this is the same locale, exit.");return}if(!this.#o(t)){d(`locale ${t.code} is not available in locales list, exit.`);return}let n=L(r.route?.name,{...r.params||{},lang:t.code});d("composedUrl by routeName",n);let c,p=o;if(this.defaultLocaleInUrl)c=n;else if(!this.defaultLocaleInUrl&&this.isDefaultLocaleCode(t.code)){let i=`${this.base}/${t.code}`,u=n.substring(i.length,n.length);c=f([this.base,u]),p=!0,d("2. after remove locale from URL",c)}else if(!this.defaultLocaleInUrl&&this.isDefaultLocaleCode(this.currentLocale.code)){let i=n.substring(this.base.length,n.length);c=f([this.base,"/",t.code,"/",i]),d("3. after add locale in URL",c)}else c=n,d("4, other case");this.currentLocale=t,c=I(c),this.#e(c,p)}redirectToBrowserLocale(t=!0){if(d("browserLocale object",this.browserLocale),!this.browserLocale){d("browserLocale is not set, redirect to defaultLocale"),this.redirectToDefaultLocale(t);return}if(location.pathname===this.base||I(location.pathname)===this.base){let o=`${this.base}/${this.browserLocale.code}`;d("redirect: to browser locale",o),this.#e(o,t)}}redirectToDefaultLocale(t=!0){if(!this.defaultLocaleInUrl){d("redirect: URLs have a locale param or locale is valid, don't redirect.");return}if(this.#o(this.#t())){d("redirect: locale from URL is valid, don't redirect");return}if(location.pathname===this.base||I(location.pathname)===this.base){let o=`${this.base}/${this.defaultLocale.code}`;d("redirect to default locale >",o),this.#e(o,t)}}isDefaultLocaleCode(t=this.currentLocale.code){return t===this.defaultLocale.code}showLocaleInUrl(){return this.defaultLocaleInUrl||!this.isDefaultLocaleCode(this.currentLocale.code)}patchLangParam(t,o=this.showLocaleInUrl()){return I(f([o&&!t.includes("*")&&"/:code",t!=="/"?t:"/"]))}addLocaleParamToRoutes(t,o=this.showLocaleInUrl()){let r=(n,c=!1)=>n.map(p=>{let i=this.#r(p),u=p.children?.length>0,l=!c&&o,m={};return p.translations&&Object.keys(p.translations).forEach(a=>{m[a]=this.patchLangParam(p.translations[a],l)}),{...p,path:this.patchLangParam(i,l),translations:Object.entries(m).length!==0?m:null,...u?{children:r(p.children,!0)}:{}}});return r(t)}#r(t,o=this.#t(this.staticLocation||window.location.pathname)?.code||this.defaultLocale.code){return t.translations?t.translations?.[o]??t.path:t.path}#n(t){return t.find(o=>o?.default)??t[0]}#i(t){if(typeof navigator>"u")return;let o=navigator.language;return d("Browser locale detected",o),t.find(r=>r.code.includes("-")?r.code===o.toLowerCase():r.code===o.toLowerCase().split("-")[0])}#t(t=this.staticLocation||window.location.pathname){let o=t.replace(this.base,"/"),r=f([o]).split("/")[1];return this.locales.find(n=>r===n.code)}#o(t,o=this.locales){return o.some(r=>r.code===t?.code)}#e(t,o=!0,r=s.history){o?!it()&&window.open(t,"_self"):r.push(t)}};import at from"@wbe/debug";var st=at("low-router-preact:staticProps");async function ct(e,t,o){let r;try{r=await t.resolve(e)}catch(i){console.error("resolve error",i);return}let n=r.context,c={},p=async i=>{if(i.route.getStaticProps)try{let u=await i.route.getStaticProps(i,o?.currentLocale),l=L(i.route?.name,i.params,t.routes,o,t.options.base);c[l]=u}catch(u){st("fetch getStaticProps data error",u)}return i.parent?p(i.parent):c};return await p(n)}import{normalizePath as ut}from"@wbe/low-router";function lt(e,t=s.i18n,o=s.base,r=s.history){let n;typeof e=="string"&&(n=ut(f([o,S(e)]))),typeof e=="object"&&(n=L(e.name,{code:t?.currentLocale?.code,...e.params})),r?.push(n)}import"@wbe/low-router";export{O as I18n,tt as Link,s as ROUTERS,X as Router,T as RouterContext,Q as Stack,L as composeUrlByRouteName,ct as getStaticPropsFromUrl,lt as setLocation,rt as useCreateRouter,P as useRouter};