Spaces:
Running
on
Zero
Running
on
Zero
| // @ts-check | |
| import { prop } from "../../utils.js"; | |
| import { $el } from "../../ui.js"; | |
| import { applyClasses } from "../utils.js"; | |
| export class ComfyPopup extends EventTarget { | |
| element = $el("div.comfyui-popup"); | |
| /** | |
| * @param {{ | |
| * target: HTMLElement, | |
| * container?: HTMLElement, | |
| * classList?: import("../utils.js").ClassList, | |
| * ignoreTarget?: boolean, | |
| * closeOnEscape?: boolean, | |
| * position?: "absolute" | "relative", | |
| * horizontal?: "left" | "right" | |
| * }} param0 | |
| * @param {...HTMLElement} children | |
| */ | |
| constructor( | |
| { | |
| target, | |
| container = document.body, | |
| classList = "", | |
| ignoreTarget = true, | |
| closeOnEscape = true, | |
| position = "absolute", | |
| horizontal = "left", | |
| }, | |
| ...children | |
| ) { | |
| super(); | |
| this.target = target; | |
| this.ignoreTarget = ignoreTarget; | |
| this.container = container; | |
| this.position = position; | |
| this.closeOnEscape = closeOnEscape; | |
| this.horizontal = horizontal; | |
| container.append(this.element); | |
| this.children = prop(this, "children", children, () => { | |
| this.element.replaceChildren(...this.children); | |
| this.update(); | |
| }); | |
| this.classList = prop(this, "classList", classList, () => applyClasses(this.element, this.classList, "comfyui-popup", horizontal)); | |
| this.open = prop(this, "open", false, (v, o) => { | |
| if (v === o) return; | |
| if (v) { | |
| this.#show(); | |
| } else { | |
| this.#hide(); | |
| } | |
| }); | |
| } | |
| toggle() { | |
| this.open = !this.open; | |
| } | |
| #hide() { | |
| this.element.classList.remove("open"); | |
| window.removeEventListener("resize", this.update); | |
| window.removeEventListener("click", this.#clickHandler, { capture: true }); | |
| window.removeEventListener("keydown", this.#escHandler, { capture: true }); | |
| this.dispatchEvent(new CustomEvent("close")); | |
| this.dispatchEvent(new CustomEvent("change")); | |
| } | |
| #show() { | |
| this.element.classList.add("open"); | |
| this.update(); | |
| window.addEventListener("resize", this.update); | |
| window.addEventListener("click", this.#clickHandler, { capture: true }); | |
| if (this.closeOnEscape) { | |
| window.addEventListener("keydown", this.#escHandler, { capture: true }); | |
| } | |
| this.dispatchEvent(new CustomEvent("open")); | |
| this.dispatchEvent(new CustomEvent("change")); | |
| } | |
| #escHandler = (e) => { | |
| if (e.key === "Escape") { | |
| this.open = false; | |
| e.preventDefault(); | |
| e.stopImmediatePropagation(); | |
| } | |
| }; | |
| #clickHandler = (e) => { | |
| /** @type {any} */ | |
| const target = e.target; | |
| if (!this.element.contains(target) && this.ignoreTarget && !this.target.contains(target)) { | |
| this.open = false; | |
| } | |
| }; | |
| update = () => { | |
| const rect = this.target.getBoundingClientRect(); | |
| this.element.style.setProperty("--bottom", "unset"); | |
| if (this.position === "absolute") { | |
| if (this.horizontal === "left") { | |
| this.element.style.setProperty("--left", rect.left + "px"); | |
| } else { | |
| this.element.style.setProperty("--left", rect.right - this.element.clientWidth + "px"); | |
| } | |
| this.element.style.setProperty("--top", rect.bottom + "px"); | |
| this.element.style.setProperty("--limit", rect.bottom + "px"); | |
| } else { | |
| this.element.style.setProperty("--left", 0 + "px"); | |
| this.element.style.setProperty("--top", rect.height + "px"); | |
| this.element.style.setProperty("--limit", rect.height + "px"); | |
| } | |
| const thisRect = this.element.getBoundingClientRect(); | |
| if (thisRect.height < 30) { | |
| // Move up instead | |
| this.element.style.setProperty("--top", "unset"); | |
| this.element.style.setProperty("--bottom", rect.height + 5 + "px"); | |
| this.element.style.setProperty("--limit", rect.height + 5 + "px"); | |
| } | |
| }; | |
| } | |