import * as colors from './00colors.js'; import * as plugins from './00plugins.js'; import { demoFunc } from './dees-contextmenu.demo.js'; import { customElement, html, DeesElement, property, type TemplateResult, cssManager, css, type CSSResult, unsafeCSS, } from '@design.estate/dees-element'; import * as domtools from '@design.estate/dees-domtools'; import { DeesWindowLayer } from './dees-windowlayer.js'; declare global { interface HTMLElementTagNameMap { 'dees-contextmenu': DeesContextmenu; } } @customElement('dees-contextmenu') export class DeesContextmenu extends DeesElement { // DEMO public static demo = demoFunc // STATIC // This will store all the accumulated menu items public static contextMenuDeactivated = false; public static accumulatedMenuItems: plugins.tsclass.website.IMenuItem[] = []; // Add a global event listener for the right-click context menu public static initializeGlobalListener() { document.addEventListener('contextmenu', (event: MouseEvent) => { if (this.contextMenuDeactivated) { return; } event.preventDefault(); // Get the target element of the right-click let target: EventTarget | null = event.target; // Clear previously accumulated items DeesContextmenu.accumulatedMenuItems = []; // Traverse up the DOM tree to accumulate menu items while (target) { if ((target as any).getContextMenuItems) { DeesContextmenu.accumulatedMenuItems.push(...(target as any).getContextMenuItems()); } target = (target as Node).parentNode; } // Open the context menu with the accumulated items DeesContextmenu.openContextMenuWithOptions(event, DeesContextmenu.accumulatedMenuItems); }); } // allows opening of a contextmenu with options public static async openContextMenuWithOptions(eventArg: MouseEvent, menuItemsArg: plugins.tsclass.website.IMenuItem[]) { if (this.contextMenuDeactivated) { return; } eventArg.preventDefault(); eventArg.stopPropagation(); const contextMenu = new DeesContextmenu(); contextMenu.style.position = 'fixed'; contextMenu.style.zIndex = '2000'; contextMenu.style.top = `${eventArg.clientY.toString()}px`; contextMenu.style.left = `${eventArg.clientX.toString()}px`; contextMenu.style.opacity = '0'; contextMenu.style.transform = 'scale(0.95,0.95)'; contextMenu.style.transformOrigin = 'top left'; contextMenu.menuItems = menuItemsArg; contextMenu.windowLayer = await DeesWindowLayer.createAndShow(); contextMenu.windowLayer.addEventListener('click', async () => { await contextMenu.destroy(); }) document.body.append(contextMenu); await domtools.plugins.smartdelay.delayFor(0); contextMenu.style.opacity = '1'; contextMenu.style.transform = 'scale(1,1)'; } // INSTANCE @property({ type: Array, }) public menuItems: plugins.tsclass.website.IMenuItem[] = []; windowLayer: DeesWindowLayer; constructor() { super(); } /** * STATIC STYLES */ public static styles = [ cssManager.defaultStyles, css` :host { display: block; transition: all 0.1s; } .mainbox { color: ${cssManager.bdTheme('#222', '#ccc')}; font-size: 14px; width: 200px; border: 1px solid ${cssManager.bdTheme('#fff', '#ffffff10')}; min-height: 34px; border-radius: 3px; background: ${cssManager.bdTheme('#fff', '#222')}; box-shadow: 0px 1px 4px ${cssManager.bdTheme('#00000020', '#000000')}; user-select: none; padding: 4px; } .mainbox .menuitem { padding: 4px 8px; border-radius: 3px; } .mainbox .menuitem dees-icon { display: inline-block; margin-right: 8px; width: 14px; transform: translateY(2px); } .mainbox .menuitem:hover { background: ${cssManager.bdTheme(colors.bright.blue, colors.dark.blue)}; } .mainbox .menuitem:active { background: #ffffff05; } `, ]; public render(): TemplateResult { return html`
${this.menuItems.map((menuItemArg) => { return html` `; })} ${this.menuItems.length === 0 ? html` ` : html``}
`; } public async firstUpdated() { } public async handleClick(menuItem: plugins.tsclass.website.IMenuItem) { menuItem.action(); await this.destroy(); } public async destroy() { if (this.windowLayer) { this.windowLayer.destroy(); } this.style.opacity = '0'; this.style.transform = 'scale(0.95,0,95)'; await domtools.plugins.smartdelay.delayFor(100); this.parentElement.removeChild(this); } } DeesContextmenu.initializeGlobalListener();