UNPKG

ranui

Version:

A framework-agnostic Web Components UI library built on native custom elements, with TypeScript types, light/dark theming, SSR and PWA support.

131 lines (130 loc) 4.88 kB
import { alignCrossAxis as A, computePlacement as I } from "ranuts/utils"; var F = { bottom: { enter: "ran-dropdown-down-in", exit: "ran-dropdown-down-out" }, top: { enter: "ran-dropdown-up-in", exit: "ran-dropdown-up-out" }, left: { enter: "ran-dropdown-left-in", exit: "ran-dropdown-left-out" }, right: { enter: "ran-dropdown-right-in", exit: "ran-dropdown-right-out" } }, L = (t) => t.getAnimationTarget?.() ?? t, R = (t, i) => { const e = L(t); if (typeof e.getAnimations != "function" || typeof requestAnimationFrame != "function") { i(); return; } requestAnimationFrame(() => { const r = e.getAnimations(); if (!r.length) { i(); return; } (async () => (await Promise.allSettled(r.map((d) => d.finished)), i()))(); }); }, N = class { options; repositionBound = !1; opened = !1; repositionFrame = 0; generation = 0; constructor(t) { this.options = t; } get anchor() { return this.options.anchor?.() ?? this.options.host; } apply = (t) => { const { host: i } = this.options; i.setAttribute("aria-expanded", t ? "true" : "false"); const e = this.options.panel(); if (!e || t === this.opened) return; this.opened = t; const r = ++this.generation; if (t) { i.dispatchEvent(new CustomEvent("show")), e.style.setProperty("display", "block"), this.attachReposition(), this.position(!0), R(e, () => { r === this.generation && (e.removeAttribute("transit"), i.dispatchEvent(new CustomEvent("after-show"))); }); return; } this.detachReposition(), i.dispatchEvent(new CustomEvent("hide")), e.setAttribute("transit", F[this.side()].exit), R(e, () => { r === this.generation && (e.style.setProperty("display", "none"), e.removeAttribute("transit"), i.dispatchEvent(new CustomEvent("after-hide"))); }); }; side = () => this.options.placement().split("-")[0]; position = (t = !1) => { if (!this.options.panel()) return; const i = () => { const e = this.options.panel(); e && this.write(e, t); }; t && typeof requestAnimationFrame == "function" ? requestAnimationFrame(i) : i(); }; write(t, i) { const { offset: e = 0, containerId: r, beforeMeasure: d, measurePanel: x, adjust: E, afterPosition: b } = this.options, o = this.anchor.getBoundingClientRect(); d?.(o, t); const B = this.options.host.getRootNode(), c = r?.() ?? "", l = c ? B.getElementById?.(c) ?? document.getElementById(c) : null, u = t.getBoundingClientRect(), y = x?.(t), P = u, f = y?.width ?? u.width, m = y?.height ?? u.height, v = this.options.placement(), [q, C] = v.split("-"), w = C ?? "start"; let p, h, a = q; if (l) { const n = l.getBoundingClientRect(); a === "top" || a === "bottom" ? (p = a === "bottom" ? o.bottom - n.top + e : o.top - n.top - m - e, h = A(w, o.left, o.width, f) - n.left) : (p = A(w, o.top, o.height, m) - n.top, h = a === "right" ? o.right - n.left + e : o.left - n.left - f - e); } else { const n = I({ anchor: { top: o.top, left: o.left, width: o.width, height: o.height }, floating: { width: f, height: m }, placement: v, offset: e }); a = n.side, p = n.top + window.scrollY, h = n.left + window.scrollX; } const s = { top: p, left: h, side: a, align: w, anchorRect: o, panelRect: P, container: l }, g = E?.(s, t); g && (s.top = g.top, s.left = g.left), t.style.setProperty("position", "absolute"), t.style.setProperty("inset", `${s.top}px auto auto ${s.left}px`), t.style.setProperty("--ran-x", `${s.left}px`), t.style.setProperty("--ran-y", `${s.top}px`), i && t.setAttribute("transit", F[s.side].enter), b?.(s, t); } reposition = () => { if (!(!this.opened || this.repositionFrame)) { if (typeof requestAnimationFrame != "function") { this.position(); return; } this.repositionFrame = requestAnimationFrame(() => { this.repositionFrame = 0, this.opened && this.position(); }); } }; attachReposition() { this.repositionBound || typeof window > "u" || (window.addEventListener("scroll", this.reposition, !0), window.addEventListener("resize", this.reposition), this.repositionBound = !0); } detachReposition() { !this.repositionBound || typeof window > "u" || (window.removeEventListener("scroll", this.reposition, !0), window.removeEventListener("resize", this.reposition), this.repositionBound = !1); } destroy = () => { this.generation++, this.opened = !1, this.repositionFrame && typeof cancelAnimationFrame == "function" && (cancelAnimationFrame(this.repositionFrame), this.repositionFrame = 0), this.detachReposition(); }; }; export { N as t };