UNPKG

@flexilla/dropdown

Version:

Utilities package for flexilla library

2 lines (1 loc) 16.6 kB
(function(f,m){typeof exports=="object"&&typeof module<"u"?m(exports):typeof define=="function"&&define.amd?define(["exports"],m):(f=typeof globalThis<"u"?globalThis:f||self,m(f["@flexilla/dropdown"]={}))})(this,function(f){"use strict";var pe=Object.defineProperty;var ge=(f,m,v)=>m in f?pe(f,m,{enumerable:!0,configurable:!0,writable:!0,value:v}):f[m]=v;var a=(f,m,v)=>ge(f,typeof m!="symbol"?m+"":m,v);var m=Object.defineProperty,v=(i,e,t)=>e in i?m(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t,p=(i,e,t)=>v(i,typeof e!="symbol"?e+"":e,t);const B="bottom",N=({reference:i,popper:e})=>{if(!i||!e)throw new Error("Reference or popper element is null or undefined");const t=new WeakMap,n=r=>(t.has(r)||t.set(r,r.getBoundingClientRect()),t.get(r)),o=n(e),s=n(i);return{popperHeight:o.height,popperWidth:o.width,refHeight:s.height,refWidth:s.width,refLeft:s.left,refTop:s.top,refRight:s.right}},V=(i,e,t,n)=>{const o=t,s=n-(t+e);return o>=(i-e)/2&&s>=(i-e)/2},X=(i,e,t,n)=>(i-e)/2<=t&&t+i/2+e/2<=n,Y=(i,e,t,n,o)=>t>o-n?e()?window.innerHeight-o:t-o:i()?0:t+n,J=(i,e,t,n)=>i<=n&&t-i<=e,Q=(i,e,t,n)=>t<=n&&-i<=e,Z=(i,e,t,n,o,s)=>{const r=o-t-s,h=t-n,g=t+s-n+(o-t-s),d=r>=0?o-n:h>=0?t-n:t;return i()?0:e()?g:d},_=(i,e,t,n)=>i<=t&&e-i-n>=i,ee=(i,e)=>i>=e,te=({placement:i,refWidth:e,refTop:t,refLeft:n,refHeight:o,popperWidth:s,popperHeight:r,windowHeight:h,windowWidth:g,offsetDistance:d})=>{const c=g-n-e,E=n,O=h-t-o,u=t,L=()=>Y(()=>Q(t,o,r,h),()=>J(t,o,r,h),t,o,r),D=()=>Z(()=>_(n,g,s,e),()=>ee(n,s),n,s,g,e),W=()=>V(s,e,n,g)?n+e/2-s/2:D(),F=()=>X(r,o,t,h)?t+o/2-r/2:L(),R=()=>n+s<=g?n:D(),k=()=>n+e-s>=0?n+e-s:D(),I=()=>t+r<=h?t:L(),de=()=>t+o-r>=0?t+o-r:L();let w=0,y=0;const $=t-r-d,T=t+o+d,H=n-s-d,C=n+e+d,U=u>=r+d,j=O>=r+d,G=E>=s+d,q=c>=s+d;switch(i.startsWith("top")?y=U?$:j?T:Math.max($,T):i.startsWith("bottom")?y=j?T:U?$:Math.max(T):i.startsWith("left")?w=G?H:q?C:Math.max(H,C):i.startsWith("right")&&(w=q?C:G?H:Math.max(C,H)),i){case"bottom":case"bottom-middle":case"top":case"top-middle":w=W();break;case"left":case"left-middle":case"right":case"right-middle":y=F();break;case"bottom-start":case"top-start":w=R();break;case"bottom-end":case"top-end":w=k();break;case"left-start":case"right-start":y=I();break;case"left-end":case"right-end":y=de();break}return{x:w,y}};class ne{constructor(e,t,n={}){p(this,"reference"),p(this,"popper"),p(this,"offsetDistance"),p(this,"placement"),p(this,"disableOnResize"),p(this,"disableOnScroll"),p(this,"onUpdate"),p(this,"isWindowEventsRegistered"),p(this,"validateElements",()=>{if(!(this.reference instanceof HTMLElement))throw new Error("Invalid HTMLElement for Reference Element");if(!(this.popper instanceof HTMLElement))throw new Error("Invalid HTMLElement for Popper");if(typeof this.offsetDistance!="number")throw new Error("OffsetDistance must be a number")}),p(this,"setPopperStyleProperty",(c,E)=>{this.popper.style.setProperty("--fx-popper-placement-x",`${c}px`),this.popper.style.setProperty("--fx-popper-placement-y",`${E}px`)}),p(this,"setInitialStyles",()=>{this.popper.style.setProperty("--fx-popper-placement-x",""),this.popper.style.setProperty("--fx-popper-placement-y","")}),p(this,"initPlacement",()=>{var c;this.validateElements(),this.setInitialStyles();const E=window.innerWidth,O=window.innerHeight,{popperHeight:u,popperWidth:L,refHeight:D,refWidth:W,refLeft:F,refTop:R}=N({reference:this.reference,popper:this.popper}),{x:k,y:I}=te({placement:this.placement,refWidth:W,refTop:R,refLeft:F,popperWidth:L,refHeight:D,popperHeight:u,windowHeight:O,windowWidth:E,offsetDistance:this.offsetDistance});this.setPopperStyleProperty(k,I),(c=this.onUpdate)==null||c.call(this,{x:k,y:I,placement:this.placement})}),p(this,"removeWindowEvents",()=>{this.isWindowEventsRegistered&&(!this.disableOnResize&&window.removeEventListener("resize",this.updatePosition),!this.disableOnScroll&&window.removeEventListener("scroll",this.updatePosition),this.isWindowEventsRegistered=!1)}),p(this,"attachWindowEvent",()=>{this.isWindowEventsRegistered&&this.removeWindowEvents(),this.disableOnResize||window.addEventListener("resize",this.updatePosition),this.disableOnScroll||window.addEventListener("scroll",this.updatePosition),this.isWindowEventsRegistered=!0}),p(this,"resetPosition",()=>{this.setInitialStyles()}),p(this,"updatePosition",()=>{this.initPlacement(),this.attachWindowEvent()}),p(this,"cleanupEvents",()=>{this.setInitialStyles(),this.removeWindowEvents()});const{offsetDistance:o=10,placement:s=B,eventEffect:r={},onUpdate:h}=n;if(!(e instanceof HTMLElement))throw new Error("Invalid HTMLElement for Reference Element");if(!(t instanceof HTMLElement))throw new Error("Invalid HTMLElement for Popper");if(n.offsetDistance&&typeof n.offsetDistance!="number")throw new Error("OffsetDistance must be a number");const{disableOnResize:g,disableOnScroll:d}=r;this.isWindowEventsRegistered=!1,this.reference=e,this.popper=t,this.offsetDistance=o,this.placement=s,this.disableOnResize=g||!1,this.disableOnScroll=d||!1,this.onUpdate=h}setOptions({placement:e,offsetDistance:t}){this.placement=e,this.offsetDistance=t||this.offsetDistance,this.initPlacement(),this.attachWindowEvent()}}var ie=Object.defineProperty,se=(i,e,t)=>e in i?ie(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t,l=(i,e,t)=>se(i,typeof e!="symbol"?e+"":e,t);const oe=(i,e=document.body)=>e.querySelector(i),A=(i,e)=>{for(const[t,n]of Object.entries(e))i.setAttribute(t,n)},re=({element:i,callback:e,type:t,keysCheck:n})=>{const o=getComputedStyle(i),s=o.transition;if(s!=="none"&&s!==""&&!n.includes(s)){const r="transitionend",h=()=>{i.removeEventListener(r,h),e()};i.addEventListener(r,h,{once:!0})}else e()},ae=({element:i,callback:e})=>{re({element:i,callback:e,type:"transition",keysCheck:["all 0s ease 0s","all"]})},b=({state:i,trigger:e,popper:t})=>{const n=i==="open";A(t,{"data-state":i}),A(e,{"aria-expanded":`${n}`})};class le{constructor({trigger:e,content:t,options:n={}}){l(this,"triggerElement"),l(this,"contentElement"),l(this,"triggerStrategy"),l(this,"placement"),l(this,"offsetDistance"),l(this,"preventFromCloseOutside"),l(this,"preventFromCloseInside"),l(this,"options"),l(this,"defaultState"),l(this,"popper"),l(this,"eventEffect"),l(this,"getElement",s=>typeof s=="string"?oe(s):s instanceof HTMLElement?s:void 0),l(this,"handleDocumentClick",s=>{this.contentElement.getAttribute("data-state")==="open"&&(!this.triggerElement.contains(s.target)&&!this.preventFromCloseInside&&!this.preventFromCloseOutside?this.hide():!this.triggerElement.contains(s.target)&&!this.contentElement.contains(s.target)&&!this.preventFromCloseOutside?this.hide():!this.triggerElement.contains(s.target)&&!this.contentElement.contains(s.target)&&!this.preventFromCloseOutside?this.hide():!this.triggerElement.contains(s.target)&&this.contentElement.contains(s.target)&&!this.preventFromCloseInside&&this.hide())}),l(this,"handleKeyDown",s=>{s.preventDefault(),this.triggerStrategy!=="hover"&&s.key==="Escape"&&this.contentElement.getAttribute("data-state")==="open"&&(this.preventFromCloseOutside||this.hide())}),l(this,"toggleStateOnClick",()=>{(this.contentElement.dataset.state||"close")==="close"?(this.show(),this.triggerStrategy==="hover"&&this.addEventOnMouseEnter()):this.hide()}),l(this,"hideOnMouseLeaseTrigger",()=>{setTimeout(()=>{this.contentElement.matches(":hover")||this.hide()},150)}),l(this,"hideOnMouseLeave",()=>{setTimeout(()=>{this.triggerElement.matches(":hover")||this.hide()},150)}),l(this,"addEventOnMouseEnter",()=>{this.triggerElement.addEventListener("mouseleave",this.hideOnMouseLeaseTrigger),this.contentElement.addEventListener("mouseleave",this.hideOnMouseLeave)}),l(this,"showOnMouseEnter",()=>{this.show(),this.addEventOnMouseEnter()}),l(this,"setShowOptions",({placement:s,offsetDistance:r})=>{var h,g,d,c;this.popper.setOptions({placement:s,offsetDistance:r}),document.addEventListener("keydown",this.handleKeyDown),document.addEventListener("click",this.handleDocumentClick),(g=(h=this.options).beforeShow)==null||g.call(h),b({state:"open",popper:this.contentElement,trigger:this.triggerElement}),this.onToggleState(!1),(c=(d=this.options).onShow)==null||c.call(d)}),l(this,"setPopperOptions",({placement:s,offsetDistance:r})=>{this.popper.setOptions({placement:s,offsetDistance:r||this.offsetDistance})}),l(this,"setPopperTrigger",(s,r)=>{this.cleanup(),this.popper.setOptions({placement:r.placement||this.placement,offsetDistance:r.offsetDistance||this.offsetDistance}),this.triggerElement=s,this.triggerElement.addEventListener("click",this.toggleStateOnClick),this.triggerStrategy==="hover"&&this.triggerElement.addEventListener("mouseenter",this.showOnMouseEnter)}),l(this,"cleanup",()=>{this.triggerElement.removeEventListener("click",this.toggleStateOnClick),this.triggerStrategy==="hover"&&this.triggerElement.removeEventListener("mouseenter",this.showOnMouseEnter)});var o;if(this.contentElement=this.getElement(t),this.triggerElement=this.getElement(e),!(this.triggerElement instanceof HTMLElement))throw new Error("Trigger element must be a valid HTML element");if(!(this.contentElement instanceof HTMLElement))throw new Error("Content element must be a valid HTML element");this.options=n,this.triggerStrategy=this.options.triggerStrategy||"click",this.placement=this.options.placement||"bottom",this.offsetDistance=this.options.offsetDistance||6,this.preventFromCloseOutside=this.options.preventFromCloseOutside||!1,this.preventFromCloseInside=this.options.preventCloseFromInside||!1,this.defaultState=this.options.defaultState||"close",this.eventEffect=(o=this.options.popper)==null?void 0:o.eventEffect,this.popper=new ne(this.triggerElement,this.contentElement,{placement:this.placement,offsetDistance:this.offsetDistance,eventEffect:this.eventEffect}),this.initInstance()}onToggleState(e){var t,n;(n=(t=this.options).onToggle)==null||n.call(t,{isHidden:e})}show(){var e,t,n,o;this.popper.updatePosition(),document.addEventListener("keydown",this.handleKeyDown),document.addEventListener("click",this.handleDocumentClick),(t=(e=this.options).beforeShow)==null||t.call(e),b({state:"open",popper:this.contentElement,trigger:this.triggerElement}),this.onToggleState(!1),(o=(n=this.options).onShow)==null||o.call(n)}hide(){var e,t;(t=(e=this.options).beforeHide)==null||t.call(e),b({state:"close",popper:this.contentElement,trigger:this.triggerElement}),this.triggerStrategy==="click"&&document.removeEventListener("click",this.handleDocumentClick),document.removeEventListener("keydown",this.handleKeyDown),this.triggerStrategy==="hover"&&(this.triggerElement.removeEventListener("mouseleave",this.hideOnMouseLeaseTrigger),this.contentElement.removeEventListener("mouseleave",this.hideOnMouseLeave)),ae({element:this.contentElement,callback:()=>{var n,o;this.onToggleState(!0),this.popper.cleanupEvents(),(o=(n=this.options).onHide)==null||o.call(n)}})}initInstance(){b({state:this.defaultState,popper:this.contentElement,trigger:this.triggerElement}),this.defaultState==="open"?this.show():b({state:"close",popper:this.contentElement,trigger:this.triggerElement}),this.triggerElement.addEventListener("click",this.toggleStateOnClick),this.triggerStrategy==="hover"&&this.triggerElement.addEventListener("mouseenter",this.showOnMouseEnter)}}const M=(i,e=document.body)=>e.querySelector(i),z=(i,e=document.body)=>Array.from(e.querySelectorAll(i)),he=i=>typeof i=="string"?M(i):i,ce=({containerElement:i,targetChildren:e="a:not([disabled]), button:not([disabled])",direction:t})=>{let n=!1;const o=he(i)||document.body,s=typeof e=="string"?z(e,o):e,r=h=>{if(h.preventDefault(),o.focus(),s.length===0)return;const g=h.key,d=document.activeElement;let c=s.findIndex(u=>u===d);if(c===-1){g==="ArrowUp"||g==="ArrowLeft"?s[s.length-1].focus():s[0].focus();return}const E=u=>u>0?u-1:s.length-1,O=u=>u<s.length-1?u+1:0;switch(g){case"ArrowDown":h.preventDefault(),c=O(c);break;case"ArrowRight":break;case"ArrowUp":h.preventDefault(),c=E(c);break;case"ArrowLeft":break;case"Home":h.preventDefault(),c=0;break;case"End":h.preventDefault(),c=s.length-1;break;default:return}s[c]!==d&&s[c].focus()};return{make:()=>{n||(document.addEventListener("keydown",r),n=!0)},destroy:()=>{n&&(document.removeEventListener("keydown",r),n=!1)}}},K=(i,e,t)=>{const n=new CustomEvent(e,{detail:t});i.dispatchEvent(n)};class x{static initGlobalRegistry(){window.$flexillaInstances||(window.$flexillaInstances={})}static register(e,t,n){return this.initGlobalRegistry(),window.$flexillaInstances[e]||(window.$flexillaInstances[e]=[]),this.getInstance(e,t)||(window.$flexillaInstances[e].push({element:t,instance:n}),n)}static getInstance(e,t){var n,o;return this.initGlobalRegistry(),(o=(n=window.$flexillaInstances[e])==null?void 0:n.find(s=>s.element===t))==null?void 0:o.instance}static removeInstance(e,t){this.initGlobalRegistry(),window.$flexillaInstances[e]&&(window.$flexillaInstances[e]=window.$flexillaInstances[e].filter(n=>n.element!==t))}}const S=class S{constructor(e,t={}){a(this,"triggerElement");a(this,"contentElement");a(this,"options");a(this,"OverlayInstance");a(this,"navigationKeys");a(this,"triggerStrategy");a(this,"placement");a(this,"offsetDistance");a(this,"preventFromCloseOutside");a(this,"preventFromCloseInside");a(this,"defaultState");a(this,"onToggle",({isHidden:e})=>{var t,n;(n=(t=this.options).onToggle)==null||n.call(t,{isHidden:e})});a(this,"beforeShow",()=>{this.contentElement.focus(),this.navigationKeys.make()});a(this,"beforeHide",()=>{this.contentElement.blur(),this.navigationKeys.destroy()});a(this,"onShow",()=>{var e,t;K(this.contentElement,"dropdown-show",{isHidden:!1}),(t=(e=this.options).onShow)==null||t.call(e)});a(this,"onHide",()=>{var e,t;K(this.contentElement,"dropdown-hide",{isHidden:!0}),(t=(e=this.options).onHide)==null||t.call(e)});a(this,"show",()=>{this.OverlayInstance.show()});a(this,"hide",()=>{this.OverlayInstance.hide()});a(this,"setShowOptions",({placement:e,offsetDistance:t})=>{this.OverlayInstance.setShowOptions({placement:e,offsetDistance:t})});a(this,"setOptions",({placement:e,offsetDistance:t})=>{this.OverlayInstance.setPopperOptions({placement:e,offsetDistance:t})});a(this,"setPopperTrigger",(e,t)=>{this.OverlayInstance.setPopperTrigger(e,t)});a(this,"cleanup",()=>{this.OverlayInstance.cleanup(),x.removeInstance("dropdown",this.contentElement)});const n=typeof e=="string"?M(e):e;if(!(n instanceof HTMLElement))throw new Error("Invalid dropdown content element: Must provide either a valid HTMLElement or a selector string that resolves to an existing HTMLElement");if(!n.id)throw new Error("Dropdown content element must have an 'id' attribute for trigger association");this.contentElement=n;const o=x.getInstance("dropdown",this.contentElement);if(o)return o;const s=`[data-dropdown-trigger][data-dropdown-id=${this.contentElement.id}]`;if(this.triggerElement=M(s),!(this.triggerElement instanceof HTMLElement))throw new Error(`No valid trigger element found. Ensure a trigger element exists with attributes: data-dropdown-trigger and data-dropdown-id="${this.contentElement.id}"`);this.options=t,this.triggerStrategy=this.options.triggerStrategy||this.contentElement.dataset.triggerStrategy||"click",this.placement=this.options.placement||this.contentElement.dataset.placement||"bottom-start",this.offsetDistance=this.options.offsetDistance||parseInt(`${this.contentElement.dataset.offsetDistance}`)|6,this.preventFromCloseOutside=this.options.preventFromCloseOutside||this.contentElement.hasAttribute("data-prevent-close-outside")||!1,this.preventFromCloseInside=this.options.preventCloseFromInside||this.contentElement.hasAttribute("data-prevent-close-inside")||!1,this.defaultState=this.options.defaultState||this.contentElement.dataset.defaultState||"close",this.OverlayInstance=new le({trigger:this.triggerElement,content:this.contentElement,options:{placement:this.placement,offsetDistance:this.offsetDistance,triggerStrategy:this.triggerStrategy,preventFromCloseOutside:this.preventFromCloseOutside,preventCloseFromInside:this.preventFromCloseInside,defaultState:this.defaultState,beforeShow:this.beforeShow,beforeHide:this.beforeHide,onShow:this.onShow,onHide:this.onHide,onToggle:({isHidden:r})=>{this.onToggle({isHidden:r})},popper:this.options.popper}}),this.navigationKeys=ce({containerElement:this.contentElement,targetChildren:"a:not([disabled]), button:not([disabled])",direction:"up-down"}),x.register("dropdown",this.contentElement,this)}static init(e,t={}){new S(e,t)}};a(S,"autoInit",(e="[data-fx-dropdown]")=>{const t=z(e);for(const n of t)new S(n)});let P=S;f.Dropdown=P,Object.defineProperty(f,Symbol.toStringTag,{value:"Module"})});