@web-package/react-widgets-router
Version:
This package is a router that provides transition animations and fully preserves the state of previous elements, offering an experience close to a Web standard API.
2 lines (1 loc) • 5.45 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react/jsx-runtime"),require("react")):"function"==typeof define&&define.amd?define(["exports","react/jsx-runtime","react"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ReactWidgetsRouter={},e.jsxRuntime,e.React)}(this,(function(e,t,n){"use strict";class s{static get pathname(){return location.pathname}static arrayOf(e){return console.assert("A given path does not exist nothing."!=e),Array.from(e.matchAll(/(?<=\/)[\w-]+(?=\/|$)/g)).map((e=>e[0]))}}function o({route:e,active:s,keepAlive:o,first:i,onDispose:r}){var a;const l=n.useRef(s),u=n.useRef(null),c=null==e?void 0:e.props.component,h=null==e?void 0:e.props.element,p=null!=h?h:c?t.jsx(c,{}):t.jsx(t.Fragment,{}),d=null!==(a=null==e?void 0:e.props.keepalive)&&void 0!==a?a:null==o||o,f=()=>{u.current.style.display="none",e&&!d&&r(e.props)};return n.useLayoutEffect((()=>{const e=u.current;if(e&&i&&l.current==s)s||(e.style.display="none");else if(e){l.current=s;const t=getComputedStyle(e),n=t.getPropertyValue("--router-fadein-keyframe").replaceAll('"',""),o=t.getPropertyValue("--router-fadein-duration"),i=t.getPropertyValue("--router-fadeout-keyframe").replaceAll('"',""),r=t.getPropertyValue("--router-fadeout-duration");if(s){if(e.style.display="unset",n)return e.style.animation=`${n} ${o||"0.3s"}`,void(e.onanimationend=null)}else{if(i)return e.style.animation=`${i} ${r||"0.3s"}`,void(e.onanimationend=f);f()}}l.current=s}),[s]),t.jsx("route-sliver",{ref:u,children:p})}addEventListener("DOMContentLoaded",(()=>{const e=new CSSStyleSheet;e.insertRule("\n route-sliver {\n position: absolute;\n width: 100%;\n height: 100%;\n }\n "),e.insertRule("\n *:has(> route-sliver) {\n position: relative;\n top: 0px;\n left: 0px;\n }\n "),document.adoptedStyleSheets=[...document.adoptedStyleSheets,e]}));class i{constructor(e){this.location=e,this.consumedPaths=[],this.paths=[],this.paths=s.arrayOf(e)}get first(){return this.paths[0]}get relPath(){return"/"+this.paths.join("/")}get absPath(){return"/"+[...this.consumedPaths,...this.paths].join("/")}get clone(){const e=new i(this.location);return e.paths=this.paths.slice(),e.consumedPaths=this.consumedPaths.slice(),e}consume(){return console.assert(0!=this.paths.length,"Not exists a path that can be consumed."),this.paths[0]&&this.consumedPaths.push(this.paths[0]),this.paths=this.paths.slice(1)}}class r{constructor(){this.listeners=[],window.onpopstate=e=>this.notifyListeners(location.pathname)}static get instance(){var e;return null!==(e=this._instance)&&void 0!==e?e:this._instance=new r}addListener(e){console.assert(!this.listeners.includes(e),"Already exists a given listener in the context."),this.listeners.push(e)}removeListener(e){console.assert(this.listeners.includes(e),"Already not exists a given listener in the context."),this.listeners=this.listeners.filter((t=>t!=e))}notifyListeners(e){this.listeners.forEach((t=>t(e)))}push(e){location.pathname!=e&&(this.notifyListeners(e),history.pushState(null,"",e))}move(e){location.pathname!=e&&(history.replaceState({},"",e),this.notifyListeners(location.pathname))}forward(){history.forward(),this.notifyListeners(location.pathname)}backward(){history.back(),this.notifyListeners(location.pathname)}}function a(){let e=n.useContext(l),t=r.instance;if(null==e){const[s,o]=n.useState(window.location.pathname);e=new i(s),n.useEffect((()=>(t.addListener(o),()=>t.removeListener(o))),[])}return e.clone}const l=n.createContext(null);var u;!function(e){e[e.absolute=0]="absolute",e[e.relative=1]="relative"}(u||(u={})),e.Route=function(e){var t;return console.assert(null!=e.element||null!=e.component,"Not exists a given component"),console.assert(null==e.element&&null!=e.component,"Cannot define rendering a component."),console.assert(null!=e.element&&null==e.component,"Cannot define rendering a component."),null!==(t=e.component)&&void 0!==t?t:e.element},e.Router=function({location:e,keepAlive:i,children:r}){const u=n.useRef(new Map),c=a(),h=Array.isArray(r)?r:[r],[p,d]=n.useState(0);let f=h.find((t=>s.arrayOf(t.props.path)[0]==c.first&&null==e||s.arrayOf(t.props.path)[0]==s.arrayOf(null!=e?e:"")[0]&&e));if(null!=f||(f=h.find((e=>e.props.default||"*"==e.props.path))),!f)throw new Error("Route corresponding to a given path was not found. Therefore, You need to define a `default` attribute to allow the router to specify a default `Route`.");return 0!=c.paths.length&&c.consume(),u.current.set(f.props.path,{context:c.clone}),t.jsx(t.Fragment,{children:Array.from(u.current).map((([e,n],s)=>{const r=(null==f?void 0:f.props.path)==e,a=h.find((t=>t.props.path==e));return t.jsx(l.Provider,{value:n.context.clone,children:t.jsx(o,{active:r,first:0==s,route:a,keepAlive:i,onDispose:e=>{u.current.delete(e.path),d(p+1)}})},e)}))})},e.RouterBinding=r,e.RouterContext=i,e.useLocation=a,e.useRoute=function(e){var t;const n=null!==(t=null==e?void 0:e.context)&&void 0!==t?t:a();return t=>{var s,o,i;const a=null!==(s=null==e?void 0:e.routing)&&void 0!==s?s:u.relative,l=t.startsWith("/")?t.slice(1):t;a==u.absolute?null!==(o=null==e?void 0:e.replace)&&void 0!==o&&o?r.instance.move(t):r.instance.push(t):null!==(i=null==e?void 0:e.replace)&&void 0!==i&&i?r.instance.move("/"+[...n.consumedPaths,l].join("/")):r.instance.push("/"+[...n.consumedPaths,l].join("/"))}}}));