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