UNPKG

@shaun/alpinejs-router

Version:

A lightweight client-side router for Alpine.js that adds declarative routes, link navigation, dynamic params, external templates, and hash or HTML5 history modes without turning your app into a larger framework.

1 lines • 10.3 kB
(function(){function e(e,t){if(t.has(e))throw TypeError(`Cannot initialize the same private elements twice on an object`)}function t(t,n){e(t,n),n.add(t)}function n(t,n,r){e(t,n),n.set(t,r)}function r(e,t,n){if(typeof e==`function`?e===t:e.has(t))return arguments.length<3?t:n;throw TypeError(`Private element is not present on this object`)}function i(e,t,n){return e.set(r(e,t),n),n}function a(e,t){return e.get(r(e,t))}function o(e){"@babel/helpers - typeof";return o=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},o(e)}function s(e,t){if(o(e)!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(o(r)!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function c(e){var t=s(e,`string`);return o(t)==`symbol`?t:t+``}function l(e,t,n){return(t=c(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function u(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function d(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?u(Object(n),!0).forEach(function(t){l(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):u(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}var f=new WeakMap,p=new WeakMap,m=new WeakSet,h=class{constructor(e,r={}){var a,o;t(this,m),n(this,f,void 0),n(this,p,void 0),i(f,this,new URL(e)),this.mode=(a=r.mode)==null?`web`:a,this.base=(o=r.base)==null?``:o}set url(e){i(f,this,new URL(e)),i(p,this,void 0)}get url(){return a(f,this).href}get path(){return a(p,this)!=null||i(p,this,r(m,this,_).call(this)),a(p,this)}get query(){let e=this.mode===`hash`&&a(f,this).hash?r(m,this,g).call(this).split(`?`).slice(1).join(`?`):a(f,this).search;return Object.fromEntries(new URLSearchParams(e))}resolve(e,t,n=!1){let r=a(f,this).origin+this.base+(this.mode===`hash`?`#`:``)+e,i=n?new URLSearchParams(t).toString():new URLSearchParams(d(d({},this.query),t)).toString();return this.url=r+(i?`?`+i:``),this}static resolveTemplatePath(e,t){if(!t||t.startsWith(`/`))return t;let n=e.slice(0,e.lastIndexOf(`/`));if(t.startsWith(`./`))return n+t.slice(1);if(t.startsWith(`../`)){let e=/\.\.\//g,r=t.match(e).length,i=n.split(`/`);for(;r--;)i.pop();return i.length===0&&(i=[``]),[...i,t.replace(e,``)].join(`/`)}return t}};function g(){return a(f,this).hash.slice(1).split(`#`).shift()}function _(){if(this.mode===`hash`&&a(f,this).hash)return r(m,this,g).call(this).split(`?`).shift()||`/`;let e=a(f,this).pathname,t=this.base&&this.base!==`/`?this.base.replace(/\/$/,``):``;return t?e===t?`/`:e.startsWith(t+`/`)?e.slice(t.length)||`/`:e:e}var v=class{static build(e){if(e.indexOf(`:`)===-1)return e;let t=new Set,n=e.split(`/`).map(n=>{if(!n.startsWith(`:`))return n;let r=n.substr(1),i=`[^/]+`,a=r.indexOf(`(`);if(a>-1){if(!r.endsWith(`)`))throw Error(`Malformed route parameter '${n}' in route '${e}'`);i=r.slice(a+1,-1),r=r.slice(0,a)}if(!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(r))throw Error(`Invalid route parameter name ':${r}' in route '${e}'`);if(t.has(r))throw Error(`Duplicate route parameter name ':${r}' in route '${e}'`);return t.add(r),`(?<${r}>${i})`}).join(`/`);try{return RegExp(`^${n}$`)}catch(t){throw Error(`Invalid route pattern '${e}': ${t.message}`)}}static match(e,t){if(t instanceof RegExp){let n=e.match(t);return n?d({},n.groups):!1}return e===t}static is(e,t){return t instanceof RegExp?t.test(e):e===t}},y,b=new WeakMap,x=new WeakMap,S=new WeakMap,C=new WeakMap,w=new WeakSet,T=class{constructor(){t(this,w),n(this,b,{}),n(this,x,new Set),n(this,S,{}),n(this,C,{})}add(e){var t;let n=(t=a(C,this)[e])==null?v.build(e):t;a(C,this)[e]=n,a(b,this)[e]=n,r(w,this,E).call(this,e,n)}match(e){console.assert(e instanceof h);let t=e.path;if(a(x,this).has(t))return{};for(let e of r(w,this,D).call(this,t))for(let[,n]of e){let e=v.match(t,n);if(e)return e===!0?{}:e}return!1}is(e,...t){console.assert(e instanceof h);let n=e.path;for(let e of t){var r,i;let t=(r=(i=a(b,this)[e])==null?a(C,this)[e]:i)==null?v.build(e):r;if(a(C,this)[e]=t,v.is(n,t))return!0}return!1}not(e,...t){console.assert(e instanceof h);let n=e.path;for(let e of t){var r,i;let t=(r=(i=a(b,this)[e])==null?a(C,this)[e]:i)==null?v.build(e):r;if(a(C,this)[e]=t,v.is(n,t))return!1}return!0}notfound(e){console.assert(e instanceof h);let t=e.path;if(a(x,this).has(t))return!1;for(let e of r(w,this,D).call(this,t))for(let[,n]of e)if(v.is(t,n))return!1;return!0}};y=T;function E(e,t){var n,r;if(!(t instanceof RegExp)){a(x,this).add(e);return}let i=A.call(y,e),o=i.length,s=(n=a(S,this)[o])==null?{static:new Map,wildcard:[]}:n,c=i[0],l=c.startsWith(`:`)?s.wildcard:(r=s.static.get(c))==null?[]:r,u=[e,t,k.call(y,e)],d=l.findIndex(([t])=>t===e);d>-1&&l.splice(d,1);let f=l.findIndex(e=>O.call(y,u,e)<0);f===-1&&(f=l.length),l.splice(f,0,u),c.startsWith(`:`)||s.static.set(c,l),a(S,this)[o]=s}function D(e){let t=A.call(y,e),n=a(S,this)[t.length];if(!n)return[];let r=[],i=t[0],o=n.static.get(i);return o&&r.push(o),n.wildcard.length&&r.push(n.wildcard),r}function O([e,,t],[n,,r]){let i=Math.max(t.length,r.length);for(let e=0;e<i;e+=1){var a,o;let n=((a=r[e])==null?0:a)-((o=t[e])==null?0:o);if(n!==0)return n}return n.length-e.length}function k(e){return e.split(`/`).filter(Boolean).map(e=>e.startsWith(`:`)?e.includes(`(`)?2:1:3)}function A(e){return e.split(`/`).filter(Boolean)}function j(e,t){return e===`/`?t===`/`:t===e||t.startsWith(e+`/`)}function M(e,t,n=location.origin){let r;try{r=new URL(t.href,n)}catch(e){return!1}return!(e.defaultPrevented||e.button!==0||e.metaKey||e.altKey||e.ctrlKey||e.shiftKey||t.target&&t.target!==`_self`||t.hasAttribute(`download`)||r.origin!==n)}function N({hasInlineTemplate:e,templateUrl:t,hasCachedTemplate:n,preloadFailed:r}){return t?n?`external`:r&&e?`inline`:`load`:e?`inline`:`missing`}function P(e,t,n=console.error){let r=e.content.firstElementChild;return r?r.nextElementSibling?(n(`Route '${t}' must render exactly one root element`),null):r:null}function F(e){let t=new T,n=0,r=e.reactive({mode:`web`,base:``,href:location.href,path:``,query:{},params:{},loading:!1}),i={get path(){return r.path},get query(){return r.query},get params(){return r.params||{}},get loading(){return r.loading},config(e={}){var t;let n=e.mode!==`hash`&&e.base&&e.base.endsWith(`/`)?e.base.slice(0,-1):e.base;r.mode=(t=e.mode)==null?`web`:t,r.base=n==null?``:n},push(...e){return u(...e)},replace(...e){return d(...e)},resolve(e={}){return c(r.href).resolve(r.path,e).url},is(...e){return t.is(s(r.href),...e)},not(...e){return t.not(s(r.href),...e)},get notfound(){return t.notfound(s(r.href))}};e.$router=i,e.magic(`router`,()=>i);let a,o;function s(e){let t=`${r.mode}|${r.base}|${e}`;return t!==a&&(a=t,o=c(e)),o}function c(e){return new h(e,{mode:r.mode,base:r.base})}function l(){let e=s(r.href);r.path=e.path,r.query=e.query,r.params=t.match(e)}e.effect(()=>l()),e.nextTick(()=>{r.mode===`web`&&!r.base&&l()}),window.addEventListener(`popstate`,()=>r.href=location.href),window.addEventListener(`hashchange`,()=>r.href=location.href);function u(e,t={}){let n=null;try{n=new URL(e)}catch(e){n=null}if(n){if(n.origin!==location.origin){console.error(`Cannot push cross-origin URL '${e}'`);return}}else e=r.mode===`hash`?location.origin+(r.base||`/`)+`#`+e:location.origin+r.base+e;location.href!==e&&(history[t.replace?`replaceState`:`pushState`]({},``,e),r.href=e)}function d(e){u(e,{replace:!0})}function f(e){return n+=1,r.loading=!0,e.finally(()=>{n=Math.max(n-1,0),r.loading=n>0})}function p(e,t,n){console.error(`Failed to load template '${t}' for route '${e}'`,n)}let m=Object.create(null),g=Object.create(null),_=new WeakSet;e.directive(`route`,(n,{modifiers:i,expression:a},{effect:o,cleanup:c})=>{var l;let u=!1;if(!i.includes(`notfound`))try{t.add(a)}catch(e){console.error(e.message),u=!0}let d=e=>(g[e]||(g[e]=fetch(e).then(e=>{if(!e.ok)throw Error(`Failed to fetch template: ${e.status} ${e.statusText}`);return e.text()}).then(t=>(m[e]=t,t)).finally(()=>delete g[e])),g[e].then(e=>(n.innerHTML=e,e))),v=h.resolveTemplatePath(location.pathname,(l=n.getAttribute(`template`))==null?n.getAttribute(`template.preload`):l),y,b=!1;n.hasAttribute(`template.preload`)&&(y=f(d(v)).then(()=>!0).catch(e=>(b=!0,p(a,v,e),!1)).finally(()=>{y=!1}));function x(){if(n._x_currentIfEl)return n._x_currentIfEl;let t=()=>{if(_.has(n))return;let t=P(n,a);if(!t)return;_.add(n);let r=t.cloneNode(!0);e.addScopeToNode(r,{},n),e.mutateDom(()=>{n.after(r),e.initTree(r)}),n._x_currentIfEl=r,n._x_undoIf=()=>{r.remove(),delete n._x_currentIfEl},e.nextTick(()=>_.delete(n))},r=()=>n.content.firstElementChild?(t(),!0):!1,i=N({hasInlineTemplate:!!n.content.firstElementChild,templateUrl:v,hasCachedTemplate:v in m,preloadFailed:b});i===`inline`?r():i===`external`?v in m&&(n.innerHTML=m[v],t()):i===`load`?y?y.then(e=>e?t():r()):f(d(v)).then(()=>t()).catch(e=>{p(a,v,e),r()||console.error(`Template for '${a}' is missing`)}):console.error(`Template for '${a}' is missing`)}function S(){n._x_undoIf&&(n._x_undoIf(),delete n._x_undoIf)}e.nextTick(()=>{o(()=>{if(u){S();return}let e=s(r.href);(i.includes(`notfound`)?t.notfound(e):t.is(e,a))?x():S()})}),c(()=>n._x_undoIf&&n._x_undoIf())}),e.directive(`link`,(e,{modifiers:t,expression:n},{evaluate:i,effect:a,cleanup:o})=>{let l=c(e.href);e.href=l.resolve(l.path,l.query,!0).url;function d(n){M(n,e,location.origin)&&(n.preventDefault(),u(e.href,{replace:t.includes(`replace`)}))}if(e.addEventListener(`click`,d),t.includes(`activity`)){let t=n?i(n):{};t.active!=null||(t.active=`active`),t.exactActive!=null||(t.exactActive=`exact-active`);let o=l.path;a(()=>{let n=s(r.href).path;e.classList.toggle(t.active,j(o,n)),e.classList.toggle(t.exactActive,o===n)})}o(()=>{e.removeEventListener(`click`,d)})})}document.addEventListener(`alpine:init`,()=>{window.Alpine.plugin(F)})})();