import { __esDecorate, __runInitializers } from "tslib";
import { html, svg } from 'lit';
import { classMap } from 'lit/directives/class-map.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { property, queryAll } from 'lit/decorators.js';
import { iconWrapper } from '../../../md/icons/Icons.js';
import { positionOverlay } from '../../../lib/ElementPositioning.js';
import UiList from '../../../md/list/internals/List.js';
import '../../../md/list/ui-list-item.js';
import '../../../md/divider/ui-divider.js';
export const arrowRight = iconWrapper(svg `<path d="M0 0h24v24H0V0z" fill="none"/><path d="M10 17l5-5-5-5v10z"/>`);
export const check = iconWrapper(svg `<path d="M0 0h24v24H0V0z" fill="none"/><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/>`);
let ContextualMenuElement = (() => {
    let _classSuper = UiList;
    let __items_decorators;
    let __items_initializers = [];
    let __items_extraInitializers = [];
    let _commands_decorators;
    let _commands_initializers = [];
    let _commands_extraInitializers = [];
    let _store_decorators;
    let _store_initializers = [];
    let _store_extraInitializers = [];
    let _target_decorators;
    let _target_initializers = [];
    let _target_extraInitializers = [];
    let _workspace_decorators;
    let _workspace_initializers = [];
    let _workspace_extraInitializers = [];
    let _customData_decorators;
    let _customData_initializers = [];
    let _customData_extraInitializers = [];
    let _subMenuTimeout_decorators;
    let _subMenuTimeout_initializers = [];
    let _subMenuTimeout_extraInitializers = [];
    let _parentCommand_decorators;
    let _parentCommand_initializers = [];
    let _parentCommand_extraInitializers = [];
    return class ContextualMenuElement extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            __items_decorators = [queryAll('ui-list-item')];
            _commands_decorators = [property({ type: Array })];
            _store_decorators = [property({ type: Object })];
            _target_decorators = [property({ type: Object })];
            _workspace_decorators = [property({ type: Object })];
            _customData_decorators = [property({ type: Object })];
            _subMenuTimeout_decorators = [property({ type: Number })];
            _parentCommand_decorators = [property({ type: String })];
            __esDecorate(this, null, __items_decorators, { kind: "accessor", name: "_items", static: false, private: false, access: { has: obj => "_items" in obj, get: obj => obj._items, set: (obj, value) => { obj._items = value; } }, metadata: _metadata }, __items_initializers, __items_extraInitializers);
            __esDecorate(this, null, _commands_decorators, { kind: "accessor", name: "commands", static: false, private: false, access: { has: obj => "commands" in obj, get: obj => obj.commands, set: (obj, value) => { obj.commands = value; } }, metadata: _metadata }, _commands_initializers, _commands_extraInitializers);
            __esDecorate(this, null, _store_decorators, { kind: "accessor", name: "store", static: false, private: false, access: { has: obj => "store" in obj, get: obj => obj.store, set: (obj, value) => { obj.store = value; } }, metadata: _metadata }, _store_initializers, _store_extraInitializers);
            __esDecorate(this, null, _target_decorators, { kind: "accessor", name: "target", static: false, private: false, access: { has: obj => "target" in obj, get: obj => obj.target, set: (obj, value) => { obj.target = value; } }, metadata: _metadata }, _target_initializers, _target_extraInitializers);
            __esDecorate(this, null, _workspace_decorators, { kind: "accessor", name: "workspace", static: false, private: false, access: { has: obj => "workspace" in obj, get: obj => obj.workspace, set: (obj, value) => { obj.workspace = value; } }, metadata: _metadata }, _workspace_initializers, _workspace_extraInitializers);
            __esDecorate(this, null, _customData_decorators, { kind: "accessor", name: "customData", static: false, private: false, access: { has: obj => "customData" in obj, get: obj => obj.customData, set: (obj, value) => { obj.customData = value; } }, metadata: _metadata }, _customData_initializers, _customData_extraInitializers);
            __esDecorate(this, null, _subMenuTimeout_decorators, { kind: "accessor", name: "subMenuTimeout", static: false, private: false, access: { has: obj => "subMenuTimeout" in obj, get: obj => obj.subMenuTimeout, set: (obj, value) => { obj.subMenuTimeout = value; } }, metadata: _metadata }, _subMenuTimeout_initializers, _subMenuTimeout_extraInitializers);
            __esDecorate(this, null, _parentCommand_decorators, { kind: "accessor", name: "parentCommand", static: false, private: false, access: { has: obj => "parentCommand" in obj, get: obj => obj.parentCommand, set: (obj, value) => { obj.parentCommand = value; } }, metadata: _metadata }, _parentCommand_initializers, _parentCommand_extraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        #_items_accessor_storage = __runInitializers(this, __items_initializers, void 0);
        get _items() { return this.#_items_accessor_storage; }
        set _items(value) { this.#_items_accessor_storage = value; }
        set items(value) {
            //
        }
        get items() {
            return Array.from(this._items);
        }
        #commands_accessor_storage = (__runInitializers(this, __items_extraInitializers), __runInitializers(this, _commands_initializers, void 0));
        /**
         * The list of commands to render.
         */
        get commands() { return this.#commands_accessor_storage; }
        set commands(value) { this.#commands_accessor_storage = value; }
        #store_accessor_storage = (__runInitializers(this, _commands_extraInitializers), __runInitializers(this, _store_initializers, void 0));
        /**
         * The commands store.
         */
        get store() { return this.#store_accessor_storage; }
        set store(value) { this.#store_accessor_storage = value; }
        #target_accessor_storage = (__runInitializers(this, _store_extraInitializers), __runInitializers(this, _target_initializers, void 0));
        /**
         * The menu triggering click target
         */
        get target() { return this.#target_accessor_storage; }
        set target(value) { this.#target_accessor_storage = value; }
        #workspace_accessor_storage = (__runInitializers(this, _target_extraInitializers), __runInitializers(this, _workspace_initializers, void 0));
        /**
         * The current workspace
         */
        get workspace() { return this.#workspace_accessor_storage; }
        set workspace(value) { this.#workspace_accessor_storage = value; }
        #customData_accessor_storage = (__runInitializers(this, _workspace_extraInitializers), __runInitializers(this, _customData_initializers, void 0));
        /**
         * Any arbitrary data to pass to the lifecycle functions.
         */
        get customData() { return this.#customData_accessor_storage; }
        set customData(value) { this.#customData_accessor_storage = value; }
        #subMenuTimeout_accessor_storage = (__runInitializers(this, _customData_extraInitializers), __runInitializers(this, _subMenuTimeout_initializers, 300
        /**
         * The id of the parent command, in case when this menu is a sub-menu.
         */
        ));
        /**
         * The timeout after which the sub menu become visible or is removed from the menu.
         */
        get subMenuTimeout() { return this.#subMenuTimeout_accessor_storage; }
        set subMenuTimeout(value) { this.#subMenuTimeout_accessor_storage = value; }
        #parentCommand_accessor_storage = (__runInitializers(this, _subMenuTimeout_extraInitializers), __runInitializers(this, _parentCommand_initializers, void 0));
        /**
         * The id of the parent command, in case when this menu is a sub-menu.
         */
        get parentCommand() { return this.#parentCommand_accessor_storage; }
        set parentCommand(value) { this.#parentCommand_accessor_storage = value; }
        nestedIdValue = __runInitializers(this, _parentCommand_extraInitializers);
        nestedTimeout;
        removingTimeout;
        constructor() {
            super();
            this.subTriggerHandler = this.subTriggerHandler.bind(this);
            this.addEventListener('mousemove', this.mouseoverHandler.bind(this));
        }
        connectedCallback() {
            super.connectedCallback();
            if (!this.hasAttribute('role')) {
                this.setAttribute('role', 'menu');
            }
            if (!this.hasAttribute('aria-label')) {
                this.setAttribute('aria-label', 'Context menu');
            }
        }
        close() {
            this.dispatchEvent(new Event('close'));
        }
        /**
         * Triggest nested menu when hovering an item that has a nested menu.
         */
        mouseoverHandler(e) {
            if (e.defaultPrevented) {
                return;
            }
            e.preventDefault();
            const path = e.composedPath();
            const target = path.find((i) => i.localName === 'ui-list-item');
            if (!target) {
                return;
            }
            const { nested, cmd } = target.dataset;
            if (nested === 'true') {
                this.buildNested(cmd);
            }
            else if (this.nestedIdValue) {
                this.removeNested();
            }
        }
        /**
         * Builds a nested menu for a command.
         * @param id The id of the command
         */
        buildNested(id) {
            if (!id || id === this.nestedIdValue) {
                return;
            }
            if (this.nestedIdValue) {
                this.clearNested();
            }
            const cmd = this.commands?.find((item) => item.id === id);
            if (!cmd || !cmd.hasChildren) {
                return;
            }
            this.nestedIdValue = id;
            if (this.nestedTimeout) {
                clearTimeout(this.nestedTimeout);
            }
            this.nestedTimeout = setTimeout(() => {
                this.nestedTimeout = undefined;
                this.createNested();
            }, this.subMenuTimeout);
        }
        /**
         * Adds the nested menu to the local DOM.
         */
        createNested(opts = {}) {
            const id = this.nestedIdValue;
            if (!id) {
                return;
            }
            const ref = this.shadowRoot.querySelector(`[data-cmd="${id}"]`);
            // const box = ref.getBoundingClientRect();
            const cmd = this.commands?.find((item) => item.id === id);
            if (!cmd) {
                return;
            }
            const { children } = cmd;
            const menu = document.createElement('contextual-menu');
            // TODO: create a type definition for processed internally menu items
            menu.commands = children;
            menu.store = this.store;
            menu.target = this.target;
            menu.workspace = this.workspace;
            menu.customData = this.customData;
            const styles = positionOverlay(menu, ref, {
                horizontal: 'left',
                vertical: 'top',
                noOverlap: true,
                verticalOffset: -56,
                horizontalOffset: -4,
            });
            if (styles.top) {
                menu.style.top = styles.top;
            }
            if (styles.left) {
                menu.style.left = styles.left;
            }
            menu.parentCommand = id;
            menu.addEventListener('close', this.handleCloseNested.bind(this));
            menu.addEventListener('trigger', this.subTriggerHandler);
            this.shadowRoot?.append(menu);
            if (opts.keyboard) {
                menu.focus({ selectFirst: true });
            }
            else {
                menu.focus();
            }
        }
        handleCloseNested() {
            this.clearNested();
        }
        /**
         * Triggers the remove nested menu action.
         */
        removeNested() {
            if (this.removingTimeout) {
                return;
            }
            this.removingTimeout = setTimeout(() => {
                this.removingTimeout = undefined;
                this.clearNested();
            }, this.subMenuTimeout);
        }
        focus(options) {
            const { activeListItem } = this;
            if (activeListItem) {
                activeListItem.focus(options);
            }
            else if (options && options.selectFirst) {
                this.focusAfterUpdate();
            }
            else {
                super.focus(options);
            }
        }
        /**
         * Waits for the update to complete and focuses on the first item
         * or self when there are no items.
         */
        async focusAfterUpdate(options) {
            await this.updateComplete;
            if (this.items.length) {
                this.activeListItem = this.items[0];
                this.activateListItem(this.activeListItem);
            }
            else {
                super.focus(options);
            }
        }
        /**
         * Removes the nested menu from the DOM.
         */
        clearNested() {
            if (!this.nestedIdValue) {
                return;
            }
            this.nestedIdValue = undefined;
            const menu = this.shadowRoot?.querySelector('contextual-menu');
            if (menu) {
                this.shadowRoot?.removeChild(menu);
            }
            this.focus();
        }
        /**
         * Opens the menu when the current focused item has a sub menu.
         */
        moveRight() {
            const { activeListItem } = this;
            if (!activeListItem) {
                return;
            }
            const { nested, cmd } = activeListItem.dataset;
            if (nested === 'true') {
                this.clearNested();
                this.nestedIdValue = cmd;
                this.createNested({ keyboard: true });
            }
        }
        /**
         * Closes the menu when this is a sub menu.
         */
        moveLeft() {
            if (!this.parentCommand) {
                return;
            }
            this.close();
        }
        /**
         * A handler for the sub-menu `trigger` event.
         * Retargets the event to the parent.
         * It adds `parent` to the detail, when the parent (currently selected command) has
         * the execute function.
         */
        subTriggerHandler(e) {
            if (!e.detail.parent) {
                const id = this.nestedIdValue;
                const cmd = this.commands?.find((item) => item.id === id);
                if (!cmd) {
                    return;
                }
                if (typeof cmd.execute === 'function') {
                    e.detail.parent = cmd;
                }
            }
            this.dispatchEvent(new CustomEvent('trigger', {
                detail: e.detail,
            }));
        }
        handleKeydown(e) {
            e.stopPropagation();
            e.stopImmediatePropagation();
            super.handleKeydown(e);
            if (e.code === 'Escape' || e.code === 'Tab') {
                this.close();
            }
            else if (['Enter', 'Space'].includes(e.code)) {
                e.preventDefault();
                this.activateFromEvent(e);
            }
            else if (e.code === 'ArrowRight') {
                e.preventDefault();
                this.moveRight();
            }
            else if (e.code === 'ArrowLeft') {
                e.preventDefault();
                this.moveLeft();
            }
        }
        activateFromEvent(e) {
            const path = e.composedPath();
            const item = path.find((i) => i.localName === 'ui-list-item');
            if (!item) {
                return;
            }
            this.activate(item.dataset.cmd);
        }
        activate(id) {
            const { commands } = this;
            if (!id || !commands) {
                return;
            }
            const index = commands.findIndex((item) => item.id === id);
            const cmd = commands[index];
            if (!cmd) {
                return;
            }
            if (cmd.hasChildren) {
                this.buildNested(id);
            }
            else {
                const detail = {
                    command: cmd,
                    item: index,
                };
                this.dispatchEvent(new CustomEvent('trigger', {
                    detail,
                }));
            }
        }
        render() {
            const { commands } = this;
            if (!Array.isArray(commands) || !commands.length) {
                return html ``;
            }
            return html ` ${commands.map((item) => this.renderMenuItem(item))} `;
        }
        renderMenuItem(item) {
            switch (item.type) {
                case 'normal':
                    return this.renderMenuEntry(item);
                case 'separator':
                    return this.renderSeparator(item);
                case 'label':
                    return this.renderLabel(item);
                case 'radio':
                    return this.renderRadioEntry(item);
                default:
                    return '';
            }
        }
        renderSeparator(item) {
            const { store, target, workspace, customData } = this;
            if (!store || !target || !workspace) {
                return html ``;
            }
            const visible = item.isVisible(store, target, workspace, customData);
            const classes = {
                'menu-divider': true,
                'hidden': !visible,
            };
            return html ` <ui-divider type="inset" class="${classMap(classes)}" data-cmd="${item.id}"></ui-divider> `;
        }
        renderLabel(item) {
            const { store, target, workspace, customData } = this;
            if (!store || !target || !workspace) {
                return html ``;
            }
            const visible = item.isVisible(store, target, workspace, customData);
            const classes = {
                'menu-section-label': true,
                'hidden': !visible,
            };
            return html ` <div class="${classMap(classes)}" data-cmd="${item.id}">${item.label}</div> `;
        }
        renderMenuEntry(item) {
            const { store, target, workspace, customData } = this;
            if (!store || !target || !workspace) {
                return html ``;
            }
            item.beforeRenderCallback(store, target, workspace, customData);
            const visible = item.isVisible(store, target, workspace, customData);
            const enabled = item.isEnabled(store, target, workspace, customData);
            const classes = {
                item: true,
                disabled: !enabled,
                hidden: !visible,
            };
            const { title, icon, label, id, hasChildren } = item;
            return html `
      <ui-list-item
        role="menuitem"
        class="${classMap(classes)}"
        ?disabled="${!visible || !enabled}"
        aria-hidden="${!visible}"
        title="${ifDefined(title)}"
        data-cmd="${id}"
        data-nested="${hasChildren}"
        aria-haspopup="${hasChildren}"
      >
        ${this.renderMenuEntryIcon(icon)}
        <span class="menu-label">${label}</span>
        ${hasChildren ? this.renderChildIcon() : ''}
      </ui-list-item>
    `;
        }
        renderRadioEntry(item) {
            const { store, target, workspace, customData } = this;
            if (!store || !target || !workspace) {
                return html ``;
            }
            item.beforeRenderCallback(store, target, workspace, customData);
            const visible = item.isVisible(store, target, workspace, customData);
            const enabled = item.isEnabled(store, target, workspace, customData);
            const checked = item.isChecked(store, target, workspace, customData);
            const classes = {
                item: true,
                disabled: !enabled,
                hidden: !visible,
            };
            const { title, label, id, hasChildren } = item;
            return html `
      <ui-list-item
        role="menuitem"
        class="${classMap(classes)}"
        ?disabled="${!visible || !enabled}"
        aria-hidden="${!visible}"
        title="${ifDefined(title)}"
        data-cmd="${id}"
        data-nested="${hasChildren}"
        data-type="radio"
        aria-haspopup="${hasChildren}"
      >
        ${this.renderCheckMark(checked)}
        <span class="menu-label">${label}</span>
        ${hasChildren ? this.renderChildIcon() : ''}
      </ui-list-item>
    `;
        }
        /**
         * @param icon The icon is not required.
         */
        renderMenuEntryIcon(icon) {
            if (!icon) {
                return html ``;
            }
            return html ` <div class="menu-icon" slot="start">${icon}</div> `;
        }
        /**
         * @return The template for sub-menu icon
         */
        renderChildIcon() {
            return html ` <div class="sub-menu-icon" slot="end">${arrowRight}</div> `;
        }
        /**
         * @return The template for the menu entry checked mark.
         */
        renderCheckMark(checked) {
            if (!checked) {
                return html `<div class="menu-icon" data-state="unchecked" slot="start"></div>`;
            }
            return html ` <div class="menu-icon" data-state="checked" slot="start">${check}</div> `;
        }
    };
})();
/**
 * @fires close - when the menu closes.
 * @fires trigger - when a command is triggered
 */
export default ContextualMenuElement;
//# sourceMappingURL=ContextualMenuElement.js.map