flexipop
Version:
203 lines (202 loc) • 9.19 kB
JavaScript
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
};