import { html, GemElement, customElement, connectStore, createStore, updateStore, styleMap } from '@mantou/gem'; import { MENU_Z_INDEX } from '../lib/const'; import { theme } from '../lib/theme'; export interface MenuItem { text: string; disabled?: boolean; selected?: boolean; handle?: () => void; menu?: MenuItem[]; } type MenuState = { activeElement: HTMLElement | null; open: boolean; menuStack: { menu: MenuItem[]; x: number; y: number; }[]; }; export const menuStore = createStore({ activeElement: null, open: false, menuStack: [], }); export function openContextMenu(activeElement: HTMLElement | null, x: number, y: number, menu: MenuItem[]) { updateStore(menuStore, { open: true, activeElement, menuStack: [{ x, y, menu }] }); } export function pointerDownHandle() { setTimeout(() => menuStore.activeElement?.focus()); updateStore(menuStore, { open: false }); } function addMenuStack(x: number, y: number, menu: MenuItem[]) { const index = menuStore.menuStack.findIndex((e) => e.menu === menu); if (index > -1) { updateStore(menuStore, { menuStack: menuStore.menuStack.slice(0, index + 1) }); } else { updateStore(menuStore, { menuStack: [...menuStore.menuStack, { x, y, menu }] }); } } @customElement('gem-panel-menu') @connectStore(menuStore) export class GemPanelMenuElement extends GemElement { #enterMenu = (evt: PointerEvent, menu: MenuItem[]) => { const { x, y, width } = (evt.target as HTMLDivElement).getBoundingClientRect(); const em = parseInt(getComputedStyle(this).fontSize); addMenuStack(x + 2 * width < innerWidth ? x + width - em : x - width + em, y - 0.4 * em, menu); }; stopPropagation = (evt: Event) => { evt.stopPropagation(); }; mounted = () => { this.addEventListener('pointerdown', pointerDownHandle); }; render = () => { if (!menuStore.open) { return html``; } const { menuStack } = menuStore; return html` ${menuStack.map( ({ x, y, menu }, index) => html`
${menu.map(({ text, handle, disabled, selected, menu: subMenu }) => text === '---' ? html`
` : html`
this.#enterMenu(evt, subMenu || menu)} @pointerdown=${disabled || !handle ? this.stopPropagation : handle} > ${text} ${subMenu ? html`
` : ''} ${selected ? html`
` : ''}
`, )}
`, )} `; }; }