UNPKG

@flexilla/popover

Version:

A lightweight and customizable Popover component for displaying additional information on hover over elements in web applications.

2 lines (1 loc) 17 kB
(function(m,d){typeof exports=="object"&&typeof module<"u"?d(exports):typeof define=="function"&&define.amd?define(["exports"],d):(m=typeof globalThis<"u"?globalThis:m||self,d(m["@flexilla/popover"]={}))})(this,function(m){"use strict";var me=Object.defineProperty;var fe=(m,d,u)=>d in m?me(m,d,{enumerable:!0,configurable:!0,writable:!0,value:u}):m[d]=u;var a=(m,d,u)=>fe(m,typeof d!="symbol"?d+"":d,u);var d=Object.defineProperty,u=(i,e,t)=>e in i?d(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t,p=(i,e,t)=>u(i,typeof e!="symbol"?e+"":e,t);const q="bottom",G=({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}},U=(i,e,t,n)=>{const o=t,s=n-(t+e);return o>=(i-e)/2&&s>=(i-e)/2},K=(i,e,t,n)=>(i-e)/2<=t&&t+i/2+e/2<=n,V=(i,e,t,n,o)=>t>o-n?e()?window.innerHeight-o:t-o:i()?0:t+n,X=(i,e,t,n)=>i<=n&&t-i<=e,Y=(i,e,t,n)=>t<=n&&-i<=e,J=(i,e,t,n,o,s)=>{const r=o-t-s,h=t-n,f=t+s-n+(o-t-s),c=r>=0?o-n:h>=0?t-n:t;return i()?0:e()?f:c},Q=(i,e,t,n)=>i<=t&&e-i-n>=i,Z=(i,e)=>i>=e,_=({placement:i,refWidth:e,refTop:t,refLeft:n,refHeight:o,popperWidth:s,popperHeight:r,windowHeight:h,windowWidth:f,offsetDistance:c})=>{const g=f-n-e,y=n,k=h-t-o,H=t,S=()=>V(()=>Y(t,o,r,h),()=>X(t,o,r,h),t,o,r),O=()=>J(()=>Q(n,f,s,e),()=>Z(n,s),n,s,f,e),P=()=>U(s,e,n,f)?n+e/2-s/2:O(),W=()=>K(r,o,t,h)?t+o/2-r/2:S(),F=()=>n+s<=f?n:O(),I=()=>n+e-s>=0?n+e-s:O(),x=()=>t+r<=h?t:S(),de=()=>t+o-r>=0?t+o-r:S();let v=0,E=0;const R=t-r-c,C=t+o+c,D=n-s-c,M=n+e+c,A=H>=r+c,z=k>=r+c,j=y>=s+c,B=g>=s+c;switch(i.startsWith("top")?E=A?R:z?C:Math.max(R,C):i.startsWith("bottom")?E=z?C:A?R:Math.max(C):i.startsWith("left")?v=j?D:B?M:Math.max(D,M):i.startsWith("right")&&(v=B?M:j?D:Math.max(M,D)),i){case"bottom":case"bottom-middle":case"top":case"top-middle":v=P();break;case"left":case"left-middle":case"right":case"right-middle":E=W();break;case"bottom-start":case"top-start":v=F();break;case"bottom-end":case"top-end":v=I();break;case"left-start":case"right-start":E=x();break;case"left-end":case"right-end":E=de();break}return{x:v,y:E}};class ee{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",(g,y)=>{this.popper.style.setProperty("--fx-popper-placement-x",`${g}px`),this.popper.style.setProperty("--fx-popper-placement-y",`${y}px`)}),p(this,"setInitialStyles",()=>{this.popper.style.setProperty("--fx-popper-placement-x",""),this.popper.style.setProperty("--fx-popper-placement-y","")}),p(this,"initPlacement",()=>{var g;this.validateElements(),this.setInitialStyles();const y=window.innerWidth,k=window.innerHeight,{popperHeight:H,popperWidth:S,refHeight:O,refWidth:P,refLeft:W,refTop:F}=G({reference:this.reference,popper:this.popper}),{x:I,y:x}=_({placement:this.placement,refWidth:P,refTop:F,refLeft:W,popperWidth:S,refHeight:O,popperHeight:H,windowHeight:k,windowWidth:y,offsetDistance:this.offsetDistance});this.setPopperStyleProperty(I,x),(g=this.onUpdate)==null||g.call(this,{x:I,y:x,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=q,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:f,disableOnScroll:c}=r;this.isWindowEventsRegistered=!1,this.reference=e,this.popper=t,this.offsetDistance=o,this.placement=s,this.disableOnResize=f||!1,this.disableOnScroll=c||!1,this.onUpdate=h}setOptions({placement:e,offsetDistance:t}){this.placement=e,this.offsetDistance=t||this.offsetDistance,this.initPlacement(),this.attachWindowEvent()}}var te=Object.defineProperty,ne=(i,e,t)=>e in i?te(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t,l=(i,e,t)=>ne(i,typeof e!="symbol"?e+"":e,t);const ie=(i,e=document.body)=>e.querySelector(i),$=(i,e)=>{for(const[t,n]of Object.entries(e))i.setAttribute(t,n)},se=({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()},oe=({element:i,callback:e})=>{se({element:i,callback:e,type:"transition",keysCheck:["all 0s ease 0s","all"]})},re=(i,e,t)=>{const n=new CustomEvent(e,{detail:t});i.dispatchEvent(n)},w=({state:i,trigger:e,popper:t})=>{const n=i==="open";$(t,{"data-state":i}),$(e,{"aria-expanded":`${n}`})};class ae{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"?ie(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,f,c,g;this.popper.setOptions({placement:s,offsetDistance:r}),document.addEventListener("keydown",this.handleKeyDown),document.addEventListener("click",this.handleDocumentClick),(f=(h=this.options).beforeShow)==null||f.call(h),w({state:"open",popper:this.contentElement,trigger:this.triggerElement}),this.onToggleState(!1),(g=(c=this.options).onShow)==null||g.call(c)}),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 ee(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),w({state:"open",popper:this.contentElement,trigger:this.triggerElement}),this.onToggleState(!1),(o=(n=this.options).onShow)==null||o.call(n)}hide(){var e,t,n;let o=!1;re(this.contentElement,"before-hide",{setExitAction:r=>{o=r}});const s=(n=(t=(e=this.options).beforeHide)==null?void 0:t.call(e))==null?void 0:n.cancelAction;o||s||(w({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)),oe({element:this.contentElement,callback:()=>{var r,h;this.onToggleState(!0),this.popper.cleanupEvents(),(h=(r=this.options).onHide)==null||h.call(r)}}))}initInstance(){w({state:this.defaultState,popper:this.contentElement,trigger:this.triggerElement}),this.defaultState==="open"?this.show():w({state:"close",popper:this.contentElement,trigger:this.triggerElement}),this.triggerElement.addEventListener("click",this.toggleStateOnClick),this.triggerStrategy==="hover"&&this.triggerElement.addEventListener("mouseenter",this.showOnMouseEnter)}}const N=(i,e=document.body)=>e.querySelector(i),le=(i,e=document.body)=>Array.from(e.querySelectorAll(i)),T=(i,e,t)=>{const n=new CustomEvent(e,{detail:t});i.dispatchEvent(n)};function he(i){const e=()=>{document.querySelector("[data-fx-component]:not([data-component-initialized])")?requestAnimationFrame(e):i()};e()}function pe(i,e,t="move"){if(!(i 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(t))throw new Error(`Invalid teleport mode: ${t}. Must be "move" or "detachable".`);let n=document.createComment("teleporter-placeholder");const o=i.parentNode;return o?o.insertBefore(n,i):console.warn("Element has no parent; placeholder not inserted."),t==="move"?(i.parentNode&&e.appendChild(i),{append(){i.parentNode!==e&&e.appendChild(i)},remove(){n!=null&&n.parentNode&&i.parentNode&&n.parentNode.insertBefore(i,n)},restore(){n!=null&&n.parentNode&&i.parentNode!==o&&n.parentNode.insertBefore(i,n)}}):(i.parentNode&&e.appendChild(i),{append(){e.contains(i)||e.appendChild(i)},remove(){i.parentNode&&i.remove()},restore(){n!=null&&n.parentNode&&!i.parentNode&&n.parentNode.insertBefore(i,n)}})}class b{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))}static setup(e){e.setAttribute("data-fx-component","fx")}static initialized(e){e.setAttribute("data-component-initialized","initialized")}}const ce={teleport:!0,teleportMode:"move"};class L{constructor(e,t={}){a(this,"triggerElement");a(this,"contentElement");a(this,"options");a(this,"PopoverInstance");a(this,"triggerStrategy");a(this,"placement");a(this,"offsetDistance");a(this,"preventFromCloseOutside");a(this,"preventFromCloseInside");a(this,"defaultState");a(this,"experimentalOptions");a(this,"teleporter");a(this,"moveElOnInit",()=>{this.experimentalOptions.teleport&&he(()=>{this.experimentalOptions.teleportMode==="detachable"?this.teleporter.remove():this.teleporter.append()})});a(this,"moveEl",()=>{this.experimentalOptions.teleport&&this.experimentalOptions.teleportMode==="detachable"&&this.teleporter.remove()});a(this,"restoreEl",()=>{this.experimentalOptions.teleport&&this.experimentalOptions.teleportMode==="detachable"&&this.teleporter.append()});a(this,"beforeShow",()=>{this.restoreEl()});a(this,"onHide",()=>{var e,t;(t=(e=this.options).onHide)==null||t.call(e),this.moveEl(),T(this.contentElement,"popover-hide",{isHidden:!0})});a(this,"onShow",()=>{var e,t;(t=(e=this.options).onShow)==null||t.call(e),T(this.contentElement,"popover-show",{isHidden:!1})});a(this,"setShowOptions",({placement:e,offsetDistance:t})=>{this.PopoverInstance.setShowOptions({placement:e,offsetDistance:t})});a(this,"setOptions",({placement:e,offsetDistance:t})=>{this.PopoverInstance.setPopperOptions({placement:e,offsetDistance:t})});a(this,"setPopperTrigger",(e,t)=>{this.PopoverInstance.setPopperTrigger(e,t)});a(this,"show",()=>{this.PopoverInstance.show()});a(this,"hide",()=>{this.PopoverInstance.hide()});a(this,"cleanup",()=>{this.PopoverInstance.cleanup(),b.removeInstance("popover",this.contentElement)});const n=typeof e=="string"?N(e):e;this.contentElement=n;const o=b.getInstance("popover",this.contentElement);if(o)return o;b.setup(this.contentElement),this.triggerElement=N(`[data-popover-trigger][data-popover-id=${n.getAttribute("id")}]`),this.options=t,this.triggerStrategy=n.dataset.triggerStrategy??this.options.triggerStrategy??"click",this.placement=n.dataset.placement??this.options.placement??"bottom-middle",this.offsetDistance=parseInt(`${n.dataset.offsetDistance}`)??this.options.offsetDistance??6,this.preventFromCloseOutside=n.hasAttribute("data-prevent-close-outside")??this.options.preventFromCloseOutside??!1,this.preventFromCloseInside=n.hasAttribute("data-close-inside")?!1:this.options.preventCloseFromInside??!0,this.defaultState=n.dataset.defaultState??this.options.defaultState??"close",this.experimentalOptions=Object.assign({},ce,t.experimental),this.teleporter=pe(this.contentElement,document.body,this.experimentalOptions.teleportMode),this.PopoverInstance=new ae({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,onShow:this.onShow,onHide:this.onHide,onToggle:({isHidden:s})=>{var r,h;(h=(r=this.options).onToggle)==null||h.call(r,{isHidden:s}),T(this.contentElement,"popover-toggle",{isHidden:s})},popper:this.options.popper}}),this.moveElOnInit(),b.register("popover",this.contentElement,this),b.initialized(this.contentElement)}static init(e,t){return new L(e,t)}static autoInit(e="[data-fx-popover]"){const t=le(e);for(const n of t)new L(n)}}m.Popover=L,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})});