import { Host, h, } from "@stencil/core";
import { getSlotElements, isPropDefined } from "../../utils/helpers";
import { createPopper, } from "@popperjs/core";
const MENU_SELECTOR = "div.menu-body";
export class PopoverMenu {
    constructor() {
        this.ARIA_LABEL = "aria-label";
        this.popoverMenuEls = [];
        this.openingFromChild = false;
        this.openingFromParent = false;
        this.popperProps = {};
        /**
         * Setting to `true` can help in situations where tooltip content is clipped by a parent element.
         */
        this.fixedPositioning = false;
        /**
         * @internal The level of menu being displayed.
         */
        this.submenuLevel = 1;
        /**
         * Sets the theme color to the dark or light theme color. "inherit" will set the color based on the system settings or ic-theme component.
         */
        this.theme = "inherit";
        /**
         * If `true`, the popover menu will be displayed.
         */
        this.open = undefined;
        this.setButtonFocus = () => {
            var _a;
            (_a = this.popoverMenuEls[this.currentFocus]) === null || _a === void 0 ? void 0 : _a.focus();
        };
        // Checks that the popover menu has an anchor
        this.findAnchorEl = (anchor) => {
            let anchorElement = null;
            if (!anchor) {
                this.submenuId === undefined &&
                    console.error("No anchor specified for popover component");
            }
            else {
                anchorElement = document.querySelector(anchor.indexOf("#") === 0 ? anchor : "#" + anchor);
                if (anchorElement === null) {
                    console.error(`Popover anchor element '${anchor}' not found`);
                }
            }
            return anchorElement;
        };
        this.isNotPopoverMenuEl = (ev) => {
            const { id, tagName } = ev.target;
            return (id !== this.anchor &&
                tagName !== "IC-MENU-ITEM" &&
                tagName !== "IC-MENU-GROUP" &&
                tagName !== "IC-POPOVER-MENU");
        };
        this.getNextItemToSelect = (currentItem, movingDown) => {
            const numButtons = this.popoverMenuEls.length - 1;
            if (currentItem < 1) {
                currentItem = 0;
            }
            let nextItem = movingDown ? currentItem + 1 : currentItem - 1;
            // Check if wrap around necessary
            if (nextItem < 0) {
                nextItem = numButtons;
            }
            else if (nextItem > numButtons) {
                nextItem = 0;
            }
            return nextItem;
        };
        this.addMenuItems = (elements) => {
            var _a;
            for (let i = 0; i < elements.length; i++) {
                const el = elements[i];
                if (el.tagName === "IC-MENU-ITEM") {
                    this.popoverMenuEls.push(el);
                }
                else if (el.tagName === "IC-MENU-GROUP") {
                    const groupSlotWrapper = (_a = el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(".menu-items-wrapper");
                    if (groupSlotWrapper) {
                        const menuGroupElements = getSlotElements(groupSlotWrapper);
                        menuGroupElements && this.addMenuItems(menuGroupElements);
                    }
                }
            }
        };
        this.getMenuAriaLabel = () => {
            const ariaLabel = this.el.getAttribute(this.ARIA_LABEL);
            if (isPropDefined(this.submenuId)) {
                return `${ariaLabel}, within nested level ${this.submenuLevel} ${this.parentLabel} submenu,`;
            }
            else {
                return ariaLabel;
            }
        };
        this.handleBackButtonClick = () => {
            var _a;
            (_a = this.parentPopover) === null || _a === void 0 ? void 0 : _a.openFromChild();
            this.open = false;
        };
        this.initPopperJS = () => {
            if (this.anchorEl) {
                this.popperInstance = createPopper(this.anchorEl, this.el, Object.assign({ strategy: this.fixedPositioning ? "fixed" : "absolute", placement: "bottom-start", modifiers: [
                        {
                            name: "offset",
                            options: {
                                offset: [0, 4],
                            },
                        },
                        {
                            name: "flip",
                            options: {
                                fallbackPlacements: ["top-start", "top-end", "bottom-end"],
                                rootBoundary: "viewport",
                            },
                        },
                    ] }, this.popperProps));
            }
        };
    }
    watchOpenHandler() {
        var _a;
        const popoverArr = (_a = this.el.parentElement) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`ic-popover-menu`);
        if (this.open) {
            if (popoverArr.length > 0) {
                popoverArr.forEach((popover) => {
                    if (popover !== this.el) {
                        popover.open = false;
                    }
                });
            }
            if (this.parentPopover !== undefined &&
                !this.popoverMenuEls.some((menuItem) => menuItem.id)) {
                this.backButton && this.popoverMenuEls.unshift(this.backButton);
            }
            this.currentFocus = 0;
            // Needed so that anchorEl isn't always focused
            setTimeout(this.setButtonFocus, 50);
        }
        else if (this.popperInstance) {
            if (popoverArr.length > 0) {
                popoverArr.forEach((popover) => {
                    if (popover !== this.el) {
                        popover.open = false;
                    }
                });
            }
            this.popperInstance.destroy();
            this.popperInstance = null;
        }
    }
    disconnectedCallback() {
        if (this.popperInstance) {
            this.popperInstance.destroy();
            this.popperInstance = null;
        }
    }
    componentDidLoad() {
        var _a;
        const slotWrapper = (_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector(MENU_SELECTOR);
        if (slotWrapper) {
            const popoverMenuElements = getSlotElements(slotWrapper);
            if (popoverMenuElements !== null) {
                this.addMenuItems(popoverMenuElements);
            }
        }
        if (this.submenuId === undefined &&
            this.el.getAttribute(this.ARIA_LABEL) === null) {
            console.error(`No aria-label specified for popover menu component - aria-label required`);
        }
        this.watchOpenHandler();
    }
    componentWillRender() {
        this.anchorEl = this.findAnchorEl(this.anchor);
    }
    componentDidRender() {
        if (this.open && !this.popperInstance) {
            this.initPopperJS();
        }
    }
    handleMenuItemClick(ev) {
        if (!ev.detail.submenuTriggerFor && ev.detail.label !== "Back") {
            this.closeMenu(false, ev.detail);
        }
    }
    // This is listening for the event emitted when a menu item is acting as a trigger button
    handleSubmenuChange(ev) {
        // Finds the trigger menu item that has emitted the event
        const target = ev.target;
        this.open = false;
        // Find the popover menu that the menu item triggers (i.e. submenu-trigger-for === submenu-id).
        const childEl = document.querySelector(`ic-popover-menu[submenu-id=${target.submenuTriggerFor}]`);
        // Set the parent popover menu of the submenu and open the submenu
        childEl.parentPopover = this.el;
        childEl.anchor = this.anchor;
        childEl.ariaLabel = this.el.getAttribute(this.ARIA_LABEL);
        childEl.openFromParent();
        childEl.submenuLevel = this.submenuLevel + 1;
        // Set the label in the submenu using the label of the menu item that has emitted the event
        childEl.parentLabel = target.label;
    }
    handleClick(ev) {
        if (this.open && this.isNotPopoverMenuEl(ev)) {
            // If menu is open and the next click on the document is not a popover El, close the popover
            this.closeMenu();
        }
    }
    // Manages the keyboard navigation in the popover menu
    handleKeyDown(ev) {
        switch (ev.key) {
            case "ArrowDown":
            case "ArrowUp":
                ev.preventDefault();
                this.currentFocus = this.getNextItemToSelect(this.currentFocus, ev.key === "ArrowDown");
                this.setButtonFocus();
                break;
            case "Home":
                //Sets home focus as first element, or back button
                this.currentFocus = 0;
                this.setButtonFocus();
                break;
            case "End":
                //Sets end focus as last element
                this.currentFocus = this.popoverMenuEls.length - 1;
                this.setButtonFocus();
                break;
            case "Escape":
            case "Tab":
                ev.preventDefault();
                if (this.open) {
                    this.closeMenu(true);
                    this.el.blur();
                }
                break;
        }
    }
    /**
     * @internal Opens the menu from the child menu.
     */
    async openFromChild() {
        this.open = true;
        this.openingFromChild = true;
        setTimeout(() => (this.openingFromChild = false), 1000);
    }
    /**
     * @internal Opens the menu from the parent menu.
     */
    async openFromParent() {
        this.open = true;
        this.openingFromParent = true;
        setTimeout(() => (this.openingFromParent = false), 1000);
    }
    /**
     * @internal Close the menu, emit icPopoverClosed of the root popover
     * @param setFocusToAnchor when true return focus to anchor element when menu is closed
     */
    async closeMenu(setFocusToAnchor = false, menuElement) {
        var _a;
        this.open = false;
        if (this.parentPopover) {
            this.parentPopover.closeMenu(setFocusToAnchor, menuElement);
        }
        else {
            if (setFocusToAnchor) {
                (_a = this.anchorEl) === null || _a === void 0 ? void 0 : _a.focus();
            }
            this.icPopoverClosed.emit(menuElement);
        }
    }
    /**
     * @internal This method allows props to be added to the PopperJS createPopper instance outside of the popover menu
     * @param props object - createPopper props set externally
     */
    async setExternalPopperProps(props) {
        this.popperProps = props;
    }
    render() {
        return (h(Host, { key: '2df7f8dce86b2a069e36c528cde49fab2a59e14d', class: {
                ["ic-popover-menu-open"]: !!this.open,
                [`ic-theme-${this.theme}`]: this.theme !== "inherit",
            } }, h("div", { key: '274adfbbf14f57d3538bd5076d4f3eaba4246b9f', id: this.parentPopover === undefined
                ? `ic-popover-submenu-${this.submenuId}`
                : "", class: {
                menu: true,
            } }, h("span", { key: 'dbb75e11d95ab6dd331e8fdde4c698627ebce128', class: {
                "opening-from-parent": this.openingFromParent,
                "opening-from-child": this.openingFromChild,
            } }, isPropDefined(this.submenuId) && (h("span", { key: 'd4f921888dbb9225abcb2470dd28df727f3beee0' }, h("span", { key: '35d3b4ef74cb4d777f50299aa374a9e3cee34889', role: "menu" }, h("ic-menu-item", { key: '1f389ff42de3e6a71f8d119a0d77c303bdd680a8', class: "ic-popover-submenu-back-button", ref: (el) => (this.backButton = el), label: "Back", onClick: this.handleBackButtonClick, id: `ic-popover-submenu-back-button-${this.submenuLevel}` }, h("svg", { key: '68719e50bc2f6735c0f7dcf6f44c9ff63c5acdea', slot: "icon", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", class: "submenu-back-icon" }, h("path", { key: '2ba5c53d18fb50b729ae2246817f7c9cf30257b0', d: "M20 11H7.83L13.42 5.41L12 4L4 12L12 20L13.41 18.59L7.83 13H20V11Z", fill: "currentColor" })))), h("ic-typography", { key: '6932f008b6d3444e0c9310c60c3fcbafae48f3ff', variant: "subtitle-small", class: "parent-label" }, this.parentLabel))), h("div", { key: '75f0187e8474d97fce7f8436cba7e6168cfd2b63', class: "menu-body", "aria-label": this.getMenuAriaLabel(), role: "menu" }, h("slot", { key: 'a547d619787fda1c2f529a0b4ec7fe3745f416ab' }))))));
    }
    static get is() { return "ic-popover-menu"; }
    static get encapsulation() { return "shadow"; }
    static get delegatesFocus() { return true; }
    static get originalStyleUrls() {
        return {
            "$": ["ic-popover-menu.css"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["ic-popover-menu.css"]
        };
    }
    static get properties() {
        return {
            "anchor": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The ID of the element the popover menu will anchor itself to. This is required unless the popover is a submenu."
                },
                "getter": false,
                "setter": false,
                "attribute": "anchor",
                "reflect": false
            },
            "fixedPositioning": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Setting to `true` can help in situations where tooltip content is clipped by a parent element."
                },
                "getter": false,
                "setter": false,
                "attribute": "fixed-positioning",
                "reflect": false,
                "defaultValue": "false"
            },
            "parentLabel": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "The parent popover menu of a child popover menu."
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "attribute": "parent-label",
                "reflect": false
            },
            "parentPopover": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "HTMLIcPopoverMenuElement",
                    "resolved": "HTMLIcPopoverMenuElement | undefined",
                    "references": {
                        "HTMLIcPopoverMenuElement": {
                            "location": "global",
                            "id": "global::HTMLIcPopoverMenuElement"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "The parent popover menu of a child popover menu."
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false
            },
            "submenuId": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The unique identifier for a popover submenu."
                },
                "getter": false,
                "setter": false,
                "attribute": "submenu-id",
                "reflect": false
            },
            "submenuLevel": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "The level of menu being displayed."
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "attribute": "submenu-level",
                "reflect": false,
                "defaultValue": "1"
            },
            "theme": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "IcThemeMode",
                    "resolved": "\"dark\" | \"inherit\" | \"light\" | undefined",
                    "references": {
                        "IcThemeMode": {
                            "location": "import",
                            "path": "../../utils/types",
                            "id": "src/utils/types.ts::IcThemeMode"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Sets the theme color to the dark or light theme color. \"inherit\" will set the color based on the system settings or ic-theme component."
                },
                "getter": false,
                "setter": false,
                "attribute": "theme",
                "reflect": false,
                "defaultValue": "\"inherit\""
            },
            "open": {
                "type": "boolean",
                "mutable": true,
                "complexType": {
                    "original": "boolean | undefined",
                    "resolved": "boolean | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "If `true`, the popover menu will be displayed."
                },
                "getter": false,
                "setter": false,
                "attribute": "open",
                "reflect": true,
                "defaultValue": "undefined"
            }
        };
    }
    static get states() {
        return {
            "openingFromChild": {},
            "openingFromParent": {},
            "popperProps": {}
        };
    }
    static get events() {
        return [{
                "method": "icPopoverClosed",
                "name": "icPopoverClosed",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the popover menu is closed."
                },
                "complexType": {
                    "original": "HTMLIcMenuItemElement",
                    "resolved": "HTMLIcMenuItemElement",
                    "references": {
                        "HTMLIcMenuItemElement": {
                            "location": "global",
                            "id": "global::HTMLIcMenuItemElement"
                        }
                    }
                }
            }];
    }
    static get methods() {
        return {
            "openFromChild": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": "Opens the menu from the child menu."
                        }]
                }
            },
            "openFromParent": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": "Opens the menu from the parent menu."
                        }]
                }
            },
            "closeMenu": {
                "complexType": {
                    "signature": "(setFocusToAnchor?: boolean, menuElement?: HTMLIcMenuItemElement) => Promise<void>",
                    "parameters": [{
                            "name": "setFocusToAnchor",
                            "type": "boolean",
                            "docs": "when true return focus to anchor element when menu is closed"
                        }, {
                            "name": "menuElement",
                            "type": "HTMLIcMenuItemElement | undefined",
                            "docs": ""
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "HTMLIcMenuItemElement": {
                            "location": "global",
                            "id": "global::HTMLIcMenuItemElement"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": "Close the menu, emit icPopoverClosed of the root popover"
                        }, {
                            "name": "param",
                            "text": "setFocusToAnchor when true return focus to anchor element when menu is closed"
                        }]
                }
            },
            "setExternalPopperProps": {
                "complexType": {
                    "signature": "<T extends Partial<Options>>(props: T) => Promise<void>",
                    "parameters": [{
                            "name": "props",
                            "type": "T",
                            "docs": "object - createPopper props set externally"
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "Partial": {
                            "location": "global",
                            "id": "global::Partial"
                        },
                        "Options": {
                            "location": "import",
                            "path": "@popperjs/core",
                            "id": "node_modules::Options"
                        },
                        "T": {
                            "location": "global",
                            "id": "global::T"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": "This method allows props to be added to the PopperJS createPopper instance outside of the popover menu"
                        }, {
                            "name": "param",
                            "text": "props object - createPopper props set externally"
                        }]
                }
            }
        };
    }
    static get elementRef() { return "el"; }
    static get watchers() {
        return [{
                "propName": "open",
                "methodName": "watchOpenHandler"
            }];
    }
    static get listeners() {
        return [{
                "name": "handleMenuItemClick",
                "method": "handleMenuItemClick",
                "target": undefined,
                "capture": false,
                "passive": false
            }, {
                "name": "triggerPopoverMenuInstance",
                "method": "handleSubmenuChange",
                "target": undefined,
                "capture": true,
                "passive": false
            }, {
                "name": "click",
                "method": "handleClick",
                "target": "document",
                "capture": false,
                "passive": false
            }, {
                "name": "keydown",
                "method": "handleKeyDown",
                "target": undefined,
                "capture": false,
                "passive": false
            }];
    }
}
//# sourceMappingURL=ic-popover-menu.js.map
