UNPKG

@gullerya/callout

Version:
1 lines 5.94 kB
import{spotlight as t,SHAPES as e}from"./spotlight.min.js";import{tooltip as n,POSITIONS as o}from"./tooltip.min.js";const s=Symbol("spotlight.key"),l=Symbol("tooltip.key"),i=Symbol("entries.list"),r=Symbol("current.entry"),a=Symbol("next.method"),c=Symbol("prev.method"),d=Symbol("move.to.method"),h=Symbol("on.first.method"),p=Symbol("on.last.method"),m=Symbol("keys.processor.method"),u=["Escape"],b=["ArrowRight","ArrowUp","Space","Enter","NumpadEnter"],v=["ArrowLeft","ArrowDown"],g=Object.freeze({shape:e.circle});export{e as SHAPES};export function callout(t){const e=(Array.isArray(t)?t:[t]).filter(t=>t&&t.target&&t.target.nodeType===Node.ELEMENT_NODE&&t.target.parentElement&&t.content);if(!e.length)return void console.error("no valid entries to call out over");t.length>e.length&&console.warn(t.length-e.length+" entries found invalid and will not participate in callout flow");const n=e.filter(t=>"number"==typeof t.order&&!isNaN(t.order)).sort((t,e)=>t.order>e.order?1:t.order===e.order?0:-1);n.push(...e.filter(t=>"number"!=typeof t.order||isNaN(t.order)));const o=n.map(t=>{let e;return t.content.nodeType===Node.DOCUMENT_FRAGMENT_NODE?e=t.content:t.content.content&&t.content.content.nodeType===Node.DOCUMENT_FRAGMENT_NODE?e=t.content.content:(e=document.createDocumentFragment()).appendChild(document.createTextNode(t.content)),Object.assign({},g,t,{content:e.cloneNode(!0)})}),s=document.createElement("call-out"),l=window.getComputedStyle(document.documentElement).overflow;document.documentElement.style.overflow="hidden",s.addEventListener("close",()=>{document.documentElement.style.overflow=l}),s[i]=o,document.documentElement.appendChild(s)};const y=document.createElement("template");y.innerHTML='\n\t<style>\n\t\t:host {\n\t\t\tposition: fixed;\n\t\t\ttop: 0;\n\t\t\tleft: 0;\n\t\t\tright: 0;\n\t\t\tbottom: 0;\n\t\t\toutline: none;\n\t\t\tz-index: 9999;\n\t\t\toverflow: hidden;\n\t\t}\n\n\t\t.man-pan {\n\t\t\tposition: absolute;\n\t\t\tdirection: ltr;\n\t\t\tdisplay: flex;\n\t\t\tjustify-content: center;\n\t\t\twidth: 100%;\n\t\t\tfont: 1.4em sans-serif;\n\t\t\tcursor: default;\n\t\t\tuser-select: none;\n\t\t\ttransition: top 1s;\n\t\t}\n\n\t\t.man-pan.above {\n\t\t\ttop: 48px;\n\t\t}\n\n\t\t.man-pan.below {\n\t\t\ttop: calc(100% - 96px);\n\t\t}\n\n\t\t.button {\n\t\t\tflex: 0 0 48px;\n\t\t\theight: 48px;\n\t\t\tmargin: 0 12px;\n\t\t\tborder-radius: 50%;\n\t\t\tcolor: #666;\n\t\t\tbackground-color: #fff;\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tbox-shadow: 0 0 8px rgba(0, 0, 0, 0.5), inset 0 0 12px rgba(0, 128, 0, 0.75);\n\t\t}\n\n\t\t.button.close {\n\t\t\tline-height: 48px;\n\t\t\tbox-shadow: 0 0 8px rgba(0, 0, 0, 0.5), inset 0 0 12px rgba(128, 0, 0, 0.75);\n\t\t}\n\n\t\t.button.disabled {\n\t\t\tcolor: #ccc;\n\t\t\tbackground-color: #ddd;\n\t\t\tbox-shadow: none;\n\t\t}\n\n\t\t.position {\n\t\t\tcolor: #fff;\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t}\n\n\t\ttool-tip {\n\t\t\tfont-size: 0.64em;\n\t\t}\n\t</style>\n\n\t<div class="man-pan">\n\t\t<div class="button prev">&#11207;</div>\n\t\t<tool-tip data-target-class="prev">\n\t\t\t<slot name="prev-label">Previous (ArrowLeft)</slot>\n\t\t</tool-tip>\n\n\t\t<div class="position">\n\t\t\t<span class="current"></span>&nbsp;/&nbsp;<span class="total"></span>\n\t\t</div>\n\n\t\t<div class="button next">&#11208;</div>\n\t\t<tool-tip data-target-class="next">\n\t\t\t<slot name="next-label">Next (ArrowRight, Space, Enter)</slot>\n\t\t</tool-tip>\n\n\t\t<div class="button close">&#128473;</div>\n\t\t<tool-tip data-target-class="close">\n\t\t\t<slot name="close-label">Close (Escape)</slot>\n\t\t</tool-tip>\n\t</div>\n',customElements.define("call-out",class extends HTMLElement{constructor(){super();const t=this.attachShadow({mode:"open"});t.appendChild(y.content.cloneNode(!0)),t.querySelector(".next").addEventListener("click",()=>this[a]()),t.querySelector(".prev").addEventListener("click",()=>this[c]()),t.querySelector(".close").addEventListener("click",()=>this.remove()),this[r]=-1}connectedCallback(){this[s]=t(),this[l]=n(),this[l].position=o.far,this[l].classList.add("light"),this.shadowRoot.querySelector(".total").textContent=this[i].length,this.tabIndex=1,this.focus(),this.addEventListener("keydown",this[m]),this[a]()}disconnectedCallback(){this.removeEventListener("keydown",this[m]),this[l].remove(),this[s].close(),this.dispatchEvent(new Event("close"))}[a](){const t=this[i],e=this[r]+1;t&&t.length&&(e>=t.length||(this[r]=e,this[d](t[e])))}[c](){const t=this[i],e=this[r]-1;t&&t.length&&(e<0||(this[r]=e,this[d](t[e])))}[d](t){this.ensureElementSeen(t.target);const e=this.getScreenRect(t.target);this[l].hide(),this[s].shape=t.shape,this[s].moveTo(t.target).then(()=>{this[l].show(this[s],t.content.cloneNode(!0))});const n=this.shadowRoot.querySelector(".man-pan");e.bottom>document.documentElement.clientHeight/2?(n.classList.remove("below"),n.classList.add("above")):(n.classList.remove("above"),n.classList.add("below")),this.shadowRoot.querySelector(".current").textContent=this[r]+1,this[h](0===this[r]),this[p](this[r]===this[i].length-1)}[p](t){const e=this.shadowRoot;t?(e.querySelector(".next").classList.add("disabled"),e.querySelector('[data-target-class="next"]').classList.add("disabled")):(e.querySelector(".next").classList.remove("disabled"),e.querySelector('[data-target-class="next"]').classList.remove("disabled"))}[h](t){t?(this.shadowRoot.querySelector(".prev").classList.add("disabled"),this.shadowRoot.querySelector('[data-target-class="prev"]').classList.add("disabled")):(this.shadowRoot.querySelector(".prev").classList.remove("disabled"),this.shadowRoot.querySelector('[data-target-class="prev"]').classList.remove("disabled"))}[m](t){u.includes(t.code)?this.remove():b.includes(t.code)?this[a]():v.includes(t.code)&&this[c]()}ensureElementSeen(t){t.scrollIntoView()}getScreenRect(t){return t.getBoundingClientRect()}});