export const TreeContextMenuMixin = (superClass) => class TreeContextMenuMixin extends superClass { async _onContextMenu(item, originalEvent) { originalEvent.preventDefault(); if (this.selectOnRightClick && this.manageState) { const pathStr = item.path.join('/'); const set = new Set(this._selectedPathSet); let changed = false; if (this.multiSelect) { if (!set.has(pathStr)) { set.add(pathStr); changed = true; } } else { if (!set.has(pathStr) || set.size !== 1) { set.clear(); set.add(pathStr); changed = true; } } if (changed) { this._selectedPathSet = set; this.selectedPaths = Array.from(set); this._rebuildManagedTree(); this.dispatchEvent(new CustomEvent('node-selected', { detail: { node: item.node, path: item.path, originalEvent }, bubbles: true, composed: true, })); } } const contextEvent = new CustomEvent('node-context', { detail: { item, originalEvent }, bubbles: true, composed: true, cancelable: true, }); this.dispatchEvent(contextEvent); if (contextEvent.defaultPrevented) return; const baseActions = this._mergeActions( this.defaultActions, this._normalizeActions(item.node?.actions) ); const maybeModified = this.beforeContextMenu ? this.beforeContextMenu(item, baseActions) : baseActions; const actions = await Promise.resolve(maybeModified); if (actions === false) return; const x = originalEvent.clientX; const y = originalEvent.clientY; this._contextMenu = { item, actions: Array.isArray(actions) ? actions : baseActions }; this.requestUpdate(); await this.updateComplete; const menu = this.shadowRoot.querySelector('.context-menu'); if (menu) { const anchor = { getBoundingClientRect: () => ({ top: y, bottom: y, left: x, right: x, width: 0, height: 0 }) }; this._posFixed(anchor, menu, { valign: 'bottom', halign: 'left' }); } this._attachOutsideHandlers(); } _onMenuAction(action, item, originalEvent) { originalEvent.stopPropagation(); this._dispatchAction(action?.action, item, 'context-menu', originalEvent); this._closeContextMenu(); } _attachOutsideHandlers() { if (this._outsideHandler) return; this._outsideHandler = (e) => { const menu = this.shadowRoot.querySelector('.context-menu'); if (menu && e.composedPath().includes(menu)) return; this._closeContextMenu(); }; this._keyHandler = (e) => { if (e.key === 'Escape') { this._closeContextMenu(); } }; window.addEventListener('pointerdown', this._outsideHandler, true); window.addEventListener('keydown', this._keyHandler, true); } _removeOutsideHandlers() { if (this._outsideHandler) { window.removeEventListener('pointerdown', this._outsideHandler, true); this._outsideHandler = null; } if (this._keyHandler) { window.removeEventListener('keydown', this._keyHandler, true); this._keyHandler = null; } } _closeContextMenu() { this._contextMenu = null; this.requestUpdate(); this._removeOutsideHandlers(); } };