File size: 3,693 Bytes
932ae62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// @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");
		}
	};
}