UNPKG

simple-details

Version:

simple animated details package

134 lines (133 loc) 5.98 kB
const r = class r { constructor(s) { this.options = { ...r.optionsDefault, ...s, selectors: { ...r.optionsDefault.selectors, ...s?.selectors, scrollbars: { ...r.optionsDefault.selectors.scrollbars, ...s?.selectors?.scrollbars } } }, this.selectors = this.options.selectors, this.elements = [], this.durationMin = this.options.durationMin, this.durationMax = this.options.durationMax, this.durationPerHeight = this.options.durationPerHeight, this.easing = this.options.easing, this.onClick = this.handleClick.bind(this), this.onResize = this.handleResize.bind(this); } init() { this.updateListeners(), this.updateElements(); } updateElements() { const { body: s } = document, e = Array.from(s.querySelectorAll(this.selectors.details)); e.length > 0 && (this.elements = this.updateElementsData(e), this.elements.forEach((i) => { i.details.classList.add(`sd_${this.options.theme.replace(" ", "_")}`); })); } openAll() { this.elements.forEach((s) => { s.parameters.isOpen = s.details.classList.contains("open"), s.parameters.isOpen || this.expand(s); }); } collapseAll() { this.elements.forEach((s) => { s.parameters.isOpen = s.details.classList.contains("open"), s.parameters.isOpen && this.shrink(s); }); } calculateDuration(s, e) { let i = this.durationMin; const n = Math.abs(e - s); return i = i + n * this.durationPerHeight, i > this.durationMax && (i = this.durationMax), i = Math.round(i), i; } expand(s) { s.parameters.isOpening = !0, s.details.classList.add("is-opening"), s.content.classList.add("is-opening"); const e = s.details.offsetHeight + "px", i = s.summary.offsetHeight + s.content.offsetHeight + "px"; s.parameters.animation && s.parameters.animation.cancel(), s.parameters.animation = s.details.animate({ height: [e, i] }, { duration: this.calculateDuration(s.details.offsetHeight, s.summary.offsetHeight + s.content.offsetHeight), easing: this.easing }), s.parameters.animation.onfinish = () => this.onAnimationFinish(s, !0), s.parameters.animation.oncancel = () => s.parameters.isOpening = !1; } shouldDisable() { return window.matchMedia(`(min-width: ${this.options.disableAfter}px)`).matches; } disable() { if (this.shouldDisable()) { this.openAll(); return; } } handleClick(s) { const e = s.target; if ((e.closest(this.selectors.summary) || e.closest(this.selectors.button)) && !e.closest("a[href]")) { s.preventDefault(); const n = e.closest(this.selectors.summary), t = this.elements.find((o) => o.summary === n ? o : !1); t && (t.details.style.overflow = "hidden", t.parameters.isClosing || !t.parameters.isOpen ? this.open(t) : (t.parameters.isOpening || t.parameters.isOpen) && this.shrink(t)); } } handleResize() { this.updateClickListeners(); } hasVerticalScrollbar(s) { return s.scrollHeight > s.clientHeight; } onAnimationFinish(s, e) { s.details.open = e, s.parameters.isOpen = e, s.parameters.animation = null, s.parameters.isClosing = !1, s.parameters.isOpening = !1, s.details.style.height = s.details.style.overflow = "", this.setupScrollbarStyles(s.details), this.updateDetailsStyles(s.details, e), this.updateDetailsStyles(s.content, e), s.content.classList.remove("is-closing"), s.content.classList.remove("is-opening"), s.details.classList.remove("is-closing"), s.details.classList.remove("is-opening"); } open(s) { s.details.style.height = s.details.offsetHeight + "px", s.details.open = !0, window.requestAnimationFrame(() => this.expand(s)); } setupScrollbarStyles(s) { this.hasVerticalScrollbar(s) ? s.classList.add(this.selectors.scrollbars.vertical) : s.classList.remove(this.selectors.scrollbars.vertical); } shrink(s) { s.parameters.isClosing = !0, s.details.classList.add("is-closing"), s.content.classList.add("is-closing"); const e = s.details.offsetHeight + "px", i = s.summary.offsetHeight + "px"; s.parameters.animation && s.parameters.animation.cancel(), s.parameters.animation = s.details.animate({ height: [e, i] }, { duration: this.calculateDuration(s.details.offsetHeight, s.summary.offsetHeight), easing: this.easing }), s.parameters.animation.onfinish = () => this.onAnimationFinish(s, !1), s.parameters.animation.oncancel = () => s.parameters.isClosing = !1; } updateClickListeners() { this.options.disableAfter !== null ? (document.removeEventListener("click", this.onClick), this.shouldDisable() ? this.openAll() : document.addEventListener("click", this.onClick)) : (document.removeEventListener("click", this.onClick), document.addEventListener("click", this.onClick)); } updateDetailsStyles(s, e) { e ? s.classList.add("open") : s.classList.remove("open"); } updateElementsData(s) { return s.map((e) => { const i = e.classList.contains("open") || e.hasAttribute("open"), n = e.querySelector(this.selectors.content); return i && n.classList.add("open"), { details: e, summary: e.querySelector(this.selectors.summary), button: e.querySelector(this.selectors.button), content: n, parameters: { isOpen: i, isClosing: !1, isOpening: !1 } }; }); } updateListeners() { window.removeEventListener("resize", this.onResize), window.addEventListener("resize", this.onResize), this.updateClickListeners(); } }; r.optionsDefault = { preferButtonIfExist: !0, selectors: { details: ".SimpleDetails", summary: ".SimpleDetailsSummary", button: ".SimpleDetailsButton", content: ".SimpleDetailsBody", scrollbars: { vertical: "has-vertical-scrollbar" } }, disableAfter: null, durationMin: 333, durationMax: 1e3, durationPerHeight: 0.5, easing: "ease-in-out", theme: "default" }; let l = r; export { l as SimpleDetails };