unfold-nav 0.1.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.
@@ -0,0 +1,446 @@
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.UnfoldNav={}))})(this,function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=/^(https?:|data:|blob:|\/|\.\.?\/)|\.(svg|png|jpe?g|gif|webp|avif)(\?.*)?$/i,n=/^[a-z][\w-]{2,}$/i;function r(e,i,a,o=0){if(e==null||e===``||o>3)return null;if(typeof e==`function`)return r(e(),i,a,o+1);if(typeof e!=`string`)return e.cloneNode(!0);let s=e.trim();if(s.startsWith(`<`)){let e=document.createElement(`template`);return e.innerHTML=s,e.content}if(t.test(s)){let e=document.createElement(`img`);return e.src=s,e.alt=``,e.decoding=`async`,e.draggable=!1,e}if(n.test(s)){let e=i?.(s,a);return e==null||e===s?null:r(e,void 0,a,o+1)}let c=document.createElement(`span`);return c.className=`glyph`,c.textContent=s,c}function i(e){let t=document.createElement(`span`);return t.className=`mono`,t.textContent=Array.from(e.trim())[0]?.toUpperCase()??`•`,t}var a=e=>`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${e}</svg>`,o=a(`<path d="M12 17.5 6 8.6M12 17.5V6.2M12 17.5l6-8.9"/><circle cx="12" cy="18.2" r="2.5" fill="currentColor" stroke="none"/><circle cx="5.6" cy="8" r="2" fill="currentColor" stroke="none"/><circle cx="12" cy="5.4" r="2" fill="currentColor" stroke="none"/><circle cx="18.4" cy="8" r="2" fill="currentColor" stroke="none"/>`),s=a(`<path d="M6.5 6.5l11 11M17.5 6.5l-11 11"/>`),c=a(`<path d="M19 12H5.5M11 6l-6 6 6 6"/>`),l=e=>Array.isArray(e)?e:[e],u=Math.PI*2,d=Math.PI/180,f=4;function p(e,t){let n=Math.max(t.x-e.x,0,e.x-(t.x+t.w)),r=Math.max(t.y-e.y,0,e.y-(t.y+t.h));return Math.hypot(n,r)}function m(e,t,n=0){return e.x<t.x+t.w+n&&t.x<e.x+e.w+n&&e.y<t.y+t.h+n&&t.y<e.y+e.h+n}var h=(e,t)=>t.x>=e.x&&t.x<=e.x+e.w&&t.y>=e.y&&t.y<=e.y+e.h,g=(e,t)=>t.x>=e.x-.5&&t.y>=e.y-.5&&t.x+t.w<=e.x+e.w+.5&&t.y+t.h<=e.y+e.h+.5,_=(e,t)=>({x:e.x-t,y:e.y-t,w:e.w+t*2,h:e.h+t*2});function v(e,t,n){let r=n.x-t.x,i=n.y-t.y,a=r*r+i*i,o=a?Math.max(0,Math.min(1,((e.x-t.x)*r+(e.y-t.y)*i)/a)):0;return Math.hypot(e.x-(t.x+o*r),e.y-(t.y+o*i))}function y(e,t){let n=1/0;for(let r=0;r<t.length-1;r++)n=Math.min(n,v(e,t[r],t[r+1]));return n}function ee(e,t,n){let r=0,i=1,a=t.x-e.x,o=t.y-e.y,s=[-a,a,-o,o],c=[e.x-n.x,n.x+n.w-e.x,e.y-n.y,n.y+n.h-e.y];for(let e=0;e<4;e++)if(s[e]===0){if(c[e]<0)return!1}else{let t=c[e]/s[e];if(s[e]<0){if(t>i)return!1;t>r&&(r=t)}else{if(t<r)return!1;t<i&&(i=t)}}return!0}function b(e,t){for(let n=0;n<e.length-1;n++)if(ee(e[n],e[n+1],t))return!0;return!1}function x(e,t,n){let r=t.x-e.x,i=t.y-e.y,a=Math.hypot(r,i)||1;return{x:e.x+r/a*n,y:e.y+i/a*n}}var S=e=>e.toFixed(1);function C(e,t,n,r){let i=()=>{let n=x(e,t,e.r),r=x(t,e,t.r);return{d:`M${S(n.x)} ${S(n.y)}L${S(r.x)} ${S(r.y)}`,points:[n,r]}};if(n===`step`){let n=x(e,t,e.r),r=x(t,e,t.r);if(Math.min(Math.abs(r.x-n.x),Math.abs(r.y-n.y))<1||Math.hypot(t.x-e.x,t.y-e.y)<=e.r+t.r)return i();let a=Math.abs(t.x-e.x)>=Math.abs(t.y-e.y),o=a?(n.x+r.x)/2:(n.y+r.y)/2,s=a?[{x:o,y:n.y},{x:o,y:r.y}]:[{x:n.x,y:o},{x:r.x,y:o}],c=[n,...s,r],l=[n],u=`M${S(n.x)} ${S(n.y)}`;return s.forEach((e,t)=>{let n=c[t],r=c[t+2],i=Math.min(10,Math.hypot(e.x-n.x,e.y-n.y)/2,Math.hypot(r.x-e.x,r.y-e.y)/2),a=x(e,n,i),o=x(e,r,i);u+=`L${S(a.x)} ${S(a.y)}Q${S(e.x)} ${S(e.y)} ${S(o.x)} ${S(o.y)}`,l.push(a);for(let t=1;t<=4;t++){let n=t/4,r=1-n;l.push({x:r*r*a.x+2*r*n*e.x+n*n*o.x,y:r*r*a.y+2*r*n*e.y+n*n*o.y})}}),l.push(r),{d:`${u}L${S(r.x)} ${S(r.y)}`,points:l}}if(n!==`curved`||r==null)return i();let a=Math.hypot(t.x-e.x,t.y-e.y)||1,o={x:e.x+Math.cos(r)*a*.5,y:e.y+Math.sin(r)*a*.5},s=x(e,o,e.r),c=x(t,o,t.r),l=[];for(let e=0;e<=6;e++){let t=e/6,n=1-t;l.push({x:n*n*s.x+2*n*t*o.x+t*t*c.x,y:n*n*s.y+2*n*t*o.y+t*t*c.y})}return{d:`M${S(s.x)} ${S(s.y)}Q${S(o.x)} ${S(o.y)} ${S(c.x)} ${S(c.y)}`,points:l}}var w=[0,...Array.from({length:7},(e,t)=>[(t+1)*22.5,-(t+1)*22.5]).flat(),180].map(e=>e*d),T=[0,12,28],te=[0,12,28,48];function E(e,t,n,r,i,a){let o=Math.cos(i),s=Math.sin(i),c=0,l=a+n+r;for(let i=0;i<14;i++){let i=(c+l)/2;p({x:e,y:t},{x:e+o*i-n/2,y:t+s*i-r/2,w:n,h:r})>=a?l=i:c=i}return{x:e+o*l-n/2,y:t+s*l-r/2,w:n,h:r}}function D(e,t,n){for(let r of n.circles)if(r!==t&&p(r,e)<r.r+n.pad)return!0;for(let t of n.taken)if(m(e,t,f))return!0;if(n.edges.length){let t=_(e,2);for(let e of n.edges)if(b(e,t))return!0}return!1}function ne(e,t,n,r){let i=l(t)[0],a=0;for(let t of T)for(let o of w){let s=E(e.x,e.y,i.w,i.h,n+o,e.r+(r.ownPad??r.pad)+t);g(r.bounds,s)&&!D(s,e,r)&&a++}return a}function O(e,t,n=(e,t)=>k(e.node,e.size,e.angle,t)){let r=r=>{let i=e.map(()=>null),a={...t,taken:[...t.taken]},o=0;for(let t of r){let r=n(e[t],a);r?a.taken.push(r):o++,i[t]=r}return{out:i,missing:o}},i=e.map((e,t)=>t),a=r(i);if(a.missing===0||e.length<2)return a.out;let o=e.map(e=>ne(e.node,e.size,e.angle,t));for(let e of[[...i].sort((e,t)=>o[e]-o[t]),[...i].reverse()]){let t=r(e);if(t.missing<a.missing&&(a=t),a.missing===0)break}return a.out}function k(e,t,n,r){for(let i of l(t)){let t=re(e,i,n,r);if(t)return t}return null}function re(e,t,n,r){for(let i of r.rings??T)for(let a of w){let o=E(e.x,e.y,t.w,t.h,n+a,e.r+(r.ownPad??r.pad)+i);if(g(r.bounds,o)&&!D(o,e,r))return o}return null}var ie=Array.from({length:41},(e,t)=>1+t*.06),A=[1,1.15,1.3,1.5,1.75,2,2.3],j=5*d,ae=200;function M(e,t,n,r,i){let a=r-i*(n-1)/2;return Array.from({length:n},(n,r)=>{let o=a+r*i;return{x:e.x+t*Math.cos(o),y:e.y+t*Math.sin(o)}})}function oe(e,t,n,r){return Array.from({length:n},(i,a)=>{let o=r+a*u/n;return{x:e.x+t*Math.cos(o),y:e.y+t*Math.sin(o)}})}function se(e,t,n,r=!1){let{bounds:i,radius:a}=t,o=t.labelPad??8,s=0,c=0;for(let n of e){s+=Math.max(0,i.x+a-n.x)+Math.max(0,n.x+a-(i.x+i.w)),s+=Math.max(0,i.y+a-n.y)+Math.max(0,n.y+a-(i.y+i.h));for(let e of t.obstacles){let r=a+e.r+t.gap*.75,i=Math.hypot(n.x-e.x,n.y-e.y);i<r&&(s+=r-i)}if(!r)for(let e of t.blocked??[]){let t=p(n,e);t<a+o&&(s+=a+o-t)}}if(n&&t.edgeStyle!==`none`&&s===0){let n=t.edgeStyle??`straight`;for(let n of e)for(let e of t.edges??[]){let t=y(n,e);t<a+4&&(c+=a+4-t)}e.forEach((r,i)=>{let o=C(t.origin,{...r,r:a},n,t.parentAngle).points;for(let e of t.obstacles){let t=y(e,o);t<e.r+4&&(c+=e.r+4-t)}e.forEach((e,t)=>{if(t===i)return;let n=y(e,o);n<a+4&&(c+=a+4-n)})})}return{base:s,edges:c}}function N(e,t,n,r,i=`optional`){if(!t.labels?.some(Boolean)&&!t.originLabel)return{labels:e.map(()=>null),originLabel:null};let a=t.radius,o=t.edgeStyle??`straight`,s=e.map(e=>({x:e.x,y:e.y,r:a})),c=o===`none`?[]:s.map(e=>C(t.origin,e,o,t.parentAngle).points),l=o===`none`?[]:[...t.edges??[],...c],u={bounds:t.bounds,circles:[...t.obstacles,t.origin,...s],taken:[...t.blocked??[]],edges:l,pad:t.labelPad??8},d=s.map((e,n)=>({i:n,node:e,size:t.labels?.[n]??null,angle:Math.atan2(e.y-t.origin.y,e.x-t.origin.x)})).filter(e=>!!e.size),f=O(d,u,(e,t)=>{let r=e.i;return k(e.node,e.size,e.angle,t)??(n===`strict`?null:k(e.node,e.size,e.angle,{...t,edges:c}))??(n===`loose`?k(e.node,e.size,e.angle,{...t,edges:c.length?[c[r]]:[]}):null)}),p=s.map(()=>null);if(d.forEach((e,t)=>p[e.i]=f[t]),!r&&d.some((e,t)=>!f[t]))return null;let m=null;if(t.originLabel){let e={...u,taken:[...u.taken,...p.filter(e=>!!e)],rings:te},n=t.parentEdge?[t.parentEdge]:[];if(m=k(t.origin,t.originLabel,t.direction,{...e,edges:[...e.edges,...n]}),!m&&i!==`clean`&&(m=k(t.origin,t.originLabel,t.direction+Math.PI,{...e,edges:e.edges.filter(e=>e!==t.parentEdge)})),!m&&i!==`optional`&&!r)return null}return{labels:p,originLabel:m}}function P(e){let{origin:t,count:n,radius:r,gap:i}=e;if(n<=0)return{points:[],labels:[]};let a=2*r+i,o=null,s=(t,n,r,i)=>{let a=se(t,e,n);if((!o||a.base<o.penalty)&&(o={points:t,penalty:a.base}),a.base>0||n&&a.edges>0||r.left<=0)return null;r.left--;let s=N(t,e,n?`strict`:`relaxed`,!1,i);return s?{points:t,...s}:null},c=ie.map(t=>e.distance*t);if(n>1&&e.maxSpread!=null){let t=a/(2*Math.sin(e.maxSpread/(2*(n-1))))+.5;t>e.distance&&c.push(t)}c.sort((e,t)=>e-t);let l=Math.min(e.maxDeviation??Math.PI,Math.PI),u=e.maxSpread!=null&&!e.ring?Math.min(e.maxSpread*1.5,1.4*Math.PI):e.maxSpread,d=[{dev:l,strict:!0,spread:e.maxSpread},{dev:Math.PI,strict:!0,spread:u},{dev:Math.PI,strict:!1,spread:u}],f=(e.originLabel?[`clean`,`breadcrumb`,`optional`]:[`optional`]).flatMap(e=>d.map(t=>({...t,needOrigin:e})));for(let r of f){if(e.ring&&n>=3){let i=Math.max(e.distance,a/(2*Math.sin(Math.PI/n)));for(let a of A){let o=s(oe(t,i*a,n,e.direction),r.strict,{left:1},r.needOrigin);if(o)return o}}for(let i of c){if(a>=2*i)continue;let o=2*Math.asin(a/(2*i)),c=Math.max(o,e.preferredStep??0),l=c>o+1e-9?[c,o]:[o],u=[];for(let t of l){if(n>1&&r.spread!=null&&t*(n-1)>r.spread+1e-9)continue;let i=t===c?0:.15;for(let n=0;n*j<=r.dev+1e-9;n++)for(let r of n===0?[0]:[1,-1]){let a=r*n*j;u.push({dir:e.direction+a,step:t,cost:Math.abs(a)+i})}}u.sort((e,t)=>e.cost-t.cost);let d={left:ae};for(let e of u){let a=s(M(t,i,n,e.dir,e.step),r.strict,d,r.needOrigin);if(a)return a}}}let p=null,m=-1,h=0,g=e.edgeStyle??`straight`,_=t=>{if(se(t,e,!1,!0).base>0)return;h++;let i=N(t,e,`loose`,!0),a=i.labels,o=g===`none`?[]:[...e.edges??[],...t.map(t=>C(e.origin,{...t,r},g,e.parentAngle).points)],s=a.filter(Boolean).length+ +!!i.originLabel,c=a.filter(e=>e&&!o.some(t=>b(t,e))).length,l=s*(n+2)+c;l>m&&(p={points:t,...i},m=l)};if(e.ring&&n>=3){let r=Math.max(e.distance,a/(2*Math.sin(Math.PI/n)));for(let i of A)_(oe(t,r*i,n,e.direction))}for(let r of c){let i=(n+ +!!e.originLabel)*(n+2)+n;if(h>=160||m===i||a>=2*r)continue;let o=2*Math.asin(a/(2*r));for(let a=0;a*j<=Math.PI&&h<160&&m<i;a++)for(let i of a===0?[0]:[1,-1])_(M(t,r,n,e.direction+i*a*j,o))}if(p)return p;let v=o?.points??M(t,e.distance,n,e.direction,a/e.distance);return{points:v,...N(v,e,`loose`,!0)}}function F(e,t=new Map){let n=new Map,r=e.edgeStyle??`straight`,i=e.nodeRadius,a=[e.hub],o=[],s=[],c=new Set,l={x:e.bounds.x+e.bounds.w/2,y:e.bounds.y+e.bounds.h/2};for(let u of e.levels){let f=u.parentId==null?null:n.get(u.parentId);if(u.parentId!=null&&!f)continue;u.parentId!=null&&c.add(u.parentId);let m=f?{x:f.x,y:f.y,r:i}:e.hub,h=t.get(u.key);if(!h||h.points.length!==u.childIds.length){let n=Math.atan2(l.y-e.hub.y,l.x-e.hub.x),p=Math.hypot(l.x-e.hub.x,l.y-e.hub.y)<1;h=P({origin:m,parentAngle:f?f.angle:null,count:u.childIds.length,direction:f?f.angle:p?-Math.PI/2:n,radius:i,distance:e.distance,gap:e.gap,bounds:e.bounds,obstacles:a.filter(e=>e.x!==m.x||e.y!==m.y),blocked:s.filter(e=>!c.has(e.id)).map(e=>e.rect),edges:o,edgeStyle:r,labels:u.childIds.map(t=>e.labelSize?.(t)??null),originLabel:f&&u.parentId?(e.branchLabelSize??e.labelSize)?.(u.parentId)??null:null,parentEdge:f?f.edge:null,labelPad:e.labelPad,...f?{maxSpread:150*d,maxDeviation:110*d}:{ring:!0,preferredStep:50*d,maxSpread:Math.PI}}),t.set(u.key,h)}f&&(f.pathLabel=h.originLabel??null,f.pathLabel&&s.push({id:`${u.parentId}\u0000open`,rect:f.pathLabel}));let g=e.labelPad??8;for(let e of s){if(c.has(e.id)||!h.points.some(t=>p(t,e.rect)<i+g-.5))continue;let[t,r]=e.id.split(`\0`),a=n.get(t);a&&(r?a.pathLabel=null:a.label=null)}u.childIds.forEach((e,t)=>{let c=h.points[t],l={x:c.x,y:c.y,r:i},u=f?f.angle:null,d=C(m,l,r,u).points;n.set(e,{x:c.x,y:c.y,from:{x:m.x,y:m.y},angle:Math.atan2(c.y-m.y,c.x-m.x),parentAngle:u,label:h.labels[t]??null,edge:d}),a.push(l),r!==`none`&&o.push(d);let p=h.labels[t];p&&s.push({id:e,rect:p})})}let u=e.levels[e.levels.length-1];if(u&&e.labelSize){let t=e.labelPad??8,a=new Map;for(let[e,t]of n)a.set(e,{x:t.x,y:t.y,r:i});let s=u.childIds.filter(e=>n.has(e)),c=e=>o.some(t=>b(t,e)),l=s.filter(t=>{let r=n.get(t).label;return e.labelSize(t)&&(!r||c(r))});if(l.length){let i={bounds:e.bounds,circles:[e.hub,...a.values()],taken:s.filter(e=>!l.includes(e)).map(e=>n.get(e).label).filter(e=>!!e),edges:o,pad:t},c=l.map(t=>({id:t,node:a.get(t),size:e.labelSize(t),angle:n.get(t).angle})),u=O(c,i,(e,t)=>{let i=n.get(e.id);return k(e.node,e.size,e.angle,t)??i.label??k(e.node,e.size,e.angle,{...t,edges:r===`none`?[]:[i.edge]})});c.forEach((e,t)=>{let r=n.get(e.id);u[t]&&u[t]!==r.label&&(r.label=u[t],r.borrowed=!0)})}}if(r===`step`&&u&&e.labelSize){let t=new Set(e.levels.flatMap(e=>e.parentId==null?[]:[e.parentId])),r=[...new Set([...t,...u.childIds])].filter(e=>n.has(e)),a=e=>t.has(e)?n.get(e).pathLabel:n.get(e).label;for(let s of r){let c=n.get(s),l=a(s),u=t.has(s)?o.filter(e=>e!==c.edge):o;if(l&&!u.some(e=>b(e,l)))continue;let d=(t.has(s)?e.branchLabelSize??e.labelSize:e.labelSize)(s);if(!d)continue;let f={x:c.x,y:c.y,r:i},p={bounds:e.bounds,circles:[e.hub,...[...n.values()].map(e=>({x:e.x,y:e.y,r:i}))],taken:r.filter(e=>e!==s).map(a).filter(e=>!!e),edges:u,pad:e.labelPad??8,rings:[...te,64,80]},m=k(f,d,c.angle,p);t.has(s)?c.pathLabel=m:c.label=m,m&&(c.borrowed=!0)}}return n}function ce(e,t,n){let r=-1,i=1/0;return t.forEach((t,a)=>{let o=Math.hypot(e.x-t.x,e.y-t.y);o<=t.r+n&&o<i&&(r=a,i=o)}),r}var le=`
2
+ --_fg: var(--unfold-fg, #17171c);
3
+ --_muted: var(--unfold-muted, rgb(23 23 28 / .68));
4
+ --_surface: var(--unfold-surface, rgb(255 255 255 / .78));
5
+ --_surface-active: var(--unfold-surface-active, rgb(255 255 255 / .96));
6
+ --_border: var(--unfold-border, rgb(255 255 255 / .7));
7
+ --_outline: var(--unfold-outline, rgb(15 15 30 / .09));
8
+ --_shadow: var(--unfold-shadow, 0 1px 2px rgb(15 15 30 / .08), 0 10px 28px -8px rgb(15 15 30 / .28));
9
+ --_edge: var(--unfold-edge, rgb(23 23 28 / .2));
10
+ --_label-bg: var(--unfold-label-bg, rgb(255 255 255 / .9));
11
+ --_label-fg: var(--unfold-label-fg, var(--_fg));
12
+ --_backdrop: var(--unfold-backdrop, rgb(244 244 248 / .42));
13
+ `,I=`
14
+ --_fg: var(--unfold-fg, #f3f3f6);
15
+ --_muted: var(--unfold-muted, rgb(243 243 246 / .7));
16
+ --_surface: var(--unfold-surface, rgb(38 38 44 / .72));
17
+ --_surface-active: var(--unfold-surface-active, rgb(56 56 64 / .92));
18
+ --_border: var(--unfold-border, rgb(255 255 255 / .12));
19
+ --_outline: var(--unfold-outline, rgb(0 0 0 / .4));
20
+ --_shadow: var(--unfold-shadow, 0 1px 2px rgb(0 0 0 / .3), 0 12px 30px -8px rgb(0 0 0 / .6));
21
+ --_edge: var(--unfold-edge, rgb(243 243 246 / .22));
22
+ --_label-bg: var(--unfold-label-bg, rgb(30 30 36 / .9));
23
+ --_label-fg: var(--unfold-label-fg, var(--_fg));
24
+ --_backdrop: var(--unfold-backdrop, rgb(8 8 12 / .45));
25
+ `,ue=`
26
+ :host {
27
+ display: inline-block;
28
+ vertical-align: middle;
29
+ }
30
+ :host([hidden]) { display: none; }
31
+
32
+ .root {
33
+ --_accent: var(--unfold-accent, #5b5bf0);
34
+ --_accent-fg: var(--unfold-accent-fg, #fff);
35
+ --_blur: var(--unfold-blur, 18px);
36
+ --_backdrop-blur: var(--unfold-backdrop-blur, 6px);
37
+ --_edge-width: var(--unfold-edge-width, 1.5px);
38
+ --_icon-size: var(--unfold-icon-size, 22px);
39
+ --_dur: var(--unfold-duration, 340ms);
40
+ --_spring: var(--unfold-easing, cubic-bezier(.22, 1.2, .36, 1));
41
+ --_ease: cubic-bezier(.3, .7, .2, 1);
42
+ --_z: var(--unfold-z-index, 2147483000);
43
+ --_node-radius: var(--unfold-node-radius, 50%);
44
+ --_trigger-radius: var(--unfold-trigger-radius, 50%);
45
+ --_border-width: var(--unfold-border-width, 1px);
46
+ --_active-scale: var(--unfold-active-scale, 1.14);
47
+ --_dim-opacity: var(--unfold-dim-opacity, .7);
48
+ --_dim-scale: var(--unfold-dim-scale, .86);
49
+ --_label-radius: var(--unfold-label-radius, 9px);
50
+ /* Follows the reader's font-size preference, never smaller than 13px. */
51
+ --_label-size: var(--unfold-label-size, max(13px, .8125rem));
52
+ --_desc-size: var(--unfold-description-size, max(12px, .75rem));
53
+ --_dock-bg: var(--unfold-dock-bg, color-mix(in srgb, var(--_surface-active) 88%, transparent));
54
+ --_dock-border: var(--unfold-dock-border, var(--_outline));
55
+ --_dock-blur: var(--unfold-dock-blur, 16px);
56
+ --_label-weight: var(--unfold-label-weight, 600);
57
+ --_label-tracking: var(--unfold-label-tracking, normal);
58
+ --_label-case: var(--unfold-label-case, none);
59
+ ${le}
60
+ /* Longhands on purpose: with no --unfold-font the family declaration is invalid and simply inherits the
61
+ page's font, while size and weight stay ours. (A shorthand with an inherited part would be dropped.) */
62
+ font-family: var(--unfold-font);
63
+ font-size: 13px;
64
+ font-weight: 500;
65
+ line-height: 1.25;
66
+ color: var(--_fg);
67
+ }
68
+ .root[data-theme="dark"] { ${I} }
69
+ @media (prefers-color-scheme: dark) {
70
+ .root[data-theme="auto"] { ${I} }
71
+ }
72
+
73
+ /* ---------------------------------------------------------------- button */
74
+
75
+ /* dock="bar": a strip along the button's edge, so page content never sits under the button. */
76
+ .dock-bar {
77
+ display: none;
78
+ position: fixed;
79
+ z-index: calc(var(--_z) - 1);
80
+ background: var(--_dock-bg);
81
+ border: 0 solid var(--_dock-border);
82
+ -webkit-backdrop-filter: blur(var(--_dock-blur)) saturate(1.4);
83
+ backdrop-filter: blur(var(--_dock-blur)) saturate(1.4);
84
+ }
85
+ .root[data-dock="bar"] .dock-bar[data-edge] { display: block; }
86
+ .dock-bar[data-edge="top"], .dock-bar[data-edge="bottom"] { left: 0; right: 0; }
87
+ .dock-bar[data-edge="left"], .dock-bar[data-edge="right"] { top: 0; bottom: 0; }
88
+ .dock-bar[data-edge="top"] { top: 0; height: calc(var(--_trigger-size) + var(--_offset-y) * 2 + env(safe-area-inset-top, 0px)); border-bottom-width: 1px; }
89
+ .dock-bar[data-edge="bottom"] { bottom: 0; height: calc(var(--_trigger-size) + var(--_offset-y) * 2 + env(safe-area-inset-bottom, 0px)); border-top-width: 1px; }
90
+ .dock-bar[data-edge="left"] { left: 0; width: calc(var(--_trigger-size) + var(--_offset-x) * 2 + env(safe-area-inset-left, 0px)); border-right-width: 1px; }
91
+ .dock-bar[data-edge="right"] { right: 0; width: calc(var(--_trigger-size) + var(--_offset-x) * 2 + env(safe-area-inset-right, 0px)); border-left-width: 1px; }
92
+
93
+ .dock {
94
+ position: fixed;
95
+ z-index: var(--_z);
96
+ width: var(--_trigger-size);
97
+ height: var(--_trigger-size);
98
+ --_ox: calc(var(--_offset-x) + env(safe-area-inset-left, 0px));
99
+ --_ox-r: calc(var(--_offset-x) + env(safe-area-inset-right, 0px));
100
+ --_oy: calc(var(--_offset-y) + env(safe-area-inset-top, 0px));
101
+ --_oy-b: calc(var(--_offset-y) + env(safe-area-inset-bottom, 0px));
102
+ }
103
+ .dock[data-position="inline"] { position: relative; z-index: auto; }
104
+ .dock[data-position^="top"] { top: var(--_oy); }
105
+ .dock[data-position^="bottom"] { bottom: var(--_oy-b); }
106
+ .dock[data-position$="left"] { left: var(--_ox); }
107
+ .dock[data-position$="right"] { right: var(--_ox-r); }
108
+ .dock[data-position="top"], .dock[data-position="bottom"], .dock[data-position="center"] {
109
+ left: calc(50% - var(--_trigger-size) / 2);
110
+ }
111
+ .dock[data-position="left"], .dock[data-position="right"], .dock[data-position="center"] {
112
+ top: calc(50% - var(--_trigger-size) / 2);
113
+ }
114
+
115
+ .trigger, .hub, .node {
116
+ all: unset;
117
+ box-sizing: border-box;
118
+ display: grid;
119
+ place-items: center;
120
+ border-radius: var(--_node-radius);
121
+ color: var(--_fg);
122
+ background: var(--_surface);
123
+ border: var(--_border-width) solid var(--_border);
124
+ box-shadow: var(--_shadow), 0 0 0 .5px var(--_outline);
125
+ -webkit-backdrop-filter: blur(var(--_blur)) saturate(1.8);
126
+ backdrop-filter: blur(var(--_blur)) saturate(1.8);
127
+ cursor: pointer;
128
+ touch-action: none;
129
+ user-select: none;
130
+ -webkit-user-select: none;
131
+ -webkit-touch-callout: none;
132
+ -webkit-tap-highlight-color: transparent;
133
+ }
134
+ .trigger:focus-visible, .hub:focus-visible, .node:focus-visible {
135
+ outline: 3px solid var(--_accent);
136
+ outline-offset: 3px;
137
+ }
138
+
139
+ .trigger, .hub { border-radius: var(--_trigger-radius); }
140
+ .trigger {
141
+ position: relative;
142
+ width: 100%;
143
+ height: 100%;
144
+ transition: scale 220ms var(--_ease), box-shadow 220ms;
145
+ }
146
+ .trigger:hover { box-shadow: var(--_shadow), 0 0 0 .5px var(--_outline), 0 0 0 6px color-mix(in srgb, var(--_accent) 10%, transparent); }
147
+ .trigger[data-pressing] { scale: .92; }
148
+ .trigger-icon, .hub-icon {
149
+ display: grid;
150
+ place-items: center;
151
+ width: var(--_icon-size);
152
+ height: var(--_icon-size);
153
+ pointer-events: none;
154
+ }
155
+ .trigger-icon[data-default] { rotate: var(--_icon-rotate, 0deg); }
156
+ .icon-own { display: contents; }
157
+ .trigger-icon[data-slotted] .icon-own { display: none; }
158
+ .icon-own > svg, .icon-own > img, .hub-icon > svg, .trigger-icon ::slotted(*) { width: 100%; height: 100%; display: block; }
159
+ .icon-own > img { object-fit: contain; }
160
+
161
+ .hold {
162
+ position: absolute;
163
+ inset: -5px;
164
+ width: calc(100% + 10px);
165
+ height: calc(100% + 10px);
166
+ rotate: -90deg;
167
+ pointer-events: none;
168
+ overflow: visible;
169
+ }
170
+ .hold circle {
171
+ fill: none;
172
+ stroke: var(--_accent);
173
+ stroke-width: 2.5;
174
+ stroke-linecap: round;
175
+ stroke-dasharray: 1 1;
176
+ stroke-dashoffset: 1;
177
+ opacity: 0;
178
+ transition: opacity 120ms, stroke-dashoffset 120ms;
179
+ }
180
+ .trigger[data-pressing] .hold circle {
181
+ opacity: 1;
182
+ stroke-dashoffset: 0;
183
+ transition: opacity 80ms, stroke-dashoffset var(--_hold) linear;
184
+ }
185
+
186
+ /* --------------------------------------------------------------- overlay */
187
+
188
+ .overlay {
189
+ position: fixed;
190
+ inset: 0;
191
+ width: 100%;
192
+ height: 100%;
193
+ max-width: none;
194
+ max-height: none;
195
+ margin: 0;
196
+ padding: 0;
197
+ border: 0;
198
+ background: transparent;
199
+ color: inherit;
200
+ overflow: hidden;
201
+ overscroll-behavior: none;
202
+ z-index: var(--_z);
203
+ touch-action: none;
204
+ }
205
+ .overlay:not([data-state]) { display: none; }
206
+ .overlay::backdrop { background: transparent; }
207
+ .overlay:focus { outline: none; }
208
+
209
+ .backdrop {
210
+ position: absolute;
211
+ inset: 0;
212
+ background: var(--_backdrop);
213
+ -webkit-backdrop-filter: blur(var(--_backdrop-blur)) saturate(1.2);
214
+ backdrop-filter: blur(var(--_backdrop-blur)) saturate(1.2);
215
+ opacity: 0;
216
+ transition: opacity var(--_dur) var(--_ease);
217
+ }
218
+ .root:not([data-backdrop]) .backdrop { background: transparent; -webkit-backdrop-filter: none; backdrop-filter: none; }
219
+ .overlay[data-state="open"] .backdrop { opacity: 1; }
220
+
221
+ .edges {
222
+ position: absolute;
223
+ inset: 0;
224
+ width: 100%;
225
+ height: 100%;
226
+ overflow: visible;
227
+ pointer-events: none;
228
+ }
229
+ .edge {
230
+ fill: none;
231
+ stroke: var(--_edge);
232
+ stroke-width: var(--_edge-width);
233
+ stroke-linecap: round;
234
+ stroke-dasharray: 1 1;
235
+ stroke-dashoffset: 1;
236
+ opacity: 0;
237
+ transition: stroke-dashoffset var(--_dur) var(--_ease) var(--_delay, 0ms), opacity 160ms var(--_delay, 0ms), stroke 160ms, stroke-width 160ms;
238
+ }
239
+ .edge[data-shown] { stroke-dashoffset: 0; opacity: 1; }
240
+ .edge[data-dim] { opacity: .45; }
241
+ .edge[data-lit] { stroke: var(--_lit, var(--_accent)); stroke-width: calc(var(--_edge-width) + .5px); }
242
+
243
+ .root[data-edges="none"] .edges { display: none; }
244
+
245
+ .layer, .labels { position: absolute; inset: 0; pointer-events: none; }
246
+
247
+ /* ----------------------------------------------------------------- nodes */
248
+
249
+ .hub {
250
+ position: absolute;
251
+ pointer-events: auto;
252
+ transition: scale 220ms var(--_ease);
253
+ }
254
+ .hub[data-active] { scale: 1.08; }
255
+ .hub-icon { transition: rotate var(--_dur) var(--_spring), opacity 160ms; }
256
+ .overlay:not([data-state="open"]) .hub-icon { rotate: -90deg; opacity: 0; }
257
+
258
+ .node {
259
+ position: absolute;
260
+ left: 0;
261
+ top: 0;
262
+ width: var(--_node-size);
263
+ height: var(--_node-size);
264
+ margin: calc(var(--_node-size) / -2) 0 0 calc(var(--_node-size) / -2);
265
+ pointer-events: auto;
266
+ scale: 1;
267
+ --_tint: var(--_node-accent, var(--_accent));
268
+ transition:
269
+ translate var(--_dur) var(--_spring) var(--_delay, 0ms),
270
+ scale var(--_dur) var(--_spring) var(--_delay, 0ms),
271
+ opacity calc(var(--_dur) * .6) var(--_ease) var(--_delay, 0ms),
272
+ background-color 160ms, border-color 160ms, box-shadow 160ms, color 160ms;
273
+ }
274
+ .node[data-state="dim"] { opacity: var(--_dim-opacity); scale: var(--_dim-scale); }
275
+ .node[data-state="path"] { border-color: color-mix(in srgb, var(--_tint) 55%, transparent); color: var(--_tint); }
276
+ .node[data-active] {
277
+ background: var(--_surface-active);
278
+ color: var(--_tint);
279
+ opacity: 1;
280
+ scale: var(--_active-scale);
281
+ box-shadow: var(--_shadow), 0 0 0 2px var(--_tint), 0 0 0 7px color-mix(in srgb, var(--_tint) 18%, transparent);
282
+ }
283
+ .node[data-current] { color: var(--_tint); }
284
+ .node[data-current]::before {
285
+ content: "";
286
+ position: absolute;
287
+ inset: -4px;
288
+ border-radius: inherit;
289
+ border: 1.5px dashed color-mix(in srgb, var(--_tint) 70%, transparent);
290
+ pointer-events: none;
291
+ }
292
+ .node[aria-disabled="true"] { opacity: .35; cursor: not-allowed; }
293
+ .node[data-enter], .node[data-leave] { scale: .35; opacity: 0; }
294
+ .node[data-leave] { pointer-events: none; transition-duration: calc(var(--_dur) * .7); }
295
+
296
+ /* A knob on the rim, pointing where the children will unfold. */
297
+ .node[data-branch]::after {
298
+ content: "";
299
+ position: absolute;
300
+ width: 7px;
301
+ height: 7px;
302
+ border-radius: 50%;
303
+ background: var(--_surface-active);
304
+ box-shadow: 0 0 0 1.5px var(--_muted);
305
+ translate: calc(cos(var(--_a, 0deg)) * (var(--_node-size) / 2 - 1px)) calc(sin(var(--_a, 0deg)) * (var(--_node-size) / 2 - 1px));
306
+ transition: background-color 160ms, box-shadow 160ms;
307
+ }
308
+ .node[data-branch][data-current-trail]::after,
309
+ .node[data-branch][data-state="path"]::after,
310
+ .node[data-branch][data-active]::after { background: var(--_tint); box-shadow: 0 0 0 1.5px var(--_tint); }
311
+ .node[data-state="path"]::after { opacity: 0; }
312
+
313
+ .icon {
314
+ display: grid;
315
+ place-items: center;
316
+ width: var(--_icon-size);
317
+ height: var(--_icon-size);
318
+ pointer-events: none;
319
+ }
320
+ .icon > svg, .icon > img { width: 100%; height: 100%; display: block; }
321
+ .icon > img { object-fit: contain; border-radius: 4px; }
322
+ .glyph { font-size: calc(var(--_icon-size) * .92); line-height: 1; }
323
+ .mono { font-weight: 650; font-size: calc(var(--_icon-size) * .8); line-height: 1; letter-spacing: -.01em; }
324
+
325
+ /* ---------------------------------------------------------------- labels */
326
+
327
+ .label {
328
+ position: absolute;
329
+ left: 0;
330
+ top: 0;
331
+ box-sizing: border-box;
332
+ width: max-content;
333
+ max-width: var(--unfold-label-max-width, 160px);
334
+ padding: 5px 10px 6px;
335
+ border-radius: var(--_label-radius);
336
+ background: var(--_label-bg);
337
+ color: var(--_label-fg);
338
+ box-shadow: 0 1px 2px rgb(0 0 0 / .06), 0 4px 14px -4px rgb(0 0 0 / .18), 0 0 0 .5px var(--_outline);
339
+ -webkit-backdrop-filter: blur(var(--_blur));
340
+ backdrop-filter: blur(var(--_blur));
341
+ overflow-wrap: anywhere;
342
+ pointer-events: none;
343
+ opacity: 0;
344
+ /* Labels never slide: a sliding label could cross another one on its way. */
345
+ transition: opacity 140ms var(--_ease);
346
+ }
347
+ .label[data-visible] { opacity: 1; transition-delay: var(--_label-delay, 0ms), 0ms; }
348
+ .label[data-instant] { transition: none; }
349
+ .label .title {
350
+ display: block;
351
+ text-wrap: balance;
352
+ font-family: var(--unfold-label-font, var(--unfold-font));
353
+ font-size: var(--_label-size);
354
+ font-weight: var(--_label-weight);
355
+ line-height: 1.25;
356
+ letter-spacing: var(--_label-tracking);
357
+ text-transform: var(--_label-case);
358
+ }
359
+ .label[data-go] .title::after { content: " →"; color: var(--_muted); font-weight: 500; }
360
+ .label .desc { display: none; margin-top: 2px; font-weight: 450; font-size: var(--_desc-size); line-height: 1.35; color: var(--_muted); }
361
+ .label[data-active] { max-width: var(--unfold-label-max-width-active, 240px); }
362
+ /* The wrapped variant, used where a one-line label doesn't fit. Words stay whole (hyphenated if needed). */
363
+ .label[data-narrow] {
364
+ max-width: var(--unfold-label-narrow-width, 96px);
365
+ min-width: min-content;
366
+ overflow-wrap: normal;
367
+ hyphens: auto;
368
+ }
369
+ .label[data-active]:not([data-compact]) .desc { display: block; }
370
+ .labels .measure { position: absolute; left: 0; top: 0; visibility: hidden; }
371
+
372
+ .sr-only {
373
+ position: absolute;
374
+ width: 1px;
375
+ height: 1px;
376
+ overflow: hidden;
377
+ clip-path: inset(50%);
378
+ white-space: nowrap;
379
+ }
380
+ .safe-probe {
381
+ position: fixed;
382
+ inset: 0;
383
+ visibility: hidden;
384
+ pointer-events: none;
385
+ padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);
386
+ }
387
+
388
+ /* Right-to-left: "back" points the other way. */
389
+ :host(:dir(rtl)) .hub[data-icon="back"] .hub-icon { scale: -1 1; }
390
+
391
+ @media (prefers-contrast: more) {
392
+ .root {
393
+ --_border-width: 2px;
394
+ --_border: currentColor;
395
+ --_muted: var(--_fg);
396
+ --_surface: var(--_surface-active);
397
+ --_label-bg: var(--_surface-active);
398
+ --_edge: color-mix(in srgb, var(--_fg) 60%, transparent);
399
+ --_dim-opacity: 1;
400
+ --_blur: 0px;
401
+ }
402
+ .label { border: 1.5px solid currentColor; }
403
+ }
404
+
405
+ @media (prefers-reduced-transparency: reduce) {
406
+ .root { --_surface: var(--_surface-active); --_label-bg: var(--_surface-active); --_blur: 0px; --_backdrop-blur: 0px; --_dock-blur: 0px; }
407
+ }
408
+
409
+ /* Windows High Contrast and other forced palettes: states move from colour/shadow to outlines. */
410
+ @media (forced-colors: active) {
411
+ .trigger, .hub, .node { border: 2px solid ButtonText; }
412
+ .node[data-active], .hub[data-active] { outline: 3px solid Highlight; outline-offset: 2px; }
413
+ .node[data-state="path"] { border-color: Highlight; }
414
+ .node[data-state="dim"] { opacity: 1; }
415
+ .node[data-current]::before { border-color: Highlight; }
416
+ .node[data-branch]::after { background: ButtonText; box-shadow: none; }
417
+ .edge { stroke: CanvasText; }
418
+ .edge[data-lit] { stroke: Highlight; }
419
+ .label { border: 1px solid CanvasText; }
420
+ .backdrop { background: Canvas; opacity: .9; }
421
+ .hold circle { stroke: Highlight; }
422
+ }
423
+
424
+ @media (prefers-reduced-motion: reduce) {
425
+ .root { --_dur: 1ms; --_spring: linear; }
426
+ .label { transition: opacity 120ms; }
427
+ }
428
+ `,L=Object.freeze({pages:`Pages`,close:`Close navigation`,backToTop:`Back to all pages`,back:`Back to {label}`}),R=Object.freeze({pages:Object.freeze([]),position:`bottom-right`,dock:`float`,offset:24,holdDelay:220,expandDelay:140,openOnTap:!0,nodeSize:52,triggerSize:60,spacing:96,gap:16,labels:`auto`,edges:`curved`,backdrop:!0,haptics:!0,theme:`auto`,current:void 0,label:`Navigation`,arrowKeys:`tree`,strings:Object.freeze({}),triggerIcon:void 0,iconResolver:void 0,navigate:void 0});function z(e){return typeof e==`string`||typeof e==`function`||typeof e==`object`&&!!e&&`cloneNode`in e&&typeof e.cloneNode==`function`}var de={position:[`top-left`,`top`,`top-right`,`left`,`center`,`right`,`bottom-left`,`bottom`,`bottom-right`,`inline`],dock:[`float`,`bar`],labels:[`auto`,`always`,`hover`,`none`],edges:[`curved`,`straight`,`step`,`none`],theme:[`auto`,`light`,`dark`],arrowKeys:[`tree`,`spatial`]};function fe(e,t){if(!t||typeof t!=`object`||Array.isArray(t))throw TypeError(`[unfold-nav] Options must be an object.`);let n={...e};for(let[e,r]of Object.entries(t)){if(!Object.hasOwn(R,e))continue;let t=e;n[t]=r===void 0?R[t]:r}for(let[e,t]of Object.entries(de))if(!t.includes(n[e]))throw TypeError(`[unfold-nav] Invalid ${e}. Expected ${t.join(`, `)}.`);for(let e of[`nodeSize`,`triggerSize`,`spacing`,`gap`,`holdDelay`,`expandDelay`]){let t=n[e],r=e===`nodeSize`||e===`triggerSize`||e===`spacing`;if(typeof t!=`number`||!Number.isFinite(t)||(r?t<=0:t<0))throw RangeError(`[unfold-nav] ${e} must be a finite ${r?`positive`:`non-negative`} number.`)}let r=n.offset,i=typeof r==`number`?[r]:r&&typeof r==`object`?[r.x,r.y]:[];if(!i.length||i.some(e=>typeof e!=`number`||!Number.isFinite(e)||e<0))throw RangeError(`[unfold-nav] offset must be a non-negative number or { x, y }.`);for(let e of[`openOnTap`,`backdrop`,`haptics`])if(typeof n[e]!=`boolean`)throw TypeError(`[unfold-nav] ${e} must be a boolean.`);if(typeof n.label!=`string`||!n.label.trim())throw TypeError(`[unfold-nav] label must be a non-empty string.`);if(n.current!=null&&typeof n.current!=`string`)throw TypeError(`[unfold-nav] current must be a URL string, null or undefined.`);for(let e of[`navigate`,`iconResolver`])if(n[e]!==void 0&&typeof n[e]!=`function`)throw TypeError(`[unfold-nav] ${e} must be a function.`);if(n.triggerIcon!==void 0&&!z(n.triggerIcon))throw TypeError(`[unfold-nav] Invalid triggerIcon.`);if(!n.strings||typeof n.strings!=`object`||Array.isArray(n.strings))throw TypeError(`[unfold-nav] strings must be an object.`);for(let e of Object.keys(L))if(n.strings[e]!==void 0&&typeof n.strings[e]!=`string`)throw TypeError(`[unfold-nav] strings.${e} must be a string.`);return n.strings=Object.fromEntries(Object.entries(n.strings).filter(([e,t])=>Object.hasOwn(L,e)&&t!==void 0)),n}function B(e){let t=Array.isArray(e)?{label:`Navigation`,children:e}:e??{label:`Navigation`,children:[]},n=new Map,r={id:``,page:t,parent:null,children:[],depth:0,index:0},i=new WeakSet,a=(e,t)=>{if(!e||typeof e!=`object`||Array.isArray(e))throw TypeError(`[unfold-nav] ${t} must be a page object.`);if(typeof e.label!=`string`||!e.label.trim())throw TypeError(`[unfold-nav] ${t}.label must be a non-empty string.`);for(let n of[`id`,`href`,`target`,`description`,`color`])if(e[n]!==void 0&&typeof e[n]!=`string`)throw TypeError(`[unfold-nav] ${t}.${n} must be a string.`);if(e.children!==void 0&&!Array.isArray(e.children))throw TypeError(`[unfold-nav] ${t}.children must be an array.`);if(e.disabled!==void 0&&typeof e.disabled!=`boolean`)throw TypeError(`[unfold-nav] ${t}.disabled must be a boolean.`);if(e.icon!==void 0&&!z(e.icon))throw TypeError(`[unfold-nav] ${t}.icon is invalid.`);if(i.has(e))throw TypeError(`[unfold-nav] ${t} contains a cyclic page tree.`)};a(t,`pages`),i.add(t);let o=(e,t,r)=>{(t??[]).forEach((t,s)=>{let c=[...r,s];a(t,`pages[${c.join(`].children[`)}]`);let l=t.id!=null&&t.id!==``?String(t.id):`n${c.join(`.`)}`;if(n.has(l)){let e=2;for(;n.has(`${l}~${e}`);)e++;l=`${l}~${e}`}let u={id:l,page:t,parent:e,children:[],depth:e.depth+1,index:s};n.set(l,u),e.children.push(u),i.add(t),o(u,t.children,c),i.delete(t)})};return o(r,t.children,[]),{root:r,byId:n}}function V(e){let t=[];for(let n=e;n&&n.depth>0;n=n.parent)t.unshift(n.id);return t}var H=e=>e.length>1?e.replace(/\/+$/,``):e;function U(e,t,n){let r;try{r=new URL(t,n)}catch{return null}let i=H(r.pathname),a=null,o=-1,s=null,c=-1;for(let t of e.byId.values()){let e=t.page.href;if(!e)continue;let l;try{l=new URL(e,n)}catch{continue}if(l.origin!==r.origin||l.search&&l.search!==r.search||l.hash&&l.hash!==r.hash)continue;let u=H(l.pathname);if(u===i){let e=+!!l.search+ +!!l.hash;(!a||e>o||e===o&&t.depth>a.depth)&&(a=t,o=e)}else u!==`/`&&i.startsWith(u+`/`)&&u.length>c&&(s=t,c=u.length)}return a??s}var pe=[`top`,`right`,`bottom`,`left`],W=new WeakMap;function me(e,t,n,r=0){let i=W.get(t);if(!i&&!n)return;i||(i={owners:new Map,previous:new Map},W.set(t,i)),n?i.owners.set(e,{edge:n,size:r}):i.owners.delete(e);let a=t.documentElement.style;for(let e of pe){let t=`--unfold-inset-${e}`,n=[...i.owners.values()].filter(t=>t.edge===e).map(e=>e.size);if(n.length)i.previous.has(e)||i.previous.set(e,{value:a.getPropertyValue(t),priority:a.getPropertyPriority(t)}),a.setProperty(t,`calc(${Math.max(...n)}px + env(safe-area-inset-${e}, 0px))`);else{let n=i.previous.get(e);n&&(n.value?a.setProperty(t,n.value,n.priority):a.removeProperty(t),i.previous.delete(e))}}i.owners.size||W.delete(t)}function he(e,t){try{let n=new URL(e,t);return[`http:`,`https:`,`mailto:`,`tel:`,`sms:`].includes(n.protocol)?n.href:null}catch{return null}}var G=Object.keys(R),K={pages:`pages`,position:`position`,dock:`dock`,offset:`offset`,"hold-delay":`holdDelay`,"expand-delay":`expandDelay`,"open-on-tap":`openOnTap`,"node-size":`nodeSize`,"trigger-size":`triggerSize`,spacing:`spacing`,gap:`gap`,labels:`labels`,edges:`edges`,backdrop:`backdrop`,haptics:`haptics`,theme:`theme`,current:`current`,label:`label`,"arrow-keys":`arrowKeys`,"trigger-icon":`triggerIcon`};function ge(e,t){if(t===null)return R[e];if(e===`offset`){let[e,n=e]=t.trim().split(/[\s,]+/).map(Number);return{x:e,y:n}}if(e===`pages`)return JSON.parse(t);switch(typeof R[e]){case`number`:return Number(t);case`boolean`:return!/^(false|0|off|no)$/i.test(t.trim())}return t}var _e=`http://www.w3.org/2000/svg`,ve=``,q=typeof HTMLElement<`u`&&`showPopover`in HTMLElement.prototype,ye=typeof HTMLElement>`u`?class{}:HTMLElement,J={ArrowUp:{x:0,y:-1},ArrowDown:{x:0,y:1},ArrowLeft:{x:-1,y:0},ArrowRight:{x:1,y:0}};function Y(e,t,n,r=``){n?e.setAttribute(t,r):e.removeAttribute(t)}function X(e,t,n){let r=[t];for(let[e,i]of Object.entries(n))i&&r.push(`${t}-${e}`);let i=r.join(` `);e.getAttribute(`part`)!==i&&e.setAttribute(`part`,i)}var Z=class extends ye{static get observedAttributes(){return Object.keys(K)}opts={...R};text=L;tree=B([]);currentId=null;currentTrail=new Set;state=`closed`;mode=`tap`;path=[];active=null;focusId=null;views=new Map;placed=new Map;fanCache=new Map;labelSizes=new Map;branchLabelSizes=new Map;narrowSizes=new Map;narrowBranchSizes=new Map;hub={x:0,y:0,r:30};bounds={x:0,y:0,w:0,h:0};animationTimers=new Set;pointerId=null;pointerType=`mouse`;downAt={x:0,y:0};lastPoint={x:0,y:0};leftHub=!1;holdTimer=0;dwellTimer=0;dwellTarget=null;closeTimer=0;resizeFrame=0;openedAt=0;lastPointerUp=-1/0;typeahead={text:``,at:0};lastKeyActivation=-1/0;els;constructor(){if(typeof document>`u`)throw Error(`[unfold-nav] Create navigation elements in a browser after mounting.`);super();let e=this.attachShadow({mode:`open`});e.innerHTML=`<style>${ue}</style>
429
+ <div class="root" part="root">
430
+ <div class="dock-bar" part="dock-bar" aria-hidden="true"></div>
431
+ <div class="dock" part="dock">
432
+ <button class="trigger" part="trigger" type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="graph">
433
+ <svg class="hold" viewBox="0 0 100 100" aria-hidden="true"><circle cx="50" cy="50" r="47" pathLength="1"/></svg>
434
+ <span class="trigger-icon" part="trigger-icon" aria-hidden="true"><slot name="icon"></slot><span class="icon-own"></span></span>
435
+ </button>
436
+ </div>
437
+ <dialog class="overlay" part="overlay" id="graph">
438
+ <div class="backdrop" part="backdrop" aria-hidden="true"></div>
439
+ <svg class="edges" part="edges" aria-hidden="true"></svg>
440
+ <div class="layer" role="tree"></div>
441
+ <div class="labels" aria-hidden="true"><div class="measure"></div></div>
442
+ <button class="hub" part="hub" type="button"><span class="hub-icon" aria-hidden="true"></span></button>
443
+ </dialog>
444
+ <div class="safe-probe" aria-hidden="true"></div>
445
+ </div>`;let t=t=>e.querySelector(t);this.els={root:t(`.root`),dockBar:t(`.dock-bar`),dock:t(`.dock`),trigger:t(`.trigger`),triggerIcon:t(`.trigger-icon`),iconSlot:t(`slot[name="icon"]`),iconOwn:t(`.icon-own`),overlay:t(`.overlay`),edges:t(`.edges`),layer:t(`.layer`),labels:t(`.labels`),measure:t(`.measure`),hub:t(`.hub`),hubIcon:t(`.hub-icon`),probe:t(`.safe-probe`)},q&&this.els.overlay.setAttribute(`popover`,`manual`),this.els.iconSlot.addEventListener(`slotchange`,()=>this.syncSlotted());let{trigger:n,overlay:r}=this.els;n.addEventListener(`pointerdown`,this.onPointerDown),n.addEventListener(`pointermove`,this.onPointerMove),n.addEventListener(`pointerup`,this.onPointerUp),n.addEventListener(`pointercancel`,this.onPointerCancel),n.addEventListener(`lostpointercapture`,this.onLostCapture),n.addEventListener(`click`,this.onTriggerClick),n.addEventListener(`keydown`,this.onTriggerKey),n.addEventListener(`contextmenu`,e=>e.preventDefault()),r.addEventListener(`click`,this.onOverlayClick),r.addEventListener(`pointermove`,this.onOverlayHover),r.addEventListener(`keydown`,this.onOverlayKey),r.addEventListener(`cancel`,this.onCancel),r.addEventListener(`close`,this.onDialogClose),r.addEventListener(`wheel`,e=>e.preventDefault(),{passive:!1}),r.addEventListener(`touchmove`,e=>e.preventDefault(),{passive:!1}),r.addEventListener(`contextmenu`,e=>e.preventDefault()),this.applyOptions()}configure(e){let t=fe(this.opts,e),n=Object.hasOwn(e,`pages`),r=n?B(t.pages):this.tree;if(this.opts=t,this.tree=r,n&&this.state!==`closed`){let e=this.state===`open`,t=this.focusInside();this.finishClose(),t&&this.isConnected&&this.els.trigger.focus({preventScroll:!0}),e&&this.emit(`unfold-close`)}return this.fanCache.clear(),this.clearLabelSizes(),this.applyOptions(),this.state===`open`&&(this.measure(),this.render()),this}get isOpen(){return this.state===`open`}open({focus:e=!1}={}){this.show(`tap`,e?`keyboard`:`pointer`)}close({focusTrigger:e=!1}={}){if(this.state!==`open`)return;let t=this.focusInside();this.state=`closing`,window.clearTimeout(this.holdTimer),window.clearTimeout(this.dwellTimer),this.holdTimer=this.dwellTimer=0,this.dwellTarget=null,this.pointerId=null,window.removeEventListener(`keydown`,this.onWindowKey,!0);let{overlay:n,trigger:r,hub:i}=this.els;if(n.dataset.state=`closing`,n.setAttribute(`aria-hidden`,`true`),i.tabIndex=-1,n.open&&(n.close(),q))try{n.showPopover()}catch{}r.setAttribute(`aria-expanded`,`false`);let a=[...this.views.values()].filter(e=>!e.leaveTimer).reverse(),o=this.reducedMotion?0:Math.min(12,120/Math.max(1,a.length));a.forEach((e,t)=>this.leave(e,this.hub,t*o)),this.closeTimer=window.setTimeout(()=>this.finishClose(),this.duration+a.length*o+60),(e||t)&&r.focus({preventScroll:!0}),this.emit(`unfold-close`)}toggle(){this.state===`open`?this.close():this.open()}connectedCallback(){for(let e of G)this.upgradeProperty(e);if(!this.tree.root.children.length){let e=this.querySelector(`script[type="application/json"]`);if(e?.textContent?.trim())try{this.configure({pages:JSON.parse(e.textContent)})}catch(e){console.warn(`[unfold-nav] Invalid inline pages:`,e)}}window.addEventListener(`resize`,this.onResize),document.fonts?.addEventListener(`loadingdone`,this.onFontsLoaded),this.publishInsets(),this.onResize()}disconnectedCallback(){window.removeEventListener(`resize`,this.onResize),window.removeEventListener(`keydown`,this.onWindowKey,!0),document.fonts?.removeEventListener(`loadingdone`,this.onFontsLoaded),window.clearTimeout(this.holdTimer),window.clearTimeout(this.dwellTimer),this.holdTimer=this.dwellTimer=0,this.pointerId=null,this.els.trigger.removeAttribute(`data-pressing`),cancelAnimationFrame(this.resizeFrame),this.resizeFrame=0,this.finishClose(),this.publishInsets()}attributeChangedCallback(e,t,n){if(t===n)return;let r=K[e];if(r)try{this.configure({[r]:ge(r,n)})}catch(t){console.warn(`[unfold-nav] Ignoring invalid ${e} attribute:`,t)}}upgradeProperty(e){if(Object.prototype.hasOwnProperty.call(this,e)){let t=this[e];delete this[e],this.configure({[e]:t})}}applyOptions(){let e=this.opts,{root:t,dock:n,dockBar:r,trigger:i,layer:a,overlay:o}=this.els;this.text={...L,...e.strings},t.dataset.theme=e.theme,t.dataset.edges=e.edges,t.dataset.dock=e.dock,Y(t,`data-backdrop`,e.backdrop),n.dataset.position=e.position;let s=this.dockEdge();Y(r,`data-edge`,!!s,s??``);let c=this.offsets;t.style.setProperty(`--_offset-x`,`${c.x}px`),t.style.setProperty(`--_offset-y`,`${c.y}px`),t.style.setProperty(`--_trigger-size`,`${e.triggerSize}px`),t.style.setProperty(`--_node-size`,`${e.nodeSize}px`),t.style.setProperty(`--_hold`,`${e.holdDelay}ms`),i.setAttribute(`aria-label`,e.label),o.setAttribute(`aria-label`,e.label),a.setAttribute(`aria-label`,this.text.pages),this.syncIcon(),this.publishInsets()}get offsets(){let e=this.opts.offset;return typeof e==`number`?{x:e,y:e}:e}dockEdge(){let e=this.opts.position;return e===`center`||e===`inline`?null:e.startsWith(`top`)?`top`:e.startsWith(`bottom`)?`bottom`:e}publishInsets(){let e=this.isConnected?this.dockEdge():null,t=this.offsets,n=this.opts.triggerSize+2*(e===`top`||e===`bottom`?t.y:t.x);me(this,this.ownerDocument,e,n)}syncIcon(){let e=this.opts,t=r(e.triggerIcon??this.tree.root.page.icon,e.iconResolver);this.els.iconOwn.replaceChildren(t??r(o,void 0)),this.els.iconOwn.toggleAttribute(`data-custom`,!!t),this.syncSlotted()}syncSlotted(){let e=this.els.iconSlot.assignedNodes().length>0;Y(this.els.triggerIcon,`data-slotted`,e),Y(this.els.triggerIcon,`data-default`,!e&&!this.els.iconOwn.hasAttribute(`data-custom`)),this.isConnected&&this.orientIcon()}show(e,t){if(this.state===`open`||!this.isConnected)return;window.clearTimeout(this.closeTimer),this.state=`open`,this.mode=e,this.path=[],this.active=null,this.focusId=null,this.dwellTarget=null,this.computeCurrent();let{overlay:n,trigger:r,hub:i}=this.els;if(n.dataset.state=`open`,n.dataset.mode=e,n.removeAttribute(`aria-hidden`),i.tabIndex=0,this.present(e===`tap`),r.setAttribute(`aria-expanded`,`true`),this.openedAt=performance.now(),this.measure(),this.render(),this.haptic(10),e===`drag`&&window.addEventListener(`keydown`,this.onWindowKey,!0),this.emit(`unfold-open`,{mode:e}),e===`tap`&&t!==`none`){let e=this.initialFocusId();e&&this.focusNode(e,t===`keyboard`)}}present(e){let t=this.els.overlay;try{e?(q&&t.matches(`:popover-open`)&&t.hidePopover(),t.open||t.showModal()):!t.open&&!(q&&t.matches(`:popover-open`))&&(q?t.showPopover():t.show())}catch{}}finishClose(){window.clearTimeout(this.closeTimer),this.state=`closed`,window.removeEventListener(`keydown`,this.onWindowKey,!0),window.clearTimeout(this.holdTimer),window.clearTimeout(this.dwellTimer),this.holdTimer=this.dwellTimer=0,this.dwellTarget=null,this.pointerId=null,this.els.trigger.removeAttribute(`data-pressing`);for(let e of this.animationTimers)window.clearTimeout(e);this.animationTimers.clear();for(let e of this.views.values())window.clearTimeout(e.leaveTimer),e.node.remove(),e.label.remove(),e.edge.remove();this.views.clear(),this.placed.clear();let{overlay:e}=this.els;try{e.open&&e.close(),q&&e.matches(`:popover-open`)&&e.hidePopover()}catch{}e.removeAttribute(`data-state`),e.removeAttribute(`aria-hidden`),this.els.trigger.setAttribute(`aria-expanded`,`false`)}onCancel=e=>{e.preventDefault(),this.state===`open`&&(this.path.length?this.goUp(!0):this.close({focusTrigger:!0}))};onDialogClose=()=>{this.state===`open`&&!this.els.overlay.open&&!(q&&this.els.overlay.matches(`:popover-open`))&&(this.finishClose(),this.emit(`unfold-close`),this.els.trigger.focus({preventScroll:!0}))};onWindowKey=e=>{e.key===`Escape`&&this.state===`open`&&this.mode===`drag`&&(e.preventDefault(),this.close())};focusInside(){let e=this.shadowRoot?.activeElement;return!!e&&this.els.overlay.contains(e)}computeCurrent(){let e=this.opts.current===void 0?location.href:this.opts.current,t=e?U(this.tree,e,location.href):null;this.currentId=t?.id??null,this.currentTrail=new Set(V(t))}initialFocusId(){return(this.currentId?V(this.tree.byId.get(this.currentId)):[])[0]??this.tree.root.children[0]?.id??null}measure(){let{trigger:e,hub:t,probe:n,overlay:r}=this.els,i=e.getBoundingClientRect(),a=e.offsetWidth/2,o={x:i.left+i.width/2,y:i.top+i.height/2,r:a};(o.x!==this.hub.x||o.y!==this.hub.y||o.r!==this.hub.r)&&this.fanCache.clear(),this.hub=o,Object.assign(t.style,{left:`${o.x-a}px`,top:`${o.y-a}px`,width:`${a*2}px`,height:`${a*2}px`});let s=r.getBoundingClientRect(),c=s.width||document.documentElement.clientWidth,l=s.height||window.innerHeight,u=getComputedStyle(n),d={t:parseFloat(u.paddingTop)||0,r:parseFloat(u.paddingRight)||0,b:parseFloat(u.paddingBottom)||0,l:parseFloat(u.paddingLeft)||0},f={x:d.l+8,y:d.t+8,w:c-d.l-d.r-16,h:l-d.t-d.b-16};(f.w!==this.bounds.w||f.h!==this.bounds.h)&&this.fanCache.clear(),this.bounds=f}orientIcon(){let e=this.els.trigger.getBoundingClientRect(),t=e.left+e.width/2,n=e.top+e.height/2,r=document.documentElement.clientWidth/2-t,i=window.innerHeight/2-n,a=Math.hypot(r,i)<2?0:Math.atan2(i,r)*180/Math.PI+90;this.els.root.style.setProperty(`--_icon-rotate`,`${a.toFixed(1)}deg`)}onResize=()=>{cancelAnimationFrame(this.resizeFrame),this.resizeFrame=requestAnimationFrame(()=>{this.resizeFrame=0,this.isConnected&&(this.orientIcon(),this.state===`open`&&(this.measure(),this.render()))})};clearLabelSizes(){for(let e of[this.labelSizes,this.branchLabelSizes,this.narrowSizes,this.narrowBranchSizes])e.clear()}onFontsLoaded=()=>{this.clearLabelSizes(),this.fanCache.clear(),this.state===`open`&&this.render()};render(){if(this.state!==`open`)return;let{root:e,byId:t}=this.tree,n=this.opts.nodeSize/2,r=[{key:``,parentId:null,childIds:e.children.map(e=>e.id)}],i=[];for(let e of this.path){let n=t.get(e);if(!n||!n.children.length||(n.parent?.id??``)!==(i[i.length-1]??``))break;i.push(e),r.push({key:i.join(ve),parentId:e,childIds:n.children.map(e=>e.id)})}this.path=i;let a=new Set(i),o=r[r.length-1].parentId??``,l=this.opts.labels!==`none`;l&&this.measureLabels(r.flatMap(e=>e.childIds)),this.placed=F({hub:this.hub,bounds:this.bounds,levels:r,nodeRadius:n,distance:this.opts.spacing,gap:this.opts.gap,edgeStyle:this.opts.edges,labelSize:l?e=>this.sizesOf(e,!1):void 0,branchLabelSize:l?e=>this.sizesOf(e,!0):void 0,labelPad:this.labelPad},this.fanCache);for(let e of this.views.values())!this.placed.has(e.tree.id)&&!e.leaveTimer&&this.leave(e,e.from,0);let u=this.focusId&&this.placed.has(this.focusId)?this.focusId:this.initialFocusId(),d=[];for(let e of r){let r=(e.parentId?this.views.get(e.parentId):null)?.node??null;for(let i of e.childIds){let s=this.placed.get(i),c=this.views.get(i);c?c.leaveTimer&&(window.clearTimeout(c.leaveTimer),c.leaveTimer=0,c.node.removeAttribute(`data-leave`),c.edge.setAttribute(`data-shown`,``)):(c=this.createView(t.get(i),s),this.views.set(i,c),r?r.after(c.node):this.els.layer.append(c.node),d.push(c)),r=c.node,c.from=s.from;let{node:l,edge:f,tree:p}=c,m=a.has(i)?`path`:(p.parent?.id??``)===o?`frontier`:`dim`;l.dataset.state=m,Y(l,`data-active`,i===this.active),Y(l,`data-current`,i===this.currentId),Y(l,`data-current-trail`,this.currentTrail.has(i)&&i!==this.currentId),i===this.currentId?l.setAttribute(`aria-current`,`page`):l.removeAttribute(`aria-current`),p.children.length&&l.setAttribute(`aria-expanded`,String(a.has(i))),l.tabIndex=i===u?0:-1,l.style.setProperty(`--_a`,`${s.angle.toFixed(4)}rad`),d.includes(c)||(l.style.translate=`${s.x}px ${s.y}px`),X(l,`node`,{active:i===this.active,current:i===this.currentId,trail:this.currentTrail.has(i)&&i!==this.currentId,path:m===`path`,frontier:m===`frontier`,dim:m===`dim`,branch:p.children.length>0,disabled:!!p.page.disabled});let h=e.parentId==null?this.hub:{...this.placed.get(e.parentId),r:n},g=a.has(i)||i===this.active,_=m===`dim`&&i!==this.active;f.setAttribute(`d`,C(h,{x:s.x,y:s.y,r:n},this.opts.edges,s.parentAngle).d),Y(f,`data-lit`,g),Y(f,`data-dim`,_),X(f,`edge`,{lit:g,dim:_})}}d.length&&this.animateIn(d),this.renderLabels();let f=this.els.hub,p=i.length?`back`:`close`;f.dataset.icon!==p&&(f.dataset.icon=p,this.els.hubIcon.innerHTML=i.length?c:s);let m=i.length>1?t.get(i[i.length-2]).page.label:null;f.setAttribute(`aria-label`,i.length?m?this.text.back.replace(`{label}`,m):this.text.backToTop:this.text.close),Y(f,`data-active`,this.mode===`drag`&&this.dwellTarget===`hub`),X(f,`hub`,{back:i.length>0,active:f.hasAttribute(`data-active`)})}get labelPad(){let e=parseFloat(getComputedStyle(this.els.root).getPropertyValue(`--_active-scale`))||1.14;return this.opts.nodeSize/2*Math.max(0,e-1)+8}buildLabel(e){let t=document.createElement(`div`);t.className=`label`,t.setAttribute(`part`,`label`);let n=document.createElement(`span`);if(n.className=`title`,n.textContent=e.page.label,t.append(n),e.page.description){let n=document.createElement(`span`);n.className=`desc`,n.textContent=e.page.description,t.append(n)}return t}sizesOf(e,t){let n=(t?this.branchLabelSizes.get(e):null)??this.labelSizes.get(e);if(!n)return null;let r=(t?this.narrowBranchSizes.get(e):null)??this.narrowSizes.get(e);return r?[n,r]:n}measureLabels(e){let t=e.filter(e=>!this.labelSizes.has(e));if(!t.length)return;let n=this.els.measure,r=e=>e.children.length&&e.page.href?[!1,!0]:[!1],i=t.flatMap(e=>{let t=this.tree.byId.get(e);return r(t).flatMap(r=>[!1,!0].map(i=>{let a=this.buildLabel(t);return Y(a,`data-go`,r),Y(a,`data-narrow`,i),n.append(a),{id:e,el:a,go:r,narrow:i}}))}),a=e=>({w:Math.ceil(e.offsetWidth)+1,h:Math.ceil(e.offsetHeight)+1});for(let{id:e,el:t,go:n,narrow:r}of i)(r?n?this.narrowBranchSizes:this.narrowSizes:n?this.branchLabelSizes:this.labelSizes).set(e,a(t));for(let[e,n]of[[this.labelSizes,this.narrowSizes],[this.branchLabelSizes,this.narrowBranchSizes]])for(let r of t){let t=n.get(r);t&&t.w>=(e.get(r)?.w??0)-1&&n.delete(r)}n.replaceChildren()}createView(e,t){let n=e.page,a=document.createElement(`button`);a.type=`button`,a.className=`node`,a.setAttribute(`part`,`node`),a.setAttribute(`role`,`treeitem`),a.setAttribute(`aria-label`,n.label),a.setAttribute(`aria-level`,String(e.depth)),a.setAttribute(`aria-setsize`,String(e.parent?.children.length??1)),a.setAttribute(`aria-posinset`,String(e.index+1)),n.description&&a.setAttribute(`aria-description`,n.description),n.disabled&&a.setAttribute(`aria-disabled`,`true`),e.children.length&&(a.dataset.branch=``),n.color&&a.style.setProperty(`--_node-accent`,n.color),a.dataset.id=e.id;let o=document.createElement(`span`);o.className=`icon`,o.setAttribute(`part`,`icon`),o.setAttribute(`aria-hidden`,`true`),o.append(r(n.icon,this.opts.iconResolver,n)??i(n.label)),a.append(o);let s=this.buildLabel(e);this.els.labels.append(s);let c=document.createElementNS(_e,`path`);return c.setAttribute(`class`,`edge`),c.setAttribute(`part`,`edge`),c.setAttribute(`pathLength`,`1`),n.color&&c.style.setProperty(`--_lit`,n.color),this.els.edges.append(c),{tree:e,node:a,label:s,edge:c,from:t.from,leaveTimer:0,shownAt:null}}animateIn(e){let t=this.reducedMotion?0:22;for(let t of e)t.node.style.transition=`none`,t.node.style.translate=`${t.from.x}px ${t.from.y}px`,t.node.dataset.enter=``;this.els.layer.offsetWidth,e.forEach((e,n)=>{let r=this.placed.get(e.tree.id),i=n*t;e.node.style.transition=``,e.node.style.setProperty(`--_delay`,`${i}ms`),e.edge.style.setProperty(`--_delay`,`${i}ms`),e.label.style.setProperty(`--_label-delay`,`${i+this.duration*.6}ms`),e.node.style.translate=`${r.x}px ${r.y}px`,e.node.removeAttribute(`data-enter`),e.edge.setAttribute(`data-shown`,``);let a=window.setTimeout(()=>{this.animationTimers.delete(a),e.node.style.removeProperty(`--_delay`),e.edge.style.removeProperty(`--_delay`),e.label.style.removeProperty(`--_label-delay`)},i+this.duration);this.animationTimers.add(a)})}leave(e,t,n){let{node:r,edge:i,label:a}=e;if(this.shadowRoot?.activeElement===r&&this.state===`open`){let t=e.tree.parent?this.views.get(e.tree.parent.id):null;t&&!t.leaveTimer?(this.focusId=t.tree.id,t.node.tabIndex=0,t.node.focus({preventScroll:!0})):this.els.hub.focus({preventScroll:!0})}r.style.setProperty(`--_delay`,`${n}ms`),i.style.setProperty(`--_delay`,`${n}ms`),r.style.translate=`${t.x}px ${t.y}px`,r.setAttribute(`data-leave`,``),r.removeAttribute(`data-active`),r.setAttribute(`part`,`node node-leaving`),i.setAttribute(`part`,`edge`),a.setAttribute(`part`,`label`),r.tabIndex=-1,i.removeAttribute(`data-shown`),a.removeAttribute(`data-visible`),e.shownAt=null,e.leaveTimer=window.setTimeout(()=>{r.remove(),a.remove(),i.remove(),this.views.delete(e.tree.id)},n+this.duration*.7+40)}renderLabels(){let e=this.opts.labels,t=this.opts.nodeSize/2,n=[...this.views.values()].filter(e=>!e.leaveTimer),r=new Map;for(let e of n){let n=this.placed.get(e.tree.id);r.set(e.tree.id,{x:n.x,y:n.y,r:t})}let i=this.opts.edges===`none`?[]:n.map(e=>this.placed.get(e.tree.id).edge),a=new Map,o=new Set,s=new Set,c=this.labelPad,l=(e,t=i)=>({bounds:this.bounds,circles:[this.hub,...r.values()],taken:[...a].filter(([t])=>t!==e).map(([,e])=>e),edges:t,pad:c}),u=(e,t=i)=>{let n=l(e,t),a=this.active?r.get(this.active):null,o=r.get(e),s=n.circles.map(e=>e===a&&e!==o?{...e,r:e.r+c-6}:e);return{...n,circles:s,pad:6,ownPad:c}},d=(e,t)=>![...a].some(([n,r])=>n!==t&&m(e,r,4)),f=(e,t,n)=>{a.set(e,t),t.w<n.w-1?o.add(e):o.delete(e)},p=(e,t)=>!!e&&!!t&&e.w>=t.w-1&&e.h>=t.h-1;for(let e of n)Y(e.label,`data-go`,this.mode===`tap`&&e.node.dataset.state===`path`&&!!e.tree.page.href),e.tree.id!==this.active&&e.label.removeAttribute(`data-active`),e.label.removeAttribute(`data-compact`),e.label.removeAttribute(`data-narrow`);if(e===`auto`||e===`always`){let t=[...n].sort((e,t)=>Number(t.node.dataset.state===`frontier`)-Number(e.node.dataset.state===`frontier`));for(let n of t){let t=n.tree.id,r=n.node.dataset.state,i=this.placed.get(t).label;(r===`frontier`||r===`dim`&&e===`always`)&&i&&d(i,t)&&f(t,i,this.labelSizes.get(t)??i)}for(let e of n){let t=e.tree.id;if(a.has(t)||t===this.active||e.node.dataset.state!==`frontier`)continue;let n=this.placed.get(t),i=this.sizesOf(t,!1);if(!i)continue;let o=r.get(t),s=u(t),c=k(o,i,n.angle,s)??k(o,i,n.angle,{...s,edges:[n.edge]});c&&f(t,c,this.labelSizes.get(t))}}let h=this.active?this.views.get(this.active):null;if(h&&!h.leaveTimer&&e!==`none`){let e=h.tree.id,t=this.placed.get(e),n=r.get(e),i=h.label,o=h.node.dataset.state===`path`,c=r=>{let i=u(e);return k(n,r,t.angle,i)??k(n,r,t.angle,{...i,edges:[t.edge]})??(o?k(n,r,t.angle,{...i,edges:[]}):null)},l=()=>({w:i.offsetWidth+1,h:i.offsetHeight+1});i.setAttribute(`data-active`,``);let m=l(),g=h.tree.page.description?c(m):null;if(!g){s.add(e),i.setAttribute(`data-compact`,``),m=l();let n=(o?this.narrowBranchSizes.get(e):null)??this.narrowSizes.get(e),r=n?[m,n]:m,f=o?t.pathLabel:t.label,h=a.get(e)??(f&&d(f,e)?f:null);if(g=h&&(p(h,m)||p(h,n))?h:c(r),!g){let t=u(e),n=Math.atan2(this.bounds.y+this.bounds.h/2-this.hub.y,this.bounds.x+this.bounds.w/2-this.hub.x);g=k(this.hub,r,n,t)??k(this.hub,r,n,{...t,edges:[]})}}g?f(e,g,m):a.delete(e)}if(e===`auto`||e===`always`)for(let e of this.path){if(e===this.active||a.has(e))continue;let t=this.views.get(e);if(!t||t.leaveTimer)continue;let n=this.placed.get(e),o={w:t.label.offsetWidth+1,h:t.label.offsetHeight+1},s=this.narrowBranchSizes.get(e)??this.narrowSizes.get(e),c=s?[o,s]:o,l=n.pathLabel&&(p(n.pathLabel,o)||p(n.pathLabel,s))&&d(n.pathLabel,e)?n.pathLabel:null,m=r.get(e),h=[0,12,28,48],g=l??k(m,c,n.angle,{...u(e),rings:h})??k(m,c,n.angle+Math.PI,{...u(e,i.filter(e=>e!==n.edge)),rings:h});g&&f(e,g,o)}for(let e of this.views.values()){let t=e.tree.id,n=e.leaveTimer?null:a.get(t)??null,r=t===this.active&&!!n;if(Y(e.label,`data-active`,r),Y(e.label,`data-narrow`,!!n&&o.has(t)),s.has(t)||e.label.removeAttribute(`data-compact`),X(e.label,`label`,{active:r,path:e.node.dataset.state===`path`}),!n){e.label.removeAttribute(`data-visible`),e.shownAt=null;continue}let i=e.shownAt&&(Math.abs(e.shownAt.x-n.x)>1||Math.abs(e.shownAt.y-n.y)>1);e.label.style.translate=`${n.x.toFixed(1)}px ${n.y.toFixed(1)}px`,e.label.setAttribute(`data-visible`,``),i&&!this.reducedMotion&&e.label.animate([{opacity:0},{opacity:1}],{duration:160,easing:`ease-out`}),e.shownAt=n}}onPointerDown=e=>{if(!e.isPrimary||e.pointerType===`mouse`&&e.button!==0||this.state===`open`)return;e.preventDefault();let{trigger:t}=this.els;try{t.setPointerCapture(e.pointerId)}catch{}this.pointerId=e.pointerId,this.pointerType=e.pointerType,this.downAt=this.lastPoint={x:e.clientX,y:e.clientY},this.leftHub=!1,t.setAttribute(`data-pressing`,``),this.holdTimer=window.setTimeout(()=>this.beginDrag(),this.opts.holdDelay)};beginDrag(){window.clearTimeout(this.holdTimer),this.holdTimer=0,this.els.trigger.removeAttribute(`data-pressing`),this.show(`drag`,`none`)}onPointerMove=e=>{if(e.pointerId!==this.pointerId)return;let t=this.lastPoint={x:e.clientX,y:e.clientY};if(this.state!==`open`){if(this.holdTimer&&Math.hypot(t.x-this.downAt.x,t.y-this.downAt.y)>10)this.beginDrag();else return}this.mode===`drag`&&this.dragTo(t)};onPointerUp=e=>{if(e.pointerId!==this.pointerId)return;this.pointerId=null,this.lastPointerUp=performance.now();let t=this.holdTimer!==0;if(window.clearTimeout(this.holdTimer),this.holdTimer=0,this.els.trigger.removeAttribute(`data-pressing`),this.state!==`open`){t&&this.opts.openOnTap&&this.show(`tap`,`pointer`);return}this.mode===`drag`&&this.release({x:e.clientX,y:e.clientY})};onPointerCancel=e=>{e.pointerId===this.pointerId&&(this.pointerId=null,window.clearTimeout(this.holdTimer),this.holdTimer=0,this.els.trigger.removeAttribute(`data-pressing`),this.state===`open`&&this.mode===`drag`&&this.close())};onLostCapture=e=>{e.pointerId===this.pointerId&&(this.pointerId=null,window.clearTimeout(this.holdTimer),this.holdTimer=0,this.els.trigger.removeAttribute(`data-pressing`),this.state===`open`&&this.mode===`drag`&&this.release(this.lastPoint))};onTriggerClick=e=>{performance.now()-this.lastPointerUp<700||(this.state===`open`?this.close({focusTrigger:!0}):this.show(`tap`,e.detail===0?`keyboard`:`pointer`))};onTriggerKey=e=>{this.state===`closed`&&(e.key===`ArrowUp`||e.key===`ArrowDown`)&&(e.preventDefault(),this.show(`tap`,`keyboard`))};hitAt(e){let t=[],n=[],r=this.opts.nodeSize/2;for(let[e,i]of this.placed){let a=this.views.get(e);a&&!a.leaveTimer&&(t.push(e),n.push({x:i.x,y:i.y,r}))}t.push(`hub`),n.push(this.hub);let i=ce(e,n,this.pointerType===`mouse`?6:14);if(i>=0)return t[i];for(let t of this.views.values())if(!t.leaveTimer&&t.shownAt&&h(t.shownAt,e))return t.tree.id;return null}dragTo(e){let t=this.hitAt(e);t===`hub`?(this.setActive(null),this.dwell(this.leftHub&&this.path.length?`hub`:null)):t?(this.leftHub=!0,this.setActive(t),this.dwell(t)):(Math.hypot(e.x-this.hub.x,e.y-this.hub.y)>this.hub.r+6&&(this.leftHub=!0),this.setActive(null),this.dwellTarget&&this.dwellTarget!==`hub`&&this.isBeyond(e,this.dwellTarget)||this.dwell(null)),Y(this.els.hub,`data-active`,this.dwellTarget===`hub`)}isBeyond(e,t){let n=this.placed.get(t);if(!n||!this.tree.byId.get(t)?.children.length)return!1;let r=n.x-n.from.x,i=n.y-n.from.y,a=Math.hypot(r,i)||1,o=r/a,s=i/a,c=e.x-n.from.x,l=e.y-n.from.y,u=c*o+l*s,d=Math.abs(c*s-l*o);return u>a&&u<a+this.opts.spacing*1.2&&d<this.opts.spacing*.55}dwell(e){e!==this.dwellTarget&&(window.clearTimeout(this.dwellTimer),this.dwellTimer=0,this.dwellTarget=e,e&&(this.dwellTimer=window.setTimeout(()=>{if(this.dwellTimer=0,e===`hub`)return this.setPath([]);let t=this.tree.byId.get(e);t&&!t.page.disabled&&this.setPath(V(t.children.length?t:t.parent))},this.opts.expandDelay)))}release(e){window.clearTimeout(this.dwellTimer),this.dwellTimer=0,this.dwellTarget=null;let t=this.hitAt(e);if(t&&t!==`hub`){let e=this.tree.byId.get(t);if(!e.page.disabled){if(e.page.href||!e.children.length)return this.select(e,`release`);this.path=V(e)}return this.toTapMode(t)}if(!this.leftHub)return this.toTapMode(null);this.close()}toTapMode(e){this.mode=`tap`,this.els.overlay.dataset.mode=`tap`,window.removeEventListener(`keydown`,this.onWindowKey,!0),this.present(!0),this.render();let t=e??this.initialFocusId();t&&this.focusNode(t,!1)}onOverlayHover=e=>{if(this.state!==`open`||this.mode!==`tap`||e.pointerType!==`mouse`)return;let t=this.hitAt({x:e.clientX,y:e.clientY});this.setActive(t===`hub`?null:t)};onOverlayClick=e=>{if(this.state!==`open`||this.mode!==`tap`)return;let t=performance.now();if(t-this.openedAt<250||e.detail===0&&t-this.lastKeyActivation<500)return;let n=e.target;if(n.closest(`.hub`))return this.hubAction(e.detail===0);let r=n.closest(`.node`)?.dataset.id??null;if(!r&&e.detail!==0){let t=this.hitAt({x:e.clientX,y:e.clientY});r=t===`hub`?null:t}let i=r?this.tree.byId.get(r):null;if(!i)return this.close();let a=e.detail===0?`keyboard`:`click`;this.focusNode(i.id,a===`keyboard`),this.activate(i,a,e.metaKey||e.ctrlKey||e.button===1)};hubAction(e){this.path.length?this.goUp(e):this.close({focusTrigger:!0})}onOverlayKey=e=>{if(this.state!==`open`)return;let t=e.key;if(t===`Escape`){e.preventDefault(),this.close({focusTrigger:!0});return}if(this.mode!==`tap`)return;let n=e.composedPath()[0],r=n instanceof Element?n.closest(`.node`):null;if(!r){if(n===this.els.hub)return;if(t in J||t===`Home`||t===`End`){e.preventDefault();let t=this.focusId&&this.placed.has(this.focusId)?this.focusId:this.initialFocusId();t&&this.focusNode(t)}return}let i=this.tree.byId.get(r.dataset.id);if(i){if(this.focusId!==i.id&&(this.focusId=i.id),t===`Enter`||t===` `)return e.preventDefault(),this.lastKeyActivation=performance.now(),this.activateKey(i,e.metaKey||e.ctrlKey);if(t===`Backspace`)return e.preventDefault(),this.stepBack(i);if(this.opts.arrowKeys===`spatial`?this.spatialKey(i,t):this.treeKey(i,t)){e.preventDefault();return}t.length===1&&!e.metaKey&&!e.ctrlKey&&!e.altKey&&t!==` `&&this.typeAhead(i,t)}};visibleOrder(){let e=[],t=n=>{for(let r of n)e.push(r.id),this.path.includes(r.id)&&t(r.children)};return t(this.tree.root.children),e}treeKey(e,t){let n=getComputedStyle(this).direction===`rtl`,r=this.visibleOrder(),i=r.indexOf(e.id),a=this.path.includes(e.id);if(t===`ArrowDown`)i<r.length-1&&this.focusNode(r[i+1]);else if(t===`ArrowUp`)i>0&&this.focusNode(r[i-1]);else if(t===(n?`ArrowLeft`:`ArrowRight`))e.children.length&&!e.page.disabled&&(a?this.focusNode(e.children[0].id):(this.path=V(e),this.haptic(6),this.focusNode(e.id)));else if(t===(n?`ArrowRight`:`ArrowLeft`))a?(this.path=V(e.parent),this.focusNode(e.id)):e.parent&&e.parent.depth>0&&this.focusNode(e.parent.id);else if(t===`Home`)this.focusNode(r[0]);else if(t===`End`)this.focusNode(r[r.length-1]);else return!1;return!0}spatialKey(e,t){if(t in J){let n=this.placed.get(e.id);if(!n)return!0;let r=J[t],i=null,a=1/0;for(let[t,o]of this.placed){if(t===e.id||this.views.get(t)?.leaveTimer)continue;let s=o.x-n.x,c=o.y-n.y,l=s*r.x+c*r.y;if(l<=1)continue;let u=Math.abs(s*r.y-c*r.x);if(u>l*2.2)continue;let d=l+u*2;d<a&&(a=d,i=t)}return i&&this.focusNode(i),!0}if(t===`Home`||t===`End`){let n=e.parent?.children??[],r=t===`Home`?n[0]:n[n.length-1];return r&&this.focusNode(r.id),!0}return!1}activateKey(e,t){if(!e.page.disabled){if(this.opts.arrowKeys===`spatial`)return this.activate(e,`keyboard`,t);if(e.page.href||!e.children.length)return this.select(e,`keyboard`,t);this.path=this.path.includes(e.id)?V(e.parent):V(e),this.haptic(6),this.focusNode(e.id)}}stepBack(e){e.parent&&e.parent.depth>0?(this.path=V(e.parent.parent),this.focusNode(e.parent.id)):this.path.length&&(this.path=[],this.focusNode(e.id))}typeAhead(e,t){let n=performance.now();this.typeahead.text=n-this.typeahead.at<700?this.typeahead.text+t.toLowerCase():t.toLowerCase(),this.typeahead.at=n;let r=this.opts.arrowKeys===`spatial`?(e.parent?.children??[]).map(e=>e.id):this.visibleOrder(),i=this.typeahead.text,a=r.indexOf(e.id),o=i.length===1?a+1:a;for(let e=0;e<r.length;e++){let t=r[(o+e)%r.length];if(this.tree.byId.get(t).page.label.toLowerCase().startsWith(i))return this.focusNode(t)}}goUp(e){let t=this.path[this.path.length-1];this.path=this.path.slice(0,-1),t?this.focusNode(t,e):this.render()}focusNode(e,t=!0){this.focusId=e,t&&(this.active=e),this.render(),this.views.get(e)?.node.focus({preventScroll:!0}),t&&this.emitHighlight()}activate(e,t,n=!1){if(e.page.disabled)return;if(n&&e.page.href)return this.select(e,t,!0);let r=this.path.includes(e.id);if(e.children.length&&!r){this.path=V(e),this.haptic(6),t===`keyboard`?this.focusNode(e.children[0].id):(this.active=e.id,this.render());return}if(e.children.length&&!e.page.href){this.path=V(e.parent),t===`keyboard`?this.focusNode(e.id):this.render();return}this.select(e,t,n)}select(e,t,n=!1){let r={page:e.page,trail:V(e).map(e=>this.tree.byId.get(e).page),via:t},i=this.emit(`unfold-select`,r,!0);if(this.haptic(12),this.close({focusTrigger:t===`keyboard`}),!i)return;let{href:a,target:o}=e.page;if(this.opts.navigate&&!(a&&(n||o&&o!==`_self`))){this.opts.navigate(e.page,r);return}if(!a)return;let s=he(a,document.baseURI);if(!s){console.warn(`[unfold-nav] Refusing an unsupported navigation URL:`,a);return}n||o&&o!==`_self`?window.open(s,n?`_blank`:o,`noopener`):location.assign(s)}setActive(e){e!==this.active&&(this.active=e,e&&this.mode===`drag`&&this.haptic(4),this.render(),this.emitHighlight())}setPath(e){e.length===this.path.length&&e.every((e,t)=>e===this.path[t])||(this.path=e,this.haptic(6),this.render())}emit(e,t,n=!1){return this.dispatchEvent(new CustomEvent(e,{detail:t,bubbles:!0,composed:!0,cancelable:n}))}emitHighlight(){let e=this.active?this.tree.byId.get(this.active)?.page??null:null;this.emit(`unfold-highlight`,{page:e})}haptic(e){if(this.opts.haptics)try{navigator.vibrate?.(e)}catch{}}get reducedMotion(){return matchMedia(`(prefers-reduced-motion: reduce)`).matches}get duration(){let e=getComputedStyle(this.els.root).getPropertyValue(`--_dur`).trim(),t=parseFloat(e);return Number.isFinite(t)?e.endsWith(`ms`)?t:e.endsWith(`s`)?t*1e3:t:340}};if(typeof HTMLElement<`u`)for(let e of G)Object.defineProperty(Z.prototype,e,{configurable:!0,enumerable:!0,get(){return this.opts[e]},set(t){this.configure({[e]:t})}});var Q=`unfold-nav`;function $(e=Q){typeof customElements>`u`||customElements.get(e)||customElements.define(e,e===`unfold-nav`?Z:class extends Z{})}$();function be(e,t){if(typeof document>`u`)throw Error(`[unfold-nav] Call createUnfoldNav in a browser after mounting.`);let n=t??document.body;if(!n)throw Error(`[unfold-nav] Wait for document.body or provide a container.`);$();let r=document.createElement(Q);return r.configure(e),n.append(r),r}e.DEFAULT_OPTIONS=R,e.DEFAULT_STRINGS=L,e.TAG=Q,e.UnfoldNav=Z,e.buildTree=B,e.createUnfoldNav=be,e.define=$,e.findCurrent=U,e.layoutGraph=F,e.placeFan=P,e.placeLabel=k});
446
+ //# sourceMappingURL=unfold-nav.umd.cjs.map