import { UIElement, UIElementView } from "../ui_element";
import { MenuItem } from "./menu_item";
import { ActionItem } from "./action_item";
import { CheckableItem } from "./checkable_item";
import { DividerItem } from "./divider_item";
import { div, px } from "../../../core/dom";
import { ToolIcon } from "../../../core/enums";
import { build_views, remove_views } from "../../../core/build_views";
import { reversed as reverse } from "../../../core/util/array";
import { execute } from "../../../core/util/callbacks";
import menus_css, * as menus from "../../../styles/menus_.css";
import icons_css from "../../../styles/icons.css";
export class MenuView extends UIElementView {
    static __name__ = "MenuView";
    _menu_views = new Map();
    *children() {
        yield* super.children();
        yield* this._menu_views.values();
    }
    async lazy_initialize() {
        await super.lazy_initialize();
        const menus = this.model.items
            .map((item) => item instanceof ActionItem ? item.menu : null)
            .filter((item) => item != null);
        await build_views(this._menu_views, menus, { parent: this });
    }
    prevent_hide;
    _open = false;
    get is_open() {
        return this._open;
    }
    _item_click = (item) => {
        if (!item.disabled) {
            const { action } = item;
            if (action != null) {
                void execute(action, this.model, { item });
            }
            this.hide();
        }
    };
    _on_mousedown = (event) => {
        if (event.composedPath().includes(this.el)) {
            return;
        }
        if (this.prevent_hide?.(event) ?? false) {
            return;
        }
        this.hide();
    };
    _on_keydown = (event) => {
        if (event.key == "Escape") {
            this.hide();
        }
    };
    _on_blur = () => {
        this.hide();
    };
    remove() {
        this._unlisten();
        remove_views(this._menu_views);
        super.remove();
    }
    _listen() {
        document.addEventListener("mousedown", this._on_mousedown);
        document.addEventListener("keydown", this._on_keydown);
        window.addEventListener("blur", this._on_blur);
    }
    _unlisten() {
        document.removeEventListener("mousedown", this._on_mousedown);
        document.removeEventListener("keydown", this._on_keydown);
        window.removeEventListener("blur", this._on_blur);
    }
    stylesheets() {
        return [...super.stylesheets(), menus_css, icons_css];
    }
    render() {
        super.render();
        const items = (() => {
            const { reversed, items } = this.model;
            return reversed ? reverse(items) : items;
        })();
        for (const item of items) {
            if (item instanceof DividerItem) {
                const item_el = div({ class: menus.divider });
                this.shadow_el.append(item_el);
            }
            else if (item instanceof ActionItem) {
                const check_el = div({ class: menus.check });
                const icon_el = div({ class: menus.icon });
                const label_el = div({ class: menus.label }, item.label);
                const shortcut_el = div({ class: menus.shortcut }, item.shortcut);
                const chevron_el = div({ class: menus.chevron });
                const { icon } = item;
                if (icon != null) {
                    if (icon.startsWith("data:image")) {
                        const url = `url("${encodeURI(icon)}")`;
                        icon_el.style.backgroundImage = url;
                    }
                    else if (icon.startsWith("--")) {
                        icon_el.style.backgroundImage = `var(${icon})`;
                    }
                    else if (icon.startsWith(".")) {
                        const cls = icon.substring(1);
                        icon_el.classList.add(cls);
                    }
                    else if (ToolIcon.valid(icon)) {
                        const cls = `bk-tool-icon-${icon.replace(/_/g, "-")}`;
                        icon_el.classList.add(cls);
                    }
                }
                const item_el = div({ class: menus.item, title: item.tooltip, tabIndex: 0 }, check_el, icon_el, label_el, shortcut_el, chevron_el);
                item_el.classList.toggle(menus.menu, item.menu != null);
                item_el.classList.toggle(menus.disabled, item.disabled);
                if (item instanceof CheckableItem) {
                    item_el.classList.add(menus.checkable);
                    item_el.classList.toggle(menus.checked, item.checked);
                }
                item_el.addEventListener("click", () => {
                    this._item_click(item);
                });
                item_el.addEventListener("keydown", (event) => {
                    if (event.key == "Enter") {
                        this._item_click(item);
                    }
                });
                const { menu } = item;
                if (menu != null) {
                    item_el.addEventListener("pointerenter", () => {
                        const menu_view = this._menu_views.get(menu);
                        menu_view._show_submenu(item_el);
                    });
                    item_el.addEventListener("pointerleave", () => {
                        const menu_view = this._menu_views.get(menu);
                        menu_view.hide();
                    });
                }
                this.shadow_el.append(item_el);
            }
        }
    }
    _show_submenu(target) {
        if (this.model.items.length == 0) {
            this.hide();
            return;
        }
        this.render();
        target.append(this.el);
        const { style } = this.el;
        style.left = "100%";
        style.top = "0";
        this._listen();
        this._open = true;
    }
    show(at) {
        if (this.model.items.length == 0) {
            this.hide();
            return;
        }
        const { parent } = this;
        if (parent == null) {
            // TODO position: fixed
            this.hide();
            return;
        }
        this.render();
        const target = parent.el.shadowRoot ?? parent.el;
        target.append(this.el);
        const { style } = this.el;
        style.left = px(at.x);
        style.top = px(at.y);
        this._listen();
        this._open = true;
    }
    hide() {
        if (this._open) {
            this._open = false;
            this._unlisten();
            this.el.remove();
        }
    }
}
export class Menu extends UIElement {
    static __name__ = "Menu";
    constructor(attrs) {
        super(attrs);
    }
    static {
        this.prototype.default_view = MenuView;
        this.define(({ Bool, List, Ref }) => ({
            items: [List(Ref(MenuItem)), []],
            reversed: [Bool, false],
        }));
    }
}
//# sourceMappingURL=menu.js.map