-
Notifications
You must be signed in to change notification settings - Fork 0
/
SelfDestruct.min.js
1 lines (1 loc) · 4.22 KB
/
SelfDestruct.min.js
1
class Timer{#t;#e;#s;#i;#r;#n;constructor(t,e){this.#s=e,this.#r=t,this.#n=e,this.start()}get timeLeft(){return this.#i&&(this.pause(),this.start()),this.#s}get isRunning(){return this.#i}pause(){this.#i=!1,clearTimeout(this.#t),this.#s-=new Date-this.#e}reset(){this.stop(),this.#s=this.#n}start(){this.#i=!0,this.#e=new Date,this.#t=setTimeout(this.#r,this.#s)}stop(){this.#i=!1,clearTimeout(this.#t),this.#s=0}}class SelfDestruct extends HTMLElement{buildBar(t){return`<span class="self-destruct-progress-bar" style="width:${100*(t=Math.min(1,Math.max(0,t)))}%;"></span>`}buildPie(t){t=Math.min(1,Math.max(0,t));const e=Math.cos(2*Math.PI*t),s=Math.sin(2*Math.PI*t);return`<svg width="1em" height="1em" class="self-destruct-svg" viewBox="-1 -1 2 2" aria-hidden="true"><circle r="1" cx="0" cy="0" class="self-destruct-svg-bg" fill="#0000"/>${t>0&&t<1?`<path d="M1 0A1 1 0 ${t>.5?1:0} 1 ${e} ${s}L0 0" class="self-destruct-svg-fg" fill="#f009" transform="rotate(-90)"/>`:""}</svg>`}constructor(){super(),this.defaultTtl=5e3,this.reduceMotion=window.matchMedia("(prefers-reduced-motion: reduce)").matches,this.progress=null}connectedCallback(){this.ttl=this.hasAttribute("ttl")?this.parseTime(this.getAttribute("ttl")):this.defaultTtl,this.animate=!this.reduceMotion&&!this.hasAttribute("no-animation")&&this.ttl>=250,this.progressType=this.getAttribute("progress")??!1,this.ttl>1e3&&this.progressType&&this.initProgress(),this.initTimer(),this.addEventListener("click",this),this.addEventListener("mouseenter",this),this.addEventListener("mouseleave",this)}destroyProgress(){this.updater&&clearInterval(this.updater),this.progressContainer&&this.progressContainer.remove()}destruct(){this.destroyProgress(),this.timer&&this.timer.stop(),this.remove()}disconnectedCallback(){this.timer&&(this.timer.stop(),this.timer=null),this.destroyProgress(),this.removeEventListener("click",this),this.removeEventListener("mouseenter",this),this.removeEventListener("mouseleave",this)}handleEvent(t){return this["on"+t.type]&&this["on"+t.type](t)}initProgress(){let t=this.childElementCount?this.firstElementChild:this;this.hasAttribute("progress-target")&&this.querySelector(this.getAttribute("progress-target"))&&(t=this.querySelector(this.getAttribute("progress-target")),t.textContent=""),this.progressContainer=document.createElement("span"),this.progressContainer.className="self-destruct-progress","pie"===this.progressType?(this.progressContainer.innerHTML=this.buildPie(1),this.progress=this.progressContainer):"bar"===this.progressType?(this.progressContainer.innerHTML=this.buildBar(1),this.progress=this.progressContainer.querySelector(".self-destruct-progress-bar"),t=this):"seconds"===this.progressType&&(this.progressContainer.textContent=this.ttl,this.progress=this.progressContainer),t.appendChild(this.progressContainer),this.updater=setInterval(this.updateProgress.bind(this),50)}initTimer(){const t=this;if(t.ttl>0){const e=t.animate?t.ttl-250:t.ttl;t.timer=new Timer((()=>{t.animate?(t.style.transition="opacity 250ms ease",t.style.opacity="0",t.timer=new Timer(t.destruct.bind(t),250)):t.destruct()}),e)}}onclick(t){const e=this.getAttribute("on-click");t.target.matches(".self-destruct")||"destroy"===e?this.destruct():"pause"===e&&this.timer.isRunning?this.timer.pause():"pause"!==e||this.timer.isRunning?"prevent"===e?this.preventDestruct():"reset"===e&&(this.timer.reset(),this.timer.start()):this.timer.start()}onmouseenter(t){const e=this.getAttribute("on-hover");"pause"===e?this.timer.pause():"prevent"===e?this.preventDestruct():"reset"===e&&this.timer.reset()}onmouseleave(t){const e=this.getAttribute("on-hover");"pause"!==e&&"reset"!==e||this.timer.start()}parseTime(t){const e=t.match(/((?:\d?\.)?\d+) ?(m?s)?/);let s=e?parseFloat(e[1]):this.defaultTtl;return e&&"s"===e[2]&&(s*=1e3),s}preventDestruct(){this.timer.stop(),this.updater&&clearInterval(this.updater),this.destroyProgress()}updateProgress(){"pie"===this.progressType?this.progressContainer.innerHTML=this.buildPie(this.timer.timeLeft/this.ttl):"bar"===this.progressType?this.progress.style.width=String(this.timer.timeLeft/this.ttl*100)+"%":"seconds"===this.progressType&&(this.progressContainer.textContent=Math.ceil(this.timer.timeLeft/1e3))}}"customElements"in window&&window.customElements.define("self-destruct",SelfDestruct);