UNPKG

eleva-router

Version:
4 lines (3 loc) 5.57 kB
/*! ElevaRouter v1.2.0-alpha | MIT License | https://github.com/TarekRaafat/eleva-router#readme */ var t,e;t=this,e=function(){"use strict";class t{constructor(t,e={}){if(this.eleva=t,this.layout=e.layout,!this.layout)throw new Error("Router requires a layout DOM element in options.");if(this.viewSelector=e.viewSelector||"view",this.view=this.layout.querySelector(`#${this.viewSelector}`)||this.layout.querySelector(`.${this.viewSelector}`)||this.layout.querySelector(this.viewSelector)||this.layout.querySelector(`[data-${this.viewSelector}]`)||this.layout,this.routes=e.routes||[],this.mode=e.mode||"hash",this.queryParam=e.queryParam||"page",this.defaultRoute=e.defaultRoute||null,this.eventListeners=[],this.isStarted=!1,!["hash","query","history"].includes(this.mode))throw new Error(`Invalid routing mode: ${this.mode}. Must be "hash", "query", or "history".`);this.routes=this.routes.map(t=>({...t,segments:this.parsePathIntoSegments(t.path)}))}parsePathIntoSegments(t){if(!t||"string"!=typeof t)throw new Error("Route path must be a non-empty string");return t.split("/").filter(Boolean).map(t=>t.startsWith(":")?{type:"param",name:t.substring(1)}:{type:"static",value:t})}async start(){if(!this.isStarted)try{if("hash"===this.mode){const t=async()=>await this.routeChanged();window.addEventListener("hashchange",t),this.eventListeners.push(()=>window.removeEventListener("hashchange",t))}else if("query"===this.mode||"history"===this.mode){const t=async()=>await this.routeChanged();window.addEventListener("popstate",t),this.eventListeners.push(()=>window.removeEventListener("popstate",t))}this.isStarted=!0,await this.routeChanged()}catch(t){throw t}}async destroy(){if(this.isStarted)try{this.eventListeners.forEach(t=>t()),this.eventListeners=[];const t=this.view._eleva_instance;t&&await t.unmount(),this.isStarted=!1}catch(t){throw t}}async routeChanged(){try{let t,e,o;if("hash"===this.mode){o=window.location.href;let s=window.location.hash.slice(1)||"";[t,e]=s.split("?"),t=t||"/"}else if("query"===this.mode){o=window.location.href;const s=window.location.search,i=new URLSearchParams(s);t=i.get(this.queryParam)||"",i.delete(this.queryParam),e=i.toString(),t=t||"/"}else"history"===this.mode&&(o=window.location.href,t=window.location.pathname||"/",e=window.location.search?window.location.search.slice(1):"");"/"!==t.charAt(0)&&(t="/"+t);const s=this.view._eleva_instance;if(s)try{await s.unmount()}catch(t){}const i=this.parseQuery(e),n=this.matchRoute(t);if(!n&&this.defaultRoute)try{const e=this.wrapComponentWithRoute(this.defaultRoute.component,{path:t,query:i,fullUrl:o,params:{},matchedRoute:this.defaultRoute.path}),s=this.defaultRoute.props||{};await this.eleva.mount(this.view,e,s)}catch(t){}else if(n)try{const{route:e,params:s}=n,a=this.wrapComponentWithRoute(e.component,{path:t,query:i,fullUrl:o,params:s,matchedRoute:e.path}),r=e.props||{};await this.eleva.mount(this.view,a,r)}catch(t){}}catch(t){}}parseQuery(t){const e={};if(!t)return e;try{t.split("&").forEach(t=>{const[o,s]=t.split("=");o&&(e[decodeURIComponent(o)]=s?decodeURIComponent(s):"")})}catch(t){}return e}matchRoute(t){if(!t||"string"!=typeof t)return null;try{if("/"===t){const t=this.routes.find(t=>"/"===t.path);return t?{route:t,params:{}}:null}const e=t.split("/").filter(Boolean);for(const t of this.routes)try{if("/"===t.path)continue;const o=t.segments;if(!o.some(t=>"param"===t.type&&t.name.endsWith("*"))&&o.length!==e.length)continue;const s={};let i=!0;for(let t=0;t<o.length;t++){const n=o[t],a=e[t];if(void 0===a){i=!1;break}if("static"===n.type){if(n.value!==a){i=!1;break}}else if("param"===n.type){if(n.name.endsWith("*")){s[n.name.slice(0,-1)]=e.slice(t).join("/");break}s[n.name]=a}}if(i)return{route:t,params:s}}catch(t){continue}return null}catch(t){return null}}async navigate(t,e={}){if(t&&"string"==typeof t)try{if(e&&Object.keys(e).length>0&&Object.keys(e).forEach(o=>{t=t.replace(`:${o}`,encodeURIComponent(e[o]))}),"hash"===this.mode)window.location.hash="/"===t||""===t?"":t;else if("query"===this.mode){const e=new URLSearchParams(window.location.search);"/"===t||""===t?e.delete(this.queryParam):e.set(this.queryParam,t);const o=e.toString(),s=window.location.pathname+(o?"?"+o:"");history.pushState({},"",s),await this.routeChanged()}else"history"===this.mode&&(history.pushState({},"",t),await this.routeChanged())}catch(t){}}addRoute(t){if(!t||!t.path||!t.component)throw new Error("Route must have both 'path' and 'component' properties");try{t.segments=this.parsePathIntoSegments(t.path),this.routes.push(t)}catch(t){throw t}}wrapComponentWithRoute(t,e){let o;if("string"==typeof t){if(o=this.eleva._components.get(t),!o)throw new Error(`Component "${t}" not registered.`)}else o=t;const s={...o},i=s.setup;if(s.setup=t=>{t.route=e;const o=this.navigate.bind(this);return t.navigate=(t,e)=>o(t,e),i?i(t):{}},s.children){const t={...s.children};s.children={},Object.keys(t).forEach(o=>{s.children[o]=this.wrapComponentWithRoute(t[o],e)})}return s}}return{name:"ElevaRouter",install(e,o={}){try{let s=0;(o.routes||[]).forEach(t=>{if("object"==typeof t.component){let o=t.component.name;o||(o="AutoRegComponent_"+s++),e.component(o,t.component),t.component=o}});const i=new t(e,o);e.router=i,!1!==o.autoStart&&queueMicrotask(async()=>{try{await i.start()}catch(t){}})}catch(t){throw t}}}},"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).ElevaRouter=e(); //# sourceMappingURL=eleva-router.umd.min.js.map