UNPKG

@magic-spells/dialog-panel

Version:

A lightweight web component wrapper for native <dialog> elements with state-driven animations.

2 lines (1 loc) 4.84 kB
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).DialogPanel={})}(this,function(e){"use strict";class DialogPanel extends HTMLElement{#e="hidden";#n=null;#t=null;#i=null;#l=null;#o=null;#r=!1;#s={click:null,dialogClick:null,cancel:null,close:null,morphShown:null,morphHidden:null,morphStop:null};#a=null;#d=null;static TRANSITION_FALLBACK_TIMEOUT=700;connectedCallback(){const e=this;if(e.#t=e.querySelector("dialog"),e.#t){if(!e.querySelector("dialog-backdrop")){const n=document.createElement("dialog-backdrop");e.insertBefore(n,e.firstChild)}e.#h("hidden"),e.#g(),e.#c()}else console.warn("DialogPanel: No <dialog> element found inside <dialog-panel>")}disconnectedCallback(){const e=this;e.#a&&(cancelAnimationFrame(e.#a),e.#a=null),e.#d&&(clearTimeout(e.#d),e.#d=null),e.#p(),e.#s.click&&e.removeEventListener("click",e.#s.click),e.#t&&(e.#s.dialogClick&&e.#t.removeEventListener("click",e.#s.dialogClick),e.#s.cancel&&e.#t.removeEventListener("cancel",e.#s.cancel),e.#s.close&&e.#t.removeEventListener("close",e.#s.close))}#g(){const e=this;e.#s.click=n=>{const t=n.target.closest("[data-action-hide-dialog]");t&&(n.stopPropagation(),e.hide(t))},e.addEventListener("click",e.#s.click),e.#s.dialogClick=n=>{const t=e.#t.getBoundingClientRect();(n.clientX<t.left||n.clientX>t.right||n.clientY<t.top||n.clientY>t.bottom)&&(n.stopPropagation(),e.hide())},e.#t.addEventListener("click",e.#s.dialogClick),e.#s.cancel=n=>{n.preventDefault(),n.stopPropagation(),e.hide()},e.#t.addEventListener("cancel",e.#s.cancel),e.#s.close=()=>{"shown"!==e.#o?.state||"shown"!==e.#e||e.#t.open||e.hide()},e.#t.addEventListener("close",e.#s.close)}#c(){const e=this;e.#o&&!e.#r&&(e.#s.morphShown||(e.#s.morphShown=e.#m.bind(e),e.#s.morphHidden=e.#u.bind(e),e.#s.morphStop=e.#E.bind(e)),e.#o.on("shown",e.#s.morphShown),e.#o.on("hidden",e.#s.morphHidden),e.#o.on("stop",e.#s.morphStop),e.#r=!0)}#p(){const e=this;e.#o&&e.#r&&(e.#o.off("shown",e.#s.morphShown),e.#o.off("hidden",e.#s.morphHidden),e.#o.off("stop",e.#s.morphStop),e.#r=!1)}#m(){const e=this;e.#t.open||e.#t.showModal(),e.#h("shown"),e.#w("shown")}#u(){this.#f()}#E(){this.#f()}#f(){const e=this;e.#t.open&&e.#t.close(),e.#h("hidden"),e.#w("hidden",{result:e.#i,triggerElement:e.#l}),e.#n&&e.#n.focus(),e.#n=null,e.#l=null,e.#i=null}show(e=null){const n=this;if("showing"===n.#e||"shown"===n.#e)return!0;const t="hiding"===n.#e&&"hiding"===n.#o?.state;return!("hiding"===n.#e&&!t)&&(t||(n.#n=e||null),!!n.#w("beforeShow",{cancelable:!0})&&(t&&(n.#l=null,n.#i=null),n.#h("showing"),n.#o&&(e||t)?(n.#o.show({from:n.#n,to:n.#t,display:n.getAttribute("morph-display")||"block"}),!0):(n.#t.showModal(),n.#a=requestAnimationFrame(()=>{n.#a=requestAnimationFrame(()=>{n.#a=null,n.#h("shown"),n.#k(()=>{n.#w("shown")})})}),!0)))}hide(e=null){const n=this;if("hiding"===n.#e||"hidden"===n.#e)return!0;const t="showing"===n.#e&&"showing"===n.#o?.state;return!("showing"===n.#e&&!t)&&(n.#i=e?.dataset?.result??null,!!n.#w("beforeHide",{cancelable:!0,result:n.#i,triggerElement:e})&&(t||"shown"===n.#o?.state?(n.#l=e,n.#t.open&&n.#t.close(),n.#o.hide(),n.#h("hiding"),!0):(n.#h("hiding"),n.#k(()=>{n.#t.close(),n.#h("hidden"),n.#w("hidden",{result:n.#i,triggerElement:e}),n.#n&&n.#n.focus(),n.#n=null,n.#i=null}),!0)))}#k(e){const n=this;let t=!1,i=null;const l=()=>{t||(t=!0,n.#t.removeEventListener("transitionend",o),clearTimeout(i),n.#d===i&&(n.#d=null),e())},o=e=>{e.target===n.#t&&l()};n.#t.addEventListener("transitionend",o),i=setTimeout(l,DialogPanel.TRANSITION_FALLBACK_TIMEOUT),n.#d=i}#h(e){this.#e=e,this.setAttribute("state",e)}#w(e,n={}){const t=this,{cancelable:i=!1,...l}=n,o=new CustomEvent(e,{bubbles:!0,composed:!0,cancelable:i,detail:{triggerElement:t.#n,result:t.#i,state:t.#e,...l}});return t.dispatchEvent(o)}get morphEngine(){return this.#o}set morphEngine(e){const n=this;n.#o!==e&&(n.#p(),n.#o=e||null,n.#o?(n.setAttribute("morph",""),n.#c()):n.removeAttribute("morph"))}get state(){return this.#e}get dialog(){return this.#t}get isOpen(){return"showing"===this.#e||"shown"===this.#e}get triggerElement(){return this.#n}}class DialogBackdrop extends HTMLElement{#b=null;#s={click:null};connectedCallback(){const e=this;e.#b=e.closest("dialog-panel"),e.#b?(e.#s.click=()=>{e.#b.hide()},e.addEventListener("click",e.#s.click)):console.warn("DialogBackdrop: Must be inside a <dialog-panel> element")}disconnectedCallback(){const e=this;e.#s.click&&e.removeEventListener("click",e.#s.click)}}customElements.get("dialog-backdrop")||customElements.define("dialog-backdrop",DialogBackdrop),customElements.get("dialog-panel")||customElements.define("dialog-panel",DialogPanel),e.DialogBackdrop=DialogBackdrop,e.DialogPanel=DialogPanel});