UNPKG

flexipop

Version:
203 lines (202 loc) 9.19 kB
var g = Object.defineProperty; var m = (n, e, t) => e in n ? g(n, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[e] = t; var i = (n, e, t) => m(n, typeof e != "symbol" ? e + "" : e, t); import { CreatePopper as p } from "./flexipop.js"; const d = (n, e = document.body) => e.querySelector(n), c = (n, e) => { for (const [t, s] of Object.entries(e)) n.setAttribute(t, s); }, E = ({ element: n, callback: e, type: t, keysCheck: s }) => { const o = getComputedStyle(n), h = o.transition; if (h !== "none" && h !== "" && !s.includes(h)) { const r = "transitionend", a = () => { n.removeEventListener(r, a), e(); }; n.addEventListener(r, a, { once: !0 }); } else e(); }, f = ({ element: n, callback: e }) => { E({ element: n, callback: e, type: "transition", keysCheck: ["all 0s ease 0s", "all"] }); }, u = (n, e, t) => { const s = new CustomEvent(e, { detail: t }); n.dispatchEvent(s); }, l = ({ state: n, trigger: e, popper: t }) => { const s = n === "open"; c(t, { "data-state": n }), c(e, { "aria-expanded": `${s}` }); }; class S { /** * Creates an instance of CreateOverlay * @param {Object} params - The initialization parameters * @param {string | HTMLElement} params.trigger - The trigger element selector or HTMLElement * @param {string | HTMLElement} params.content - The content element selector or HTMLElement * @param {OverlayOptions} [params.options] - Configuration options for the overlay */ constructor({ trigger: e, content: t, options: s = {} }) { i(this, "triggerElement"); i(this, "contentElement"); i(this, "triggerStrategy"); i(this, "placement"); i(this, "offsetDistance"); i(this, "preventFromCloseOutside"); i(this, "preventFromCloseInside"); i(this, "options"); i(this, "defaultState"); i(this, "popper"); i(this, "eventEffect"); i(this, "getElement", (e) => typeof e == "string" ? d(e) : e instanceof HTMLElement ? e : void 0); i(this, "handleDocumentClick", (e) => { this.contentElement.getAttribute("data-state") === "open" && (!this.triggerElement.contains(e.target) && !this.preventFromCloseInside && !this.preventFromCloseOutside ? this.hide() : !this.triggerElement.contains(e.target) && !this.contentElement.contains(e.target) && !this.preventFromCloseOutside ? this.hide() : !this.triggerElement.contains(e.target) && !this.contentElement.contains(e.target) && !this.preventFromCloseOutside ? this.hide() : !this.triggerElement.contains(e.target) && this.contentElement.contains(e.target) && !this.preventFromCloseInside && this.hide()); }); i(this, "handleKeyDown", (e) => { e.preventDefault(), this.triggerStrategy !== "hover" && e.key === "Escape" && this.contentElement.getAttribute("data-state") === "open" && (this.preventFromCloseOutside || this.hide()); }); i(this, "toggleStateOnClick", () => { (this.contentElement.dataset.state || "close") === "close" ? (this.show(), this.triggerStrategy === "hover" && this.addEventOnMouseEnter()) : this.hide(); }); i(this, "hideOnMouseLeaseTrigger", () => { setTimeout(() => { this.contentElement.matches(":hover") || this.hide(); }, 150); }); i(this, "hideOnMouseLeave", () => { setTimeout(() => { this.triggerElement.matches(":hover") || this.hide(); }, 150); }); i(this, "addEventOnMouseEnter", () => { this.triggerElement.addEventListener("mouseleave", this.hideOnMouseLeaseTrigger), this.contentElement.addEventListener("mouseleave", this.hideOnMouseLeave); }); i(this, "showOnMouseEnter", () => { this.show(), this.addEventOnMouseEnter(); }); /** * Updates the overlay's show options and displays it * @param {Object} params - The show options * @param {Placement} params.placement - The new placement position * @param {number} [params.offsetDistance] - The new offset distance */ i(this, "setShowOptions", ({ placement: e, offsetDistance: t }) => { var s, o, h, r; this.popper.setOptions({ placement: e, offsetDistance: t }), document.addEventListener("keydown", this.handleKeyDown), document.addEventListener("click", this.handleDocumentClick), (o = (s = this.options).beforeShow) == null || o.call(s), l({ state: "open", popper: this.contentElement, trigger: this.triggerElement }), this.onToggleState(!1), (r = (h = this.options).onShow) == null || r.call(h); }); /** * Updates the popper's positioning options * @param {Object} params - The popper options * @param {Placement} params.placement - The new placement position * @param {number} [params.offsetDistance] - The new offset distance */ i(this, "setPopperOptions", ({ placement: e, offsetDistance: t }) => { this.popper.setOptions({ placement: e, offsetDistance: t || this.offsetDistance }); }); /** * Updates the popper's trigger reference Element and options * The new set trigger will be used as reference for the popper */ i(this, "setPopperTrigger", (e, t) => { this.cleanup(), this.popper.setOptions({ placement: t.placement || this.placement, offsetDistance: t.offsetDistance || this.offsetDistance }), this.triggerElement = e, this.triggerElement.addEventListener("click", this.toggleStateOnClick), this.triggerStrategy === "hover" && this.triggerElement.addEventListener("mouseenter", this.showOnMouseEnter); }); /** * Cleans up event listeners and related callbacks */ i(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 = s, 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 p( this.triggerElement, this.contentElement, { placement: this.placement, offsetDistance: this.offsetDistance, eventEffect: this.eventEffect } ), this.initInstance(); } onToggleState(e) { var t, s; (s = (t = this.options).onToggle) == null || s.call(t, { isHidden: e }); } /** * Shows the overlay * Positions the overlay, adds event listeners, and triggers related callbacks */ show() { var e, t, s, o; this.popper.updatePosition(), document.addEventListener("keydown", this.handleKeyDown), document.addEventListener("click", this.handleDocumentClick), (t = (e = this.options).beforeShow) == null || t.call(e), l({ state: "open", popper: this.contentElement, trigger: this.triggerElement }), this.onToggleState(!1), (o = (s = this.options).onShow) == null || o.call(s); } /** * Hides the overlay * Removes event listeners and triggers related callbacks */ hide() { var s, o, h; let e = !1; u(this.contentElement, "before-hide", { setExitAction: (r) => { e = r; } }); const t = (h = (o = (s = this.options).beforeHide) == null ? void 0 : o.call(s)) == null ? void 0 : h.cancelAction; e || t || (l({ 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)), f({ element: this.contentElement, callback: () => { var r, a; this.onToggleState(!0), this.popper.cleanupEvents(), (a = (r = this.options).onHide) == null || a.call(r); } })); } initInstance() { l({ state: this.defaultState, popper: this.contentElement, trigger: this.triggerElement }), this.defaultState === "open" ? this.show() : l({ state: "close", popper: this.contentElement, trigger: this.triggerElement }), this.triggerElement.addEventListener("click", this.toggleStateOnClick), this.triggerStrategy === "hover" && this.triggerElement.addEventListener("mouseenter", this.showOnMouseEnter); } } export { S as CreateOverlay };