@jasonshimmy/custom-elements-runtime 2.4.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("./custom-elements-runtime.cjs.js"),b=require("./namespace-helpers-BsKQl3aH.cjs"),N=require("./custom-elements-runtime.store.cjs.js"),y=require("./logger-DiXdWaF-.cjs"),U=require("./custom-elements-runtime.directives.cjs.js"),j=n=>n?typeof URLSearchParams>"u"?{}:Object.fromEntries(new URLSearchParams(n)):{},T=new WeakMap;function F(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function q(n){if(!n)return"/";let r=n.replace(/\/+/g,"/");return r.startsWith("/")||(r="/"+r),r.length>1&&r.endsWith("/")&&(r=r.slice(0,-1)),r}function I(n){const r=n.path||"/",t=q(r),h=t==="/"?[]:t.split("/").filter(Boolean),o=[],s=[];for(let l=0;l<h.length;l++){const d=h[l];if(d==="*"){if(l!==h.length-1)return y.devWarn(`Route '${n.path}' contains a '*' splat in a non-terminal position; splats must be the last segment. This route will be ignored.`),{invalid:!0};const p=`splat${o.length}`;o.push(p),s.push("__SPLAT__");continue}const R=d.match(/^:([A-Za-z0-9_-]+)(\*)?$/);if(R){const p=R[1],$=!!R[2];if($&&l!==h.length-1)return y.devWarn(`Route '${n.path}' contains a splat param ':${p}*' in a non-terminal position; splats must be the last segment. This route will be ignored.`),{invalid:!0};o.push(p),s.push($?"__SPLAT__":"([^/]+)");continue}s.push(F(d))}let c;if(s.length===0)c="^/$";else if(s[s.length-1]==="__SPLAT__"){const d=s.slice(0,-1).join("/");d?c=`^/${d}(?:/(.*))?(?:/)?$`:c="^(?:/(.*))?(?:/)?$"}else c=`^/${s.join("/")}(?:/)?$`;try{return{regex:new RegExp(c),paramNames:o}}catch(l){return y.devWarn(`Failed to compile route regex for '${n.path}': ${String(l)}`),{invalid:!0}}}const x=(n,r)=>{const t=q(r);for(const h of n){let o=T.get(h);if(o||(o=I(h),T.set(h,o)),o.invalid)continue;const{regex:s,paramNames:c}=o,l=s.exec(t);if(l){const d={},R=p=>{try{return decodeURIComponent(p)}catch{return p}};for(let p=0;p<c.length;p++){const $=l[p+1]||"";d[c[p]]=$?R($):""}return{route:h,params:d}}}return{route:null,params:{}}};function W(n,r){for(const t of n)if(x([t],r).route!==null)return t;return null}const A={};async function B(n){if(n.component)return n.component;if(n.load){if(A[n.path])return A[n.path];try{const r=await n.load();return A[n.path]=r.default,r.default}catch{throw new Error(`Failed to load component for route: ${n.path}`)}}throw new Error(`No component or loader defined for route: ${n.path}`)}function D(n){const{routes:r,base:t="",initialUrl:h}=n;let o,s,c,l,d,R,p;const $=async(f,i)=>{const e=W(r,f.path);if(!e||!e.beforeEnter)return!0;try{const a=await e.beforeEnter(f,i);return typeof a=="string"?(await E(a,!0),!1):a!==!1}catch(a){return y.devError("beforeEnter error",a),!1}},O=async(f,i)=>{const e=W(r,f.path);if(!e||!e.onEnter)return!0;try{const a=await e.onEnter(f,i);return typeof a=="string"?(await E(a,!0),!1):a!==!1}catch(a){return y.devError("onEnter error",a),!1}},_=(f,i)=>{const e=W(r,f.path);if(!(!e||!e.afterEnter))try{e.afterEnter(f,i)}catch(a){y.devError("afterEnter error",a)}},E=async(f,i=!1)=>{try{const e=f.indexOf("#"),a=e>=0?f.slice(e+1):"",u={path:(e>=0?f.slice(0,e):f).replace(t,"")||"/",query:{},fragment:a},m=x(r,u.path);if(!m.route)throw new Error(`No route found for ${u.path}`);const w=c.getState(),S={path:u.path,params:m.params,query:u.query,fragment:u.fragment};if(!await $(S,w)||!await O(S,w))return;typeof window<"u"&&typeof document<"u"&&(i?window.history.replaceState({},"",t+f):window.history.pushState({},"",t+f)),c.setState(S),_(S,w)}catch(e){y.devError("Navigation error:",e)}};if(typeof window<"u"&&typeof document<"u"&&typeof h>"u"){o=()=>{const i=new URL(window.location.href),e=i.pathname.replace(t,"")||"/",a=j(i.search),v=i.hash&&i.hash.length?i.hash.slice(1):"";return{path:e,query:a,fragment:v}},s=o();const f=x(r,s.path);c=N.createStore({path:s.path,params:f.params,query:s.query,fragment:s.fragment}),l=async(i=!1)=>{const e=o();await E(e.path,i)},window.addEventListener("popstate",()=>l(!0)),d=i=>E(i,!1),R=i=>E(i,!0),p=()=>window.history.back()}else{o=()=>{const e=new URL(h||"/","http://localhost"),a=e.pathname.replace(t,"")||"/",v=j(e.search),u=e.hash&&e.hash.length?e.hash.slice(1):"";return{path:a,query:v,fragment:u}},s=o();const f=x(r,s.path);c=N.createStore({path:s.path,params:f.params,query:s.query,fragment:s.fragment}),l=async()=>{const e=o();await i(e.path)};const i=async e=>{try{const a=e.indexOf("#"),v=a>=0?e.slice(a+1):"",m={path:(a>=0?e.slice(0,a):e).replace(t,"")||"/",query:{},fragment:v},w=x(r,m.path);if(!w.route)throw new Error(`No route found for ${m.path}`);const S=c.getState(),k={path:m.path,params:w.params,query:m.query,fragment:m.fragment},P=W(r,k.path);if(P?.beforeEnter){const C=await P.beforeEnter(k,S);if(typeof C=="string"){await i(C);return}if(C===!1)return}if(P?.onEnter){const C=await P.onEnter(k,S);if(typeof C=="string"){await i(C);return}if(C===!1)return}c.setState(k),P?.afterEnter&&P.afterEnter(k,S)}catch(a){throw y.devError("SSR navigation error:",a),a}};d=async e=>i(e),R=async e=>i(e),p=()=>{}}return{store:c,push:d,replace:R,back:p,subscribe:c.subscribe,matchRoute:f=>x(r,f),getCurrent:()=>c.getState(),resolveRouteComponent:B}}function M(n,r){return x(n,r)}let L=null;function z(n){const r=D(n);return L=r,g.component("router-view",async()=>{const t=L||r;if(!t)return g.html`<div>Router not initialized.</div>`;const h=b.ref(t.getCurrent());let o;g.useOnConnected(()=>{try{t&&typeof t.subscribe=="function"&&(o=t.subscribe(c=>{try{h.value=c}catch(l){y.devWarn("router-view subscription update failed",l)}}))}catch(c){y.devWarn("router-view subscribe failed",c)}}),g.useOnDisconnected(()=>{if(typeof o=="function")try{o()}catch(c){y.devWarn("router-view unsubscribe failed",c)}});const s=t.matchRoute(h.value.path);if(!s||!s.route)return g.html`<div>Not found</div>`;try{const l=await t.resolveRouteComponent(s.route);if(typeof l=="string")return{tag:l,props:{},children:[]};if(typeof l=="function"){const d=l();return(d instanceof Promise?d:Promise.resolve(d)).then(p=>typeof p=="string"?{tag:p,props:{},children:[]}:p)}return g.html`<div>Invalid route component</div>`}catch{return g.html`<div>Invalid route component</div>`}}),g.component("router-link",()=>{const t=g.useProps({to:"",tag:"a",replace:!1,exact:!1,activeClass:"active",exactActiveClass:"exact-active",ariaCurrentValue:"page",disabled:!1,external:!1,class:"",style:""}),h=L||r,o=b.ref(h.getCurrent());let s;g.useStyle(()=>"a,button{display:inline-block;}");const c=b.ref(t.class||""),l=b.ref(t.style||"");g.useOnConnected(v=>{try{h&&typeof h.subscribe=="function"&&(s=h.subscribe(u=>{try{o.value=u}catch(m){y.devWarn("router-link subscription update failed",m)}}))}catch(u){y.devWarn("router-link subscribe failed",u)}try{const u=v?._host;if(u instanceof HTMLElement){const m=u.getAttribute("class"),w=u.getAttribute("style");m&&(c.value=m),w&&(l.value=w),m!==null&&u.removeAttribute("class"),w!==null&&u.removeAttribute("style")}}catch(u){y.devWarn("router-link host migration failed",u)}}),g.useOnDisconnected(()=>{if(typeof s=="function")try{s()}catch(v){y.devWarn("router-link unsubscribe failed",v)}});const d=b.computed(()=>{const u=(t.to||"").split("#")[0];try{return q(o.value.path)===q(u)}catch{return o.value.path===u}}),R=b.computed(()=>{const u=(t.to||"").split("#")[0];if(t.exact)return d.value;try{const m=q(o.value.path),w=q(u);return m.startsWith(w)}catch{return o.value&&typeof o.value.path=="string"&&o.value.path.startsWith(u)}}),p=b.computed(()=>{const u=(c&&c.value||t.class||"").split(/\s+/).filter(Boolean),m={};for(const w of u)m[w]=!0;return m}),$=b.computed(()=>({...p.value,[t.activeClass||"active"]:R.value,[t.exactActiveClass||"exact-active"]:d.value})),O=b.computed(()=>Object.keys($.value).filter(v=>$.value[v]).join(" ")),_=b.computed(()=>t.tag==="button"),E=b.computed(()=>d.value?t.ariaCurrentValue:""),f=b.computed(()=>!!t.disabled),i=b.computed(()=>!!t.external&&(t.tag==="a"||!t.tag)),e=b.computed(()=>l&&l.value||t.style||""),a=v=>{if(t.disabled){v.preventDefault();return}t.external&&(t.tag==="a"||!t.tag)||(v.preventDefault(),t.replace?h.replace(t.to):h.push(t.to))};return g.html`
|
|
2
|
-
${
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const A=require("./custom-elements-runtime.cjs.js"),E=require("./namespace-helpers-BsKQl3aH.cjs"),G=require("./custom-elements-runtime.store.cjs.js"),S=require("./logger-DiXdWaF-.cjs"),at=require("./custom-elements-runtime.directives.cjs.js"),F=o=>o?typeof URLSearchParams>"u"?{}:Object.fromEntries(new URLSearchParams(o)):{},et=o=>{if(!o||Object.keys(o).length===0)return"";try{return"?"+new URLSearchParams(o).toString()}catch{return""}},J=o=>o?/^\s*javascript\s*:/i.test(o):!1,tt=new WeakMap;function ot(o){return o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function q(o){if(!o)return"/";let c=o.replace(/\/+/g,"/");return c.startsWith("/")||(c="/"+c),c.length>1&&c.endsWith("/")&&(c=c.slice(0,-1)),c}function st(o){const c=o.path||"/",s=q(c),p=s==="/"?[]:s.split("/").filter(Boolean),h=[],l=[];for(let i=0;i<p.length;i++){const d=p[i];if(d==="*"){if(i!==p.length-1)return S.devWarn(`Route '${o.path}' contains a '*' splat in a non-terminal position; splats must be the last segment. This route will be ignored.`),{invalid:!0};const v=`splat${h.length}`;h.push(v),l.push("__SPLAT__");continue}const b=d.match(/^:([A-Za-z0-9_-]+)(\*)?$/);if(b){const v=b[1],C=!!b[2];if(C&&i!==p.length-1)return S.devWarn(`Route '${o.path}' contains a splat param ':${v}*' in a non-terminal position; splats must be the last segment. This route will be ignored.`),{invalid:!0};h.push(v),l.push(C?"__SPLAT__":"([^/]+)");continue}l.push(ot(d))}let m;if(l.length===0)m="^/$";else if(l[l.length-1]==="__SPLAT__"){const d=l.slice(0,-1).join("/");d?m=`^/${d}(?:/(.*))?(?:/)?$`:m="^(?:/(.*))?(?:/)?$"}else m=`^/${l.join("/")}(?:/)?$`;try{return{regex:new RegExp(m),paramNames:h}}catch(i){return S.devWarn(`Failed to compile route regex for '${o.path}': ${String(i)}`),{invalid:!0}}}const I=(o,c)=>{const s=q(c);for(const p of o){let h=tt.get(p);if(h||(h=st(p),tt.set(p,h)),h.invalid)continue;const{regex:l,paramNames:m}=h,i=l.exec(s);if(i){const d={},b=v=>{try{return decodeURIComponent(v)}catch{return v}};for(let v=0;v<m.length;v++){const C=i[v+1]||"";d[m[v]]=C?b(C):""}return{route:p,params:d}}}return{route:null,params:{}}};function V(o,c){for(const s of o)if(I([s],c).route!==null)return s;return null}const H={};async function rt(o){if(o.component)return o.component;if(o.load){if(H[o.path])return H[o.path];try{const c=await o.load();return H[o.path]=c.default,c.default}catch{throw new Error(`Failed to load component for route: ${o.path}`)}}throw new Error(`No component or loader defined for route: ${o.path}`)}function nt(o){const{routes:c,base:s="",initialUrl:p,scrollToFragment:h=!0}=o,l=(()=>{if(!s)return"";const n=q(s);return n==="/"?"":n})(),m=typeof h=="boolean"?{enabled:!!h,offset:0,timeoutMs:2e3}:{enabled:h.enabled??!0,offset:h.offset??0,timeoutMs:h.timeoutMs??2e3};let i,d,b,v,C,B,D;const Y=async(n,e)=>{const t=V(c,n.path);if(!t||!t.beforeEnter)return!0;try{const r=await t.beforeEnter(n,e);return typeof r=="string"?(await y(r,!0),!1):r!==!1}catch(r){return S.devError("beforeEnter error",r),!1}},Q=async(n,e)=>{const t=V(c,n.path);if(!t||!t.onEnter)return!0;try{const r=await t.onEnter(n,e);return typeof r=="string"?(await y(r,!0),!1):r!==!1}catch(r){return S.devError("onEnter error",r),!1}},Z=(n,e)=>{const t=V(c,n.path);if(!(!t||!t.afterEnter))try{t.afterEnter(n,e)}catch(r){S.devError("afterEnter error",r)}};let g=0,O=null,P=null,L=null;async function a(n,e=0){try{const t=document.getElementById(n);if(!t)return!1;if(e&&e>0)try{const r=t.getBoundingClientRect(),$=Math.max(0,window.scrollY+r.top-e);typeof window.scrollTo=="function"&&window.scrollTo({top:$,behavior:"auto"})}catch{try{t.scrollIntoView()}catch{}}else if(typeof t.scrollIntoView=="function")try{t.scrollIntoView({behavior:"auto",block:"start",inline:"nearest"})}catch{try{t.scrollIntoView()}catch{}}return!0}catch{return!1}}function u(){if(O){try{O.disconnect()}catch{}O=null}if(P){try{clearTimeout(P)}catch{}P=null}}function w(n,e,t){g+=1;const r=g;if(L){try{L(!1)}catch{}L=null}return u(),new Promise($=>{L=$;const f=W=>{if(r===g){u();try{$(W)}finally{L=null}}};queueMicrotask(async()=>{if(r!==g)return f(!1);if(await a(n,e))return f(!0);if(typeof window.requestAnimationFrame=="function")window.requestAnimationFrame(async()=>{if(r!==g)return f(!1);if(await a(n,e))return f(!0);if(r!==g)return f(!1);const W=document.querySelector("router-view")||document.body;try{const _=new MutationObserver(async()=>{r===g&&await a(n,e)&&f(!0)});O=_,_.observe(W,{childList:!0,subtree:!0,attributes:!1}),P=window.setTimeout(()=>{if(r===g){try{_.disconnect()}catch{}O=null,P=null,f(!1)}},t??2e3)}catch{let R=0;const x=async()=>{if(r!==g)return f(!1);if(await a(n,e))return f(!0);R+=1,R<40?window.setTimeout(x,50):f(!1)};x()}});else{const W=document.querySelector("router-view")||document.body;try{const _=new MutationObserver(async()=>{r===g&&await a(n,e)&&f(!0)});O=_,_.observe(W,{childList:!0,subtree:!0,attributes:!1}),P=window.setTimeout(()=>{if(r===g){try{_.disconnect()}catch{}O=null,P=null,f(!1)}},t??2e3)}catch{let R=0;const x=async()=>{if(r!==g)return f(!1);if(await a(n,e))return f(!0);R+=1,R<40?window.setTimeout(x,50):f(!1)};x()}}})})}const y=async(n,e=!1)=>{try{const t=n.indexOf("#"),r=t>=0?n.slice(t+1):"",$=t>=0?n.slice(0,t):n,f=$.indexOf("?"),T=f>=0?$.slice(0,f):$,W=f>=0?F($.slice(f)):{},_=T.startsWith(l)?T.slice(l.length):T,R={path:q(_||"/"),query:W,fragment:r},x=I(c,R.path);if(!x.route)throw new Error(`No route found for ${R.path}`);const N=b.getState(),z={path:R.path,params:x.params,query:R.query,fragment:R.fragment};if(!await Y(z,N)||!await Q(z,N))return;if(typeof window<"u"&&typeof document<"u"){const k=et(R.query),X=l+R.path+(k||"")+(R.fragment?"#"+R.fragment:"");e?window.history.replaceState({},"",X):window.history.pushState({},"",X)}b.setState(z),Z(z,N);try{const k=z.fragment;m.enabled&&k&&typeof window<"u"&&typeof document<"u"&&w(String(k),m.offset,m.timeoutMs).catch(()=>{})}catch{}}catch(t){S.devError("Navigation error:",t)}};if(typeof window<"u"&&typeof document<"u"&&typeof p>"u"){i=()=>{const e=new URL(window.location.href),t=e.pathname,r=t.startsWith(l)?t.slice(l.length):t,$=q(r||"/"),f=F(e.search),T=e.hash&&e.hash.length?e.hash.slice(1):"";return{path:$,query:f,fragment:T}},d=i();const n=I(c,d.path);b=G.createStore({path:d.path,params:n.params,query:d.query,fragment:d.fragment}),v=async(e=!1)=>{const t=i();await y(t.path,e)},window.addEventListener("popstate",()=>v(!0)),C=e=>y(e,!1),B=e=>y(e,!0),D=()=>window.history.back()}else{i=()=>{const t=new URL(p||"/","http://localhost"),r=t.pathname,$=r.startsWith(l)?r.slice(l.length):r,f=q($||"/"),T=F(t.search),W=t.hash&&t.hash.length?t.hash.slice(1):"";return{path:f,query:T,fragment:W}},d=i();const n=I(c,d.path);b=G.createStore({path:d.path,params:n.params,query:d.query,fragment:d.fragment}),v=async()=>{const t=i();await e(t.path)};const e=async t=>{try{const r=t.indexOf("#"),$=r>=0?t.slice(r+1):"",f=r>=0?t.slice(0,r):t,T=f.indexOf("?"),W=T>=0?f.slice(0,T):f,_=T>=0?F(f.slice(T)):{},U=W.startsWith(l)?W.slice(l.length):W,x={path:q(U||"/"),query:_,fragment:$},N=I(c,x.path);if(!N.route)throw new Error(`No route found for ${x.path}`);const z=b.getState(),j={path:x.path,params:N.params,query:x.query,fragment:x.fragment},M=V(c,j.path);if(M?.beforeEnter){const k=await M.beforeEnter(j,z);if(typeof k=="string"){await e(k);return}if(k===!1)return}if(M?.onEnter){const k=await M.onEnter(j,z);if(typeof k=="string"){await e(k);return}if(k===!1)return}b.setState(j),M?.afterEnter&&M.afterEnter(j,z)}catch(r){throw S.devError("SSR navigation error:",r),r}};C=async t=>e(t),B=async t=>e(t),D=()=>{}}return{store:b,push:C,replace:B,back:D,subscribe:b.subscribe,matchRoute:n=>I(c,n),getCurrent:()=>b.getState(),resolveRouteComponent:rt,base:l,scrollToFragment:n=>{const e=n||b.getState().fragment;return!e||typeof window>"u"||typeof document>"u"?Promise.resolve(!1):w(String(e),m.offset,m.timeoutMs)}}}function ct(o,c){return I(o,c)}let K=null;function it(o){const c=nt(o);return K=c,A.component("router-view",async()=>{const s=K||c;if(!s)return A.html`<div>Router not initialized.</div>`;const p=E.ref(s.getCurrent());let h;A.useOnConnected(()=>{try{s&&typeof s.subscribe=="function"&&(h=s.subscribe(m=>{try{p.value=m}catch(i){S.devWarn("router-view subscription update failed",i)}}))}catch(m){S.devWarn("router-view subscribe failed",m)}}),A.useOnDisconnected(()=>{if(typeof h=="function")try{h()}catch(m){S.devWarn("router-view unsubscribe failed",m)}});const l=s.matchRoute(p.value.path);if(!l||!l.route)return A.html`<div>Not found</div>`;try{const i=await s.resolveRouteComponent(l.route);if(typeof i=="string")return{tag:i,props:{},children:[]};if(typeof i=="function"){const d=i();return(d instanceof Promise?d:Promise.resolve(d)).then(v=>typeof v=="string"?{tag:v,props:{},children:[]}:v)}return A.html`<div>Invalid route component</div>`}catch{return A.html`<div>Invalid route component</div>`}}),A.component("router-link",()=>{const s=A.useProps({to:"",tag:"a",replace:!1,exact:!1,activeClass:"active",exactActiveClass:"exact-active",ariaCurrentValue:"page",disabled:!1,external:!1,class:"",style:""}),p=K||c,h=E.ref(p.getCurrent());let l;A.useStyle(()=>"a,button{display:inline-block;}");const m=E.ref(s.class||""),i=E.ref(s.style||"");A.useOnConnected(a=>{try{p&&typeof p.subscribe=="function"&&(l=p.subscribe(u=>{try{h.value=u}catch(w){S.devWarn("router-link subscription update failed",w)}}))}catch(u){S.devWarn("router-link subscribe failed",u)}try{const u=a?._host;if(u instanceof HTMLElement){const w=u.getAttribute("class"),y=u.getAttribute("style");w&&(m.value=w),y&&(i.value=y),w!==null&&u.removeAttribute("class"),y!==null&&u.removeAttribute("style")}}catch(u){S.devWarn("router-link host migration failed",u)}}),A.useOnDisconnected(()=>{if(typeof l=="function")try{l()}catch(a){S.devWarn("router-link unsubscribe failed",a)}});const d=E.computed(()=>{const a=p?.base??"",u=s.to||"";if(/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(u)||u.startsWith("//"))return!1;const w=(u.split("#")[0]||"/").split("?")[0];try{let y=w;a&&y.startsWith(a)&&(y=y.slice(a.length)||"/");const n=q(h.value.path),e=q(y);return n===e}catch{return h.value.path===w}}),b=E.computed(()=>{const a=p?.base??"",u=s.to||"";if(/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(u)||u.startsWith("//"))return!1;const w=(u.split("#")[0]||"/").split("?")[0];if(s.exact)return d.value;try{let y=w;a&&y.startsWith(a)&&(y=y.slice(a.length)||"/");const n=q(h.value.path),e=q(y);return e==="/"?n==="/":n===e?!0:n.startsWith(e.endsWith("/")?e:e+"/")}catch{return h.value&&typeof h.value.path=="string"&&h.value.path.startsWith(w)}}),v=E.computed(()=>{const a=String(s.to||"");if(J(a))return null;if(/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(a)||a.startsWith("//"))return a;const[u,w]=a.split("#"),[y,n]=(u||"").split("?"),e=p?.base??"";let t=y||"/";e&&t.startsWith(e)&&(t=t.slice(e.length)||"/");const r=q(t||"/");return e+r+(n?"?"+n:"")+(w?"#"+w:"")}),C=E.computed(()=>{const u=(m&&m.value||s.class||"").split(/\s+/).filter(Boolean),w={};for(const y of u)w[y]=!0;return w}),B=E.computed(()=>({...C.value,[s.activeClass||"active"]:b.value,[s.exactActiveClass||"exact-active"]:d.value})),D=E.computed(()=>Object.keys(B.value).filter(a=>B.value[a]).join(" ")),Y=E.computed(()=>s.tag||"a"),Q=E.computed(()=>Y.value==="button"),Z=E.computed(()=>d.value?s.ariaCurrentValue:null),g=E.computed(()=>!!s.disabled),O=E.computed(()=>{const a=String(s.to||"");return(/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(a)||a.startsWith("//")||!!s.external)&&Y.value==="a"}),P=E.computed(()=>i&&i.value||s.style||""),L=a=>{if(a.defaultPrevented||a.button!==0||a.metaKey||a.altKey||a.ctrlKey||a.shiftKey)return;if(g.value){a.preventDefault();return}const u=String(s.to||"");if(J(u)){try{a.preventDefault()}catch{}S.devWarn("Blocked unsafe javascript: URI in router-link.to");return}O.value||(a.preventDefault(),s.replace?p.replace(s.to):p.push(s.to))};return A.html`
|
|
2
|
+
${at.match().when(Q.value,A.html`
|
|
3
3
|
<button
|
|
4
4
|
part="button"
|
|
5
|
-
class="${
|
|
6
|
-
style="${
|
|
7
|
-
aria-current="${
|
|
8
|
-
disabled="${
|
|
9
|
-
aria-disabled="${
|
|
10
|
-
tabindex="${
|
|
11
|
-
@click="${
|
|
5
|
+
class="${D.value}"
|
|
6
|
+
style="${P.value||null}"
|
|
7
|
+
aria-current="${Z.value}"
|
|
8
|
+
disabled="${g.value?"":null}"
|
|
9
|
+
aria-disabled="${g.value?"true":null}"
|
|
10
|
+
tabindex="${g.value?"-1":null}"
|
|
11
|
+
@click="${L}"
|
|
12
12
|
>
|
|
13
13
|
<slot></slot>
|
|
14
14
|
</button>
|
|
15
|
-
`).otherwise(
|
|
15
|
+
`).otherwise(A.html`
|
|
16
16
|
<a
|
|
17
17
|
part="link"
|
|
18
|
-
href="${
|
|
19
|
-
class="${
|
|
20
|
-
style="${
|
|
21
|
-
aria-current="${
|
|
22
|
-
aria-disabled="${
|
|
23
|
-
tabindex="${
|
|
24
|
-
target="${
|
|
25
|
-
rel="${
|
|
26
|
-
@click="${
|
|
18
|
+
href="${g.value?null:v.value}"
|
|
19
|
+
class="${D.value}"
|
|
20
|
+
style="${P.value||null}"
|
|
21
|
+
aria-current="${Z.value}"
|
|
22
|
+
aria-disabled="${g.value?"true":null}"
|
|
23
|
+
tabindex="${g.value?"-1":null}"
|
|
24
|
+
target="${O.value?"_blank":null}"
|
|
25
|
+
rel="${O.value?"noopener noreferrer":null}"
|
|
26
|
+
@click="${L}"
|
|
27
27
|
><slot></slot
|
|
28
28
|
></a>
|
|
29
29
|
`).done()}
|
|
30
|
-
`}),
|
|
30
|
+
`}),c}exports.initRouter=it;exports.matchRoute=I;exports.matchRouteSSR=ct;exports.normalizePathForRoute=q;exports.parseQuery=F;exports.resolveRouteComponent=rt;exports.serializeQuery=et;exports.useRouter=nt;
|
|
31
31
|
//# sourceMappingURL=custom-elements-runtime.router.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom-elements-runtime.router.cjs.js","sources":["../src/lib/router.ts"],"sourcesContent":["import { html } from './runtime/template-compiler';\nimport { component } from './runtime/component';\nimport {\n useProps,\n useOnConnected,\n useOnDisconnected,\n useStyle,\n} from './runtime/hooks';\nimport { ref, computed } from './runtime/reactive';\nimport { createStore, type Store } from './store';\nimport { devError, devWarn } from './runtime/logger';\nimport { match } from './directives';\n\nexport type RouteComponent =\n | { new (...args: unknown[]): unknown } // class components\n | ((...args: unknown[]) => unknown); // functional components\n\nexport interface RouteState {\n path: string;\n params: Record<string, string>;\n query: Record<string, string>;\n // Optional fragment (hash) portion of the URL, without the leading '#'\n fragment?: string;\n}\n\nexport type GuardResult = boolean | string | Promise<boolean | string>;\n\nexport interface Route {\n path: string;\n\n /**\n * Statically available component (already imported)\n */\n component?: string | (() => unknown);\n\n /**\n * Lazy loader that resolves to something renderable\n */\n load?: () => Promise<{\n default: string | HTMLElement | ((...args: unknown[]) => unknown);\n }>;\n\n /**\n * Runs before matching — return false to cancel,\n * or a string to redirect\n */\n beforeEnter?: (to: RouteState, from: RouteState) => GuardResult;\n\n /**\n * Runs right before navigation commits — can cancel or redirect\n */\n onEnter?: (to: RouteState, from: RouteState) => GuardResult;\n\n /**\n * Runs after navigation completes — cannot cancel\n */\n afterEnter?: (to: RouteState, from: RouteState) => void;\n}\n\nexport interface RouterLinkProps {\n to: string;\n tag: string;\n replace: boolean;\n exact: boolean;\n activeClass: string;\n exactActiveClass: string;\n ariaCurrentValue: string;\n disabled: boolean;\n external: boolean;\n class?: string;\n style?: string;\n}\n\nexport interface RouterLinkComputed {\n current: RouteState;\n isExactActive: boolean;\n isActive: boolean;\n className: string;\n ariaCurrent: string;\n isButton: boolean;\n disabledAttr: string;\n externalAttr: string;\n}\n\nexport interface RouterConfig {\n routes: Route[];\n base?: string;\n initialUrl?: string; // For SSR: explicitly pass the URL\n}\n\nexport const parseQuery = (search: string): Record<string, string> => {\n if (!search) return {};\n if (typeof URLSearchParams === 'undefined') return {};\n return Object.fromEntries(new URLSearchParams(search));\n};\n\n// Cache compiled route regexes to avoid rebuilding on every navigation.\ntype CompiledRoute =\n | { regex: RegExp; paramNames: string[] }\n | { invalid: true };\nconst compileCache: WeakMap<Route, CompiledRoute> = new WeakMap();\n\nfunction escapeSeg(seg: string) {\n return seg.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function normalizePathForRoute(p: string) {\n if (!p) return '/';\n // Collapse duplicate slashes, ensure leading slash, remove trailing slash\n let out = p.replace(/\\/+/g, '/');\n if (!out.startsWith('/')) out = '/' + out;\n if (out.length > 1 && out.endsWith('/')) out = out.slice(0, -1);\n return out;\n}\n\nfunction compileRoute(route: Route): CompiledRoute {\n const raw = route.path || '/';\n const routePath = normalizePathForRoute(raw);\n\n const segments =\n routePath === '/' ? [] : routePath.split('/').filter(Boolean);\n\n const paramNames: string[] = [];\n const regexParts: string[] = [];\n\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i];\n\n // Anonymous wildcard\n if (seg === '*') {\n // splat must be terminal\n if (i !== segments.length - 1) {\n devWarn(\n `Route '${route.path}' contains a '*' splat in a non-terminal position; splats must be the last segment. This route will be ignored.`,\n );\n return { invalid: true };\n }\n const name = `splat${paramNames.length}`;\n paramNames.push(name);\n // mark splat token; pattern will be built specially so the\n // preceding slash can be optional (allow empty splat)\n regexParts.push('__SPLAT__');\n continue;\n }\n\n const paramMatch = seg.match(/^:([A-Za-z0-9_-]+)(\\*)?$/);\n if (paramMatch) {\n const name = paramMatch[1];\n const isSplat = !!paramMatch[2];\n // If splat, ensure terminal\n if (isSplat && i !== segments.length - 1) {\n devWarn(\n `Route '${route.path}' contains a splat param ':${name}*' in a non-terminal position; splats must be the last segment. This route will be ignored.`,\n );\n return { invalid: true };\n }\n paramNames.push(name);\n regexParts.push(isSplat ? '__SPLAT__' : '([^/]+)');\n continue;\n }\n\n // Static\n regexParts.push(escapeSeg(seg));\n }\n\n let pattern: string;\n if (regexParts.length === 0) {\n pattern = '^/$';\n } else {\n const last = regexParts[regexParts.length - 1];\n if (last === '__SPLAT__') {\n const prefix = regexParts.slice(0, -1).join('/');\n if (!prefix) {\n // route is like '/:rest*' or '/*' -> allow '/' or '/x' etc.\n pattern = '^(?:/(.*))?(?:/)?$';\n } else {\n pattern = `^/${prefix}(?:/(.*))?(?:/)?$`;\n }\n } else {\n pattern = `^/${regexParts.join('/')}(?:/)?$`;\n }\n }\n try {\n const regex = new RegExp(pattern);\n return { regex, paramNames };\n } catch (e) {\n devWarn(`Failed to compile route regex for '${route.path}': ${String(e)}`);\n return { invalid: true };\n }\n}\n\nexport const matchRoute = (\n routes: Route[],\n path: string,\n): { route: Route | null; params: Record<string, string> } => {\n const incoming = normalizePathForRoute(path);\n\n for (const route of routes) {\n let compiled = compileCache.get(route);\n if (!compiled) {\n compiled = compileRoute(route);\n compileCache.set(route, compiled);\n }\n\n if ((compiled as { invalid?: true }).invalid) continue;\n\n const { regex, paramNames } = compiled as {\n regex: RegExp;\n paramNames: string[];\n };\n const m = regex.exec(incoming);\n if (m) {\n const params: Record<string, string> = {};\n const safeDecode = (v: string) => {\n try {\n return decodeURIComponent(v);\n } catch {\n return v;\n }\n };\n\n for (let i = 0; i < paramNames.length; i++) {\n const raw = m[i + 1] || '';\n params[paramNames[i]] = raw ? safeDecode(raw) : '';\n }\n\n return { route, params };\n }\n }\n\n return { route: null, params: {} };\n};\n\n/**\n * Find the first route that matches the given path.\n * Consolidates repeated inline checks like `routes.find(r => matchRoute([r], path).route !== null)`\n */\nfunction findMatchedRoute(routes: Route[], path: string): Route | null {\n for (const r of routes) {\n if (matchRoute([r], path).route !== null) return r;\n }\n return null;\n}\n\n// Async component loader cache\nconst componentCache: Record<\n string,\n string | HTMLElement | ((...args: unknown[]) => unknown)\n> = {};\n\n/**\n * Loads a route's component, supporting both static and async.\n * @param route Route object\n * @returns Promise resolving to the component\n */\nexport async function resolveRouteComponent(\n route: Route,\n): Promise<string | HTMLElement | ((...args: unknown[]) => unknown)> {\n if (route.component) return route.component;\n if (route.load) {\n if (componentCache[route.path]) return componentCache[route.path];\n try {\n const mod = await route.load();\n componentCache[route.path] = mod.default;\n return mod.default;\n } catch {\n throw new Error(`Failed to load component for route: ${route.path}`);\n }\n }\n throw new Error(`No component or loader defined for route: ${route.path}`);\n}\n\nexport function useRouter(config: RouterConfig) {\n const { routes, base = '', initialUrl } = config;\n\n let getLocation: () => { path: string; query: Record<string, string> };\n let initial: { path: string; query: Record<string, string> };\n let store: Store<RouteState>;\n let update: (replace?: boolean) => Promise<void>;\n let push: (path: string) => Promise<void>;\n let replaceFn: (path: string) => Promise<void>;\n let back: () => void;\n\n // Run matching route guards/hooks\n const runBeforeEnter = async (to: RouteState, from: RouteState) => {\n const matched = findMatchedRoute(routes, to.path);\n if (!matched || !matched.beforeEnter) return true;\n try {\n const result = await matched.beforeEnter(to, from);\n if (typeof result === 'string') {\n // Redirect\n await navigate(result, true);\n return false;\n }\n return result !== false;\n } catch (err) {\n devError('beforeEnter error', err);\n return false;\n }\n };\n\n const runOnEnter = async (to: RouteState, from: RouteState) => {\n const matched = findMatchedRoute(routes, to.path);\n if (!matched || !matched.onEnter) return true;\n try {\n const result = await matched.onEnter(to, from);\n if (typeof result === 'string') {\n await navigate(result, true);\n return false;\n }\n return result !== false;\n } catch (err) {\n devError('onEnter error', err);\n return false;\n }\n };\n\n const runAfterEnter = (to: RouteState, from: RouteState) => {\n const matched = findMatchedRoute(routes, to.path);\n if (!matched || !matched.afterEnter) return;\n try {\n matched.afterEnter(to, from);\n } catch (err) {\n devError('afterEnter error', err);\n }\n };\n\n const navigate = async (path: string, replace = false) => {\n try {\n // Separate fragment (hash) from path so matching ignores it while\n // the fragment is preserved on the RouteState.\n const hashIndex = path.indexOf('#');\n const fragment = hashIndex >= 0 ? path.slice(hashIndex + 1) : '';\n const rawPath = hashIndex >= 0 ? path.slice(0, hashIndex) : path;\n const loc = {\n path: rawPath.replace(base, '') || '/',\n query: {},\n fragment,\n };\n const match = matchRoute(routes, loc.path);\n if (!match.route) throw new Error(`No route found for ${loc.path}`);\n\n const from = store.getState();\n const to: RouteState = {\n path: loc.path,\n params: match.params,\n query: loc.query,\n fragment: (loc as { fragment?: string }).fragment,\n };\n\n // beforeEnter guard\n const allowedBefore = await runBeforeEnter(to, from);\n if (!allowedBefore) return;\n\n // onEnter guard (right before commit)\n const allowedOn = await runOnEnter(to, from);\n if (!allowedOn) return;\n\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n if (replace) {\n window.history.replaceState({}, '', base + path);\n } else {\n window.history.pushState({}, '', base + path);\n }\n }\n\n store.setState(to);\n\n // afterEnter hook (post commit)\n runAfterEnter(to, from);\n } catch (err) {\n devError('Navigation error:', err);\n }\n };\n\n // If an explicit `initialUrl` is provided we treat this as SSR/static rendering\n // even if a `window` exists (useful for hydration tests). Browser mode only\n // applies when `initialUrl` is undefined.\n if (\n typeof window !== 'undefined' &&\n typeof document !== 'undefined' &&\n typeof initialUrl === 'undefined'\n ) {\n // Browser mode\n getLocation = () => {\n const url = new URL(window.location.href);\n const path = url.pathname.replace(base, '') || '/';\n const query = parseQuery(url.search);\n const fragment = url.hash && url.hash.length ? url.hash.slice(1) : '';\n return { path, query, fragment };\n };\n\n initial = getLocation();\n const match = matchRoute(routes, initial.path);\n store = createStore<RouteState>({\n path: initial.path,\n params: match.params,\n query: initial.query,\n fragment: (initial as { fragment?: string }).fragment,\n });\n\n update = async (replace = false) => {\n const loc = getLocation();\n await navigate(loc.path, replace);\n };\n\n window.addEventListener('popstate', () => update(true));\n\n push = (path: string) => navigate(path, false);\n replaceFn = (path: string) => navigate(path, true);\n back = () => window.history.back();\n } else {\n // SSR mode\n getLocation = () => {\n const url = new URL(initialUrl || '/', 'http://localhost');\n const path = url.pathname.replace(base, '') || '/';\n const query = parseQuery(url.search);\n const fragment = url.hash && url.hash.length ? url.hash.slice(1) : '';\n return { path, query, fragment };\n };\n\n initial = getLocation();\n const match = matchRoute(routes, initial.path);\n store = createStore<RouteState>({\n path: initial.path,\n params: match.params,\n query: initial.query,\n fragment: (initial as { fragment?: string }).fragment,\n });\n\n update = async () => {\n const loc = getLocation();\n await navigateSSR(loc.path);\n };\n\n // SSR navigation contract:\n // - `push` / `replace` call into `navigateSSR` and return a Promise.\n // - On the server we intentionally surface navigation failures so\n // server-side logic (or tests) can react: missing routes or thrown\n // errors from `beforeEnter`/`onEnter` will cause the Promise to\n // reject. This lets the server render 404s or abort builds.\n // - For valid routes the server-side navigation resolves and updates\n // the internal store state so rendered output matches the target\n // path. The `back()` operation is client-only and is a synchronous\n // no-op in SSR mode.\n const navigateSSR = async (path: string) => {\n try {\n const hashIndex = path.indexOf('#');\n const fragment = hashIndex >= 0 ? path.slice(hashIndex + 1) : '';\n const rawPath = hashIndex >= 0 ? path.slice(0, hashIndex) : path;\n const loc = {\n path: rawPath.replace(base, '') || '/',\n query: {},\n fragment,\n };\n const match = matchRoute(routes, loc.path);\n // In SSR mode we intentionally surface navigation errors (missing\n // route) to the caller so server-side logic may handle them. If no\n // route matches, throw and let the caller observe the rejection.\n if (!match.route) throw new Error(`No route found for ${loc.path}`);\n\n const from = store.getState();\n const to: RouteState = {\n path: loc.path,\n params: match.params,\n query: loc.query,\n fragment: (loc as { fragment?: string }).fragment,\n };\n\n // beforeEnter guard\n const matched = findMatchedRoute(routes, to.path);\n if (matched?.beforeEnter) {\n const result = await matched.beforeEnter(to, from);\n if (typeof result === 'string') {\n // Redirect\n await navigateSSR(result);\n return;\n }\n if (result === false) return;\n }\n\n // onEnter guard\n if (matched?.onEnter) {\n const result = await matched.onEnter(to, from);\n if (typeof result === 'string') {\n await navigateSSR(result);\n return;\n }\n if (result === false) return;\n }\n\n store.setState(to);\n\n // afterEnter hook\n if (matched?.afterEnter) {\n matched.afterEnter(to, from);\n }\n } catch (err) {\n // Surface SSR navigation errors so callers (and tests) can observe\n // failures during server-side resolution.\n devError('SSR navigation error:', err);\n throw err;\n }\n };\n\n push = async (path: string) => navigateSSR(path);\n replaceFn = async (path: string) => navigateSSR(path);\n back = () => {};\n }\n\n return {\n store,\n push,\n replace: replaceFn,\n back,\n subscribe: store.subscribe,\n matchRoute: (path: string) => matchRoute(routes, path),\n getCurrent: (): RouteState => store.getState(),\n resolveRouteComponent,\n };\n}\n\n// SSR/static site support: match route for a given path\nexport function matchRouteSSR(routes: Route[], path: string) {\n return matchRoute(routes, path);\n}\n\n// Module-level reference to the latest initialized router. Tests and\n// components may rely on re-initializing the router during their setup,\n// so exposing this lets components pick up the most recent instance.\nlet activeRouter: ReturnType<typeof useRouter> | null = null;\n\n/**\n * Singleton router instance for global access.\n *\n * Define here to prevent circular dependency\n * issue with component.\n */\n\nexport function initRouter(config: RouterConfig) {\n const router = useRouter(config);\n // Expose the most recently initialized router to components defined\n // earlier in the process (tests may call initRouter multiple times).\n // Components reference `activeRouter` so re-calling initRouter updates\n // the router instance they use.\n activeRouter = router;\n\n component('router-view', async () => {\n // Prefer the latest initialized router (tests may re-init). Fallback\n // to the router captured at init time.\n const r = activeRouter || router;\n // Reactive current route so the component re-renders when router updates\n if (!r) return html`<div>Router not initialized.</div>`;\n\n const current = ref(r.getCurrent());\n\n // We'll capture the unsubscribe function when the component connects\n // and register a disconnect cleanup during render-time (useOnDisconnected\n // must be called during the component render/execution).\n let unsubRouterView: (() => void) | undefined;\n\n useOnConnected(() => {\n try {\n if (r && typeof r.subscribe === 'function') {\n unsubRouterView = r.subscribe((s) => {\n try {\n current.value = s;\n } catch (e) {\n devWarn('router-view subscription update failed', e);\n }\n });\n }\n } catch (e) {\n devWarn('router-view subscribe failed', e);\n }\n });\n\n useOnDisconnected(() => {\n if (typeof unsubRouterView === 'function') {\n try {\n unsubRouterView();\n } catch (e) {\n devWarn('router-view unsubscribe failed', e);\n }\n }\n });\n\n const match = r.matchRoute(current.value.path);\n if (!match || !match.route) return html`<div>Not found</div>`;\n\n // Resolve the component (supports cached async loaders)\n try {\n const compRaw = await r.resolveRouteComponent(match.route);\n const comp = compRaw as\n | string\n | HTMLElement\n | ((...args: unknown[]) => unknown)\n | undefined;\n // String tag (custom element) -> render as VNode\n if (typeof comp === 'string') {\n return { tag: comp, props: {}, children: [] };\n }\n\n // Function component (sync or async) -> call and return its VNode(s)\n if (typeof comp === 'function') {\n const out = comp();\n const resolved = out instanceof Promise ? out : Promise.resolve(out);\n return resolved.then((resolvedComp) => {\n if (typeof resolvedComp === 'string')\n return { tag: resolvedComp, props: {}, children: [] };\n return resolvedComp;\n });\n }\n\n return html`<div>Invalid route component</div>`;\n } catch {\n return html`<div>Invalid route component</div>`;\n }\n });\n\n component('router-link', () => {\n // Declare props via useProps so observedAttributes are correct\n const props = useProps<Partial<RouterLinkProps>>({\n to: '',\n tag: 'a',\n replace: false,\n exact: false,\n activeClass: 'active',\n exactActiveClass: 'exact-active',\n ariaCurrentValue: 'page',\n disabled: false,\n external: false,\n // allow host `class` and `style` attributes to be read via useProps\n class: '',\n style: '',\n });\n\n // Prefer the latest initialized router (tests may re-init). Fallback\n // to the router captured at init time.\n const r = activeRouter || router;\n // Reactive current state so link updates when route changes\n const current = ref(r.getCurrent());\n // Capture unsubscribe for link subscriptions and register disconnect\n // cleanup during render time.\n let unsubRouterLink: (() => void) | undefined;\n\n // Keep a minimal internal host-scoped style for element display.\n // Host `style` will be applied to the inner anchor/button element.\n useStyle(() => `a,button{display:inline-block;}`);\n\n // We capture host attributes at connection time and migrate them to\n // internal refs so we can remove them from the host. This prevents\n // global/author CSS targeting the host from styling the host element\n // itself while still allowing authors to use `class`/`style` on the\n // router-link to style the inner anchor/button.\n const hostClassRef = ref((props.class as string) || '');\n const hostStyleRef = ref((props.style as string) || '');\n\n useOnConnected((ctx?: unknown) => {\n try {\n if (r && typeof r.subscribe === 'function') {\n unsubRouterLink = r.subscribe((s) => {\n try {\n current.value = s;\n } catch (e) {\n devWarn('router-link subscription update failed', e);\n }\n });\n }\n } catch (e) {\n devWarn('router-link subscribe failed', e);\n }\n\n // Migrate host `class`/`style` into internal refs and remove them\n // from the host so only the inner element is styled.\n try {\n const host = (ctx as { _host?: HTMLElement } | undefined)?._host;\n if (host instanceof HTMLElement) {\n const hc = host.getAttribute('class');\n const hs = host.getAttribute('style');\n if (hc) hostClassRef.value = hc;\n if (hs) hostStyleRef.value = hs;\n // Remove attributes from host to avoid styling the host\n if (hc !== null) host.removeAttribute('class');\n if (hs !== null) host.removeAttribute('style');\n }\n } catch (e) {\n devWarn('router-link host migration failed', e);\n }\n });\n\n useOnDisconnected(() => {\n if (typeof unsubRouterLink === 'function') {\n try {\n unsubRouterLink();\n } catch (e) {\n devWarn('router-link unsubscribe failed', e);\n }\n }\n });\n\n const isExactActive = computed(() => {\n const targetRaw = (props.to as string) || '';\n // strip fragment from target when comparing\n const targetPathOnly = targetRaw.split('#')[0];\n try {\n return (\n normalizePathForRoute(current.value.path) ===\n normalizePathForRoute(targetPathOnly)\n );\n } catch {\n return current.value.path === targetPathOnly;\n }\n });\n\n const isActive = computed(() => {\n const targetRaw = (props.to as string) || '';\n const targetPathOnly = targetRaw.split('#')[0];\n if (props.exact) return isExactActive.value;\n try {\n const cur = normalizePathForRoute(current.value.path);\n const tgt = normalizePathForRoute(targetPathOnly);\n return cur.startsWith(tgt);\n } catch {\n return (\n current.value &&\n typeof current.value.path === 'string' &&\n current.value.path.startsWith(targetPathOnly)\n );\n }\n });\n\n // Build user classes reactively from the host `class` attribute prop.\n // We intentionally apply classes to the inner element so the consumer\n // can style the link via `class=\"...\"`.\n const userClasses = computed(() => {\n const rawHost =\n (hostClassRef && hostClassRef.value) || (props.class as string) || '';\n const list = rawHost.split(/\\s+/).filter(Boolean);\n const map: Record<string, boolean> = {};\n for (const c of list) map[c] = true;\n return map;\n });\n\n const classObject = computed(() => ({\n ...userClasses.value,\n [(props.activeClass as string) || 'active']: isActive.value,\n [(props.exactActiveClass as string) || 'exact-active']:\n isExactActive.value,\n }));\n\n // Compute a final class string (template accepts object or string; we\n // convert to string to safely include host classes and conditionals).\n const classString = computed(() =>\n Object.keys(classObject.value)\n .filter((k) => classObject.value[k])\n .join(' '),\n );\n\n const isButton = computed(() => (props.tag as string) === 'button');\n // Instead of pre-building attribute fragments as strings (which can\n // accidentally inject invalid attribute names into the template and\n // cause DOMExceptions), compute simple booleans/values and apply\n // attributes explicitly in the template below.\n const ariaCurrentValue = computed(() =>\n isExactActive.value ? (props.ariaCurrentValue as string) : '',\n );\n const isDisabled = computed(() => !!props.disabled);\n const isExternal = computed(\n () =>\n !!props.external &&\n ((props.tag as string) === 'a' || !(props.tag as string)),\n );\n\n // Inline style from host `style` attribute.\n const inlineStyle = computed(\n () =>\n (hostStyleRef && hostStyleRef.value) || (props.style as string) || '',\n );\n\n const navigate = (e: MouseEvent) => {\n if (props.disabled) {\n e.preventDefault();\n return;\n }\n if (\n props.external &&\n ((props.tag as string) === 'a' || !(props.tag as string))\n ) {\n return;\n }\n e.preventDefault();\n if (props.replace) {\n r.replace(props.to as string);\n } else {\n r.push(props.to as string);\n }\n };\n\n return html`\n ${match()\n .when(\n isButton.value,\n html`\n <button\n part=\"button\"\n class=\"${classString.value}\"\n style=\"${inlineStyle.value || null}\"\n aria-current=\"${ariaCurrentValue.value}\"\n disabled=\"${isDisabled.value ? '' : null}\"\n aria-disabled=\"${isDisabled.value ? 'true' : null}\"\n tabindex=\"${isDisabled.value ? '-1' : null}\"\n @click=\"${navigate}\"\n >\n <slot></slot>\n </button>\n `,\n )\n .otherwise(html`\n <a\n part=\"link\"\n href=\"${props.to}\"\n class=\"${classString.value}\"\n style=\"${inlineStyle.value || null}\"\n aria-current=\"${ariaCurrentValue.value}\"\n aria-disabled=\"${isDisabled.value ? 'true' : null}\"\n tabindex=\"${isDisabled.value ? '-1' : null}\"\n target=\"${isExternal.value ? '_blank' : null}\"\n rel=\"${isExternal.value ? 'noopener noreferrer' : null}\"\n @click=\"${navigate}\"\n ><slot></slot\n ></a>\n `)\n .done()}\n `;\n });\n\n return router;\n}\n"],"names":["parseQuery","search","compileCache","escapeSeg","seg","normalizePathForRoute","p","out","compileRoute","route","raw","routePath","segments","paramNames","regexParts","i","devWarn","name","paramMatch","isSplat","pattern","prefix","e","matchRoute","routes","path","incoming","compiled","regex","m","params","safeDecode","v","findMatchedRoute","r","componentCache","resolveRouteComponent","mod","useRouter","config","base","initialUrl","getLocation","initial","store","update","push","replaceFn","back","runBeforeEnter","to","from","matched","result","navigate","err","devError","runOnEnter","runAfterEnter","replace","hashIndex","fragment","loc","match","url","query","createStore","navigateSSR","matchRouteSSR","activeRouter","initRouter","router","component","html","current","ref","unsubRouterView","useOnConnected","s","useOnDisconnected","comp","resolvedComp","props","useProps","unsubRouterLink","useStyle","hostClassRef","hostStyleRef","ctx","host","hc","hs","isExactActive","computed","targetPathOnly","isActive","cur","tgt","userClasses","list","map","c","classObject","classString","k","isButton","ariaCurrentValue","isDisabled","isExternal","inlineStyle"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"custom-elements-runtime.router.cjs.js","sources":["../src/lib/router.ts"],"sourcesContent":["import { html } from './runtime/template-compiler';\nimport { component } from './runtime/component';\nimport {\n useProps,\n useOnConnected,\n useOnDisconnected,\n useStyle,\n} from './runtime/hooks';\nimport { ref, computed } from './runtime/reactive';\nimport { createStore, type Store } from './store';\nimport { devError, devWarn } from './runtime/logger';\nimport { match } from './directives';\n\nexport type RouteComponent =\n | { new (...args: unknown[]): unknown } // class components\n | ((...args: unknown[]) => unknown); // functional components\n\nexport interface RouteState {\n path: string;\n params: Record<string, string>;\n query: Record<string, string>;\n // Optional fragment (hash) portion of the URL, without the leading '#'\n fragment?: string;\n}\n\nexport type GuardResult = boolean | string | Promise<boolean | string>;\n\nexport interface Route {\n path: string;\n\n /**\n * Statically available component (already imported)\n */\n component?: string | (() => unknown);\n\n /**\n * Lazy loader that resolves to something renderable\n */\n load?: () => Promise<{\n default: string | HTMLElement | ((...args: unknown[]) => unknown);\n }>;\n\n /**\n * Runs before matching — return false to cancel,\n * or a string to redirect\n */\n beforeEnter?: (to: RouteState, from: RouteState) => GuardResult;\n\n /**\n * Runs right before navigation commits — can cancel or redirect\n */\n onEnter?: (to: RouteState, from: RouteState) => GuardResult;\n\n /**\n * Runs after navigation completes — cannot cancel\n */\n afterEnter?: (to: RouteState, from: RouteState) => void;\n}\n\nexport interface RouterLinkProps {\n to: string;\n tag: string;\n replace: boolean;\n exact: boolean;\n activeClass: string;\n exactActiveClass: string;\n ariaCurrentValue: string;\n disabled: boolean;\n external: boolean;\n class?: string;\n style?: string;\n}\n\nexport interface RouterLinkComputed {\n current: RouteState;\n isExactActive: boolean;\n isActive: boolean;\n className: string;\n ariaCurrent: string;\n isButton: boolean;\n disabledAttr: string;\n externalAttr: string;\n}\n\nexport interface RouterConfig {\n routes: Route[];\n base?: string;\n initialUrl?: string; // For SSR: explicitly pass the URL\n /**\n * Configure fragment (hash) scrolling behavior. Either a boolean to enable/disable\n * or an object to enable and provide an offset in pixels to account for fixed\n * headers.\n */\n scrollToFragment?:\n | boolean\n | {\n enabled?: boolean;\n offset?: number; // pixels\n timeoutMs?: number; // ms to wait for element to appear\n };\n}\n\nexport const parseQuery = (search: string): Record<string, string> => {\n if (!search) return {};\n if (typeof URLSearchParams === 'undefined') return {};\n return Object.fromEntries(new URLSearchParams(search));\n};\n\n// Serialize a query object into a leading `?a=b&c=d` string. Returns empty\n// string when there are no keys. Centralized so client history URLs and\n// other code use consistent encoding.\nexport const serializeQuery = (q: Record<string, string> | undefined) => {\n if (!q || Object.keys(q).length === 0) return '';\n try {\n return '?' + new URLSearchParams(q as Record<string, string>).toString();\n } catch {\n return '';\n }\n};\n\n// Detect obviously dangerous javascript: URIs. We intentionally block these\n// from becoming clickable hrefs to avoid accidental XSS when `to` is\n// derived from untrusted input.\nconst isDangerousScheme = (s: string) => {\n if (!s) return false;\n return /^\\s*javascript\\s*:/i.test(s);\n};\n\n// Cache compiled route regexes to avoid rebuilding on every navigation.\ntype CompiledRoute =\n | { regex: RegExp; paramNames: string[] }\n | { invalid: true };\nconst compileCache: WeakMap<Route, CompiledRoute> = new WeakMap();\n\nfunction escapeSeg(seg: string) {\n return seg.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function normalizePathForRoute(p: string) {\n if (!p) return '/';\n // Collapse duplicate slashes, ensure leading slash, remove trailing slash\n let out = p.replace(/\\/+/g, '/');\n if (!out.startsWith('/')) out = '/' + out;\n if (out.length > 1 && out.endsWith('/')) out = out.slice(0, -1);\n return out;\n}\n\nfunction compileRoute(route: Route): CompiledRoute {\n const raw = route.path || '/';\n const routePath = normalizePathForRoute(raw);\n\n const segments =\n routePath === '/' ? [] : routePath.split('/').filter(Boolean);\n\n const paramNames: string[] = [];\n const regexParts: string[] = [];\n\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i];\n\n // Anonymous wildcard\n if (seg === '*') {\n // splat must be terminal\n if (i !== segments.length - 1) {\n devWarn(\n `Route '${route.path}' contains a '*' splat in a non-terminal position; splats must be the last segment. This route will be ignored.`,\n );\n return { invalid: true };\n }\n const name = `splat${paramNames.length}`;\n paramNames.push(name);\n // mark splat token; pattern will be built specially so the\n // preceding slash can be optional (allow empty splat)\n regexParts.push('__SPLAT__');\n continue;\n }\n\n const paramMatch = seg.match(/^:([A-Za-z0-9_-]+)(\\*)?$/);\n if (paramMatch) {\n const name = paramMatch[1];\n const isSplat = !!paramMatch[2];\n // If splat, ensure terminal\n if (isSplat && i !== segments.length - 1) {\n devWarn(\n `Route '${route.path}' contains a splat param ':${name}*' in a non-terminal position; splats must be the last segment. This route will be ignored.`,\n );\n return { invalid: true };\n }\n paramNames.push(name);\n regexParts.push(isSplat ? '__SPLAT__' : '([^/]+)');\n continue;\n }\n\n // Static\n regexParts.push(escapeSeg(seg));\n }\n\n let pattern: string;\n if (regexParts.length === 0) {\n pattern = '^/$';\n } else {\n const last = regexParts[regexParts.length - 1];\n if (last === '__SPLAT__') {\n const prefix = regexParts.slice(0, -1).join('/');\n if (!prefix) {\n // route is like '/:rest*' or '/*' -> allow '/' or '/x' etc.\n pattern = '^(?:/(.*))?(?:/)?$';\n } else {\n pattern = `^/${prefix}(?:/(.*))?(?:/)?$`;\n }\n } else {\n pattern = `^/${regexParts.join('/')}(?:/)?$`;\n }\n }\n try {\n const regex = new RegExp(pattern);\n return { regex, paramNames };\n } catch (e) {\n devWarn(`Failed to compile route regex for '${route.path}': ${String(e)}`);\n return { invalid: true };\n }\n}\n\nexport const matchRoute = (\n routes: Route[],\n path: string,\n): { route: Route | null; params: Record<string, string> } => {\n const incoming = normalizePathForRoute(path);\n\n for (const route of routes) {\n let compiled = compileCache.get(route);\n if (!compiled) {\n compiled = compileRoute(route);\n compileCache.set(route, compiled);\n }\n\n if ((compiled as { invalid?: true }).invalid) continue;\n\n const { regex, paramNames } = compiled as {\n regex: RegExp;\n paramNames: string[];\n };\n const m = regex.exec(incoming);\n if (m) {\n const params: Record<string, string> = {};\n const safeDecode = (v: string) => {\n try {\n return decodeURIComponent(v);\n } catch {\n return v;\n }\n };\n\n for (let i = 0; i < paramNames.length; i++) {\n const raw = m[i + 1] || '';\n params[paramNames[i]] = raw ? safeDecode(raw) : '';\n }\n\n return { route, params };\n }\n }\n\n return { route: null, params: {} };\n};\n\n/**\n * Find the first route that matches the given path.\n * Consolidates repeated inline checks like `routes.find(r => matchRoute([r], path).route !== null)`\n */\nfunction findMatchedRoute(routes: Route[], path: string): Route | null {\n for (const r of routes) {\n if (matchRoute([r], path).route !== null) return r;\n }\n return null;\n}\n\n// Async component loader cache\nconst componentCache: Record<\n string,\n string | HTMLElement | ((...args: unknown[]) => unknown)\n> = {};\n\n/**\n * Loads a route's component, supporting both static and async.\n * @param route Route object\n * @returns Promise resolving to the component\n */\nexport async function resolveRouteComponent(\n route: Route,\n): Promise<string | HTMLElement | ((...args: unknown[]) => unknown)> {\n if (route.component) return route.component;\n if (route.load) {\n if (componentCache[route.path]) return componentCache[route.path];\n try {\n const mod = await route.load();\n componentCache[route.path] = mod.default;\n return mod.default;\n } catch {\n throw new Error(`Failed to load component for route: ${route.path}`);\n }\n }\n throw new Error(`No component or loader defined for route: ${route.path}`);\n}\n\nexport function useRouter(config: RouterConfig) {\n const { routes, base = '', initialUrl, scrollToFragment = true } = config;\n\n // Canonicalize base so callers and internal logic have a single\n // representation. Normalized base will be '' for root or '/x' (no\n // trailing slash). This prevents accidental double-prefixing like\n // '/app/app/about' and makes startsWith checks reliable.\n const canonicalBase = (() => {\n if (!base) return '';\n const nb = normalizePathForRoute(base);\n return nb === '/' ? '' : nb;\n })();\n\n // Normalize scroll config: either boolean or object { enabled?, offset?, timeoutMs }\n const _scrollConfig =\n typeof scrollToFragment === 'boolean'\n ? { enabled: !!scrollToFragment, offset: 0, timeoutMs: 2000 }\n : {\n enabled: scrollToFragment.enabled ?? true,\n offset: scrollToFragment.offset ?? 0,\n timeoutMs: scrollToFragment.timeoutMs ?? 2000,\n };\n\n // getLocation/initial include an optional `fragment` field in practice.\n let getLocation: () => {\n path: string;\n query: Record<string, string>;\n fragment?: string;\n };\n let initial: {\n path: string;\n query: Record<string, string>;\n fragment?: string;\n };\n let store: Store<RouteState>;\n let update: (replace?: boolean) => Promise<void>;\n let push: (path: string) => Promise<void>;\n let replaceFn: (path: string) => Promise<void>;\n let back: () => void;\n\n // Run matching route guards/hooks\n const runBeforeEnter = async (to: RouteState, from: RouteState) => {\n const matched = findMatchedRoute(routes, to.path);\n if (!matched || !matched.beforeEnter) return true;\n try {\n const result = await matched.beforeEnter(to, from);\n if (typeof result === 'string') {\n // Redirect\n await navigate(result, true);\n return false;\n }\n return result !== false;\n } catch (err) {\n devError('beforeEnter error', err);\n return false;\n }\n };\n\n const runOnEnter = async (to: RouteState, from: RouteState) => {\n const matched = findMatchedRoute(routes, to.path);\n if (!matched || !matched.onEnter) return true;\n try {\n const result = await matched.onEnter(to, from);\n if (typeof result === 'string') {\n await navigate(result, true);\n return false;\n }\n return result !== false;\n } catch (err) {\n devError('onEnter error', err);\n return false;\n }\n };\n\n const runAfterEnter = (to: RouteState, from: RouteState) => {\n const matched = findMatchedRoute(routes, to.path);\n if (!matched || !matched.afterEnter) return;\n try {\n matched.afterEnter(to, from);\n } catch (err) {\n devError('afterEnter error', err);\n }\n };\n\n // Scroll-to-fragment helpers: a cancellable per-navigation flow that\n // first attempts immediate scroll, then uses rAF and MutationObserver as\n // a robust fallback. Resolves true if scroll executed, false if timed out\n // or cancelled.\n let _navToken = 0;\n let _activeObserver: MutationObserver | null = null;\n let _activeTimeout: number | null = null;\n let _activeResolve: ((v: boolean) => void) | null = null;\n\n async function doScrollToElement(id: string, offset = 0) {\n try {\n const el = document.getElementById(id) as HTMLElement | null;\n if (!el) return false;\n if (offset && offset > 0) {\n try {\n const rect = el.getBoundingClientRect();\n const top = Math.max(0, window.scrollY + rect.top - offset);\n if (typeof window.scrollTo === 'function') {\n window.scrollTo({ top, behavior: 'auto' });\n }\n } catch {\n try {\n el.scrollIntoView();\n } catch {\n /* swallow */\n }\n }\n } else {\n if (typeof el.scrollIntoView === 'function') {\n try {\n el.scrollIntoView({\n behavior: 'auto',\n block: 'start',\n inline: 'nearest',\n });\n } catch {\n try {\n el.scrollIntoView();\n } catch {\n /* swallow */\n }\n }\n }\n }\n return true;\n } catch {\n return false;\n }\n }\n\n function clearActiveScrollAttempt() {\n if (_activeObserver) {\n try {\n _activeObserver.disconnect();\n } catch {\n /* swallow */\n }\n _activeObserver = null;\n }\n if (_activeTimeout) {\n try {\n clearTimeout(_activeTimeout);\n } catch {\n /* swallow */\n }\n _activeTimeout = null;\n }\n // NOTE: do NOT resolve/clear `_activeResolve` here. Resolution of the\n // active promise must be handled explicitly by the creator/canceller so\n // we avoid double-resolve races where both cleanup and the active\n // flow attempt try to resolve the same promise. Clearing observer/timeout\n // here is sufficient for cleanup; callers should resolve any prior\n // `_activeResolve` before calling this helper.\n }\n\n function startScrollForNavigation(\n id: string,\n offset: number | undefined,\n timeoutMs: number | undefined,\n ) {\n _navToken += 1;\n const myToken = _navToken;\n\n // If there is a previous pending resolver, resolve it as cancelled\n // (false) so callers awaiting it observe cancellation before we clear\n // internal observers/timeouts. This ensures the previous Promise is\n // resolved exactly once with `false` when a new navigation/scroll\n // attempt starts.\n if (_activeResolve) {\n try {\n _activeResolve(false);\n } catch {\n /* swallow */\n }\n _activeResolve = null;\n }\n\n clearActiveScrollAttempt();\n\n return new Promise<boolean>((resolve) => {\n // Register the new active resolver for potential cancellation by a\n // future navigation. We deliberately set this after clearing prior\n // observers/timeouts and resolving any previous resolver above.\n _activeResolve = resolve;\n\n const finish = (did: boolean) => {\n if (myToken !== _navToken) return;\n clearActiveScrollAttempt();\n try {\n resolve(did);\n } finally {\n // Avoid retaining a reference to the resolver after it has\n // been used — prevents later attempts from re-calling an old\n // function and keeps lifecycle explicit.\n _activeResolve = null;\n }\n };\n\n const tryNow = async () => {\n if (myToken !== _navToken) return finish(false);\n if (await doScrollToElement(id, offset)) return finish(true);\n\n // After rAF try once more so layout can settle\n if (typeof window.requestAnimationFrame === 'function') {\n window.requestAnimationFrame(async () => {\n if (myToken !== _navToken) return finish(false);\n if (await doScrollToElement(id, offset)) return finish(true);\n\n if (myToken !== _navToken) return finish(false);\n const container =\n document.querySelector('router-view') || document.body;\n try {\n const obs = new MutationObserver(async () => {\n if (myToken !== _navToken) return;\n if (await doScrollToElement(id, offset)) {\n finish(true);\n }\n });\n _activeObserver = obs;\n obs.observe(container as Node, {\n childList: true,\n subtree: true,\n attributes: false,\n });\n\n _activeTimeout = window.setTimeout(() => {\n if (myToken !== _navToken) return;\n try {\n obs.disconnect();\n } catch {\n /* swallow */\n }\n _activeObserver = null;\n _activeTimeout = null;\n finish(false);\n }, timeoutMs ?? 2000);\n } catch {\n // Fallback to polling\n const MAX_RETRIES = 40;\n const RETRY_DELAY = 50;\n let n = 0;\n const poll = async () => {\n if (myToken !== _navToken) return finish(false);\n if (await doScrollToElement(id, offset)) return finish(true);\n n += 1;\n if (n < MAX_RETRIES) window.setTimeout(poll, RETRY_DELAY);\n else finish(false);\n };\n poll();\n }\n });\n } else {\n // no rAF — try MutationObserver immediately\n const container =\n document.querySelector('router-view') || document.body;\n try {\n const obs = new MutationObserver(async () => {\n if (myToken !== _navToken) return;\n if (await doScrollToElement(id, offset)) {\n finish(true);\n }\n });\n _activeObserver = obs;\n obs.observe(container as Node, {\n childList: true,\n subtree: true,\n attributes: false,\n });\n _activeTimeout = window.setTimeout(() => {\n if (myToken !== _navToken) return;\n try {\n obs.disconnect();\n } catch {\n /* swallow */\n }\n _activeObserver = null;\n _activeTimeout = null;\n finish(false);\n }, timeoutMs ?? 2000);\n } catch {\n // fallback polling\n const MAX_RETRIES = 40;\n const RETRY_DELAY = 50;\n let n = 0;\n const poll = async () => {\n if (myToken !== _navToken) return finish(false);\n if (await doScrollToElement(id, offset)) return finish(true);\n n += 1;\n if (n < MAX_RETRIES) window.setTimeout(poll, RETRY_DELAY);\n else finish(false);\n };\n poll();\n }\n }\n };\n\n queueMicrotask(tryNow);\n });\n }\n\n const navigate = async (path: string, replace = false) => {\n try {\n // Separate fragment (hash) from path so matching ignores it while\n // the fragment is preserved on the RouteState.\n const hashIndex = path.indexOf('#');\n const fragment = hashIndex >= 0 ? path.slice(hashIndex + 1) : '';\n const rawPath = hashIndex >= 0 ? path.slice(0, hashIndex) : path;\n // Parse query string (if any) so queries are available on RouteState\n // and do not end up inside the normalized path used for matching.\n const qIndex = rawPath.indexOf('?');\n const pathBeforeQuery = qIndex >= 0 ? rawPath.slice(0, qIndex) : rawPath;\n const query = qIndex >= 0 ? parseQuery(rawPath.slice(qIndex)) : {};\n const stripped = pathBeforeQuery.startsWith(canonicalBase)\n ? pathBeforeQuery.slice(canonicalBase.length)\n : pathBeforeQuery;\n const normalized = normalizePathForRoute(stripped || '/');\n const loc = {\n path: normalized,\n query,\n fragment,\n };\n const match = matchRoute(routes, loc.path);\n if (!match.route) throw new Error(`No route found for ${loc.path}`);\n\n const from = store.getState();\n const to: RouteState = {\n path: loc.path,\n params: match.params,\n query: loc.query,\n fragment: (loc as { fragment?: string }).fragment,\n };\n\n // beforeEnter guard\n const allowedBefore = await runBeforeEnter(to, from);\n if (!allowedBefore) return;\n\n // onEnter guard (right before commit)\n const allowedOn = await runOnEnter(to, from);\n if (!allowedOn) return;\n\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n const qstr = serializeQuery(loc.query);\n const href =\n canonicalBase +\n loc.path +\n (qstr || '') +\n (loc.fragment ? '#' + loc.fragment : '');\n if (replace) {\n window.history.replaceState({}, '', href);\n } else {\n window.history.pushState({}, '', href);\n }\n }\n\n store.setState(to);\n\n // afterEnter hook (post commit)\n runAfterEnter(to, from);\n\n // If there's a fragment (hash) preserve it on the URL and attempt to\n // scroll to the element with that id on client-side navigation.\n try {\n const frag = (to as { fragment?: string }).fragment;\n if (\n _scrollConfig.enabled &&\n frag &&\n typeof window !== 'undefined' &&\n typeof document !== 'undefined'\n ) {\n // Start the robust scroll flow (observer + timeout + cancellation)\n startScrollForNavigation(\n String(frag),\n _scrollConfig.offset,\n _scrollConfig.timeoutMs,\n ).catch(() => {});\n }\n } catch {\n /* swallow */\n }\n } catch (err) {\n devError('Navigation error:', err);\n }\n };\n\n // If an explicit `initialUrl` is provided we treat this as SSR/static rendering\n // even if a `window` exists (useful for hydration tests). Browser mode only\n // applies when `initialUrl` is undefined.\n if (\n typeof window !== 'undefined' &&\n typeof document !== 'undefined' &&\n typeof initialUrl === 'undefined'\n ) {\n // Browser mode\n getLocation = () => {\n const url = new URL(window.location.href);\n const raw = url.pathname;\n const stripped = raw.startsWith(canonicalBase)\n ? raw.slice(canonicalBase.length)\n : raw;\n const path = normalizePathForRoute(stripped || '/');\n const query = parseQuery(url.search);\n const fragment = url.hash && url.hash.length ? url.hash.slice(1) : '';\n return { path, query, fragment };\n };\n\n initial = getLocation();\n const match = matchRoute(routes, initial.path);\n store = createStore<RouteState>({\n path: initial.path,\n params: match.params,\n query: initial.query,\n fragment: (initial as { fragment?: string }).fragment,\n });\n\n update = async (replace = false) => {\n const loc = getLocation();\n await navigate(loc.path, replace);\n };\n\n window.addEventListener('popstate', () => update(true));\n\n push = (path: string) => navigate(path, false);\n replaceFn = (path: string) => navigate(path, true);\n back = () => window.history.back();\n } else {\n // SSR mode\n getLocation = () => {\n const url = new URL(initialUrl || '/', 'http://localhost');\n const raw = url.pathname;\n const stripped = raw.startsWith(canonicalBase)\n ? raw.slice(canonicalBase.length)\n : raw;\n const path = normalizePathForRoute(stripped || '/');\n const query = parseQuery(url.search);\n const fragment = url.hash && url.hash.length ? url.hash.slice(1) : '';\n return { path, query, fragment };\n };\n\n initial = getLocation();\n const match = matchRoute(routes, initial.path);\n store = createStore<RouteState>({\n path: initial.path,\n params: match.params,\n query: initial.query,\n fragment: (initial as { fragment?: string }).fragment,\n });\n\n update = async () => {\n const loc = getLocation();\n await navigateSSR(loc.path);\n };\n\n // SSR navigation contract:\n // - `push` / `replace` call into `navigateSSR` and return a Promise.\n // - On the server we intentionally surface navigation failures so\n // server-side logic (or tests) can react: missing routes or thrown\n // errors from `beforeEnter`/`onEnter` will cause the Promise to\n // reject. This lets the server render 404s or abort builds.\n // - For valid routes the server-side navigation resolves and updates\n // the internal store state so rendered output matches the target\n // path. The `back()` operation is client-only and is a synchronous\n // no-op in SSR mode.\n const navigateSSR = async (path: string) => {\n try {\n const hashIndex = path.indexOf('#');\n const fragment = hashIndex >= 0 ? path.slice(hashIndex + 1) : '';\n const rawPath = hashIndex >= 0 ? path.slice(0, hashIndex) : path;\n // Parse query on SSR navigation as well so server-side logic and\n // tests can observe query params.\n const qIndex = rawPath.indexOf('?');\n const pathBeforeQuery =\n qIndex >= 0 ? rawPath.slice(0, qIndex) : rawPath;\n const query = qIndex >= 0 ? parseQuery(rawPath.slice(qIndex)) : {};\n const stripped = pathBeforeQuery.startsWith(canonicalBase)\n ? pathBeforeQuery.slice(canonicalBase.length)\n : pathBeforeQuery;\n const normalized = normalizePathForRoute(stripped || '/');\n const loc = {\n path: normalized,\n query,\n fragment,\n };\n const match = matchRoute(routes, loc.path);\n // In SSR mode we intentionally surface navigation errors (missing\n // route) to the caller so server-side logic may handle them. If no\n // route matches, throw and let the caller observe the rejection.\n if (!match.route) throw new Error(`No route found for ${loc.path}`);\n\n const from = store.getState();\n const to: RouteState = {\n path: loc.path,\n params: match.params,\n query: loc.query,\n fragment: (loc as { fragment?: string }).fragment,\n };\n\n // beforeEnter guard\n const matched = findMatchedRoute(routes, to.path);\n if (matched?.beforeEnter) {\n const result = await matched.beforeEnter(to, from);\n if (typeof result === 'string') {\n // Redirect\n await navigateSSR(result);\n return;\n }\n if (result === false) return;\n }\n\n // onEnter guard\n if (matched?.onEnter) {\n const result = await matched.onEnter(to, from);\n if (typeof result === 'string') {\n await navigateSSR(result);\n return;\n }\n if (result === false) return;\n }\n\n store.setState(to);\n\n // afterEnter hook\n if (matched?.afterEnter) {\n matched.afterEnter(to, from);\n }\n } catch (err) {\n // Surface SSR navigation errors so callers (and tests) can observe\n // failures during server-side resolution.\n devError('SSR navigation error:', err);\n throw err;\n }\n };\n\n push = async (path: string) => navigateSSR(path);\n replaceFn = async (path: string) => navigateSSR(path);\n back = () => {};\n }\n\n return {\n store,\n push,\n replace: replaceFn,\n back,\n subscribe: store.subscribe,\n matchRoute: (path: string) => matchRoute(routes, path),\n getCurrent: (): RouteState => store.getState(),\n resolveRouteComponent,\n base: canonicalBase,\n // Public API: allow components or tests to explicitly request scrolling to\n // a fragment when they know their DOM is ready. Returns true if scrolled.\n scrollToFragment: (frag?: string) => {\n const id = frag || (store.getState() as RouteState).fragment;\n if (!id) return Promise.resolve(false);\n if (typeof window === 'undefined' || typeof document === 'undefined')\n return Promise.resolve(false);\n return startScrollForNavigation(\n String(id),\n _scrollConfig.offset,\n _scrollConfig.timeoutMs,\n );\n },\n };\n}\n\n/**\n * Explicit Router instance type exported for clearer typing across the\n * codebase and tests.\n */\nexport interface Router {\n store: Store<RouteState>;\n push: (path: string) => Promise<void>;\n replace: (path: string) => Promise<void>;\n back: () => void;\n subscribe: Store<RouteState>['subscribe'];\n matchRoute: (path: string) => {\n route: Route | null;\n params: Record<string, string>;\n };\n getCurrent: () => RouteState;\n resolveRouteComponent: typeof resolveRouteComponent;\n base: string;\n scrollToFragment: (frag?: string) => Promise<boolean>;\n}\n\n// SSR/static site support: match route for a given path\nexport function matchRouteSSR(routes: Route[], path: string) {\n return matchRoute(routes, path);\n}\n\n// Module-level reference to the latest initialized router. Tests and\n// components may rely on re-initializing the router during their setup,\n// so exposing this lets components pick up the most recent instance.\nlet activeRouter: ReturnType<typeof useRouter> | null = null;\n\n/**\n * Singleton router instance for global access.\n *\n * Define here to prevent circular dependency\n * issue with component.\n */\n\nexport function initRouter(config: RouterConfig) {\n const router = useRouter(config);\n // Expose the most recently initialized router to components defined\n // earlier in the process (tests may call initRouter multiple times).\n // Components reference `activeRouter` so re-calling initRouter updates\n // the router instance they use.\n // Expose the most recently initialized router to components defined\n // earlier in the process (tests may call initRouter multiple times).\n // Components reference `activeRouter` so re-calling initRouter updates\n // the router instance they use.\n activeRouter = router;\n\n component('router-view', async () => {\n // Prefer the latest initialized router (tests may re-init). Fallback\n // to the router captured at init time.\n const r = activeRouter || router;\n // Reactive current route so the component re-renders when router updates\n if (!r) return html`<div>Router not initialized.</div>`;\n\n const current = ref(r.getCurrent());\n\n // We'll capture the unsubscribe function when the component connects\n // and register a disconnect cleanup during render-time (useOnDisconnected\n // must be called during the component render/execution).\n let unsubRouterView: (() => void) | undefined;\n\n useOnConnected(() => {\n try {\n if (r && typeof r.subscribe === 'function') {\n unsubRouterView = r.subscribe((s) => {\n try {\n current.value = s;\n } catch (e) {\n devWarn('router-view subscription update failed', e);\n }\n });\n }\n } catch (e) {\n devWarn('router-view subscribe failed', e);\n }\n });\n\n useOnDisconnected(() => {\n if (typeof unsubRouterView === 'function') {\n try {\n unsubRouterView();\n } catch (e) {\n devWarn('router-view unsubscribe failed', e);\n }\n }\n });\n\n const match = r.matchRoute(current.value.path);\n if (!match || !match.route) return html`<div>Not found</div>`;\n\n // Resolve the component (supports cached async loaders)\n try {\n const compRaw = await r.resolveRouteComponent(match.route);\n const comp = compRaw as\n | string\n | HTMLElement\n | ((...args: unknown[]) => unknown)\n | undefined;\n // String tag (custom element) -> render as VNode\n if (typeof comp === 'string') {\n return { tag: comp, props: {}, children: [] };\n }\n\n // Function component (sync or async) -> call and return its VNode(s)\n if (typeof comp === 'function') {\n const out = comp();\n const resolved = out instanceof Promise ? out : Promise.resolve(out);\n return resolved.then((resolvedComp) => {\n if (typeof resolvedComp === 'string')\n return { tag: resolvedComp, props: {}, children: [] };\n return resolvedComp;\n });\n }\n\n return html`<div>Invalid route component</div>`;\n } catch {\n return html`<div>Invalid route component</div>`;\n }\n });\n\n component('router-link', () => {\n // Declare props via useProps so observedAttributes are correct\n const props = useProps<Partial<RouterLinkProps>>({\n to: '',\n tag: 'a',\n replace: false,\n exact: false,\n activeClass: 'active',\n exactActiveClass: 'exact-active',\n ariaCurrentValue: 'page',\n disabled: false,\n external: false,\n // allow host `class` and `style` attributes to be read via useProps\n class: '',\n style: '',\n });\n\n // Prefer the latest initialized router (tests may re-init). Fallback\n // to the router captured at init time.\n const r = activeRouter || router;\n // Reactive current state so link updates when route changes\n const current = ref(r.getCurrent());\n // Capture unsubscribe for link subscriptions and register disconnect\n // cleanup during render time.\n let unsubRouterLink: (() => void) | undefined;\n\n // Keep a minimal internal host-scoped style for element display.\n // Host `style` will be applied to the inner anchor/button element.\n useStyle(() => `a,button{display:inline-block;}`);\n\n // We capture host attributes at connection time and migrate them to\n // internal refs so we can remove them from the host. This prevents\n // global/author CSS targeting the host from styling the host element\n // itself while still allowing authors to use `class`/`style` on the\n // router-link to style the inner anchor/button.\n const hostClassRef = ref((props.class as string) || '');\n const hostStyleRef = ref((props.style as string) || '');\n\n useOnConnected((ctx?: unknown) => {\n try {\n if (r && typeof r.subscribe === 'function') {\n unsubRouterLink = r.subscribe((s) => {\n try {\n current.value = s;\n } catch (e) {\n devWarn('router-link subscription update failed', e);\n }\n });\n }\n } catch (e) {\n devWarn('router-link subscribe failed', e);\n }\n\n // Migrate host `class`/`style` into internal refs and remove them\n // from the host so only the inner element is styled.\n try {\n const host = (ctx as { _host?: HTMLElement } | undefined)?._host;\n if (host instanceof HTMLElement) {\n const hc = host.getAttribute('class');\n const hs = host.getAttribute('style');\n if (hc) hostClassRef.value = hc;\n if (hs) hostStyleRef.value = hs;\n // Remove attributes from host to avoid styling the host\n if (hc !== null) host.removeAttribute('class');\n if (hs !== null) host.removeAttribute('style');\n }\n } catch (e) {\n devWarn('router-link host migration failed', e);\n }\n });\n\n useOnDisconnected(() => {\n if (typeof unsubRouterLink === 'function') {\n try {\n unsubRouterLink();\n } catch (e) {\n devWarn('router-link unsubscribe failed', e);\n }\n }\n });\n\n const isExactActive = computed(() => {\n const runtimeBase = r?.base ?? '';\n const targetRaw = (props.to as string) || '';\n // If the target is an absolute or protocol-relative URL, it's external\n // and should not be considered active.\n if (\n /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(targetRaw) ||\n targetRaw.startsWith('//')\n )\n return false;\n // strip fragment and query from target when comparing. Default to '/'\n const targetPathOnly = (targetRaw.split('#')[0] || '/').split('?')[0];\n try {\n // Remove runtime base if present on the provided target so comparisons\n // are made against the router-internal path format (paths stored\n // without base).\n let tgtCandidate = targetPathOnly;\n if (runtimeBase && tgtCandidate.startsWith(runtimeBase)) {\n tgtCandidate = tgtCandidate.slice(runtimeBase.length) || '/';\n }\n const cur = normalizePathForRoute(current.value.path);\n const tgt = normalizePathForRoute(tgtCandidate);\n return cur === tgt;\n } catch {\n return current.value.path === targetPathOnly;\n }\n });\n\n const isActive = computed(() => {\n const runtimeBase = r?.base ?? '';\n const targetRaw = (props.to as string) || '';\n // External targets are never \"active\" in the SPA sense\n if (\n /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(targetRaw) ||\n targetRaw.startsWith('//')\n )\n return false;\n // strip fragment and query from target when comparing\n const targetPathOnly = (targetRaw.split('#')[0] || '/').split('?')[0];\n if (props.exact) return isExactActive.value;\n try {\n // Normalize and strip base from target to compare against\n let tgtCandidate = targetPathOnly;\n if (runtimeBase && tgtCandidate.startsWith(runtimeBase)) {\n tgtCandidate = tgtCandidate.slice(runtimeBase.length) || '/';\n }\n const cur = normalizePathForRoute(current.value.path);\n const tgt = normalizePathForRoute(tgtCandidate);\n // Special-case the root target: '/' should only be active when\n // the current path is exactly '/'. Without this, '/' matches all\n // routes (every path starts with '/').\n if (tgt === '/') return cur === '/';\n // Consider active when current is the target or a child of the target\n if (cur === tgt) return true;\n // Ensure we match whole path segment (avoid '/guide-api' matching '/guide')\n return cur.startsWith(tgt.endsWith('/') ? tgt : tgt + '/');\n } catch {\n return (\n current.value &&\n typeof current.value.path === 'string' &&\n current.value.path.startsWith(targetPathOnly)\n );\n }\n });\n\n // Compute a normalized href for the inner anchor so middle-click / open-in-new-tab\n // uses a canonical absolute path (includes base and fragment). We keep using\n // props.to for router navigation so current behavior (literal `to`) remains.\n const hrefTarget = computed(() => {\n const raw = String(props.to || '');\n // Block obviously dangerous javascript: URIs from becoming clickable\n // hrefs. See isDangerousScheme for rationale.\n if (isDangerousScheme(raw)) return null;\n\n // Preserve absolute URLs with a scheme (http:, mailto:, data:, etc.)\n // and protocol-relative URLs that begin with `//`.\n if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(raw) || raw.startsWith('//'))\n return raw;\n\n // Split fragment and query explicitly so both are preserved.\n const [pathWithQuery, frag] = raw.split('#');\n const [pathOnly, query] = (pathWithQuery || '').split('?');\n\n // Read base dynamically from the current router instance so repeated\n // calls to initRouter (tests) do not leave a stale captured value.\n const runtimeBase = r?.base ?? '';\n // If the provided path already contains the runtime base, strip it to\n // avoid duplicating e.g. '/app/app/about'. Keep a fallback of '/'.\n let candidate = pathOnly || '/';\n if (runtimeBase && candidate.startsWith(runtimeBase)) {\n candidate = candidate.slice(runtimeBase.length) || '/';\n }\n const norm = normalizePathForRoute(candidate || '/');\n return (\n runtimeBase +\n norm +\n (query ? '?' + query : '') +\n (frag ? '#' + frag : '')\n );\n });\n\n // Build user classes reactively from the host `class` attribute prop.\n // We intentionally apply classes to the inner element so the consumer\n // can style the link via `class=\"...\"`.\n const userClasses = computed(() => {\n const rawHost =\n (hostClassRef && hostClassRef.value) || (props.class as string) || '';\n const list = rawHost.split(/\\s+/).filter(Boolean);\n const map: Record<string, boolean> = {};\n for (const c of list) map[c] = true;\n return map;\n });\n\n const classObject = computed(() => ({\n ...userClasses.value,\n [(props.activeClass as string) || 'active']: isActive.value,\n [(props.exactActiveClass as string) || 'exact-active']:\n isExactActive.value,\n }));\n\n // Compute a final class string (template accepts object or string; we\n // convert to string to safely include host classes and conditionals).\n const classString = computed(() =>\n Object.keys(classObject.value)\n .filter((k) => classObject.value[k])\n .join(' '),\n );\n\n const tagName = computed(() => (props.tag as string) || 'a');\n const isButton = computed(() => tagName.value === 'button');\n // Instead of pre-building attribute fragments as strings (which can\n // accidentally inject invalid attribute names into the template and\n // cause DOMExceptions), compute simple booleans/values and apply\n // attributes explicitly in the template below.\n // Return null when not exact so the attribute is omitted from the DOM\n const ariaCurrentValue = computed<null | string>(() =>\n isExactActive.value ? (props.ariaCurrentValue as string) : null,\n );\n const isDisabled = computed(() => !!props.disabled);\n // External should only apply to anchor tags (links). Make the check explicit.\n // Detect absolute/protocol-relative URLs as external even if the prop\n // wasn't explicitly set by the caller. Only apply to anchor tags.\n const isExternal = computed(() => {\n const toStr = String(props.to || '');\n const looksAbsolute =\n /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(toStr) || toStr.startsWith('//');\n return (looksAbsolute || !!props.external) && tagName.value === 'a';\n });\n\n // Inline style from host `style` attribute.\n const inlineStyle = computed(\n () =>\n (hostStyleRef && hostStyleRef.value) || (props.style as string) || '',\n );\n\n const navigate = (e: MouseEvent) => {\n // Respect pre-handled events, non-left clicks, and modifier keys so\n // default browser behaviors (open-in-new-tab, context menu) work.\n if (\n e.defaultPrevented ||\n e.button !== 0 ||\n e.metaKey ||\n e.altKey ||\n e.ctrlKey ||\n e.shiftKey\n )\n return;\n\n if (isDisabled.value) {\n // Prevent navigation and let assistive tech see disabled state\n e.preventDefault();\n return;\n }\n\n // Block dangerous javascript: URIs explicitly to avoid accidental XSS\n const _targetRaw = String(props.to || '');\n if (isDangerousScheme(_targetRaw)) {\n try {\n e.preventDefault();\n } catch {\n /* swallow */\n }\n devWarn('Blocked unsafe javascript: URI in router-link.to');\n return;\n }\n\n // If this is an external anchor, allow default browser behavior\n if (isExternal.value) return;\n\n e.preventDefault();\n if (props.replace) {\n r.replace(props.to as string);\n } else {\n r.push(props.to as string);\n }\n };\n\n return html`\n ${match()\n .when(\n isButton.value,\n html`\n <button\n part=\"button\"\n class=\"${classString.value}\"\n style=\"${inlineStyle.value || null}\"\n aria-current=\"${ariaCurrentValue.value}\"\n disabled=\"${isDisabled.value ? '' : null}\"\n aria-disabled=\"${isDisabled.value ? 'true' : null}\"\n tabindex=\"${isDisabled.value ? '-1' : null}\"\n @click=\"${navigate}\"\n >\n <slot></slot>\n </button>\n `,\n )\n .otherwise(html`\n <a\n part=\"link\"\n href=\"${isDisabled.value ? null : hrefTarget.value}\"\n class=\"${classString.value}\"\n style=\"${inlineStyle.value || null}\"\n aria-current=\"${ariaCurrentValue.value}\"\n aria-disabled=\"${isDisabled.value ? 'true' : null}\"\n tabindex=\"${isDisabled.value ? '-1' : null}\"\n target=\"${isExternal.value ? '_blank' : null}\"\n rel=\"${isExternal.value ? 'noopener noreferrer' : null}\"\n @click=\"${navigate}\"\n ><slot></slot\n ></a>\n `)\n .done()}\n `;\n });\n\n return router;\n}\n"],"names":["parseQuery","search","serializeQuery","q","isDangerousScheme","s","compileCache","escapeSeg","seg","normalizePathForRoute","p","out","compileRoute","route","raw","routePath","segments","paramNames","regexParts","devWarn","name","paramMatch","isSplat","pattern","prefix","e","matchRoute","routes","path","incoming","compiled","regex","m","params","safeDecode","i","findMatchedRoute","r","componentCache","resolveRouteComponent","mod","useRouter","config","base","initialUrl","scrollToFragment","canonicalBase","nb","_scrollConfig","getLocation","initial","store","update","push","replaceFn","back","runBeforeEnter","to","from","matched","result","navigate","err","devError","runOnEnter","runAfterEnter","_navToken","_activeObserver","_activeTimeout","_activeResolve","doScrollToElement","id","offset","el","rect","top","clearActiveScrollAttempt","startScrollForNavigation","timeoutMs","myToken","resolve","finish","did","container","obs","n","poll","replace","hashIndex","fragment","rawPath","qIndex","pathBeforeQuery","query","stripped","loc","match","qstr","href","frag","url","createStore","navigateSSR","matchRouteSSR","activeRouter","initRouter","router","component","html","current","ref","unsubRouterView","useOnConnected","useOnDisconnected","comp","resolvedComp","props","useProps","unsubRouterLink","useStyle","hostClassRef","hostStyleRef","ctx","host","hc","hs","isExactActive","computed","runtimeBase","targetRaw","targetPathOnly","tgtCandidate","cur","tgt","isActive","hrefTarget","pathWithQuery","pathOnly","candidate","norm","userClasses","list","map","c","classObject","classString","k","tagName","isButton","ariaCurrentValue","isDisabled","isExternal","toStr","inlineStyle","_targetRaw"],"mappings":"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"}
|