@zumer/orbit 2.0.0 → 2.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.
package/dist/orbit.min.js CHANGED
@@ -1,10 +1,10 @@
1
1
  /*
2
2
  * orbit
3
- * v.2.0.0
3
+ * v.2.1.0
4
4
  * Author Juan Martin Muda - Zumerlab
5
5
  * License MIT
6
6
  */
7
- (()=>{var b=Symbol.for("zumer.orbit.layout.state.v1"),C=Symbol.for("zumer.orbit.layout.registry.v1"),H=Symbol.for("zumer.orbit.layout.probe.v1"),z="o-arc, o-progress",j={subtree:!0,childList:!0,characterData:!0,attributes:!0,attributeOldValue:!0};function $(s){var t;for(let r of s.classList||[])if(/^orbit-\d+$/.test(r))return Number(r.slice(6));return(t=s.classList)!=null&&t.contains("orbit")?null:void 0}var W=Symbol.for("zumer.orbit.warned.v1");function p(s,t,r){let i=s[W]||(s[W]=new Set);i.has(t)||(i.add(t),console.warn(`[orbit] ${r}`))}function _(s,t){var r,i;for(let e=s;e;e=e.parentElement||((r=e.getRootNode)==null?void 0:r.call(e).host))if((i=e.matches)!=null&&i.call(e,t))return e;return null}var Q=".satellite, .vector, .side, o-arc, o-progress";function A(s){let t=[...s.classList].slice(0,3).map(r=>"."+r).join("");return`<${s.localName}${t?" "+t:""}>`}function tt(s){let t=s.parentElement,r=_(t.parentElement,".bigbang, .satellite");r?r.getClientRects().length&&(!r.clientWidth||!r.clientHeight)&&p(r,"empty",`${A(r)} has no size (${r.clientWidth}\xD7${r.clientHeight}px), so its system is invisible. Give it a width, or place it in a parent with a width.`):p(t,"universe",'A .gravity-spot is not inside a .bigbang, so it measures the viewport. Wrap it: <div class="bigbang"><div class="gravity-spot">\u2026</div></div>.');let i=s.querySelector(":scope > o-arc, :scope > o-progress");if(i){let e=s.ownerDocument.defaultView.getComputedStyle(s),n=e.getPropertyValue("--o-ellipse-x").trim(),o=e.getPropertyValue("--o-ellipse-y").trim();(n&&Number(n)!==1||o&&Number(o)!==1)&&p(s,"ellipse-visual",`${A(i)} is on ${A(s)}, which is stretched into an ellipse (--o-ellipse-x: ${n||1}, --o-ellipse-y: ${o||1}). Arcs and progress are drawn on circles only, so it is hidden. Put it on a round ring.`)}if(_(s,".dev-orbit")){for(let e of s.children)if($(e)!==void 0)p(e,"nested-ring",`${A(e)} is inside another ring. Rings must be direct children of .gravity-spot; to nest a system, put a .gravity-spot directly inside a .satellite.`);else if(!e.matches(Q))p(e,"ring-child",`${A(e)} is not placed by its ring. A ring holds only .satellite, .vector, .side, <o-arc> and <o-progress>; wrap content as <div class="satellite"><div class="capsule">\u2026</div></div>.`);else if(e.classList.contains("satellite"))for(let n of e.children)n.matches(".capsule, .gravity-spot, .bigbang")||p(n,"satellite-child",`${A(n)} sits directly in a .satellite. Put content in a .capsule so it stays upright and centered.`)}}function v(s,t,r){let i=String(r);s.style.getPropertyValue(t)!==i&&s.style.setProperty(t,i)}function y(s,t,r=0,i="number"){let e=String(t||"").trim();if(!e)return r;if(i==="number"&&/^[+-]?(?:\d+\.?\d*|\.\d+)$/.test(e))return Number(e);let n=e.match(/^([+-]?(?:\d+\.?\d*|\.\d+))(deg|rad|grad|turn)?$/);if(i==="angle"&&n)return Number(n[1])*({deg:1,rad:180/Math.PI,grad:.9,turn:360}[n[2]]||1);let o=s.ownerDocument;if(!(o!=null&&o.documentElement))return r;let c=o[H];c||(c=o.createElement("span"),c.setAttribute("data-orbit-measure",""),c.setAttribute("aria-hidden","true"),c.style.cssText="all:initial!important;position:fixed!important;visibility:hidden!important;pointer-events:none!important;width:0!important;height:0!important;overflow:hidden!important;",o.documentElement.appendChild(c),Object.defineProperty(o,H,{value:c,configurable:!0}));let a=i==="angle"?"rotate":"scale";if(c.style.removeProperty(a),c.style.setProperty(a,e,"important"),!c.style.getPropertyValue(a))return r;let l=o.defaultView.getComputedStyle(c).getPropertyValue(a),u=parseFloat(l);return Number.isFinite(u)?u:r}function et(s){if(s.localName==="o-arc")return"arc";for(let t of["satellite","vector","side"])if(s.classList.contains(t))return t;return null}function rt(s){let t={arc:0,satellite:0,vector:0,side:0};for(let n of s.children){let o=et(n);o?v(n,"--o-layout-index",t[o]++-(o==="side"?1:0)):n.localName==="o-progress"&&v(n,"--o-layout-index",0)}let r=Math.max(t.arc,t.satellite,t.vector,1),i=t.satellite||t.vector,e=t.side?String(t.side):i?`max(1, ${r} - var(--o-fit-range, 0))`:String(r);v(s,"--o-layout-angle",`calc(var(--o-range, 360deg) / ${e})`)}function B(s){return(s==null?void 0:s.nodeType)===9||(s==null?void 0:s.nodeType)===11&&!!s.host}function R(s){var r;if(B(s))return s;let t=(r=s==null?void 0:s.getRootNode)==null?void 0:r.call(s);return B(t)?t:null}function V(s,t){var r,i;for(let e=t;e;e=(r=e.getRootNode)==null?void 0:r.call(e).host)if(s===e||(i=s.contains)!=null&&i.call(s,e))return!0;return!1}function st(s){return s[C]||Object.defineProperty(s,C,{value:{states:new Set},configurable:!0}),s[C]}function O(s){s.frame<0?s.view.clearTimeout(-s.frame):s.frame&&s.view.cancelAnimationFrame(s.frame),s.frame=0}function Z(s){for(let t of s.waiters.splice(0))t()}function q(s){if(!s.disposed){s.disposed=!0,O(s),Z(s),s.observer.disconnect(),s.resize.disconnect();for(let t of s.listeners)t();s.rings.clear(),s.visuals.clear(),s.dirty.clear(),s.registry.states.delete(s),s.scope[b]===s&&delete s.scope[b]}}function F(s){for(let t of s.states)t.scope.host&&!t.scope.host.isConnected&&q(t)}function k(s,t=s.scope){for(let r of s.registry.states)r!==s&&r.scope.host&&V(t,r.scope.host)&&(r.all=!0,r.queue())}function it(s){return s.nodeType!==1||s.hasAttribute("data-orbit-measure")?!1:$(s)!==void 0||s.matches(".gravity-spot, o-arc, o-progress")?!0:!!s.querySelector(".gravity-spot, .orbit, [data-orbit-ring], o-arc, o-progress")}function nt(s){return s.nodeType===1&&(s.matches('style, link[rel~="stylesheet"]')||!!s.querySelector('style, link[rel~="stylesheet"]'))}function ot(s,t){if(s.type==="childList")return[...s.addedNodes,...s.removedNodes].some(it);if(s.attributeName!=="class")return!1;let r=s.target;return t.rings.has(r)||r.classList.contains("gravity-spot")||$(r)!==void 0||(s.oldValue||"").split(/\s+/).some(i=>i==="gravity-spot"||i==="orbit"||/^orbit-\d+$/.test(i))}function at(s){let t=s.nodeType===9?s:s.ownerDocument,r=t.defaultView,i=st(t),e={scope:s,doc:t,view:r,registry:i,rings:new Set,visuals:new Set,dirty:new Set,scan:!0,all:!0,frame:0,disposed:!1,listeners:[],waiters:[]},n=(a,l,u,h)=>{a==null||a.addEventListener(l,u,h),e.listeners.push(()=>a==null?void 0:a.removeEventListener(l,u,h))},o=()=>{if(e.disposed||e.frame)return;let a=()=>{e.frame=0,e.flush()};e.frame=t.visibilityState==="hidden"?-r.setTimeout(a,0):r.requestAnimationFrame(a)};e.queue=o,e.flush=()=>lt(e),e.invalidate=(a=s,l=!0)=>{var u,h;if(l&&(a===s||a===t.documentElement||a===t.head))e.all=!0;else{for(let d of e.rings)(d===a||d.contains(a)||l&&((u=a.contains)!=null&&u.call(a,d)))&&e.dirty.add(d);for(let d of e.visuals)(d===a||d.contains(a)||l&&((h=a.contains)!=null&&h.call(a,d)))&&e.dirty.add(d)}(e.all||e.dirty.size||e.scan)&&o()},e.observer=new r.MutationObserver(a=>{var l,u;if(a.some(h=>h.type==="childList")&&F(i),!e.disposed)for(let h of a){let d=h.target.nodeType===3?h.target.parentElement:h.target;if(!d||(l=d.hasAttribute)!=null&&l.call(d,"data-orbit-measure"))continue;let g=ot(h,e);g&&(e.scan=!0),h.type==="childList"&&[...h.addedNodes,...h.removedNodes].some(nt)||(u=d.closest)!=null&&u.call(d,"head, style")||d.localName==="link"?(e.all=!0,k(e)):h.type==="attributes"&&k(e,d),e.invalidate(d,h.type==="attributes"||g)}}),e.observer.observe(s,j),e.resize=new r.ResizeObserver(a=>{for(let l of a)e.dirty.add(l.target);o()});let c=()=>{e.all=!0,k(e),o()};n(t,"visibilitychange",()=>{t.visibilityState==="hidden"&&e.frame>0&&(O(e),o())}),s===t&&(n(r,"resize",c),n(t.fonts,"loadingdone",c)),n(s,"load",a=>{a.target.localName==="link"&&c()},!0);for(let a of["pointerover","pointerout","focusin","focusout"])n(s,a,l=>{e.invalidate(l.target),k(e,l.target)},!0);return Object.defineProperty(s,b,{value:e,configurable:!0}),i.states.add(e),o(),e}function M(s){let t=s.nodeType===9?s:s.ownerDocument;if(!(t!=null&&t.defaultView)||!t.documentElement||s.host&&!s.host.isConnected)return null;if(s[b]&&s[b].doc!==t&&q(s[b]),s.host){let r=R(s.host);r&&M(r)}return s[b]||at(s)}function ct(s){let t=new Set,r=new Map;for(let e of s.scope.querySelectorAll(".gravity-spot > *")){let n=$(e);if(n===void 0)continue;let o=r.get(e.parentElement)||0;e.classList.contains("orbit")&&r.set(e.parentElement,++o);let c=n===null?o:n;e.setAttribute("data-orbit-ring",""),v(e,"--o-layout-number",c===0?1e-5:c),t.add(e),s.dirty.add(e),s.rings.has(e)||s.resize.observe(e)}for(let e of s.rings)if(!t.has(e)){s.resize.unobserve(e),e.removeAttribute("data-orbit-ring");for(let n of["--o-layout-number","--o-layout-angle"])e.style.removeProperty(n)}s.rings=t;let i=new Set(s.scope.querySelectorAll(z));for(let e of s.visuals)i.has(e)||s.resize.unobserve(e);for(let e of i)s.visuals.has(e)||(s.resize.observe(e),s.dirty.add(e));s.visuals=i,s.scan=!1}function lt(s){if(s.disposed)return;if(s.scope.host&&!s.scope.host.isConnected){q(s);return}s.observer.disconnect();let t=[];try{s.scan&&ct(s);let r=s.all?new Set([...s.rings,...s.visuals]):s.dirty,i=new Set;for(let e of r)if(e.isConnected)if(s.rings.has(e)){rt(e),tt(e);for(let n of e.querySelectorAll(z))i.add(n)}else s.visuals.has(e)&&i.add(e);for(let e of s.visuals)i.has(e)&&e.update&&(e.update(),t.push(e));s.dirty=new Set,s.all=!1}finally{s.disposed||s.observer.observe(s.scope,j)}for(let r of t)r.dispatchEvent(new s.view.Event("o-rendered",{bubbles:!0,composed:!0}));s.frame||Z(s)}function E(s=globalThis.document){var i;let t=R(s);if(!t)return;let r=M(t);r&&((i=s==null?void 0:s.matches)!=null&&i.call(s,z)&&!r.visuals.has(s)&&(r.scan=!0),r.invalidate(s||t))}function D(s=globalThis.document){let t=R(s);if(!t)return;let r=M(t);if(r){F(r.registry);for(let i of r.registry.states)i!==r&&(!i.scope.host||!V(s,i.scope.host))||(i.scan=!0,i.all=!0,O(i),i.flush())}}function G(s=globalThis.document){let t=R(s),r=t&&M(t);if(!r)return Promise.resolve();F(r.registry);let i=[...r.registry.states].filter(e=>e===r||e.scope.host&&V(s,e.scope.host));return Promise.all(i.map(e=>new Promise(n=>{e.waiters.push(n),e.queue()}))).then(()=>{})}var w=class extends(globalThis.HTMLElement||class{}){constructor(){super()}connectedCallback(){for(let t of["value","max"])if(Object.prototype.hasOwnProperty.call(this,t)){let r=this[t];delete this[t],this[t]=r}E(this)}get value(){let t=this.getAttribute("value");return t===null||t.trim()===""?null:Number(t)}set value(t){t==null||t===""?this.removeAttribute("value"):this.setAttribute("value",String(t))}get max(){let t=this.getAttribute("max");return t===null?100:Number(t)}set max(t){t==null||t===""?this.removeAttribute("max"):this.setAttribute("max",String(t))}disconnectedCallback(){this._textFrame&&this.ownerDocument.defaultView.cancelAnimationFrame(this._textFrame),this._textFrame=0}readNumber(t,r,i=0){return y(this,t.getPropertyValue(r),i)}readAngle(t,r,i=0){return y(this,t.getPropertyValue(r),i,"angle")}readValue(){let t=this.getAttribute("value");if(t===null||t.trim()==="")return 0;let r=Number(t);return Number.isFinite(r)?r:(p(this,"value:"+t,`<${this.localName} value="${t}"> is not a number, so nothing is drawn.`),0)}readMax(){let t=this.getAttribute("max");if(t===null)return 100;let r=Number(t);return r>0?r:(p(this,"max:"+t,`<${this.localName} max="${t}"> must be a positive number, so nothing is drawn.`),0)}getCommonAttributes(t){var g;let r=t.ownerDocument.defaultView.getComputedStyle(t),i=parseFloat(r.getPropertyValue("r")),e=Math.max(0,Number.isFinite(i)?i:(((g=t.parentElement)==null?void 0:g.clientWidth)||0)/2),n=Math.max(1e-5,this.readNumber(r,"--o-orbit-number",1)),o=Math.max(0,this.readNumber(r,"--o-size-ratio",1)),c=Math.max(0,this.readNumber(r,"--o-stroke-width",1)),a=t.getAttribute("shape")||"none",l=Math.max(0,e/n*o-c+.3),u=e>0?Math.min(49.999,l*25/e):0,h=0;t.classList.contains("outer-orbit")?h=u:t.classList.contains("quarter-outer-orbit")?h=u*-.5:t.classList.contains("inner-orbit")?h=u*-1:t.classList.contains("quarter-inner-orbit")&&(h=u*.5);let d=50+h;return{orbitRadius:e,arcHeight:l,realRadius:d,arcAngle:0,shape:a,arcHeightPercentage:u,orbitNumber:n,size:o,strokeWidth:c,style:r}}getProgressAngle(t,r,i=100){return!Number.isFinite(r)||!Number.isFinite(i)||i<=0?0:Math.min(1,Math.max(0,r/i))*Math.max(0,Math.min(360,t))}arcPoint(t,r,i=0,e=0){let n=t+i,o=r+e*Math.PI/180;return{x:50+n*Math.cos(o),y:50+n*Math.sin(o)}}calculateCommonArcParameters(t,r,i,e,n,o,c,a=0){let l=Math.PI/2,u=Math.max(0,Math.min(360,t))*Math.PI/180,h=r+i,d=Math.max(.001,r-i),g=Math.min(u*.49,(a+o*1.25)/e/h),m=Math.min(u*.49,(a+o*1.25)/e/d),f=g-l,x=u-g-l,P=m-l,S=u-m-l,U=this.arcPoint(h,f),X=this.arcPoint(h,x),Y=this.arcPoint(d,P),J=this.arcPoint(d,S);return{upperArcStart:U,upperArcEnd:X,innerArcStart:Y,innerArcEnd:J,bigRadius:h,smallRadius:d,radius:r,upperAngleStart:f,upperAngleEnd:x,innerAngleStart:P,innerAngleEnd:S}}generatePathData(t,r){switch(t){case"rounded":return this.generateRoundedPath(r);case"circle":case"circle-a":case"bullet":return this.generateCirclePath(r,t);case"circle-b":return this.generateCircleBPath(r);case"arrow":return this.generateArrowPath(r);case"backslash":case"slash":return this.generateSlashPath(r,t);case"zigzag":return this.generateZigzagPath(r);default:return this.generateDefaultPath(r)}}pt(t,r){let i=this.arcPoint(t,r);return`${i.x},${i.y}`}arcTo(t,r,i){let e=Math.max(1,Math.ceil(Math.abs(i-r)/(Math.PI/2)-1e-9)),n=i>=r?1:0,o="";for(let c=1;c<=e;c++)o+=` A ${t},${t} 0 0 ${n} ${this.pt(t,r+(i-r)*c/e)}`;return o}linePath(t,r,i){return`M ${this.pt(t,r)}${this.arcTo(t,r,i)}`}ending(t,r){let{bigRadius:i,smallRadius:e}=t,n=(i-e)/2,o=(i+e)/2,c=Math.min(t.upperAngleEnd-t.upperAngleStart,t.innerAngleEnd-t.innerAngleStart),a=Math.max(0,Math.min(n*r,c*e*.49));return{h:n,middle:o,length:a,angle:a/o}}generateDefaultPath(t){let{bigRadius:r,smallRadius:i,upperAngleStart:e,upperAngleEnd:n,innerAngleStart:o,innerAngleEnd:c}=t;return`M ${this.pt(r,e)}${this.arcTo(r,e,n)} L ${this.pt(i,c)}${this.arcTo(i,c,o)} Z`}generateRoundedPath(t){let{bigRadius:r,smallRadius:i,upperAngleStart:e,upperAngleEnd:n,innerAngleStart:o,innerAngleEnd:c}=t,{length:a}=this.ending(t,.5),l=(h,d)=>` A ${a},${a} 0 0 1 ${this.pt(h,d)}`,u=`M ${this.pt(r,e+a/r)}${this.arcTo(r,e+a/r,n-a/r)}`;return u+=`${l(r-a,n)} L ${this.pt(i+a,c)}${l(i,c-a/i)}`,u+=this.arcTo(i,c-a/i,o+a/i),u+=`${l(i+a,o)} L ${this.pt(r-a,e)}${l(r,e+a/r)} Z`,u}generateCirclePath(t,r){let{bigRadius:i,smallRadius:e,upperAngleStart:n,upperAngleEnd:o,innerAngleStart:c,innerAngleEnd:a}=t,l=r==="bullet"?0:1,u=`M ${this.pt(i,n)}${this.arcTo(i,n,o)} A 1,1 0 0 1 ${this.pt(e,a)}`;return u+=`${this.arcTo(e,a,c)} A 1,1 0 0 ${l} ${this.pt(i,n)} Z`,u}generateCircleBPath(t){let{bigRadius:r,smallRadius:i}=t,{h:e,angle:n}=this.ending(t,1),o=t.upperAngleStart+n,c=t.upperAngleEnd-n,a=`M ${this.pt(r,o)}${this.arcTo(r,o,c)} A ${e},${e} 0 0 1 ${this.pt(i,c)}`;return a+=`${this.arcTo(i,c,o)} A ${e},${e} 0 0 1 ${this.pt(r,o)} Z`,a}generateArrowPath(t){let{bigRadius:r,smallRadius:i}=t,{middle:e,angle:n}=this.ending(t,1.6),o=t.upperAngleStart,c=t.upperAngleEnd,a=`M ${this.pt(r,o)}${this.arcTo(r,o,c-n)}`;return a+=` L ${this.pt(e,c)} L ${this.pt(i,c-n)}`,a+=`${this.arcTo(i,c-n,o)} L ${this.pt(e,o+n)} Z`,a}generateSlashPath(t,r){let{bigRadius:i,smallRadius:e}=t,{angle:n}=this.ending(t,1),o=t.upperAngleStart,c=t.upperAngleEnd,[a,l,u,h]=r==="backslash"?[o,c-n,o+n,c]:[o+n,c,o,c-n];return`M ${this.pt(i,a)}${this.arcTo(i,a,l)} L ${this.pt(e,h)}${this.arcTo(e,h,u)} Z`}generateZigzagPath(t){let{bigRadius:r,smallRadius:i}=t,{middle:e,angle:n}=this.ending(t,1.6),o=t.upperAngleStart,c=t.upperAngleEnd,a=`M ${this.pt(r,o+n)}${this.arcTo(r,o+n,c)}`;return a+=` L ${this.pt(e,c-n)} L ${this.pt(i,c)}`,a+=`${this.arcTo(i,c,o+n)} L ${this.pt(e,o)} Z`,a}updateHitArea(t,r,i,e){let n=Math.max(0,Number(this.getAttribute("hit-width"))||0);if(this.fitCanvas(r,this.hasAttribute("interactive")?n:0),!this.hasAttribute("interactive")||!(e>i)||!(r.orbitRadius>0)){t.removeAttribute("d");return}let o=c=>(c-90)*Math.PI/180;t.setAttribute("d",this.linePath(r.realRadius,o(i),o(Math.min(e,i+360)))),t.style.strokeWidth=`${r.arcHeight+r.strokeWidth+2*n}px`}fitCanvas(t,r){let i=this.shadowRoot.querySelector("svg"),e=t.orbitRadius/50;if(!i||!(e>0))return;let n=(t.realRadius+t.arcHeightPercentage)*e+t.strokeWidth+r,o=Math.max(0,Math.ceil(n-t.orbitRadius)),c=o/e;i.setAttribute("viewBox",`${-c} ${-c} ${100+2*c} ${100+2*c}`),i.style.inset=`${-o}px`}};var T=class extends w{constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML=`
7
+ (()=>{var w=Symbol.for("zumer.orbit.layout.state.v1"),q=Symbol.for("zumer.orbit.layout.registry.v1"),j=Symbol.for("zumer.orbit.layout.probe.v1"),F="o-arc, o-progress",U={subtree:!0,childList:!0,characterData:!0,attributes:!0,attributeOldValue:!0};function M(i){var t;for(let r of i.classList||[])if(/^orbit-\d+$/.test(r))return Number(r.slice(6));return(t=i.classList)!=null&&t.contains("orbit")?null:void 0}var Z=Symbol.for("zumer.orbit.warned.v1");function p(i,t,r){let s=i[Z]||(i[Z]=new Set);s.has(t)||(s.add(t),console.warn(`[orbit] ${r}`))}function G(i,t){var r,s;for(let e=i;e;e=e.parentElement||((r=e.getRootNode)==null?void 0:r.call(e).host))if((s=e.matches)!=null&&s.call(e,t))return e;return null}var Q=".satellite, .vector, .side, o-arc, o-progress";function P(i){let t=[...i.classList].slice(0,3).map(r=>"."+r).join("");return`<${i.localName}${t?" "+t:""}>`}function tt(i){let t=i.parentElement,r=G(t.parentElement,".bigbang, .satellite");r?r.getClientRects().length&&(!r.clientWidth||!r.clientHeight)&&p(r,"empty",`${P(r)} has no size (${r.clientWidth}\xD7${r.clientHeight}px), so its system is invisible. Give it a width, or place it in a parent with a width.`):p(t,"universe",'A .gravity-spot is not inside a .bigbang, so it measures the viewport. Wrap it: <div class="bigbang"><div class="gravity-spot">\u2026</div></div>.');let s=i.querySelector(":scope > o-arc, :scope > o-progress");if(s){let e=i.ownerDocument.defaultView.getComputedStyle(i),n=e.getPropertyValue("--o-ellipse-x").trim(),o=e.getPropertyValue("--o-ellipse-y").trim();(n&&Number(n)!==1||o&&Number(o)!==1)&&p(i,"ellipse-visual",`${P(s)} is on ${P(i)}, which is stretched into an ellipse (--o-ellipse-x: ${n||1}, --o-ellipse-y: ${o||1}). Arcs and progress are drawn on circles only, so it is hidden. Put it on a round ring.`)}if(G(i,".dev-orbit")){for(let e of i.children)if(M(e)!==void 0)p(e,"nested-ring",`${P(e)} is inside another ring. Rings must be direct children of .gravity-spot; to nest a system, put a .gravity-spot directly inside a .satellite.`);else if(!e.matches(Q))p(e,"ring-child",`${P(e)} is not placed by its ring. A ring holds only .satellite, .vector, .side, <o-arc> and <o-progress>; wrap content as <div class="satellite"><div class="capsule">\u2026</div></div>.`);else if(e.classList.contains("satellite"))for(let n of e.children)n.matches(".capsule, .gravity-spot, .bigbang")||p(n,"satellite-child",`${P(n)} sits directly in a .satellite. Put content in a .capsule so it stays upright and centered.`)}}function v(i,t,r){let s=String(r);i.style.getPropertyValue(t)!==s&&i.style.setProperty(t,s)}function y(i,t,r=0,s="number"){let e=String(t||"").trim();if(!e)return r;if(s==="number"&&/^[+-]?(?:\d+\.?\d*|\.\d+)$/.test(e))return Number(e);let n=e.match(/^([+-]?(?:\d+\.?\d*|\.\d+))(deg|rad|grad|turn)?$/);if(s==="angle"&&n)return Number(n[1])*({deg:1,rad:180/Math.PI,grad:.9,turn:360}[n[2]]||1);let o=i.ownerDocument;if(!(o!=null&&o.documentElement))return r;let l=o[j];l||(l=o.createElement("span"),l.setAttribute("data-orbit-measure",""),l.setAttribute("aria-hidden","true"),l.style.cssText="all:initial!important;position:fixed!important;visibility:hidden!important;pointer-events:none!important;width:0!important;height:0!important;overflow:hidden!important;",o.documentElement.appendChild(l),Object.defineProperty(o,j,{value:l,configurable:!0}));let a=s==="angle"?"rotate":"scale";if(l.style.removeProperty(a),l.style.setProperty(a,e,"important"),!l.style.getPropertyValue(a))return r;let c=o.defaultView.getComputedStyle(l).getPropertyValue(a),u=parseFloat(c);return Number.isFinite(u)?u:r}function et(i){if(i.localName==="o-arc")return i.hasAttribute("start")?null:"arc";for(let t of["satellite","vector","side"])if(i.classList.contains(t))return t;return null}function rt(i){let t={arc:0,satellite:0,vector:0,side:0};for(let n of i.children){let o=et(n);o?v(n,"--o-layout-index",t[o]++-(o==="side"?1:0)):n.localName==="o-progress"&&v(n,"--o-layout-index",0)}let r=Math.max(t.arc,t.satellite,t.vector,1),s=t.satellite||t.vector,e=t.side?String(t.side):s?`max(1, ${r} - var(--o-fit-range, 0))`:String(r);v(i,"--o-layout-angle",`calc(var(--o-range, 360deg) / ${e})`)}function K(i){return(i==null?void 0:i.nodeType)===9||(i==null?void 0:i.nodeType)===11&&!!i.host}function E(i){var r;if(K(i))return i;let t=(r=i==null?void 0:i.getRootNode)==null?void 0:r.call(i);return K(t)?t:null}function D(i,t){var r,s;for(let e=t;e;e=(r=e.getRootNode)==null?void 0:r.call(e).host)if(i===e||(s=i.contains)!=null&&s.call(i,e))return!0;return!1}function it(i){return i[q]||Object.defineProperty(i,q,{value:{states:new Set},configurable:!0}),i[q]}function I(i){i.frame<0?i.view.clearTimeout(-i.frame):i.frame&&i.view.cancelAnimationFrame(i.frame),i.frame=0}function X(i){for(let t of i.waiters.splice(0))t()}function W(i){if(!i.disposed){i.disposed=!0,I(i),X(i),i.observer.disconnect(),i.resize.disconnect();for(let t of i.listeners)t();i.rings.clear(),i.visuals.clear(),i.dirty.clear(),i.registry.states.delete(i),i.scope[w]===i&&delete i.scope[w]}}function H(i){for(let t of i.states)t.scope.host&&!t.scope.host.isConnected&&W(t)}function R(i,t=i.scope){for(let r of i.registry.states)r!==i&&r.scope.host&&D(t,r.scope.host)&&(r.all=!0,r.queue())}function st(i){return i.nodeType!==1||i.hasAttribute("data-orbit-measure")?!1:M(i)!==void 0||i.matches(".gravity-spot, o-arc, o-progress")?!0:!!i.querySelector(".gravity-spot, .orbit, [data-orbit-ring], o-arc, o-progress")}function nt(i){return i.nodeType===1&&(i.matches('style, link[rel~="stylesheet"]')||!!i.querySelector('style, link[rel~="stylesheet"]'))}function ot(i,t){if(i.type==="childList")return[...i.addedNodes,...i.removedNodes].some(st);if(i.attributeName!=="class")return!1;let r=i.target;return t.rings.has(r)||r.classList.contains("gravity-spot")||M(r)!==void 0||(i.oldValue||"").split(/\s+/).some(s=>s==="gravity-spot"||s==="orbit"||/^orbit-\d+$/.test(s))}function at(i){let t=i.nodeType===9?i:i.ownerDocument,r=t.defaultView,s=it(t),e={scope:i,doc:t,view:r,registry:s,rings:new Set,visuals:new Set,dirty:new Set,scan:!0,all:!0,frame:0,disposed:!1,listeners:[],waiters:[]},n=(a,c,u,h)=>{a==null||a.addEventListener(c,u,h),e.listeners.push(()=>a==null?void 0:a.removeEventListener(c,u,h))},o=()=>{if(e.disposed||e.frame)return;let a=()=>{e.frame=0,e.flush()};e.frame=t.visibilityState==="hidden"?-r.setTimeout(a,0):r.requestAnimationFrame(a)};e.queue=o,e.flush=()=>ct(e),e.invalidate=(a=i,c=!0)=>{var u,h;if(c&&(a===i||a===t.documentElement||a===t.head))e.all=!0;else{for(let d of e.rings)(d===a||d.contains(a)||c&&((u=a.contains)!=null&&u.call(a,d)))&&e.dirty.add(d);for(let d of e.visuals)(d===a||d.contains(a)||c&&((h=a.contains)!=null&&h.call(a,d)))&&e.dirty.add(d)}(e.all||e.dirty.size||e.scan)&&o()},e.observer=new r.MutationObserver(a=>{var c,u;if(a.some(h=>h.type==="childList")&&H(s),!e.disposed)for(let h of a){let d=h.target.nodeType===3?h.target.parentElement:h.target;if(!d||(c=d.hasAttribute)!=null&&c.call(d,"data-orbit-measure"))continue;let g=ot(h,e);g&&(e.scan=!0),h.type==="childList"&&[...h.addedNodes,...h.removedNodes].some(nt)||(u=d.closest)!=null&&u.call(d,"head, style")||d.localName==="link"?(e.all=!0,R(e)):h.type==="attributes"&&R(e,d),e.invalidate(d,h.type==="attributes"||g)}}),e.observer.observe(i,U),e.resize=new r.ResizeObserver(a=>{for(let c of a)e.dirty.add(c.target);o()});let l=()=>{e.all=!0,R(e),o()};n(t,"visibilitychange",()=>{t.visibilityState==="hidden"&&e.frame>0&&(I(e),o())}),i===t&&(n(r,"resize",l),n(t.fonts,"loadingdone",l)),n(i,"load",a=>{a.target.localName==="link"&&l()},!0);for(let a of["pointerover","pointerout","focusin","focusout"])n(i,a,c=>{e.invalidate(c.target),R(e,c.target)},!0);return Object.defineProperty(i,w,{value:e,configurable:!0}),s.states.add(e),o(),e}function N(i){let t=i.nodeType===9?i:i.ownerDocument;if(!(t!=null&&t.defaultView)||!t.documentElement||i.host&&!i.host.isConnected)return null;if(i[w]&&i[w].doc!==t&&W(i[w]),i.host){let r=E(i.host);r&&N(r)}return i[w]||at(i)}function lt(i){let t=new Set,r=new Map;for(let e of i.scope.querySelectorAll(".gravity-spot > *")){let n=M(e);if(n===void 0)continue;let o=r.get(e.parentElement)||0;e.classList.contains("orbit")&&r.set(e.parentElement,++o);let l=n===null?o:n;e.setAttribute("data-orbit-ring",""),v(e,"--o-layout-number",l===0?1e-5:l),t.add(e),i.dirty.add(e),i.rings.has(e)||i.resize.observe(e)}for(let e of i.rings)if(!t.has(e)){i.resize.unobserve(e),e.removeAttribute("data-orbit-ring");for(let n of["--o-layout-number","--o-layout-angle"])e.style.removeProperty(n)}i.rings=t;let s=new Set(i.scope.querySelectorAll(F));for(let e of i.visuals)s.has(e)||i.resize.unobserve(e);for(let e of s)i.visuals.has(e)||(i.resize.observe(e),i.dirty.add(e));i.visuals=s,i.scan=!1}function ct(i){if(i.disposed)return;if(i.scope.host&&!i.scope.host.isConnected){W(i);return}i.observer.disconnect();let t=[];try{i.scan&&lt(i);let r=i.all?new Set([...i.rings,...i.visuals]):i.dirty,s=new Set;for(let e of r)if(e.isConnected)if(i.rings.has(e)){rt(e),tt(e);for(let n of e.querySelectorAll(F))s.add(n)}else i.visuals.has(e)&&s.add(e);for(let e of i.visuals)s.has(e)&&e.update&&(e.update(),t.push(e));i.dirty=new Set,i.all=!1}finally{i.disposed||i.observer.observe(i.scope,U)}for(let r of t)r.dispatchEvent(new i.view.Event("o-rendered",{bubbles:!0,composed:!0}));i.frame||X(i)}function T(i=globalThis.document){var s;let t=E(i);if(!t)return;let r=N(t);r&&((s=i==null?void 0:i.matches)!=null&&s.call(i,F)&&!r.visuals.has(i)&&(r.scan=!0),r.invalidate(i||t))}function _(i=globalThis.document){let t=E(i);if(!t)return;let r=N(t);if(r){H(r.registry);for(let s of r.registry.states)s!==r&&(!s.scope.host||!D(i,s.scope.host))||(s.scan=!0,s.all=!0,I(s),s.flush())}}function Y(i=globalThis.document){let t=E(i),r=t&&N(t);if(!r)return Promise.resolve();H(r.registry);let s=[...r.registry.states].filter(e=>e===r||e.scope.host&&D(i,e.scope.host));return Promise.all(s.map(e=>new Promise(n=>{e.waiters.push(n),e.queue()}))).then(()=>{})}var S=class extends(globalThis.HTMLElement||class{}){constructor(){super()}connectedCallback(){for(let t of["value","max"])if(Object.prototype.hasOwnProperty.call(this,t)){let r=this[t];delete this[t],this[t]=r}T(this)}get value(){let t=this.getAttribute("value");return t===null||t.trim()===""?null:Number(t)}set value(t){t==null||t===""?this.removeAttribute("value"):this.setAttribute("value",String(t))}get max(){let t=this.getAttribute("max");return t===null?100:Number(t)}set max(t){t==null||t===""?this.removeAttribute("max"):this.setAttribute("max",String(t))}disconnectedCallback(){this._textFrame&&this.ownerDocument.defaultView.cancelAnimationFrame(this._textFrame),this._textFrame=0}readNumber(t,r,s=0){return y(this,t.getPropertyValue(r),s)}readAngle(t,r,s=0){return y(this,t.getPropertyValue(r),s,"angle")}readValue(){let t=this.getAttribute("value");if(t===null||t.trim()==="")return 0;let r=Number(t);return Number.isFinite(r)?r:(p(this,"value:"+t,`<${this.localName} value="${t}"> is not a number, so nothing is drawn.`),0)}readMax(t){let r=this.getAttribute("max");if(r===null){let e=t==null?void 0:t.getPropertyValue("--o-max").trim();if(!e)return 100;let n=y(this,e,NaN);return n>0?n:(p(this,"o-max:"+e,`--o-max: ${e} on <${this.localName}> must be a positive number, so nothing is drawn.`),0)}let s=Number(r);return s>0?s:(p(this,"max:"+r,`<${this.localName} max="${r}"> must be a positive number, so nothing is drawn.`),0)}getCommonAttributes(t){var g;let r=t.ownerDocument.defaultView.getComputedStyle(t),s=parseFloat(r.getPropertyValue("r")),e=Math.max(0,Number.isFinite(s)?s:(((g=t.parentElement)==null?void 0:g.clientWidth)||0)/2),n=Math.max(1e-5,this.readNumber(r,"--o-orbit-number",1)),o=Math.max(0,this.readNumber(r,"--o-size-ratio",1)),l=Math.max(0,this.readNumber(r,"--o-stroke-width",1)),a=t.getAttribute("shape")||"none",c=Math.max(0,e/n*o-l+.3),u=e>0?Math.min(49.999,c*25/e):0,h=0;t.classList.contains("outer-orbit")?h=u:t.classList.contains("quarter-outer-orbit")?h=u*-.5:t.classList.contains("inner-orbit")?h=u*-1:t.classList.contains("quarter-inner-orbit")&&(h=u*.5);let d=50+h;return{orbitRadius:e,arcHeight:c,realRadius:d,arcAngle:0,shape:a,arcHeightPercentage:u,orbitNumber:n,size:o,strokeWidth:l,style:r}}getProgressAngle(t,r,s=100){return!Number.isFinite(r)||!Number.isFinite(s)||s<=0?0:Math.min(1,Math.max(0,r/s))*Math.max(0,Math.min(360,t))}arcPoint(t,r,s=0,e=0){let n=t+s,o=r+e*Math.PI/180;return{x:50+n*Math.cos(o),y:50+n*Math.sin(o)}}calculateCommonArcParameters(t,r,s,e,n,o,l,a=0){let c=Math.PI/2,u=Math.max(0,Math.min(360,t))*Math.PI/180,h=r+s,d=Math.max(.001,r-s),g=Math.min(u*.49,(a+o*1.25)/e/h),x=Math.min(u*.49,(a+o*1.25)/e/d),A=g-c,b=u-g-c,m=x-c,$=u-x-c,f=this.arcPoint(h,A),k=this.arcPoint(h,b),z=this.arcPoint(d,m),O=this.arcPoint(d,$);return{upperArcStart:f,upperArcEnd:k,innerArcStart:z,innerArcEnd:O,bigRadius:h,smallRadius:d,radius:r,upperAngleStart:A,upperAngleEnd:b,innerAngleStart:m,innerAngleEnd:$}}generatePathData(t,r){switch(t){case"rounded":return this.generateRoundedPath(r);case"circle":case"circle-a":case"bullet":return this.generateCirclePath(r,t);case"circle-b":return this.generateCircleBPath(r);case"arrow":return this.generateArrowPath(r);case"backslash":case"slash":return this.generateSlashPath(r,t);case"zigzag":return this.generateZigzagPath(r);default:return this.generateDefaultPath(r)}}pt(t,r){let s=this.arcPoint(t,r);return`${s.x},${s.y}`}arcTo(t,r,s){let e=Math.max(1,Math.ceil(Math.abs(s-r)/(Math.PI/2)-1e-9)),n=s>=r?1:0,o="";for(let l=1;l<=e;l++)o+=` A ${t},${t} 0 0 ${n} ${this.pt(t,r+(s-r)*l/e)}`;return o}linePath(t,r,s){return`M ${this.pt(t,r)}${this.arcTo(t,r,s)}`}ending(t,r){let{bigRadius:s,smallRadius:e}=t,n=(s-e)/2,o=(s+e)/2,l=Math.min(t.upperAngleEnd-t.upperAngleStart,t.innerAngleEnd-t.innerAngleStart),a=Math.max(0,Math.min(n*r,l*e*.49));return{h:n,middle:o,length:a,angle:a/o}}generateDefaultPath(t){let{bigRadius:r,smallRadius:s,upperAngleStart:e,upperAngleEnd:n,innerAngleStart:o,innerAngleEnd:l}=t;return`M ${this.pt(r,e)}${this.arcTo(r,e,n)} L ${this.pt(s,l)}${this.arcTo(s,l,o)} Z`}generateRoundedPath(t){let{bigRadius:r,smallRadius:s,upperAngleStart:e,upperAngleEnd:n,innerAngleStart:o,innerAngleEnd:l}=t,{length:a}=this.ending(t,.5),c=(h,d)=>` A ${a},${a} 0 0 1 ${this.pt(h,d)}`,u=`M ${this.pt(r,e+a/r)}${this.arcTo(r,e+a/r,n-a/r)}`;return u+=`${c(r-a,n)} L ${this.pt(s+a,l)}${c(s,l-a/s)}`,u+=this.arcTo(s,l-a/s,o+a/s),u+=`${c(s+a,o)} L ${this.pt(r-a,e)}${c(r,e+a/r)} Z`,u}generateCirclePath(t,r){let{bigRadius:s,smallRadius:e,upperAngleStart:n,upperAngleEnd:o,innerAngleStart:l,innerAngleEnd:a}=t,c=r==="bullet"?0:1,u=`M ${this.pt(s,n)}${this.arcTo(s,n,o)} A 1,1 0 0 1 ${this.pt(e,a)}`;return u+=`${this.arcTo(e,a,l)} A 1,1 0 0 ${c} ${this.pt(s,n)} Z`,u}generateCircleBPath(t){let{bigRadius:r,smallRadius:s}=t,{h:e,angle:n}=this.ending(t,1),o=t.upperAngleStart+n,l=t.upperAngleEnd-n,a=`M ${this.pt(r,o)}${this.arcTo(r,o,l)} A ${e},${e} 0 0 1 ${this.pt(s,l)}`;return a+=`${this.arcTo(s,l,o)} A ${e},${e} 0 0 1 ${this.pt(r,o)} Z`,a}generateArrowPath(t){let{bigRadius:r,smallRadius:s}=t,{middle:e,angle:n}=this.ending(t,1.6),o=t.upperAngleStart,l=t.upperAngleEnd,a=`M ${this.pt(r,o)}${this.arcTo(r,o,l-n)}`;return a+=` L ${this.pt(e,l)} L ${this.pt(s,l-n)}`,a+=`${this.arcTo(s,l-n,o)} L ${this.pt(e,o+n)} Z`,a}generateSlashPath(t,r){let{bigRadius:s,smallRadius:e}=t,{angle:n}=this.ending(t,1),o=t.upperAngleStart,l=t.upperAngleEnd,[a,c,u,h]=r==="backslash"?[o,l-n,o+n,l]:[o+n,l,o,l-n];return`M ${this.pt(s,a)}${this.arcTo(s,a,c)} L ${this.pt(e,h)}${this.arcTo(e,h,u)} Z`}generateZigzagPath(t){let{bigRadius:r,smallRadius:s}=t,{middle:e,angle:n}=this.ending(t,1.6),o=t.upperAngleStart,l=t.upperAngleEnd,a=`M ${this.pt(r,o+n)}${this.arcTo(r,o+n,l)}`;return a+=` L ${this.pt(e,l-n)} L ${this.pt(s,l)}`,a+=`${this.arcTo(s,l,o+n)} L ${this.pt(e,o)} Z`,a}updateHitArea(t,r,s,e){let n=Math.max(0,Number(this.getAttribute("hit-width"))||0);if(this.fitCanvas(r,this.hasAttribute("interactive")?n:0),!this.hasAttribute("interactive")||!(e>s)||!(r.orbitRadius>0)){t.removeAttribute("d");return}let o=l=>(l-90)*Math.PI/180;t.setAttribute("d",this.linePath(r.realRadius,o(s),o(Math.min(e,s+360)))),t.style.strokeWidth=`${r.arcHeight+r.strokeWidth+2*n}px`}fitCanvas(t,r){let s=this.shadowRoot.querySelector("svg"),e=t.orbitRadius/50;if(!s||!(e>0))return;let n=((t.realRadius+t.arcHeightPercentage)*e+t.strokeWidth)*(t.reach||1)+r,o=Math.max(0,Math.ceil(n-t.orbitRadius)),l=o/e;s.setAttribute("viewBox",`${-l} ${-l} ${100+2*l} ${100+2*l}`),s.style.inset=`${-o}px`}};var L=class extends S{constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML=`
8
8
  <style>
9
9
  :host {
10
10
  --o-fill: var(--o-gray-light);
@@ -82,7 +82,7 @@
82
82
  <path class="progress-bg" shape-rendering="geometricPrecision" vector-effect="non-scaling-stroke"></path>
83
83
  <path class="progress-bar" shape-rendering="geometricPrecision" vector-effect="non-scaling-stroke"></path>
84
84
  </svg>
85
- `}update(){let t=this.getAttributes(),r=this.getAttribute("variant")==="stroke",i=r?this.calculateStrokeArc(t,!0):this.calculateArcParameters(t,!0),e=r?this.calculateStrokeArc(t,!1):this.calculateArcParameters(t,!1);this.shadowRoot.querySelector(".progress-bg").setAttribute("d",i),this.shadowRoot.querySelector(".progress-bar").setAttribute("d",e),this.updateHitArea(this.shadowRoot.querySelector(".hit"),t,0,t.range)}calculateStrokeArc(t,r){let{realRadius:i}=t,e=Math.max(0,Math.min(this.getProgressAngle(t,r),360));if(!(e>0)||!(t.orbitRadius>0))return"";let n=-Math.PI/2;return this.linePath(i,n,n+e*Math.PI/180)}getAttributes(){let t=super.getCommonAttributes(this),r=Math.max(0,Math.min(360,this.readAngle(t.style,"--o-range",360))),e=t.style.getPropertyValue("--o-progress").trim()?this.readNumber(t.style,"--o-progress",0):this.readValue(),n=this.readMax();return{...t,range:r,progress:e,maxValue:n}}getProgressAngle(t,r){let{range:i,progress:e,maxValue:n}=t;return r?i:super.getProgressAngle(i,e,n)}calculateArcParameters(t,r){let{shape:i,realRadius:e,arcHeightPercentage:n,orbitNumber:o,strokeWidth:c,arcHeight:a}=t,l=this.getProgressAngle(t,r);if(!(l>0)||!(t.orbitRadius>0))return"";let u=super.calculateCommonArcParameters(l,e,n,o,i,c,a);return super.generatePathData(i,u)}};var I=typeof document=="undefined"?null:document.createElement("template");I&&(I.innerHTML=`
85
+ `}update(){let t=this.getAttributes(),r=this.getAttribute("variant")==="stroke",s=r?this.calculateStrokeArc(t,!0):this.calculateArcParameters(t,!0),e=r?this.calculateStrokeArc(t,!1):this.calculateArcParameters(t,!1);this.shadowRoot.querySelector(".progress-bg").setAttribute("d",s),this.shadowRoot.querySelector(".progress-bar").setAttribute("d",e),this.updateHitArea(this.shadowRoot.querySelector(".hit"),t,0,t.range);let n=this.parentElement;this._valueRing&&this._valueRing!==n&&this._valueRing.style.removeProperty("--o-value-angle"),this._valueRing=n,n&&v(n,"--o-value-angle",`${this.getProgressAngle(t,!1)}deg`)}disconnectedCallback(){var t;super.disconnectedCallback(),(t=this._valueRing)==null||t.style.removeProperty("--o-value-angle"),this._valueRing=null}calculateStrokeArc(t,r){let{realRadius:s}=t,e=Math.max(0,Math.min(this.getProgressAngle(t,r),360));if(!(e>0)||!(t.orbitRadius>0))return"";let n=-Math.PI/2;return this.linePath(s,n,n+e*Math.PI/180)}getAttributes(){let t=super.getCommonAttributes(this),r=Math.max(0,Math.min(360,this.readAngle(t.style,"--o-range",360))),e=t.style.getPropertyValue("--o-progress").trim()?this.readNumber(t.style,"--o-progress",0):this.readValue(),n=this.readMax(t.style);return{...t,range:r,progress:e,maxValue:n}}getProgressAngle(t,r){let{range:s,progress:e,maxValue:n}=t;return r?s:super.getProgressAngle(s,e,n)}calculateArcParameters(t,r){let{shape:s,realRadius:e,arcHeightPercentage:n,orbitNumber:o,strokeWidth:l,arcHeight:a}=t,c=this.getProgressAngle(t,r);if(!(c>0)||!(t.orbitRadius>0))return"";let u=super.calculateCommonArcParameters(c,e,n,o,s,l,a);return super.generatePathData(s,u)}};var B=typeof document=="undefined"?null:document.createElement("template");B&&(B.innerHTML=`
86
86
  <style>
87
87
  :host {
88
88
  --o-fill: var(--o-gray-light);
@@ -108,6 +108,12 @@
108
108
  :host([interactive]) svg * {
109
109
  pointer-events: visiblePainted;
110
110
  }
111
+ /* Text lets the pointer through to the band under it: WebKit fires no
112
+ click on SVG text inside a shadow root. */
113
+ :host([interactive]) svg text,
114
+ :host([interactive]) svg textPath {
115
+ pointer-events: none;
116
+ }
111
117
  /* The touch area catches the pointer even where the band is transparent. */
112
118
  #orbitHit {
113
119
  fill: none;
@@ -134,9 +140,32 @@
134
140
  stroke: none;
135
141
  pointer-events: none;
136
142
  }
143
+ /* .ripple: a copy of the band grows out from the center of the ring and
144
+ fades, over and over. The band itself stays. */
145
+ #orbitWave {
146
+ display: none;
147
+ fill: var(--o-ripple-color, var(--o-fill));
148
+ stroke: none;
149
+ pointer-events: none;
150
+ transform-origin: 50px 50px;
151
+ }
152
+ :host(.ripple) #orbitWave {
153
+ display: inline;
154
+ animation: orbit-ripple var(--o-ripple-duration, 1.6s) ease-out infinite;
155
+ }
156
+ @keyframes orbit-ripple {
157
+ from { transform: scale(1); opacity: .9; }
158
+ to { transform: scale(var(--o-ripple-scale, 1.14)); opacity: 0; }
159
+ }
160
+ @media (prefers-reduced-motion: reduce) {
161
+ :host(.ripple) #orbitWave {
162
+ display: none;
163
+ }
164
+ }
137
165
  </style>
138
166
  <svg viewBox="0 0 100 100">
139
167
  <path id="orbitHit" vector-effect="non-scaling-stroke"></path>
168
+ <path id="orbitWave" shape-rendering="geometricPrecision"></path>
140
169
  <path id="orbitShape" shape-rendering="geometricPrecision" vector-effect="non-scaling-stroke"></path>
141
170
  <path id="orbitPath" shape-rendering="geometricPrecision" vector-effect="non-scaling-stroke"></path>
142
171
  <text>
@@ -144,4 +173,4 @@
144
173
  </text>
145
174
  <text id="measure" visibility="hidden" aria-hidden="true"></text>
146
175
  </svg>
147
- `);var L=class extends w{constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.appendChild(I.content.cloneNode(!0))}update(){let t=this.getAttributes(),{fitRange:r,stacked:i}=t;if(i){let a=t.auto&&this.hasAttribute("text-anchor")&&{middle:-.5,end:-1}[t.textAnchor]||0;v(this,"--o-arc-start",`${t.stackOffset+a*t.arcAngle}deg`),v(this,"--o_stack",t.stackOffset+t.arcAngle)}else this.style.removeProperty("--o-arc-start"),this.style.removeProperty("--o_stack");let e=this.shadowRoot.querySelector("#orbitPath"),n=this.shadowRoot.querySelector("#orbitShape"),o=this.shadowRoot.querySelector("textPath");n.setAttribute("d",this.calculateArcParameters(t).dShape),e.setAttribute("d",this.calculateTextArcParameters(t).dPath),this.updateHitArea(this.shadowRoot.querySelector("#orbitHit"),t,0,t.arcAngle);let c=t.textAnchor;c==="start"?(o.setAttribute("startOffset","0%"),o.setAttribute("text-anchor","start")):c==="middle"?(o.setAttribute("startOffset","50%"),o.setAttribute("text-anchor","middle")):c==="end"&&(o.setAttribute("startOffset","100%"),o.setAttribute("text-anchor","end")),r?o.parentElement.setAttribute("textLength",e.getTotalLength()):o.parentElement.removeAttribute("textLength"),o.parentElement.style.fontSize=t.svgFontSize,o.textContent=this.textContent,t.auto||this.warnIfTextOverflows(e,o,r)}warnIfTextOverflows(t,r,i){let e=(this.textContent||"").trim();!e||i||!this.isConnected||(this._textFrame&&this.ownerDocument.defaultView.cancelAnimationFrame(this._textFrame),this._textFrame=this.ownerDocument.defaultView.requestAnimationFrame(()=>{if(this._textFrame=0,!!this.isConnected)try{let n=t.getTotalLength(),o=r.parentElement.getComputedTextLength();n>0&&o>n&&this._truncWarned!==e&&(this._truncWarned=e,console.warn(`[orbit] <o-arc> text "${e.length>34?e.slice(0,34)+"\u2026":e}" overflows its arc (${Math.round(o)} > ${Math.round(n)} units) and will clip. Shorten the text, widen --o-range, add range="auto" to fit the arc to the text, or fit-range to squeeze it.`))}catch(n){}}))}getAttributes(){let t=super.getCommonAttributes(this),{style:r}=t,i=Math.max(0,Math.min(360,this.readAngle(r,"--o-range",360))),e=this.hasAttribute("flip")||this.classList.contains("flip"),n=this.hasAttribute("fit-range")||this.classList.contains("fit-range"),o=t.orbitRadius*24/t.orbitNumber||100,c=this.getAttribute("text-anchor")||"middle",a=r.fontSize||"16px",l=Math.max(0,this.readNumber(r,"--o-gap",1)),u=`calc(${a} * (100 / (${o}) * (12 / var(--o-orbit-number)))`,h=this.getAttribute("range")==="auto",d=h||this.hasAttribute("value"),g;h?g=this.measureTextAngle(u,t.realRadius,l):this.hasAttribute("value")?g=super.getProgressAngle(i,this.readValue(),this.readMax()):g=Math.max(0,Math.min(360,this.readAngle(r,"--o-angle",0))),this._autoAngle=h?g:0;let m=0;if(d)for(let f=this.previousElementSibling;f;f=f.previousElementSibling){if(f.localName!=="o-arc")continue;let x=this.ownerDocument.defaultView.getComputedStyle(f);if(f.getAttribute("range")==="auto")m+=f._autoAngle||0;else if(f.hasAttribute("value")){let P=f.hasAttribute("max")?Number(f.getAttribute("max")):100,S=y(f,x.getPropertyValue("--o-range"),i,"angle");m+=super.getProgressAngle(S,Number(f.getAttribute("value")),P)}else m+=y(f,x.getPropertyValue("--o-angle"),0,"angle")}return{...t,gap:l,arcAngle:g,stackOffset:m,flip:e,fitRange:n,length:o,fontSize:a,svgFontSize:u,textAnchor:c,auto:h,stacked:d}}measureTextAngle(t,r,i){let e=(this.textContent||"").trim();if(!e||!(r>0))return 0;let n=this.shadowRoot.querySelector("#measure");n.style.fontSize=t,n.textContent=e;let o=0;try{o=n.getComputedTextLength()+parseFloat(this.ownerDocument.defaultView.getComputedStyle(n).fontSize)}catch(c){}return o>0?Math.min(360,o/r*180/Math.PI+i):0}calculateArcParameters(t){let{arcAngle:r,realRadius:i,arcHeightPercentage:e,orbitNumber:n,shape:o,strokeWidth:c,arcHeight:a,gap:l}=t;if(!(r>0)||!(t.orbitRadius>0))return{dShape:""};let u=super.calculateCommonArcParameters(r,i,e,n,o,c,a,l);return{dShape:super.generatePathData(o,u)}}calculateTextArcParameters(t){let{arcAngle:r,realRadius:i,gap:e,flip:n}=t;if(!(r>0))return{dPath:""};let o=Math.min(e*.5,r*.49),c=(o-90)*Math.PI/180,a=(r-o-90)*Math.PI/180;return{dPath:n?this.linePath(i,a,c):this.linePath(i,c,a)}}resolveAngle(t){return y(this,t,0,"angle")}calcularExpresionCSS(t){return this.resolveAngle(t)}};var N=new WeakMap,ut=/^[+-]?(?:\d+\.?\d*|\.\d+)px$/,K={refresh:D,ready:G,resize(s){var o,c;let t=typeof s=="string"?(o=globalThis.document)==null?void 0:o.querySelector(s):s;if(!(t!=null&&t.ownerDocument))return console.error("Orbit.resize: element not found:",s),()=>{};(c=N.get(t))==null||c();let r=t.ownerDocument.defaultView,i=a=>{if(!(a>0))return;let l=0;for(let u of t.querySelectorAll(".gravity-spot")){if(!ut.test(r.getComputedStyle(u).getPropertyValue("--o-force").trim()))continue;l++;let h=String(a/500);u.style.getPropertyValue("--o-force-ratio")!==h&&u.style.setProperty("--o-force-ratio",h)}l||p(t,"resize","Orbit.resize() has nothing to do here: every .bigbang already scales with its container. It only scales systems that set a fixed px --o-force."),D(t)},e=new r.ResizeObserver(a=>{for(let l of a)i(l.contentRect.width)});e.observe(t),i(t.clientWidth||t.getBoundingClientRect().width);let n=()=>{e.disconnect(),N.get(t)===n&&N.delete(t)};return N.set(t,n),n}};function ht(){typeof customElements=="undefined"||typeof document=="undefined"||(customElements.get("o-progress")||customElements.define("o-progress",T),customElements.get("o-arc")||customElements.define("o-arc",L),E(document),window.Orbit=K)}ht();})();
176
+ `);var C=class extends S{constructor(){super(),this.attachShadow({mode:"open"}),this.shadowRoot.appendChild(B.content.cloneNode(!0))}update(){let t=this.getAttributes(),{fitRange:r,stacked:s}=t;if(s){let c=t.auto&&this.hasAttribute("text-anchor")&&{middle:-.5,end:-1}[t.textAnchor]||0;v(this,"--o-arc-start",`${t.stackOffset+c*t.arcAngle}deg`),v(this,"--o_stack",t.stackOffset+t.arcAngle)}else this.style.removeProperty("--o-arc-start"),this.style.removeProperty("--o_stack");let e=this.shadowRoot.querySelector("#orbitPath"),n=this.shadowRoot.querySelector("#orbitShape"),o=this.shadowRoot.querySelector("textPath"),{dShape:l}=this.calculateArcParameters(t);n.setAttribute("d",l),this.shadowRoot.querySelector("#orbitWave").setAttribute("d",l),e.setAttribute("d",this.calculateTextArcParameters(t).dPath),this.updateHitArea(this.shadowRoot.querySelector("#orbitHit"),t,0,t.arcAngle);let a=t.textAnchor;a==="start"?(o.setAttribute("startOffset","0%"),o.setAttribute("text-anchor","start")):a==="middle"?(o.setAttribute("startOffset","50%"),o.setAttribute("text-anchor","middle")):a==="end"&&(o.setAttribute("startOffset","100%"),o.setAttribute("text-anchor","end")),r?o.parentElement.setAttribute("textLength",e.getTotalLength()):o.parentElement.removeAttribute("textLength"),o.parentElement.style.fontSize=t.svgFontSize,o.textContent=this.textContent,t.auto||this.warnIfTextOverflows(e,o,r)}warnIfTextOverflows(t,r,s){let e=(this.textContent||"").trim();!e||s||!this.isConnected||(this._textFrame&&this.ownerDocument.defaultView.cancelAnimationFrame(this._textFrame),this._textFrame=this.ownerDocument.defaultView.requestAnimationFrame(()=>{if(this._textFrame=0,!!this.isConnected)try{let n=t.getTotalLength(),o=r.parentElement.getComputedTextLength();n>0&&o>n&&this._truncWarned!==e&&(this._truncWarned=e,console.warn(`[orbit] <o-arc> text "${e.length>34?e.slice(0,34)+"\u2026":e}" overflows its arc (${Math.round(o)} > ${Math.round(n)} units) and will clip. Shorten the text, widen --o-range, add range="auto" to fit the arc to the text, or fit-range to squeeze it.`))}catch(n){}}))}getAttributes(){let t=super.getCommonAttributes(this),{style:r}=t,s=Math.max(0,Math.min(360,this.readAngle(r,"--o-range",360))),e=this.hasAttribute("flip")||this.classList.contains("flip"),n=this.hasAttribute("fit-range")||this.classList.contains("fit-range"),o=t.orbitRadius*24/t.orbitNumber||100,l=this.getAttribute("text-anchor")||"middle",a=r.fontSize||"16px",c=Math.max(0,this.readNumber(r,"--o-gap",1)),u=`calc(${a} * (100 / (${o}) * (12 / var(--o-orbit-number)))`,h=this.getAttribute("range")==="auto",d=this.hasAttribute("value"),g=this.hasAttribute("start"),x=h||d||g,A=this.readMax(r),b;h?b=this.measureTextAngle(u,t.realRadius,c):d?b=super.getProgressAngle(s,this.readValue(),A):b=Math.max(0,Math.min(360,this.readAngle(r,"--o-angle",0))),this._autoAngle=h?b:0;let m=0;if(g){if(m=A>0?this.readStart()/A*s:0,!h&&s<360){let f=Math.min(s,m+b);m=Math.max(0,m),b=Math.max(0,f-m)}}else if(x)for(let f=this.previousElementSibling;f;f=f.previousElementSibling){if(f.localName!=="o-arc"||f.hasAttribute("start"))continue;let k=this.ownerDocument.defaultView.getComputedStyle(f);if(f.getAttribute("range")==="auto")m+=f._autoAngle||0;else if(f.hasAttribute("value")){let z=this.readMax.call(f,k),O=y(f,k.getPropertyValue("--o-range"),s,"angle");m+=super.getProgressAngle(O,Number(f.getAttribute("value")),z)}else m+=y(f,k.getPropertyValue("--o-angle"),0,"angle")}let $=this.classList.contains("ripple")?Math.max(1,this.readNumber(r,"--o-ripple-scale",1.14)):1;return{...t,gap:c,max:A,arcAngle:b,stackOffset:m,flip:e,fitRange:n,length:o,fontSize:a,svgFontSize:u,textAnchor:l,auto:h,placed:g,stacked:x,reach:$}}readStart(){let t=this.getAttribute("start"),r=Number(t);return Number.isFinite(r)?r:(p(this,"start:"+t,`<o-arc start="${t}"> is not a number, so the arc starts at 0.`),0)}measureTextAngle(t,r,s){let e=(this.textContent||"").trim();if(!e||!(r>0))return 0;let n=this.shadowRoot.querySelector("#measure");n.style.fontSize=t,n.textContent=e;let o=0;try{o=n.getComputedTextLength()+parseFloat(this.ownerDocument.defaultView.getComputedStyle(n).fontSize)}catch(l){}return o>0?Math.min(360,o/r*180/Math.PI+s):0}calculateArcParameters(t){let{arcAngle:r,realRadius:s,arcHeightPercentage:e,orbitNumber:n,shape:o,strokeWidth:l,arcHeight:a,gap:c}=t;if(!(r>0)||!(t.orbitRadius>0))return{dShape:""};let u=super.calculateCommonArcParameters(r,s,e,n,o,l,a,c);return{dShape:super.generatePathData(o,u)}}calculateTextArcParameters(t){let{arcAngle:r,realRadius:s,gap:e,flip:n}=t;if(!(r>0))return{dPath:""};let o=Math.min(e*.5,r*.49),l=(o-90)*Math.PI/180,a=(r-o-90)*Math.PI/180;return{dPath:n?this.linePath(s,a,l):this.linePath(s,l,a)}}resolveAngle(t){return y(this,t,0,"angle")}calcularExpresionCSS(t){return this.resolveAngle(t)}};var V=new WeakMap,ut=/^[+-]?(?:\d+\.?\d*|\.\d+)px$/,J={refresh:_,ready:Y,resize(i){var o,l;let t=typeof i=="string"?(o=globalThis.document)==null?void 0:o.querySelector(i):i;if(!(t!=null&&t.ownerDocument))return console.error("Orbit.resize: element not found:",i),()=>{};(l=V.get(t))==null||l();let r=t.ownerDocument.defaultView,s=a=>{if(!(a>0))return;let c=0;for(let u of t.querySelectorAll(".gravity-spot")){if(!ut.test(r.getComputedStyle(u).getPropertyValue("--o-force").trim()))continue;c++;let h=String(a/500);u.style.getPropertyValue("--o-force-ratio")!==h&&u.style.setProperty("--o-force-ratio",h)}c||p(t,"resize","Orbit.resize() has nothing to do here: every .bigbang already scales with its container. It only scales systems that set a fixed px --o-force."),_(t)},e=new r.ResizeObserver(a=>{for(let c of a)s(c.contentRect.width)});e.observe(t),s(t.clientWidth||t.getBoundingClientRect().width);let n=()=>{e.disconnect(),V.get(t)===n&&V.delete(t)};return V.set(t,n),n}};function ht(){typeof customElements=="undefined"||typeof document=="undefined"||(customElements.get("o-progress")||customElements.define("o-progress",L),customElements.get("o-arc")||customElements.define("o-arc",C),T(document),window.Orbit=J)}ht();})();
package/dist/orbit.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * orbit
3
- * v.2.0.0
3
+ * v.2.1.0
4
4
  * Author Juan Martin Muda - Zumerlab
