@flexilla/alpine-modal
Version:
AlpineJS plugin for creating Modal, Dialog, alert dialog components
2 lines (1 loc) • 11.7 kB
JavaScript
(()=>{var I=Object.defineProperty,T=(e,t,o)=>t in e?I(e,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[t]=o,a=(e,t,o)=>T(e,typeof t!="symbol"?t+"":t,o),v=(e,t=document.body)=>t.querySelector(e),y=(e,t=document.body)=>Array.from(t.querySelectorAll(e)),D=({newElement:e,existingElement:t})=>{if(!(e instanceof HTMLElement)||!(t instanceof HTMLElement))throw new Error("Both parameters must be valid HTML elements.");let o=t.parentElement;if(o)o.insertBefore(e,t);else throw new Error("Existing element must have a parent element.")},k=({element:e,callback:t,type:o,keysCheck:s})=>{let l=getComputedStyle(e),d=l.animation;if(d!=="none"&&d!==""&&!s.includes(d)){let c="animationend",u=()=>{e.removeEventListener(c,u),t()};e.addEventListener(c,u,{once:!0})}else t()},A=({element:e,callback:t})=>{k({element:e,callback:t,type:"animation",keysCheck:["none 0s ease 0s 1 normal none running"]})},g=(e,t,o)=>{let s=new CustomEvent(t,{detail:o});e.dispatchEvent(s)},C=(e,t,o)=>{if(!(t instanceof HTMLElement))throw new Error("No modal-content found");e.setAttribute("aria-hidden",o==="open"?"false":"true"),e.setAttribute("data-state",o),t.setAttribute("data-state",o);let s=v("[data-modal-overlay]",e);s instanceof HTMLElement&&s.setAttribute("data-state",o)},$=(e,t,o)=>{if(!e){t||(document.body.style.overflowY="auto");return}y("[data-fx-modal][data-state=open]:not([data-allow-body-scroll=true]").filter(s=>s!==o).length===0&&!t&&(document.body.style.overflowY="auto")},w=class{static initGlobalRegistry(){window.$flexillaInstances||(window.$flexillaInstances={})}static register(t,o,s){return this.initGlobalRegistry(),window.$flexillaInstances[t]||(window.$flexillaInstances[t]=[]),this.getInstance(t,o)||(window.$flexillaInstances[t].push({element:o,instance:s}),s)}static getInstance(t,o){var s,l;return this.initGlobalRegistry(),(l=(s=window.$flexillaInstances[t])==null?void 0:s.find(d=>d.element===o))==null?void 0:l.instance}static removeInstance(t,o){this.initGlobalRegistry(),window.$flexillaInstances[t]&&(window.$flexillaInstances[t]=window.$flexillaInstances[t].filter(s=>s.element!==o))}},H=e=>{var t;e instanceof HTMLElement&&((t=e.parentElement)==null||t.removeChild(e))},B=({modalContent:e,overlayClassName:t})=>{let o=document.createElement("span");return o.setAttribute("aria-hidden","true"),D({newElement:o,existingElement:e}),o.classList.add(...t),o.setAttribute("data-modal-overlay",""),o},f=class{constructor(t,o={},s){a(this,"modalElement"),a(this,"modalId"),a(this,"modalContent"),a(this,"triggerButtons",[]),a(this,"overlayElement"),a(this,"dispatchEventToDocument"),a(this,"options"),a(this,"state"),a(this,"animationEnter"),a(this,"animationExit"),a(this,"animateContent"),a(this,"hasDefaultOverlay"),a(this,"enableStackedModals"),a(this,"preventCloseModal"),a(this,"isKeyDownEventRegistered"),a(this,"closeButtons"),a(this,"overlayClassName"),a(this,"allowBodyScroll"),a(this,"initAsOpen"),a(this,"closeAll",n=>{if(this.enableStackedModals)return;let r=y("[data-fx-modal][data-state=open]");for(let i of r){let m=i.dataset.modalId;if(m!==n.dataset.modalId){i.blur(),v("[data-modal-overlay]",i).setAttribute("data-state","close");let h=v("[data-modal-content]",i);C(i,h,"close"),document.dispatchEvent(new CustomEvent(`modal:${m}:close`))}}}),a(this,"closeModalEsc",n=>{n.key==="Escape"&&(n.preventDefault(),this.preventCloseModal||this.hideModal())}),a(this,"initModal",(n,r)=>{var i;if(!(n instanceof HTMLDialogElement))throw new Error("Modal Element must be a valid HTMLDialog Element");let{allowBodyScroll:m,animateContent:h,preventCloseModal:E,overlayClass:p,enableStackedModals:b}=r;this.allowBodyScroll=n.hasAttribute("data-allow-body-scroll")&&n.getAttribute("data-allow-body-scroll")!=="false"||m||!1,this.preventCloseModal=n.hasAttribute("data-prevent-close-modal")&&n.getAttribute("data-prevent-close-modal")!=="false"||E||!1,this.enableStackedModals=n.hasAttribute("data-enable-stacked")&&n.getAttribute("data-enable-stacked")!=="false"||b||!1,this.overlayClassName=((i=n.dataset.modalOverlay)==null?void 0:i.split(" "))||p?.split(" ")||"",this.isKeyDownEventRegistered=!1,n.setAttribute("data-allow-body-scroll",`${this.allowBodyScroll}`),this.closeButtons=y("[data-close-modal]",n),this.hasDefaultOverlay=!1,v("[data-modal-overlay]",n)instanceof HTMLElement&&(this.overlayElement=v("[data-modal-overlay]",n),this.overlayElement.setAttribute("data-overlay-nature","default"),this.hasDefaultOverlay=!0),this.animateContent=h,this.animationEnter=this.modalContent.dataset.enterAnimation||"",this.animationExit=this.modalContent.dataset.exitAnimation||"",this.overlayElement&&this.overlayElement.setAttribute("data-state","close"),this.addEvents()}),a(this,"closeModalOnX",n=>{n.preventDefault(),this.hideModal()}),a(this,"addEvents",()=>{for(let n of this.triggerButtons)n.addEventListener("click",this.showModal);if(this.closeButtons.length>0)for(let n of this.closeButtons)n.addEventListener("click",this.closeModalOnX);this.dispatchEventToDocument&&document.addEventListener(`modal:${this.modalId}:open`,this.showModal),this.dispatchEventToDocument&&document.addEventListener(`modal:${this.modalId}:close`,this.hideModal)}),a(this,"showModal",()=>{var n,r,i,m,h;if(!(!this.initAsOpen&&this.modalElement.getAttribute("data-state")==="open")){if(this.initAsOpen=!1,this.closeAll(this.modalElement),this.overlayElement=this.hasDefaultOverlay?this.overlayElement:B({modalContent:this.modalContent,overlayClassName:this.overlayClassName}),(n=this.overlayElement)==null||n.setAttribute("data-state","open"),g(this.modalElement,"modal-open",{modalId:this.modalId}),this.animateContent||this.animationEnter!==""){let E=this.animateContent?this.animateContent.enterAnimation:this.animationEnter;E&&E!==""&&this.modalContent.style.setProperty("--un-modal-animation",E),C(this.modalElement,this.modalContent,"open"),A({element:this.modalContent,callback:()=>{this.modalContent.style.removeProperty("--un-modal-animation")}})}else C(this.modalElement,this.modalContent,"open");this.allowBodyScroll||(document.body.style.overflow="hidden"),this.isKeyDownEventRegistered||(document.addEventListener("keydown",this.closeModalEsc),this.isKeyDownEventRegistered=!0),this.modalContent.focus(),this.preventCloseModal||this.overlayElement.addEventListener("click",this.hideModal),(i=(r=this.options).onShow)==null||i.call(r),(h=(m=this.options).onToggle)==null||h.call(m,{isHidden:!1}),this.modalElement.showModal()}}),a(this,"closeModal",()=>{this.modalElement.setAttribute("aria-hidden","true"),this.modalElement.setAttribute("data-state","close"),this.modalElement.blur(),$(this.enableStackedModals||!1,this.allowBodyScroll||!1,this.modalElement),this.hasDefaultOverlay||H(this.overlayElement),g(this.modalElement,"modal-close",{modalId:this.modalElement.id})}),a(this,"closeLastAction",()=>{var n,r,i,m;this.isKeyDownEventRegistered&&(document.removeEventListener("keydown",this.closeModalEsc),this.isKeyDownEventRegistered=!1),this.modalElement.blur(),(r=(n=this.options).onHide)==null||r.call(n),(m=(i=this.options).onToggle)==null||m.call(i,{isHidden:!0})}),a(this,"hideModal",()=>{var n,r,i,m,h;let E=!1;g(this.modalElement,"before-hide",{modalId:this.modalId,setExitAction:M=>{E=M}});let p=(i=(r=(n=this.options).beforeHide)==null?void 0:r.call(n))==null?void 0:i.cancelAction;if(E||p)return;let b=((m=this.animateContent)==null?void 0:m.exitAnimation)&&this.animateContent.exitAnimation!==""||this.animationExit&&this.animationExit!=="";if((h=this.overlayElement)==null||h.setAttribute("data-state","close"),this.modalContent.setAttribute("data-state","close"),b){let M=this.animationExit?this.animationExit:this.animateContent&&this.animateContent.exitAnimation||"";this.modalContent.style.setProperty("--un-modal-animation",M)}A({element:this.modalContent,callback:()=>{b&&this.modalContent.style.removeProperty("--un-modal-animation"),this.closeModal(),this.closeLastAction(),document.activeElement instanceof HTMLElement&&document.activeElement.blur(),this.modalElement.close("modal-closed")}})}),a(this,"cleanup",()=>{for(let n of this.triggerButtons)n.removeEventListener("click",this.showModal);if(this.closeButtons.length>0)for(let n of this.closeButtons)n.removeEventListener("click",this.closeModalOnX);!this.preventCloseModal&&this.overlayElement instanceof HTMLElement&&this.overlayElement.removeEventListener("click",this.hideModal),this.dispatchEventToDocument&&document.removeEventListener(`modal:${this.modalId}:open`,this.showModal),this.dispatchEventToDocument&&document.removeEventListener(`modal:${this.modalId}:close`,this.hideModal),w.removeInstance("modal",this.modalElement)}),a(this,"setOptions",({state:n,allowBodyscroll:r})=>{n&&(this.state=n),r!==void 0&&(this.allowBodyScroll=r),this.state==="open"?this.showModal():this.state==="close"&&this.hideModal()});let l=typeof t=="string"?v(t):t;if(!(l instanceof HTMLDialogElement))throw new Error("Modal element not found or invalid. Please provide a valid HTMLDialogElement or selector.");this.modalElement=l,this.options=o,this.state=o?.defaultState||this.modalElement.dataset.state||"close";let d=w.getInstance("modal",this.modalElement);if(d)return d;this.modalElement.hasAttribute("data-fx-modal")||this.modalElement.setAttribute("data-fx-modal","");let c=v("[data-modal-content]",l);if(!(c instanceof HTMLElement))throw new Error("Modal content element not found or invalid. Please provide a valid HTMLElement or selector.");this.modalContent=c;let u=l.dataset.modalId;this.modalId=`${u}`,this.initializeTriggers(s,u),this.dispatchEventToDocument=this.options.dispatchEventToDocument||!0,this.initModal(this.modalElement,this.options),this.state==="open"?(this.initAsOpen=!0,this.showModal()):(this.initAsOpen=!1,this.modalElement.blur(),this.modalContent.setAttribute("data-state","close"),this.modalElement.setAttribute("aria-hidden","true"),this.modalElement.setAttribute("data-state","close")),w.register("modal",this.modalElement,this)}initializeTriggers(t,o){if(!t&&o){let l=y(`[data-modal-target='${o}'], [data-modal-trigger][data-modal-id='${o}']`);this.triggerButtons=l;return}if(!t)return;let s=Array.isArray(t)?t:[t];this.triggerButtons=s.map(l=>{if(typeof l=="string"){let d=v(l);if(!(d instanceof HTMLElement))throw new Error(`Trigger element not found: ${l}`);return d}if(!(l instanceof HTMLElement))throw new Error("Invalid trigger element provided");return l})}};a(f,"autoInit",(e="[data-fx-modal]")=>{let t=y(e);for(let o of t)new f(o)}),a(f,"init",(e,t={},o)=>new f(e,t,o));var L=f;function S(e){e.directive("modal",(t,{},{cleanup:o})=>{let s=t.getAttribute("data-modal-id");if(!s){console.error("\u274C data-modal-id is required but missing on element:",t);return}if(!(t instanceof HTMLDialogElement)){console.error("\u274C x-modal must be used only on an HTMLDialogElement:",t);return}if(!t.querySelector("[data-modal-content]")){console.error("\u274C data-modal-content Element is required but missing in Modal Element:",t);return}let d=new L(t,{dispatchEventToDocument:!1});e.store("modals")||e.store("modals",{}),e.store("modals")[s]=d;let c=()=>d.showModal(),u=()=>d.hideModal();document.addEventListener(`modal:${s}:open`,c),document.addEventListener(`modal:${s}:close`,u),o(()=>{d.cleanup(),delete e.store("modals")[s],document.removeEventListener(`modal:${s}:open`,c),document.removeEventListener(`modal:${s}:close`,u)})}),e.magic("modal",()=>t=>e.store("modals")?e.store("modals")[t]?e.store("modals")[t]:(console.warn(`\u26A0\uFE0F No modal instance found for ID: ${t}`),null):(console.warn("\u26A0\uFE0F Alpine store for modals is not initialized."),null))}var x=S;document.addEventListener("alpine:init",()=>{x(window.Alpine)});})();