// - Create your context menu by instantiating ContextMenu and adding elements to it // - Open your menu in response to a contextmenu event by using globalContextMenuSpace.openAtCursor(event, menu) import { listen } from "rkgk/framework.js"; export class ContextMenu extends HTMLElement { connectedCallback() { this.classList.add("rkgk-panel"); this.closeController = new AbortController(); this.hasMouse = false; this.addEventListener("mouseover", () => (this.hasMouse = true)); this.addEventListener("mouseleave", () => (this.hasMouse = false)); window.addEventListener( "mousedown", () => { if (!this.hasMouse) { this.close(); } }, { signal: this.closeController.signal }, ); window.addEventListener( "keydown", (event) => { if (event.key == "Escape") { this.close(); } }, { signal: this.closeController.signal }, ); } disconnectedCallback() { this.closeController.abort(); } close() { this.space.close(this); } addButton(label, options) { let { classList, disabled, tooltip, noCloseOnClick } = options ?? {}; classList ??= []; disabled ??= false; tooltip ??= ""; noCloseOnClick ??= false; let button = this.appendChild(document.createElement("button")); button.classList.add(...classList); button.innerText = label; button.disabled = disabled; button.title = tooltip; button.addEventListener("click", () => { if (!noCloseOnClick) this.close(); }); return button; } addHtmlP(text, options) { let { classList } = options ?? {}; classList ??= []; let p = this.appendChild(document.createElement("p")); p.innerHTML = text; p.classList.add(...classList); return p; } addSeparator() { this.appendChild(document.createElement("hr")); } } customElements.define("rkgk-context-menu", ContextMenu); export class ContextMenuSpace extends HTMLElement { open(contextMenu) { contextMenu.space = this; this.appendChild(contextMenu); } close(contextMenu) { this.removeChild(contextMenu); } openAtCursor(cursorEvent, contextMenu) { this.open(contextMenu); // NOTE: This assumes the context menu space is positioned at (0, 0) and spans the full page. let areaWidth = this.clientWidth; let areaHeight = this.clientHeight; let menuWidth = contextMenu.clientWidth; let menuHeight = contextMenu.clientHeight; let x = cursorEvent.clientX; let y = cursorEvent.clientY; // If the menu would reach outside the screen bounds, snap it back in. if (x + menuWidth > areaWidth) x -= menuWidth; if (y + menuHeight > areaHeight) y -= menuHeight; contextMenu.style.transform = `translate(${x}px, ${y}px)`; } } customElements.define("rkgk-context-menu-space", ContextMenuSpace); export const globalContextMenuSpace = document.querySelector("rkgk-context-menu-space");