@flexilla/offcanvas
Version:
An offcanvas component for creating responsive and off-screen navigation panels in web applications.
2 lines (1 loc) • 8.4 kB
JavaScript
(function(f,i){typeof exports=="object"&&typeof module<"u"?i(exports):typeof define=="function"&&define.amd?define(["exports"],i):(f=typeof globalThis<"u"?globalThis:f||self,i(f["@flexilla/offcanvas"]={}))})(this,function(f){"use strict";var T=Object.defineProperty;var N=(f,i,c)=>i in f?T(f,i,{enumerable:!0,configurable:!0,writable:!0,value:c}):f[i]=c;var o=(f,i,c)=>N(f,typeof i!="symbol"?i+"":i,c);const i=(t,e=document.body)=>e.querySelector(t),c=(t,e=document.body)=>Array.from(e.querySelectorAll(t)),g=({newElement:t,existingElement:e})=>{if(!(t instanceof HTMLElement)||!(e instanceof HTMLElement))throw new Error("Both parameters must be valid HTML elements.");const s=e.parentElement;if(s)s.insertBefore(t,e);else throw new Error("Existing element must have a parent element.")},w=({element:t,callback:e,type:s,keysCheck:n})=>{const a=getComputedStyle(t),l=a.transition;if(l!=="none"&&l!==""&&!n.includes(l)){const r="transitionend",d=()=>{t.removeEventListener(r,d),e()};t.addEventListener(r,d,{once:!0})}else e()},y=({element:t,callback:e})=>{w({element:t,callback:e,type:"transition",keysCheck:["all 0s ease 0s","all"]})},p=(t,e,s)=>{const n=new CustomEvent(e,{detail:s});t.dispatchEvent(n)};function O(t){const e=()=>{document.querySelector("[data-fx-component]:not([data-component-initialized])")?requestAnimationFrame(e):t()};e()}function k(t,e,s="move"){if(!(t instanceof HTMLElement))throw new Error("Source element must be an HTMLElement");if(!(e instanceof HTMLElement))throw new Error("Target element must be an HTMLElement");if(!["move","detachable"].includes(s))throw new Error(`Invalid teleport mode: ${s}. Must be "move" or "detachable".`);let n=document.createComment("teleporter-placeholder");const a=t.parentNode;return a?a.insertBefore(n,t):console.warn("Element has no parent; placeholder not inserted."),s==="move"?(t.parentNode&&e.appendChild(t),{append(){t.parentNode!==e&&e.appendChild(t)},remove(){n!=null&&n.parentNode&&t.parentNode&&n.parentNode.insertBefore(t,n)},restore(){n!=null&&n.parentNode&&t.parentNode!==a&&n.parentNode.insertBefore(t,n)}}):(t.parentNode&&e.appendChild(t),{append(){e.contains(t)||e.appendChild(t)},remove(){t.parentNode&&t.remove()},restore(){n!=null&&n.parentNode&&!t.parentNode&&n.parentNode.insertBefore(t,n)}})}const A=t=>{var e;return(e=t.parentElement)==null?void 0:e.removeChild(t)},E=t=>{t.setAttribute("data-state","invisible"),y({element:t,callback(){A(t)}})},B=(t,e)=>{const s=t;if(s===""||!s)return;const n=document.createElement("div");if(n.setAttribute("aria-hidden","true"),n.setAttribute("data-state","visible"),n.setAttribute("data-fx-offcanvas-overlay",""),n.setAttribute("data-offcanvas-el",e),s==="")return;const a=s.split(" ");return s!==""&&n.classList.add(...a),n},C=(t,e,s)=>{t.setAttribute("aria-hidden",s==="open"?"false":"true"),t.setAttribute("data-state",s),e||S(s)},S=t=>{document.body.style.overflow=t==="open"?"hidden":"",document.body.style.overflowY=t==="open"?"hidden":"auto"},x=(t,e)=>{if(t===e)return;t.setAttribute("aria-hidden","true"),t.setAttribute("data-state","close");const s=i(`[data-fx-offcanvas-overlay][data-offcanvas-el=${t.getAttribute("id")}]`,t.parentElement);s instanceof HTMLElement&&E(s)},L=t=>{const e=c("[data-fx-offcanvas][data-state=open]");if(!(e.length<=0))for(const s of e)x(s,t)};class h{static initGlobalRegistry(){window.$flexillaInstances||(window.$flexillaInstances={})}static register(e,s,n){return this.initGlobalRegistry(),window.$flexillaInstances[e]||(window.$flexillaInstances[e]=[]),this.getInstance(e,s)||(window.$flexillaInstances[e].push({element:s,instance:n}),n)}static getInstance(e,s){var n,a;return this.initGlobalRegistry(),(a=(n=window.$flexillaInstances[e])==null?void 0:n.find(l=>l.element===s))==null?void 0:a.instance}static removeInstance(e,s){this.initGlobalRegistry(),window.$flexillaInstances[e]&&(window.$flexillaInstances[e]=window.$flexillaInstances[e].filter(n=>n.element!==s))}static setup(e){e.setAttribute("data-fx-component","fx")}static initialized(e){e.setAttribute("data-component-initialized","initialized")}}const v=class v{constructor(e,s={}){o(this,"offCanvasElement");o(this,"offCanvasTriggers");o(this,"offCanvasCloseBtns");o(this,"allowBodyScroll");o(this,"staticBackdrop");o(this,"backdrop");o(this,"options");o(this,"teleporter");o(this,"moveElOnInit",()=>{O(()=>this.teleporter.append())});o(this,"closeWhenClickOutSide",e=>{const s=this.offCanvasElement.getAttribute("data-state")==="open",n=!this.offCanvasElement.contains(e.target)&&![...this.offCanvasTriggers].includes(e.target);s&&n&&this.closeOffCanvas()});o(this,"closeOffCanvas",()=>{var l,r,d,m,b;let e=!1;if(p(this.offCanvasElement,"offcanvas-before-hide",{offcanvasId:this.offCanvasElement.id,setExitAction:I=>{e=I}}),((d=(r=(l=this.options).beforeHide)==null?void 0:r.call(l))==null?void 0:d.cancelAction)||e)return;const n=this.offCanvasElement.getAttribute("id"),a=i(`[data-fx-offcanvas-overlay][data-offcanvas-el=${n}]`);a instanceof HTMLElement&&E(a),this.offCanvasElement.blur(),C(this.offCanvasElement,this.allowBodyScroll,"close"),document.removeEventListener("keydown",this.closeWithEsc),!this.allowBodyScroll&&!a&&document.removeEventListener("click",this.closeWhenClickOutSide),(b=(m=this.options).onHide)==null||b.call(m),p(this.offCanvasElement,"offcanvas-close",{offcanvasId:this.offCanvasElement.id})});o(this,"closeWithEsc",e=>{e.key==="Escape"&&(e.preventDefault(),this.closeOffCanvas())});o(this,"changeState",()=>{this.offCanvasElement.getAttribute("data-state")==="open"?this.closeOffCanvas():this.openOffCanvas()});o(this,"setOptions",({allowBodyscroll:e})=>{e!==void 0&&(this.allowBodyScroll=e)});const n=typeof e=="string"?i(e):e;if(!(n instanceof HTMLElement))throw new Error("Invalid Offcanvas, the provided Element is not a valid HTMLElement");this.offCanvasElement=n;const a=h.getInstance("offcanvas",n);if(a)return a;h.setup(this.offCanvasElement),this.options=s;const{staticBackdrop:l,allowBodyScroll:r,backdrop:d}=this.options;this.setupAttributes(),this.staticBackdrop=l||n.hasAttribute("data-static-backdrop")&&n.dataset.staticBackdrop!=="false"||!1,this.allowBodyScroll=r||n.hasAttribute("data-allow-body-scroll")&&n.dataset.allowBodyScroll!=="false"||!1;const m=this.offCanvasElement.getAttribute("id");this.offCanvasTriggers=this.findOffCanvasElements("[data-offcanvas-trigger]",!1,m),this.offCanvasCloseBtns=this.findOffCanvasElements("[data-offcanvas-close]",!0,m,this.offCanvasElement),this.backdrop=d||this.offCanvasElement.dataset.offcanvasBackdrop||"",this.teleporter=k(this.offCanvasElement,document.body,"move"),this.setupOffcanvas(),this.moveElOnInit(),h.register("offcanvas",this.offCanvasElement,this),h.initialized(this.offCanvasElement)}findOffCanvasElements(e,s,n,a){return s?c(`${e}`,a):c(`${e}[data-target=${n}]`)}setupAttributes(){this.offCanvasElement.hasAttribute("data-fx-offcanvas")||this.offCanvasElement.setAttribute("data-fx-offcanvas","")}openOffCanvas(){var n,a,l,r;(a=(n=this.options).beforeShow)==null||a.call(n),L(this.offCanvasElement),C(this.offCanvasElement,this.allowBodyScroll,"open");const e=this.offCanvasElement.getAttribute("id"),s=B(this.backdrop,e);s instanceof HTMLElement&&(g({newElement:s,existingElement:this.offCanvasElement}),this.staticBackdrop||s.addEventListener("click",this.closeOffCanvas)),document.addEventListener("keydown",this.closeWithEsc),(r=(l=this.options).onShow)==null||r.call(l),p(this.offCanvasElement,"offcanvas-open",{offcanvasId:this.offCanvasElement.id})}initCloseBtns(){for(const e of this.offCanvasCloseBtns)e.addEventListener("click",this.closeOffCanvas)}initTriggers(){for(const e of this.offCanvasTriggers)e.addEventListener("click",this.changeState)}setupOffcanvas(){this.initTriggers(),this.initCloseBtns()}open(){this.openOffCanvas()}close(){this.closeOffCanvas()}cleanup(){for(const e of this.offCanvasTriggers)e.removeEventListener("click",this.changeState);for(const e of this.offCanvasCloseBtns)e.removeEventListener("click",this.closeOffCanvas);document.removeEventListener("keydown",this.closeWithEsc),this.allowBodyScroll||document.removeEventListener("click",this.closeWhenClickOutSide),h.removeInstance("offcanvas",this.offCanvasElement)}};o(v,"autoInit",(e="[data-fx-offcanvas]")=>{const s=c(e);for(const n of s)new v(n)}),o(v,"init",(e,s={})=>new v(e,s));let u=v;f.OffCanvas=u,Object.defineProperty(f,Symbol.toStringTag,{value:"Module"})});