UNPKG

@flexilla/collapse

Version:

A versatile and interactive collapse component for creating collapsible sections in web applications, conserving space and improving user experience.

209 lines (208 loc) 7.99 kB
var u = Object.defineProperty; var m = (t, e, s) => e in t ? u(t, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : t[e] = s; var n = (t, e, s) => m(t, typeof e != "symbol" ? e + "" : e, s); const c = (t, e = document.body) => e.querySelector(t), x = (t, e = document.body) => Array.from(e.querySelectorAll(t)), w = ({ element: t, callback: e, type: s, keysCheck: i }) => { const l = getComputedStyle(t), a = l.transition; if (a !== "none" && a !== "" && !i.includes(a)) { const g = "transitionend", p = () => { t.removeEventListener(g, p), e(); }; t.addEventListener(g, p, { once: !0 }); } else e(); }, E = ({ element: t, callback: e }) => { w({ element: t, callback: e, type: "transition", keysCheck: ["all 0s ease 0s", "all"] }); }, r = (t, e, s) => { const i = new CustomEvent(e, { detail: s }); t.dispatchEvent(i); }, d = (t, e) => { t.setAttribute("aria-hidden", e === "open" ? "false" : "true"), t.setAttribute("data-state", e); }, b = (t, e = "close", s = "0px") => { t.style.height = e === "open" ? "auto" : s, d(t, e); }, y = (t) => { if (t.getAttribute("data-state") === "open") return; d(t, "open"); const e = t.scrollHeight; t.style.height = `${e}px`, E({ element: t, callback: () => { t.getAttribute("data-state") === "open" && (t.style.height = "auto"); } }); }, I = (t, e = "0px") => { t.getAttribute("data-state") !== "close" && (t.style.height = `${t.scrollHeight}px`, t.offsetHeight, t.style.height = e, d(t, "close")); }; class h { static initGlobalRegistry() { window.$flexillaInstances || (window.$flexillaInstances = {}); } static register(e, s, i) { return this.initGlobalRegistry(), window.$flexillaInstances[e] || (window.$flexillaInstances[e] = []), this.getInstance(e, s) || (window.$flexillaInstances[e].push({ element: s, instance: i }), i); } static getInstance(e, s) { var i, l; return this.initGlobalRegistry(), (l = (i = window.$flexillaInstances[e]) == null ? void 0 : i.find( (a) => a.element === s )) == null ? void 0 : l.instance; } static removeInstance(e, s) { this.initGlobalRegistry(), window.$flexillaInstances[e] && (window.$flexillaInstances[e] = window.$flexillaInstances[e].filter( (i) => i.element !== s )); } static setup(e) { e.setAttribute("data-fx-component", "fx"); } static initialized(e) { e.setAttribute("data-component-initialized", "initialized"); } } const o = class o { /** * Creates a new Collapse instance. * @param selector - The CSS selector string or HTMLElement to be collapsed/expanded * @param options - Configuration options for the collapse behavior * @param triggerSelector - Optional CSS selector for the trigger element. If not provided, * it will look for an element with data-collapse-trigger attribute * @throws {Error} When the provided element is not a valid HTMLElement */ constructor(e, s = {}, i) { n(this, "element"); n(this, "defaultState"); n(this, "collapseId"); n(this, "collapseTrigger"); n(this, "options"); n(this, "closeHeight"); /** * Expands the collapse element to show its content. * Triggers 'beforeshow' and 'aftershow' events, and calls the onToggle callback if provided. * * @example * ```ts * const collapse = new Collapse('#myCollapse'); * collapse.show(); * ``` */ n(this, "show", () => { var e, s; r(this.element, "before-expand", { isExpanded: !1 }), this.collapseTrigger && (this.collapseTrigger.ariaExpanded = "true"), y(this.element), (s = (e = this.options).onToggle) == null || s.call(e, { isExpanded: !0 }), r(this.element, "expanded", { isExpanded: !1 }); }); /** * Collapses the element to hide its content. * Triggers 'beforehide' and 'afterhide' events, and calls the onToggle callback if provided. * * @example * ```ts * const collapse = new Collapse('#myCollapse'); * collapse.hide(); * ``` */ n(this, "hide", () => { var e, s; this.collapseTrigger && (this.collapseTrigger.ariaExpanded = "false"), I(this.element, `${this.closeHeight}px`), (s = (e = this.options).onToggle) == null || s.call(e, { isExpanded: !1 }), r(this.element, "collapsed", { isExpanded: !1 }); }); /** * Toggles the collapse element between expanded and collapsed states. * Triggers 'beforetoggle' and 'aftertoggle' events, and calls the onToggle callback if provided. * * @example * ```ts * const collapse = new Collapse('#myCollapse'); * collapse.toggle(); * ``` */ n(this, "toggle", () => { var s, i; const e = this.element.dataset.state === "open"; e ? this.hide() : this.show(), (i = (s = this.options).onToggle) == null || i.call(s, { isExpanded: !e }); }); n(this, "setCloseHeight", (e) => { this.closeHeight = e; }); let l; if (l = typeof e == "string" ? c(`${e}`) : e, typeof e == "string" && !l) throw new Error(`No element found matching selector: ${e}`); if (!(l instanceof HTMLElement)) throw new Error("Provided element must be a valid HTMLElement or selector"); this.element = l; const a = h.getInstance("collapse", this.element); if (a) return a; this.collapseId = this.element.getAttribute("id"), this.collapseTrigger = c(`${i}`) || c(`[data-collapse-trigger][data-target*='${this.collapseId}']`), this.options = s, this.defaultState = this.element.dataset.state ? this.element.dataset.state === "open" ? "open" : "close" : this.options.defaultState || "close", this.closeHeight = this.element.dataset.closeHeight ? parseInt(this.element.dataset.closeHeight || "0") : this.options.closeHeight || 0, this.initCollapse(), h.register("collapse", this.element, this); } initCollapse() { this.collapseTrigger instanceof HTMLElement && (this.collapseTrigger.addEventListener("click", this.toggle), this.collapseTrigger.ariaExpanded = this.defaultState === "open" ? "true" : "false"), b(this.element, this.defaultState, `${this.closeHeight}px`); } /** * Cleans up the Collapse instance by removing event listeners. * This method should be called when the collapse component is no longer needed * to prevent memory leaks. * * @example * ```ts * const collapse = new Collapse('#myCollapse'); * // When done with the collapse component * collapse.cleanup(); * ``` */ cleanup() { this.collapseTrigger instanceof HTMLElement && this.collapseTrigger.removeEventListener("click", this.toggle), h.removeInstance("collapse", this.element); } }; /** * Initializes a new Collapse instance with the specified configuration. * * @param selector - The CSS selector string or HTMLElement to be collapsed/expanded * @param options - Configuration options for the collapse behavior * @param triggerSelector - Optional CSS selector for the trigger element * @returns A new Collapse instance * * @example * ```ts * const collapse = Collapse.init('#myCollapse', { * defaultState: 'open', * onToggle: ({ isExpanded }) => console.log(isExpanded) * }); * ``` */ n(o, "init", (e, s = {}, i) => new o(e, s, i)), /** * Automatically initializes all collapse components in the document that match the provided selector. * This is useful for setting up multiple collapse elements at once without manual initialization. * * @param selector - CSS selector to identify collapse elements. Defaults to '[data-fx-collapse]' * * @example * ```ts * // Initialize all elements with data-fx-collapse attribute * Collapse.autoInit(); * * // Initialize elements with custom selector * Collapse.autoInit('.custom-collapse'); * ``` */ n(o, "autoInit", (e = "[data-fx-collapse]") => { const s = x(e); for (const i of s) new o(i); }); let f = o; export { f as Collapse };