5
5
  * License MIT
6
6
  */
@@ -100,7 +100,7 @@ function cssNumber(element, value, fallback = 0, type = "number") {
100
100
  return Number.isFinite(resolved) ? resolved : fallback;
101
101
  }
102
102
  function group(element) {
103
- if (element.localName === "o-arc") return "arc";
103
+ if (element.localName === "o-arc") return element.hasAttribute("start") ? null : "arc";
104
104
  for (const name of ["satellite", "vector", "side"]) if (element.classList.contains(name)) return name;
105
105
  return null;
106
106
  }
@@ -445,10 +445,22 @@ var OrbitBase = class extends (globalThis.HTMLElement || class {
445
445
  }
446
446
  return value;
447
447
  }
448
- /** The max attribute (default 100). It must be a positive number. */
449
- readMax() {
448
+ /**
449
+ * The max attribute, else --o-max from the ring or system (default 100).
450
+ * It must be a positive number.
451
+ */
452
+ readMax(style) {
450
453
  const raw = this.getAttribute("max");
451
- if (raw === null) return 100;
454
+ if (raw === null) {
455
+ const css = style == null ? void 0 : style.getPropertyValue("--o-max").trim();
456
+ if (!css) return 100;
457
+ const max2 = cssNumber(this, css, NaN);
458
+ if (!(max2 > 0)) {
459
+ warnOnce(this, "o-max:" + css, `--o-max: ${css} on <${this.localName}> must be a positive number, so nothing is drawn.`);
460
+ return 0;
461
+ }
462
+ return max2;
463
+ }
452
464
  const max = Number(raw);
453
465
  if (!(max > 0)) {
454
466
  warnOnce(this, "max:" + raw, `<${this.localName} max="${raw}"> must be a positive number, so nothing is drawn.`);
@@ -668,14 +680,15 @@ var OrbitBase = class extends (globalThis.HTMLElement || class {
668
680
  }
669
681
  /**
670
682
  * Grow the SVG canvas past the ring's box so it covers the whole band, its
671
- * stroke and touch area. Some engines (WebKit) neither paint reliably nor
672
- * hit-test SVG content that overflows its box.
683
+ * stroke and touch area, and as far as a ripple reaches (attrs.reach).
684
+ * Some engines (WebKit) neither paint reliably nor hit-test SVG content that
685
+ * overflows its box.
673
686
  */
674
687
  fitCanvas(attrs, extra) {
675
688
  const svg = this.shadowRoot.querySelector("svg");
676
689
  const scale = attrs.orbitRadius / 50;
677
690
  if (!svg || !(scale > 0)) return;
678
- const outer = (attrs.realRadius + attrs.arcHeightPercentage) * scale + attrs.strokeWidth + extra;
691
+ const outer = ((attrs.realRadius + attrs.arcHeightPercentage) * scale + attrs.strokeWidth) * (attrs.reach || 1) + extra;
679
692
  const pad = Math.max(0, Math.ceil(outer - attrs.orbitRadius));
680
693
  const units = pad / scale;
681
694
  svg.setAttribute("viewBox", `${-units} ${-units} ${100 + 2 * units} ${100 + 2 * units}`);
@@ -776,6 +789,16 @@ var OrbitProgress = class extends OrbitBase {
776
789
  this.shadowRoot.querySelector(".progress-bg").setAttribute("d", dBg);
777
790
  this.shadowRoot.querySelector(".progress-bar").setAttribute("d", dBar);
778
791
  this.updateHitArea(this.shadowRoot.querySelector(".hit"), attrs, 0, attrs.range);
792
+ const ring = this.parentElement;
793
+ if (this._valueRing && this._valueRing !== ring) this._valueRing.style.removeProperty("--o-value-angle");
794
+ this._valueRing = ring;
795
+ if (ring) setLayoutProperty(ring, "--o-value-angle", `${this.getProgressAngle(attrs, false)}deg`);
796
+ }
797
+ disconnectedCallback() {
798
+ var _a;
799
+ super.disconnectedCallback();
800
+ (_a = this._valueRing) == null ? void 0 : _a.style.removeProperty("--o-value-angle");
801
+ this._valueRing = null;
779
802
  }
780
803
  /**
781
804
  * variant="stroke": open arc along the orbit radius (no closed band),
@@ -793,7 +816,7 @@ var OrbitProgress = class extends OrbitBase {
793
816
  const range = Math.max(0, Math.min(360, this.readAngle(common.style, "--o-range", 360)));
794
817
  const rawValue = common.style.getPropertyValue("--o-progress").trim();
795
818
  const progress = rawValue ? this.readNumber(common.style, "--o-progress", 0) : this.readValue();
796
- const maxValue = this.readMax();
819
+ const maxValue = this.readMax(common.style);
797
820
  return {
798
821
  ...common,
799
822
  range,
@@ -850,6 +873,12 @@ if (template) template.innerHTML = `
850
873
  :host([interactive]) svg * {
851
874
  pointer-events: visiblePainted;
852
875
  }
876
+ /* Text lets the pointer through to the band under it: WebKit fires no
877
+ click on SVG text inside a shadow root. */
878
+ :host([interactive]) svg text,
879
+ :host([interactive]) svg textPath {
880
+ pointer-events: none;
881
+ }
853
882
  /* The touch area catches the pointer even where the band is transparent. */
854
883
  #orbitHit {
855
884
  fill: none;
@@ -876,9 +905,32 @@ if (template) template.innerHTML = `
876
905
  stroke: none;
877
906
  pointer-events: none;
878
907
  }
908
+ /* .ripple: a copy of the band grows out from the center of the ring and
909
+ fades, over and over. The band itself stays. */
910
+ #orbitWave {
911
+ display: none;
912
+ fill: var(--o-ripple-color, var(--o-fill));
913
+ stroke: none;
914
+ pointer-events: none;
915
+ transform-origin: 50px 50px;
916
+ }
917
+ :host(.ripple) #orbitWave {
918
+ display: inline;
919
+ animation: orbit-ripple var(--o-ripple-duration, 1.6s) ease-out infinite;
920
+ }
921
+ @keyframes orbit-ripple {
922
+ from { transform: scale(1); opacity: .9; }
923
+ to { transform: scale(var(--o-ripple-scale, 1.14)); opacity: 0; }
924
+ }
925
+ @media (prefers-reduced-motion: reduce) {
926
+ :host(.ripple) #orbitWave {
927
+ display: none;
928
+ }
929
+ }
879
930
  </style>
880
931
  <svg viewBox="0 0 100 100">
881
932
  <path id="orbitHit" vector-effect="non-scaling-stroke"></path>
933
+ <path id="orbitWave" shape-rendering="geometricPrecision"></path>
882
934
  <path id="orbitShape" shape-rendering="geometricPrecision" vector-effect="non-scaling-stroke"></path>
883
935
  <path id="orbitPath" shape-rendering="geometricPrecision" vector-effect="non-scaling-stroke"></path>
884
936
  <text>
@@ -907,7 +959,9 @@ var OrbitArc = class extends OrbitBase {
907
959
  const orbitPath = this.shadowRoot.querySelector("#orbitPath");
908
960
  const orbitShape = this.shadowRoot.querySelector("#orbitShape");
909
961
  const textPath = this.shadowRoot.querySelector("textPath");
910
- orbitShape.setAttribute("d", this.calculateArcParameters(attrs).dShape);
962
+ const { dShape } = this.calculateArcParameters(attrs);
963
+ orbitShape.setAttribute("d", dShape);
964
+ this.shadowRoot.querySelector("#orbitWave").setAttribute("d", dShape);
911
965
  orbitPath.setAttribute("d", this.calculateTextArcParameters(attrs).dPath);
912
966
  this.updateHitArea(this.shadowRoot.querySelector("#orbitHit"), attrs, 0, attrs.arcAngle);
913
967
  const textAnchor = attrs.textAnchor;
@@ -968,26 +1022,45 @@ var OrbitArc = class extends OrbitBase {
968
1022
  const gap = Math.max(0, this.readNumber(style, "--o-gap", 1));
969
1023
  const svgFontSize = `calc(${fontSize} * (100 / (${length}) * (12 / var(--o-orbit-number)))`;
970
1024
  const auto = this.getAttribute("range") === "auto";
971
- const stacked = auto || this.hasAttribute("value");
1025
+ const valued = this.hasAttribute("value");
1026
+ const placed = this.hasAttribute("start");
1027
+ const stacked = auto || valued || placed;
1028
+ const max = this.readMax(style);
972
1029
  let arcAngle;
973
1030
  if (auto) arcAngle = this.measureTextAngle(svgFontSize, common.realRadius, gap);
974
- else if (this.hasAttribute("value")) arcAngle = super.getProgressAngle(range, this.readValue(), this.readMax());
1031
+ else if (valued) arcAngle = super.getProgressAngle(range, this.readValue(), max);
975
1032
  else arcAngle = Math.max(0, Math.min(360, this.readAngle(style, "--o-angle", 0)));
976
1033
  this._autoAngle = auto ? arcAngle : 0;
977
1034
  let stackOffset = 0;
978
- if (stacked) {
1035
+ if (placed) {
1036
+ stackOffset = max > 0 ? this.readStart() / max * range : 0;
1037
+ if (!auto && range < 360) {
1038
+ const end = Math.min(range, stackOffset + arcAngle);
1039
+ stackOffset = Math.max(0, stackOffset);
1040
+ arcAngle = Math.max(0, end - stackOffset);
1041
+ }
1042
+ } else if (stacked) {
979
1043
  for (let prev = this.previousElementSibling; prev; prev = prev.previousElementSibling) {
980
- if (prev.localName !== "o-arc") continue;
1044
+ if (prev.localName !== "o-arc" || prev.hasAttribute("start")) continue;
981
1045
  const previousStyle = this.ownerDocument.defaultView.getComputedStyle(prev);
982
1046
  if (prev.getAttribute("range") === "auto") stackOffset += prev._autoAngle || 0;
983
1047
  else if (prev.hasAttribute("value")) {
984
- const prevMax = prev.hasAttribute("max") ? Number(prev.getAttribute("max")) : 100;
1048
+ const prevMax = this.readMax.call(prev, previousStyle);
985
1049
  const prevRange = cssNumber(prev, previousStyle.getPropertyValue("--o-range"), range, "angle");
986
1050
  stackOffset += super.getProgressAngle(prevRange, Number(prev.getAttribute("value")), prevMax);
987
1051
  } else stackOffset += cssNumber(prev, previousStyle.getPropertyValue("--o-angle"), 0, "angle");
988
1052
  }
989
1053
  }
990
- return { ...common, gap, arcAngle, stackOffset, flip, fitRange, length, fontSize, svgFontSize, textAnchor, auto, stacked };
1054
+ const reach = this.classList.contains("ripple") ? Math.max(1, this.readNumber(style, "--o-ripple-scale", 1.14)) : 1;
1055
+ return { ...common, gap, max, arcAngle, stackOffset, flip, fitRange, length, fontSize, svgFontSize, textAnchor, auto, placed, stacked, reach };
1056
+ }
1057
+ /** The start attribute: where a placed arc begins, on the ring's scale. */
1058
+ readStart() {
1059
+ const raw = this.getAttribute("start");
1060
+ const start = Number(raw);
1061
+ if (Number.isFinite(start)) return start;
1062
+ warnOnce(this, "start:" + raw, `<o-arc start="${raw}"> is not a number, so the arc starts at 0.`);
1063
+ return 0;
991
1064
  }
992
1065
  /** range="auto": the angle that fits this arc's text, with half an em of room at each end. */
993
1066
  measureTextAngle(svgFontSize, radius, gap) {
@@ -11,7 +11,7 @@
11
11
  },
12
12
  {
13
13
  "name": "max",
14
- "description": "Value that fills the ring's range. Must be positive. Default: 100."
14
+ "description": "Value that fills the ring's range. Must be positive. Without it, --o-max of the ring or system. Default: 100."
15
15
  },
16
16
  {
17
17
  "name": "shape",
@@ -58,6 +58,10 @@
58
58
  "name": "hit-width",
59
59
  "description": "Extra touch area in px on each side of an interactive band. Default: 0."
60
60
  },
61
+ {
62
+ "name": "start",
63
+ "description": "Where the arc begins, on the same scale as value. A placed arc takes no slot and moves no other arc: text over a ring that already has arcs, or segments on a timeline."
64
+ },
61
65
  {
62
66
  "name": "text-anchor",
63
67
  "description": "Where curved text sits on the arc. With range=\"auto\", an explicit value anchors the arc at its angle: middle centers it, end ends it there. Default: middle.",
@@ -104,7 +108,7 @@
104
108
  },
105
109
  {
106
110
  "name": "max",
107
- "description": "Value that fills the ring's range. Must be positive. Default: 100."
111
+ "description": "Value that fills the ring's range. Must be positive. Without it, --o-max of the ring or system. Default: 100."
108
112
  },
109
113
  {
110
114
  "name": "shape",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zumer/orbit",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Orbit builds radial interfaces with CSS geometry and a small JavaScript layout runtime",
5
5
  "main": "./dist/orbit.js",
6
6
  "module": "./dist/orbit.mjs",
@@ -29,7 +29,7 @@
29
29
  "scripts": {
30
30
  "compile": "node esbuild.config.mjs",
31
31
  "demo": "npm run compile && node scripts/demo.mjs",
32
- "docs": "npm run compile && node scripts/docs-sync.mjs && node scripts/demo.mjs",
32
+ "docs": "npm run compile && node scripts/docs-sync.mjs && node scripts/sitemap.mjs && node scripts/demo.mjs",
33
33
  "docs:sync": "node scripts/docs-sync.mjs",
34
34
  "bump:dry": "npx @zumerbox/bump -d",
35
35
  "bump": "npx @zumerbox/bump && npx @zumerbox/changelog",