import { h, Host, Fragment, } from "@stencil/core";
import { createPopper, } from "@popperjs/core";
import Check from "../../assets/check-icon.svg";
import { getOptionsWithoutGroupTitlesCount, isMacDevice, onComponentRequiredPropUndefined, } from "../../utils/helpers";
import { sanitizeHTMLString, sanitizeHTMLIconString, } from "../../utils/common-helpers";
export class Menu {
    constructor() {
        this.ACTIVE_DESCENDANT = "aria-activedescendant";
        this.CLEAR_BUTTON_ID = "clear-button";
        this.SEARCH_BAR_TAG = "IC-SEARCH-BAR";
        this.disabledOptionSelected = false;
        this.hasPreviouslyBlurred = false;
        this.hasTimedOut = false;
        this.isLoading = false;
        this.lastOptionSelected = null; // Index of last option selected
        this.lastOptionFocused = null; // Index of last option focused
        this.multiOptionClicked = null;
        this.preventClickOpen = false; // Prevents menu re-opening immediately after it is closed on blur when clicking input.
        this.preventMenuFocus = false; // (When multiple) ensures focus moves straight to select all button from menu.
        this.shiftPressed = false;
        this.ungroupedOptions = [];
        this.focusFromSearchKeypress = false;
        this.initialOptionsListRender = false;
        this.keyboardNav = false;
        this.preventIncorrectTabOrder = false;
        this.popperProps = {};
        /**
         * Determines whether options manually set as values (by pressing 'Enter') when they receive focus using keyboard navigation.
         */
        this.activationType = "automatic";
        /**
         * @internal If `true`, autofocus will be applied on selected item when menu is open.
         */
        this.autofocusOnSelected = true;
        /**
         *  If `true`, the menu will close when an option is selected.
         */
        this.closeOnSelect = true;
        /**
         *  If `true`, the menu will fill the width of the container.
         */
        this.fullWidth = false;
        /**
         * The custom name for the label field for IcMenuOption.
         */
        this.labelField = "label";
        /**
         * @internal - flag to specify if menu is in a ic-select multiple.
         */
        this.multiSelect = false;
        /**
         * @internal - flag to specify if menu is in a searchable ic-select.
         */
        this.searchableSelect = false;
        /**
         * @internal - flag to specify if menu is in a ic-search-bar.
         */
        this.searchBar = false;
        /**
         * Specify the mode search bar uses to search. `navigation` allows for quick lookups of a set of values, `query` allows for more general searches.
         */
        this.searchMode = "navigation";
        /**
         * @internal If `true`, the icOptionSelect event will be fired on enter instead of ArrowUp and ArrowDown.
         */
        this.selectOnEnter = false;
        /**
         * The size of the menu.
         */
        this.size = "medium";
        /**
         * The custom name for the value field for IcMenuOption.
         */
        this.valueField = "value";
        /**
         * @internal If `true`, allows the menu to receive focus when opened.
         */
        this.allowMenuFocus = true;
        this.emitOptionId = (index) => {
            let option;
            if (index >= 0 && index < this.ungroupedOptions.length) {
                option = this.ungroupedOptions[index];
            }
            else if (this.ungroupedOptions.length > 0) {
                option =
                    index < 0
                        ? this.ungroupedOptions[this.ungroupedOptions.length - 1]
                        : this.ungroupedOptions[0];
            }
            if (option) {
                this.menuOptionId.emit({
                    optionId: this.getOptionId(option[this.valueField]),
                });
            }
            else {
                this.menuOptionId.emit({ optionId: undefined });
            }
        };
        this.handleClearListener = () => {
            this.optionHighlighted = "";
        };
        this.handleSubmitSearch = () => {
            const highlightedOptionIndex = this.options.findIndex((option) => option[this.valueField] === this.optionHighlighted);
            this.setInputValue(highlightedOptionIndex);
        };
        this.handleMenuChange = (open, focusInput) => {
            var _a;
            this.menuStateChange.emit({ open, focusInput });
            if (!open) {
                if (focusInput !== false) {
                    if (this.allowMenuFocus) {
                        (_a = this.inputEl) === null || _a === void 0 ? void 0 : _a.focus();
                    }
                    this.preventClickOpen = false;
                }
                // Reset optionHighlighted so previously highlighted option doesn't get reselected when Enter pressed
                if (this.multiSelect) {
                    this.optionHighlighted = undefined;
                    this.multiOptionClicked = null;
                }
            }
        };
        this.setNextOptionValue = (selectedOptionIndex) => {
            if (this.ungroupedOptions[selectedOptionIndex + 1]) {
                this.menuOptionSelect.emit({
                    value: this.ungroupedOptions[selectedOptionIndex + 1][this.valueField],
                    optionId: this.getOptionId(this.ungroupedOptions[selectedOptionIndex + 1][this.valueField]),
                });
            }
            else {
                this.menuOptionSelect.emit({
                    value: this.ungroupedOptions[0][this.valueField],
                    optionId: this.getOptionId(this.ungroupedOptions[0][this.valueField]),
                });
            }
        };
        this.setPreviousOptionValue = (selectedOptionIndex) => {
            if (this.ungroupedOptions[selectedOptionIndex - 1]) {
                this.menuOptionSelect.emit({
                    value: this.ungroupedOptions[selectedOptionIndex - 1][this.valueField],
                    optionId: this.getOptionId(this.ungroupedOptions[selectedOptionIndex - 1][this.valueField]),
                });
            }
            else {
                this.menuOptionSelect.emit({
                    value: this.ungroupedOptions[this.ungroupedOptions.length - 1][this.valueField],
                    optionId: this.getOptionId(this.ungroupedOptions[this.ungroupedOptions.length - 1][this.valueField]),
                });
            }
        };
        // Open menu when up or down arrow keys are pressed
        this.arrowBehaviour = (event) => {
            event.preventDefault();
            this.handleMenuChange(true);
        };
        this.getMenuOptions = () => this.searchBar ? this.options : this.ungroupedOptions;
        // Set option that is focused and so should show focus state
        this.setHighlightedOption = (highlightedIndex) => {
            const menuOptions = this.getMenuOptions();
            menuOptions[highlightedIndex] &&
                !menuOptions[highlightedIndex].timedOut &&
                (this.optionHighlighted =
                    menuOptions[highlightedIndex][this.valueField] || undefined);
        };
        // Determines keyboard behaviour when selection is automatic
        // (i.e. you don't have to press Enter select an option - just focus on it)
        // and menu is closed
        this.autoSetInputValueKeyboardOpen = (event) => {
            const selectedOptionIndex = this.ungroupedOptions.findIndex((option) => option[this.valueField] === this.value);
            this.keyboardNav = false;
            switch (event.key) {
                case "ArrowDown": {
                    this.keyboardNav = true;
                    this.arrowBehaviour(event);
                    const nextIndex = selectedOptionIndex < this.ungroupedOptions.length - 1
                        ? selectedOptionIndex + 1
                        : 0;
                    this.setNextOptionValue(selectedOptionIndex);
                    this.emitOptionId(nextIndex);
                    break;
                }
                case "ArrowUp": {
                    this.keyboardNav = true;
                    this.arrowBehaviour(event);
                    const prevIndex = selectedOptionIndex > 0
                        ? selectedOptionIndex - 1
                        : this.ungroupedOptions.length - 1;
                    this.setPreviousOptionValue(selectedOptionIndex);
                    this.emitOptionId(prevIndex);
                    break;
                }
                case "Home": {
                    this.keyboardNav = true;
                    event.preventDefault();
                    this.arrowBehaviour(event);
                    this.setNextOptionValue(-1);
                    this.emitOptionId(0);
                    break;
                }
                case "End": {
                    this.keyboardNav = true;
                    event.preventDefault();
                    this.arrowBehaviour(event);
                    this.setPreviousOptionValue(this.ungroupedOptions.length);
                    this.emitOptionId(this.ungroupedOptions.length - 1);
                    break;
                }
                case " ":
                case "Enter":
                    if (event.target.id !== this.CLEAR_BUTTON_ID) {
                        this.handleMenuChange(true);
                    }
                    break;
            }
        };
        this.selectHighlightedOption = (options, highlightedOptionIndex) => {
            if (!this.isLoading && !this.hasTimedOut) {
                this.keyboardNav = true;
            }
            const isOpen = this.searchBar || this.searchableSelect || this.open;
            if (isOpen) {
                if (highlightedOptionIndex >= 0) {
                    if (options[highlightedOptionIndex] !== undefined) {
                        if (this.searchBar &&
                            options[highlightedOptionIndex].disabled === true) {
                            this.disabledOptionSelected = true;
                        }
                        else {
                            this.setInputValue(highlightedOptionIndex);
                        }
                    }
                }
                else {
                    this.setInputValue(highlightedOptionIndex);
                }
            }
            else {
                this.handleMenuChange(true);
            }
        };
        // Check if option is selected based on the index of the option
        this.isOptionSelected = (index) => {
            const menuOptions = this.getMenuOptions();
            return this.value
                ? this.value.includes(menuOptions[index][this.valueField])
                : false;
        };
        // Deselect currently selected options when shift pressed, but keep certain options selected
        this.deselectSelectedOptions = (optionsToKeepSelected) => {
            const menuOptions = this.getMenuOptions();
            if (this.value) {
                const selectedOptionIndexes = this.value.map((value) => {
                    return menuOptions.findIndex((option) => option[this.valueField] === value);
                });
                // Call setInputValue (which toggles the selected state) on options that need to be deselected
                selectedOptionIndexes.forEach((index) => !optionsToKeepSelected.includes(index) && this.setInputValue(index));
            }
        };
        // Determines keyboard behaviour when selection is manual (i.e. when you have to press Enter to select an option)
        this.manualSetInputValueKeyboardOpen = (event) => {
            const menuOptions = this.getMenuOptions();
            // For preventing focus disappearing on currently focused option when Shift / Cmd / Ctrl pressed
            // (i.e. when user is likely in the middle of executing a keyboard combination to select options)
            const isKeyboardCombination = event.shiftKey || event.metaKey || event.ctrlKey;
            const highlightedOptionIndex = this.getOptionHighlightedIndex();
            const clickedMultiOptionIndex = menuOptions.findIndex((option) => option[this.valueField] === this.multiOptionClicked);
            const getOptionId = (index) => { var _a; return (_a = Array.from(this.host.querySelectorAll("li"))[index]) === null || _a === void 0 ? void 0 : _a.id; };
            // Space press should be equivalent to Enter when multi-select
            if (event.key === " " && this.multiSelect) {
                this.handleOptionSelect(event, highlightedOptionIndex);
            }
            else {
                switch (event.key) {
                    case "ArrowDown":
                        this.keyboardNav = true;
                        this.arrowBehaviour(event);
                        if (this.multiOptionClicked) {
                            // Set focus to option last clicked
                            // Prevents it resetting to the top of the menu when user switches to using keyboard
                            this.setHighlightedOption(clickedMultiOptionIndex);
                            this.multiOptionClicked = null;
                        }
                        else {
                            this.handleSingleShiftSelect(event, highlightedOptionIndex, menuOptions);
                            if (highlightedOptionIndex < menuOptions.length - 1) {
                                this.setHighlightedOption(highlightedOptionIndex + 1);
                                this.menuOptionId.emit({
                                    optionId: getOptionId(highlightedOptionIndex + 1),
                                });
                                this.handleSingleShiftSelect(event, highlightedOptionIndex + 1, menuOptions);
                            }
                            else {
                                this.setHighlightedOption(0);
                                this.menuOptionId.emit({
                                    optionId: getOptionId(0),
                                });
                                this.handleSingleShiftSelect(event, 0, menuOptions);
                            }
                            // Deselect currently selected options if arrow was pressed for first time after shift is held
                            if (this.multiSelect && this.shiftPressed) {
                                this.deselectSelectedOptions([
                                    highlightedOptionIndex,
                                    this.getOptionHighlightedIndex(),
                                ]);
                                this.shiftPressed = false;
                            }
                        }
                        this.lastOptionFocused = this.getOptionHighlightedIndex();
                        this.preventIncorrectTabOrder = false;
                        this.focusFromSearchKeypress = false;
                        break;
                    case "ArrowUp":
                        this.keyboardNav = true;
                        this.arrowBehaviour(event);
                        if (this.multiOptionClicked) {
                            // Set focus to option last clicked
                            // Prevents it resetting to the bottom of the menu when user switches to using keyboard
                            this.setHighlightedOption(clickedMultiOptionIndex);
                            this.multiOptionClicked = null;
                        }
                        else {
                            this.handleSingleShiftSelect(event, highlightedOptionIndex, menuOptions);
                            if (highlightedOptionIndex <= 0 ||
                                highlightedOptionIndex > menuOptions.length + 1) {
                                this.setHighlightedOption(menuOptions.length - 1);
                                this.menuOptionId.emit({
                                    optionId: getOptionId(menuOptions.length - 1),
                                });
                                this.handleSingleShiftSelect(event, menuOptions.length - 1, menuOptions);
                            }
                            else {
                                this.setHighlightedOption(highlightedOptionIndex - 1);
                                this.menuOptionId.emit({
                                    optionId: getOptionId(highlightedOptionIndex - 1),
                                });
                                this.handleSingleShiftSelect(event, highlightedOptionIndex - 1, menuOptions);
                            }
                            // Deselect currently selected options if arrow was pressed for first time after shift is held
                            if (this.multiSelect && this.shiftPressed) {
                                this.deselectSelectedOptions([
                                    highlightedOptionIndex,
                                    this.getOptionHighlightedIndex(),
                                ]);
                                this.shiftPressed = false;
                            }
                        }
                        this.lastOptionFocused = this.getOptionHighlightedIndex();
                        this.preventIncorrectTabOrder = false;
                        this.focusFromSearchKeypress = false;
                        break;
                    case "Home": {
                        const startOptionIndex = 0;
                        this.keyboardNav = true;
                        event.preventDefault();
                        this.arrowBehaviour(event);
                        this.setHighlightedOption(startOptionIndex);
                        this.menuOptionId.emit({
                            optionId: getOptionId(startOptionIndex),
                        });
                        if (event.shiftKey && event.ctrlKey) {
                            this.handleMultipleShiftSelect(startOptionIndex);
                        }
                        this.lastOptionFocused = startOptionIndex;
                        this.lastOptionSelected = startOptionIndex;
                        break;
                    }
                    case "End": {
                        const endOptionIndex = menuOptions.length - 1;
                        this.keyboardNav = true;
                        event.preventDefault();
                        this.arrowBehaviour(event);
                        this.setHighlightedOption(endOptionIndex);
                        this.menuOptionId.emit({
                            optionId: getOptionId(endOptionIndex),
                        });
                        if (event.shiftKey && event.ctrlKey) {
                            this.handleMultipleShiftSelect(endOptionIndex);
                        }
                        this.lastOptionFocused = endOptionIndex;
                        this.lastOptionSelected = endOptionIndex;
                        break;
                    }
                    case " ":
                        if (!isKeyboardCombination) {
                            this.keyboardNav = false;
                        }
                        if (this.searchBar || this.searchableSelect) {
                            break;
                        }
                        else {
                            if (event.target.id !== this.CLEAR_BUTTON_ID) {
                                this.handleMenuChange(true);
                            }
                        }
                        break;
                    case "Enter":
                        event.preventDefault();
                        if (!isKeyboardCombination) {
                            this.keyboardNav = false;
                        }
                        this.handleOptionSelect(event, highlightedOptionIndex);
                        break;
                    case "Escape":
                        if (this.open) {
                            event.stopImmediatePropagation();
                        }
                        this.handleMenuChange(false, !this.allowMenuFocus);
                        this.menuOptionId.emit({ optionId: undefined });
                        break;
                    case "a":
                        // Checks if Cmd (meta) key is pressed if Mac device (while excluding meta key on Windows)
                        // Otherwise, if a different OS, checks Ctrl key
                        if (this.multiSelect &&
                            ((isMacDevice() && event.metaKey) ||
                                (!isMacDevice() && event.ctrlKey))) {
                            this.emitSelectAllEvents();
                            this.lastOptionFocused = null;
                            this.lastOptionSelected = null;
                        }
                        break;
                    case "Shift":
                    case "Tab":
                        if (event.key === "Shift") {
                            this.shiftPressed = true;
                        }
                        if (this.searchBar) {
                            this.keyboardNav = true;
                        }
                        if (this.multiSelect) {
                            if (this.open && !event.shiftKey && this.selectAllButton) {
                                event.preventDefault();
                                this.selectAllButton.focus(); // Move focus to select all button instead of focused option
                                this.preventMenuFocus = true;
                                this.preventClickOpen = true;
                                this.optionHighlighted = undefined; // Stop any option focus states showing when focus moved to select all button
                            }
                        }
                        else {
                            this.preventIncorrectTabOrder = true;
                        }
                        break;
                    default:
                        if (!isKeyboardCombination) {
                            this.keyboardNav = false;
                        }
                        this.focusOnSearchOrSelectInput(menuOptions, highlightedOptionIndex);
                }
            }
        };
        this.setInputValue = (highlightedOptionIndex) => {
            const menuOptions = this.getMenuOptions();
            if (menuOptions[highlightedOptionIndex] !== undefined) {
                this.menuOptionSelect.emit({
                    value: menuOptions[highlightedOptionIndex][this.valueField],
                });
                if (this.closeOnSelect) {
                    this.optionHighlighted = undefined;
                    this.menuOptionId.emit({ optionId: undefined });
                }
            }
            if (this.closeOnSelect) {
                if (!this.hasTimedOut) {
                    this.handleMenuChange(false);
                }
                else {
                    this.parentEl.setFocus();
                }
            }
        };
        this.handleOptionClick = (event) => {
            const { value, label } = event.target.dataset;
            if (this.multiSelect) {
                const menuOptions = this.getMenuOptions();
                const selectedOptionIndex = menuOptions.findIndex((option) => option[this.valueField] === value);
                this.handleOptionSelect(event, selectedOptionIndex, true);
                this.multiOptionClicked = value || null;
            }
            else {
                this.menuOptionSelect.emit({ value, label });
                this.handleMenuChange(false);
            }
            this.optionHighlighted = undefined;
        };
        this.handleRetry = () => {
            this.retryButtonClicked.emit({ value: this.value });
        };
        this.handleRetryKeyDown = (ev) => {
            if (ev.key === "Enter" || ev.key === " ") {
                ev.preventDefault();
                this.retryButtonClicked.emit({ value: this.value, keyPressed: ev.key });
            }
        };
        this.handleBlur = (event) => {
            var _a, _b, _c, _d;
            if (event.relatedTarget !== this.inputEl) {
                if (event.relatedTarget === this.selectAllButton) {
                    (_a = this.menu) === null || _a === void 0 ? void 0 : _a.removeAttribute(this.ACTIVE_DESCENDANT);
                }
                if (!(((_b = this.menu) === null || _b === void 0 ? void 0 : _b.contains(event.relatedTarget)) ||
                    event.relatedTarget === this.selectAllButton)) {
                    this.handleMenuChange(false, this.hasPreviouslyBlurred);
                    (_c = this.menu) === null || _c === void 0 ? void 0 : _c.removeAttribute(this.ACTIVE_DESCENDANT);
                    this.lastOptionFocused = null;
                    this.lastOptionSelected = null;
                }
            }
            else {
                this.handleMenuChange(false);
                this.preventClickOpen = true;
                (_d = this.menu) === null || _d === void 0 ? void 0 : _d.removeAttribute(this.ACTIVE_DESCENDANT);
                this.lastOptionFocused = null;
                this.lastOptionSelected = null;
            }
            if (!this.searchBar)
                this.hasPreviouslyBlurred = !!event.relatedTarget;
        };
        this.handleMouseDown = (event) => {
            event.preventDefault();
        };
        this.handleMenuKeyUp = (event) => {
            if (event.key === "Tab" && event.shiftKey) {
                this.preventClickOpen = false;
            }
            if (event.key === "Enter" && this.disabledOptionSelected) {
                this.disabledOptionSelected = false;
                event.stopImmediatePropagation();
            }
            if (event.key === "Shift") {
                this.shiftPressed = false;
            }
        };
        this.handleSelectAllClick = () => {
            var _a;
            this.keyboardNav = false;
            if (this.allowMenuFocus) {
                (_a = this.menu) === null || _a === void 0 ? void 0 : _a.focus();
            }
            this.emitSelectAllEvents();
            this.lastOptionFocused = null;
            this.lastOptionSelected = null;
        };
        this.handleSelectAllBlur = (event) => {
            var _a, _b, _c;
            this.host.classList.remove("ic-select-select-all-focused");
            const relatedTarget = event.relatedTarget;
            if (!((_a = this.menu) === null || _a === void 0 ? void 0 : _a.contains(relatedTarget)) &&
                !((_c = (_b = this.parentEl) === null || _b === void 0 ? void 0 : _b.shadowRoot) === null || _c === void 0 ? void 0 : _c.contains(relatedTarget))) {
                this.handleMenuChange(false, false);
            }
        };
        this.handleSelectAllFocus = () => {
            this.host.classList.add("ic-select-select-all-focused");
            this.lastOptionFocused = null;
            this.lastOptionSelected = null;
        };
        // Fix for Safari - select all button click was causing menu to close
        this.handleSelectAllMouseDown = (event) => {
            event.preventDefault();
        };
        // When shift key is being used to select contiguous options one by one on a multi-select
        // I.e. holding shift and pressing up and down arrow keys
        this.handleSingleShiftSelect = (event, optionToSelectIndex, options) => {
            if (this.multiSelect &&
                event.shiftKey &&
                !this.isOptionSelected(optionToSelectIndex)) {
                this.selectHighlightedOption(options, optionToSelectIndex);
                this.lastOptionSelected = optionToSelectIndex;
            }
        };
        // When shift key is being used to select multiple options at once on a multi-select
        // I.e. holding shift when selecting another option
        this.handleMultipleShiftSelect = (lastOptionInSelection, useFocusForSelection = false, firstOptionSelected = null) => {
            this.shiftPressed = false;
            const firstOptionInSelection = firstOptionSelected === null
                ? this.getFirstOptionInSelection(useFocusForSelection)
                : firstOptionSelected;
            if (firstOptionInSelection !== null) {
                const optionsToSelect = [];
                if (firstOptionInSelection < lastOptionInSelection) {
                    for (let i = firstOptionInSelection; i < lastOptionInSelection + 1; i++) {
                        optionsToSelect.push(i);
                    }
                }
                else {
                    for (let i = firstOptionInSelection; i > lastOptionInSelection - 1; i--) {
                        optionsToSelect.push(i);
                    }
                }
                optionsToSelect.forEach((optionIndex) => !this.isOptionSelected(optionIndex) && this.setInputValue(optionIndex));
                this.deselectSelectedOptions(optionsToSelect);
            }
        };
        this.handleOptionSelect = (event, optionIndex, useFocusForSelection = false) => {
            const menuOptions = this.getMenuOptions();
            const firstOptionInSelection = this.getFirstOptionInSelection(useFocusForSelection);
            if (event.shiftKey && firstOptionInSelection !== null) {
                this.handleMultipleShiftSelect(optionIndex, useFocusForSelection, firstOptionInSelection);
            }
            else {
                this.selectHighlightedOption(menuOptions, optionIndex);
            }
            this.lastOptionFocused = optionIndex;
            this.lastOptionSelected = optionIndex;
        };
        this.getFirstOptionInSelection = (useFocusForSelection) => {
            return useFocusForSelection && this.lastOptionFocused !== null
                ? this.lastOptionFocused
                : this.lastOptionSelected !== null
                    ? this.lastOptionSelected
                    : null;
        };
        this.emitSelectAllEvents = () => {
            var _a, _b;
            // Select all if there is either no value or not all options are selected
            // 'true' means select all, 'false' means clear all
            this.menuOptionSelectAll.emit({
                select: !this.value || !(((_a = this.value) === null || _a === void 0 ? void 0 : _a.length) === this.ungroupedOptions.length),
            });
            // Emit clear event if all options are selected
            if (((_b = this.value) === null || _b === void 0 ? void 0 : _b.length) === this.ungroupedOptions.length) {
                this.icClear.emit();
            }
        };
        this.emitMenuKeyPress = (isNavKey, key) => {
            this.menuKeyPress.emit({ isNavKey: isNavKey, key: key });
        };
        // Determines keyboard behaviour when selection is automatic
        // (i.e. you don't have to press Enter select an option - just focus on it)
        // and menu is focused
        this.autoSetValueOnMenuKeyDown = (event) => {
            var _a;
            event.cancelBubble = true;
            const selectedOptionIndex = this.ungroupedOptions.findIndex((option) => option[this.valueField] === this.value);
            const isSearchableSelect = !!this.inputEl && this.inputEl.tagName === "INPUT";
            this.keyboardNav = false;
            switch (event.key) {
                case " ":
                    event.preventDefault();
                    break;
                case "ArrowUp":
                    if (!this.hasTimedOut) {
                        event.preventDefault();
                        this.setPreviousOptionValue(selectedOptionIndex);
                        this.emitOptionId(selectedOptionIndex > 0
                            ? selectedOptionIndex - 1
                            : this.ungroupedOptions.length - 1);
                        this.keyboardNav = true;
                    }
                    break;
                case "ArrowDown":
                    if (!this.hasTimedOut) {
                        event.preventDefault();
                        this.setNextOptionValue(selectedOptionIndex);
                        this.emitOptionId(selectedOptionIndex < this.ungroupedOptions.length - 1
                            ? selectedOptionIndex + 1
                            : 0);
                        this.keyboardNav = true;
                    }
                    break;
                case "Home":
                    this.menuOptionSelect.emit({
                        value: this.ungroupedOptions[0][this.valueField],
                    });
                    this.emitOptionId(0);
                    this.keyboardNav = true;
                    break;
                case "End":
                    this.menuOptionSelect.emit({
                        value: this.ungroupedOptions[this.ungroupedOptions.length - 1][this.valueField],
                    });
                    this.emitOptionId(this.ungroupedOptions.length - 1);
                    this.keyboardNav = true;
                    break;
                case "Enter":
                    !this.hasTimedOut && this.handleMenuChange(false);
                    break;
                case "Escape":
                    this.handleMenuChange(false, !this.allowMenuFocus);
                    break;
                case "Backspace":
                    break;
                case "Shift":
                    break;
                default:
                    if (isSearchableSelect && event.key !== "Tab" && !this.hasTimedOut) {
                        (_a = this.inputEl) === null || _a === void 0 ? void 0 : _a.focus();
                    }
                    if (event.key.length === 1) {
                        this.keyboardNav = true;
                    }
                    break;
            }
            this.emitMenuKeyPress(this.keyboardNav, event.key);
        };
        this.getOptionId = (value) => {
            return `${this.menuId}-${value}`;
        };
        this.getOptionAriaLabel = (option, parentOption) => {
            let ariaLabel = option[this.labelField];
            if (option.description) {
                ariaLabel = `${ariaLabel}, ${option.description}`;
            }
            if (option.element) {
                ariaLabel = `${ariaLabel}, ${option.element.ariaLabel}`;
            }
            if (parentOption) {
                return `${ariaLabel}, ${parentOption[this.labelField]} group`;
            }
            else {
                return ariaLabel;
            }
        };
        this.getSortedOptions = (options) => {
            let sorted = [];
            if (options.sort) {
                sorted = options.sort((optionA, optionB) => optionA.recommended && !optionB.recommended ? -1 : 0);
            }
            return sorted;
        };
        this.getOptionHighlightedIndex = () => {
            const menuOptions = this.getMenuOptions();
            return menuOptions.findIndex((option) => option[this.valueField] === this.optionHighlighted);
        };
        this.isManualMode = this.activationType === "manual";
        // Scroll to highlighted option, or selected option if no highlighted option (i.e. when the menu opens)
        this.scrollToSelected = () => {
            var _a;
            const menu = this.menu;
            const selectedOption = this.selectOnEnter || this.searchableSelect || this.multiSelect
                ? this.host.querySelector(`li[data-value="${this.optionHighlighted}"]`)
                : menu.querySelector(".option[aria-selected='true']");
            if (selectedOption) {
                const menuRect = menu.getBoundingClientRect();
                const optionRect = selectedOption.getBoundingClientRect();
                if (optionRect.top < menuRect.top) {
                    menu.scrollTop -= menuRect.top - optionRect.top;
                }
                else if (optionRect.bottom > menuRect.bottom) {
                    menu.scrollTop += optionRect.bottom - menuRect.bottom;
                }
                // 'aria-activedescendant' affects screen reader focus
                // https://www.w3.org/TR/2017/WD-wai-aria-practices-1.1-20170628/#kbd_focus_activedescendant
                (_a = this.menu) === null || _a === void 0 ? void 0 : _a.setAttribute(this.ACTIVE_DESCENDANT, selectedOption.id);
                if (this.allowMenuFocus) {
                    selectedOption.focus();
                }
            }
        };
        // Set 'ungroupedOptions' variable and emit its value
        // - this is all the options with disabled options and group titles removed
        this.loadUngroupedOptions = () => {
            if (this.options.length > 0 && this.options.map) {
                this.options.map((option) => {
                    if (option.children) {
                        option.children.map((option) => !option.disabled && this.ungroupedOptions.push(option));
                    }
                    else if (!option.disabled) {
                        this.ungroupedOptions.push(option);
                    }
                });
            }
            this.ungroupedOptions = this.getSortedOptions(this.ungroupedOptions);
            this.ungroupedOptionsSet.emit({ options: this.ungroupedOptions });
        };
        this.setMenuScrollbar = () => {
            var _a;
            let optionsHeight = 0;
            this.host
                .querySelectorAll(".option, .option-group-title")
                .forEach((option) => (optionsHeight += option.clientHeight));
            if (optionsHeight >= 320) {
                (_a = this.menu) === null || _a === void 0 ? void 0 : _a.classList.add("menu-scroll");
            }
        };
        this.handleTimeoutBlur = (ev) => {
            this.timeoutBlur.emit({ ev });
        };
        this.optionContent = (option, selected) => {
            var _a;
            const showCheckIcon = !!option[this.valueField] &&
                !!this.value &&
                selected &&
                ((_a = this.parentEl) === null || _a === void 0 ? void 0 : _a.tagName) !== this.SEARCH_BAR_TAG;
            return (h(Fragment, null, option.loading && h("ic-loading-indicator", { size: "icon" }), h("div", { class: {
                    "option-text-container": true,
                    "show-check-icon": showCheckIcon,
                } }, (option.icon || !option.hideLabel) && (h("div", { class: "option-label" }, option.icon && (h("div", { class: "option-icon", innerHTML: sanitizeHTMLIconString(option.icon), "aria-hidden": "true" })), !option.hideLabel && (h("ic-typography", { variant: "body", "aria-hidden": "true" }, option[this.labelField])))), option.description && (h("ic-typography", { id: `${this.getOptionId(option[this.valueField])}-description`, class: "option-description", variant: "caption", "aria-hidden": "true" }, h("p", null, option.description))), option.element && (h("div", { class: {
                    "option-element": option.icon || !option.hideLabel || option.description,
                }, innerHTML: sanitizeHTMLString(option.element.component), "aria-hidden": "true" }))), showCheckIcon && (h("span", { class: "check-icon", innerHTML: Check, "aria-hidden": "true" }))));
        };
        this.displayOption = (option, selected, index, parentOption) => {
            var _a;
            const { open, keyboardNav, isManualMode, initialOptionsListRender, optionHighlighted, options, } = this;
            return (h("li", Object.assign({ id: this.getOptionId(option[this.valueField]), class: {
                    option: true,
                    "focused-option": isManualMode
                        ? (keyboardNav || initialOptionsListRender) &&
                            option[this.valueField] === optionHighlighted
                        : keyboardNav && selected,
                    "last-recommended-option": !!(option.recommended &&
                        options[index + 1] &&
                        !options[index + 1].recommended),
                    "disabled-option": !!option.disabled,
                    "loading-option": !!option.loading,
                    timeout: !!option.timedOut,
                }, role: "option", tabindex: !this.allowMenuFocus
                    ? "-1"
                    : open &&
                        (selected || option[this.valueField] === optionHighlighted) &&
                        keyboardNav
                        ? "0"
                        : "-1", "aria-label": this.getOptionAriaLabel(option, parentOption), "aria-selected": selected ? "true" : "false", "aria-disabled": option.disabled ? "true" : "false", onClick: !option.timedOut && !option.loading
                    ? this.handleOptionClick
                    : undefined, onBlur: this.handleBlur, onMouseDown: this.handleMouseDown, "data-value": option[this.valueField], "data-label": option[this.labelField] }, ((_a = option.htmlProps) !== null && _a !== void 0 ? _a : {})), option.timedOut ? (h(Fragment, null, h("div", { class: "loading-error-info" }, h("svg", { class: "error-icon-svg", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "#000000" }, h("title", null, "Error"), h("g", null, h("path", { d: "M8.77 3L3.5 8.27V15.73L8.77 21H16.23L21.5 15.73V8.27L16.23 3M8.91 7L12.5 10.59L16.09 7L17.5 8.41L13.91 12L17.5 15.59L16.09 17L12.5 13.41L8.91 17L7.5 15.59L11.09 12L7.5 8.41" }))), h("ic-typography", { variant: "label" }, option[this.labelField])), h("ic-button", { size: "small", variant: "tertiary", onClick: this.handleRetry, onKeyDown: this.handleRetryKeyDown, onBlur: this.handleTimeoutBlur, id: "retry-button" }, "Retry"))) : (this.optionContent(option, selected))));
        };
    }
    watchOpenHandler() {
        if (!this.open && this.popperInstance) {
            this.popperInstance.destroy();
            this.popperInstance = null;
        }
    }
    watchOptionsHandler(newOptions) {
        this.hasTimedOut = newOptions.some((opt) => opt.timedOut);
        this.isLoading = newOptions.some((opt) => opt.loading);
        this.ungroupedOptions = [];
        this.loadUngroupedOptions();
    }
    connectedCallback() {
        if (this.searchBar) {
            if (this.searchMode === "navigation")
                this.setHighlightedOption(0);
            this.initialOptionsListRender = true;
        }
    }
    disconnectedCallback() {
        var _a, _b, _c;
        (_a = this.popperInstance) === null || _a === void 0 ? void 0 : _a.destroy();
        (_b = this.parentEl) === null || _b === void 0 ? void 0 : _b.removeEventListener("icClear", this.handleClearListener);
        (_c = this.parentEl) === null || _c === void 0 ? void 0 : _c.removeEventListener("icSubmitSearch", this.handleSubmitSearch);
    }
    componentWillLoad() {
        var _a, _b, _c, _d;
        this.loadUngroupedOptions();
        (_a = this.parentEl) === null || _a === void 0 ? void 0 : _a.addEventListener("icClear", this.handleClearListener);
        (_b = this.parentEl) === null || _b === void 0 ? void 0 : _b.addEventListener("icSubmitSearch", this.handleSubmitSearch);
        this.hasTimedOut = (_c = this.options) === null || _c === void 0 ? void 0 : _c.some((opt) => opt.timedOut);
        this.isLoading = (_d = this.options) === null || _d === void 0 ? void 0 : _d.some((opt) => opt.loading);
    }
    componentDidLoad() {
        if (this.searchBar &&
            this.parentEl.disableAutoFiltering) {
            this.focusFromSearchKeypress = true;
        }
        onComponentRequiredPropUndefined([
            { prop: this.open, propName: "open" },
            { prop: this.options, propName: "options" },
            { prop: this.menuId, propName: "menu-id" },
            { prop: this.inputLabel, propName: "input-label" },
            //NOTE: no check for value, input-el or anchor-el as otherwise get console errors on first load of select component
        ], "Menu");
    }
    componentDidUpdate() {
        const inputValueInOptions = this.options.some((option) => option[this.valueField] === this.value);
        if (this.menu &&
            this.open &&
            this.options.length !== 0 &&
            !this.preventMenuFocus) {
            if (this.value &&
                this.keyboardNav &&
                inputValueInOptions &&
                this.autofocusOnSelected &&
                !this.searchableSelect) {
                this.scrollToSelected();
            }
            else if (!!this.optionHighlighted &&
                !this.focusFromSearchKeypress &&
                !this.preventIncorrectTabOrder) {
                const highlightedEl = this.host.querySelector(`li[data-value="${this.optionHighlighted}"]`);
                if (highlightedEl) {
                    this.menu.setAttribute(this.ACTIVE_DESCENDANT, highlightedEl.id);
                    if (this.allowMenuFocus) {
                        highlightedEl.focus();
                    }
                }
            }
            else if (this.inputEl &&
                this.inputEl.tagName !== "INPUT" &&
                this.allowMenuFocus) {
                this.menu.focus();
            }
        }
        if (this.menu && this.open) {
            this.scrollToSelected();
        }
        this.preventMenuFocus = false;
    }
    componentDidRender() {
        if (this.open && !this.popperInstance && this.anchorEl) {
            this.initPopperJs(this.anchorEl);
        }
        if (this.open && !!this.options.length) {
            this.setMenuScrollbar();
        }
    }
    /**
     * @internal If menu is opened with the mouse, emit menuStateChange custom event.
     */
    async handleClickOpen() {
        if (!this.preventClickOpen) {
            this.menuStateChange.emit({ open: !this.open });
            this.keyboardNav = false;
        }
        this.preventClickOpen = false;
    }
    /**
     * Used alongside activationType
     * If menu is opened via keyboard navigation (i.e. Enter, ArrowUp or ArrowDown), emit optionSelect custom event.
     * @param {KeyboardEvent} event The keyboard event which is available when handleKeyboardOpen is invoked.
     */
    async handleKeyboardOpen(event) {
        if (this.activationType === "automatic") {
            this.autoSetInputValueKeyboardOpen(event);
        }
        else {
            this.manualSetInputValueKeyboardOpen(event);
        }
    }
    /**
     * Used alongside activationType
     * If menu is open and user navigates options via keyboard, emit optionSelect custom event.
     * @param {KeyboardEvent} event The keyboard event which is available when handleMenuKeydown is invoked.
     */
    async handleMenuKeyDown(event) {
        if (this.activationType === "automatic") {
            this.autoSetValueOnMenuKeyDown(event);
        }
        else if (this.activationType === "manual" && !this.searchBar) {
            this.manualSetInputValueKeyboardOpen(event);
        }
    }
    /**
     * @internal Used to highlight the first option in the menu.
     */
    async handleSetFirstOption() {
        this.setHighlightedOption(0);
    }
    /**
     * @internal Used to initialize popperJS with an anchor element.
     * 5/12/2023: Tested with Floating UI, however, discovered inconsistent
     * boundary behaviour so sticking with PopperJS.
     */
    async initPopperJs(anchor) {
        // Placements set to "-start" to accommodate for custom menu width - menu should always be aligned to the left
        this.popperInstance = createPopper(anchor, this.host, Object.assign({ placement: "bottom-start", modifiers: [
                {
                    name: "offset",
                    options: {
                        offset: [0, 7],
                    },
                },
                {
                    name: "flip",
                    options: {
                        fallbackPlacements: ["top-start"],
                        rootBoundary: "viewport",
                    },
                },
            ] }, this.popperProps));
    }
    /**
     * @internal This method allows props to be added to the PopperJS createPopper instance outside of the menu
     * @param props object - createPopper props set externally
     */
    async setExternalPopperProps(props) {
        this.popperProps = props;
    }
    focusOnSearchOrSelectInput(menuOptions, highlightedOptionIndex) {
        if (!menuOptions[highlightedOptionIndex])
            return;
        if (this.searchBar) {
            this.parentEl.setFocus();
            if (this.searchMode === "navigation")
                this.setHighlightedOption(0);
        }
        if (this.searchableSelect) {
            this.parentEl.setFocus();
        }
        this.focusFromSearchKeypress = true;
    }
    render() {
        const { inputLabel, options, menuId, value, fullWidth, hasTimedOut, isLoading, size, open, inputEl, keyboardNav, parentEl, SEARCH_BAR_TAG, multiSelect, } = this;
        const selectAllButtonText = `${(value === null || value === void 0 ? void 0 : value.length) === this.ungroupedOptions.length ? "Clear" : "Select"} all`;
        const hasNoResults = this.host.classList.contains("no-results");
        return (h(Host, { key: '8b0e06f14c1979c3658e6e13fca3e4c6828c795d', class: {
                "ic-menu-full-width": !!fullWidth,
                "ic-menu-no-focus": ((inputEl === null || inputEl === void 0 ? void 0 : inputEl.tagName) === "INPUT" &&
                    (parentEl === null || parentEl === void 0 ? void 0 : parentEl.tagName) !== SEARCH_BAR_TAG) ||
                    hasTimedOut ||
                    isLoading,
                [`ic-menu-${size}`]: true,
                "ic-menu-open": open && options.length !== 0,
                "ic-menu-multiple": multiSelect,
            } }, options.length !== 0 && (h("ul", { key: '5af8ebaf798f09d020cab17adf4ef04e0fe2f9d4', id: menuId, class: "menu", role: "listbox", "aria-label": `${inputLabel} pop-up`, "aria-multiselectable": multiSelect ? "true" : "false", "aria-activedescendant": this.optionHighlighted
                ? this.getOptionId(this.optionHighlighted)
                : undefined, tabindex: !this.allowMenuFocus
                ? "-1"
                : open &&
                    !keyboardNav &&
                    ((inputEl === null || inputEl === void 0 ? void 0 : inputEl.tagName) !== "INPUT" ||
                        (parentEl === null || parentEl === void 0 ? void 0 : parentEl.tagName) === SEARCH_BAR_TAG)
                    ? "0"
                    : "-1", ref: (el) => (this.menu = el), onKeyDown: this.handleMenuKeyDown, onKeyUp: this.handleMenuKeyUp, onBlur: this.handleBlur }, this.getSortedOptions(options).map((option, index) => {
            if (option.children) {
                if (option.children.length > 0) {
                    return (h("div", null, h("ic-typography", { class: "option-group-title", role: "presentation", variant: "subtitle-small" }, h("p", null, option[this.labelField])), option.children.map((childOption) => childOption[this.labelField] &&
                        this.displayOption(childOption, multiSelect
                            ? value === null || value === void 0 ? void 0 : value.includes(childOption[this.valueField])
                            : childOption[this.valueField] === value, index, option))));
                }
                else {
                    return null;
                }
            }
            else {
                // Display option only if it has a label (rather than displaying an empty space)
                return (option[this.labelField] &&
                    this.displayOption(option, multiSelect
                        ? value === null || value === void 0 ? void 0 : value.includes(option[this.valueField])
                        : option[this.valueField] === value, index));
            }
        }))), options.length !== 0 &&
            multiSelect &&
            !isLoading &&
            !hasTimedOut &&
            !hasNoResults && (h("div", { key: 'f1a670781a41df910d8d55d2a956e062faf5a425', class: "option-bar" }, h("ic-typography", { key: '9687b26a0a275e9a6cff54180f2962d836ef4262' }, h("p", { key: '33e219ebba6ad3eb4ed60d77d9ed86551cb93a48' }, `${value ? value.length : 0}/${getOptionsWithoutGroupTitlesCount(this.options)} selected`)), h("ic-button", { key: '05e39e54ef176fb303ba59dcc3b91745cf38deef', class: "select-all-button", "aria-label": `${selectAllButtonText} options for ${inputLabel}`, ref: (el) => (this.selectAllButton = el), variant: "tertiary", onClick: this.handleSelectAllClick, onMouseDown: this.handleSelectAllMouseDown, onBlur: this.handleSelectAllBlur, onFocus: this.handleSelectAllFocus, size: size === "small" ? "small" : "medium" }, selectAllButtonText)))));
    }
    static get is() { return "ic-menu"; }
    static get encapsulation() { return "scoped"; }
    static get originalStyleUrls() {
        return {
            "$": ["ic-menu.css"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["ic-menu.css"]
        };
    }
    static get properties() {
        return {
            "activationType": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "IcActivationTypes",
                    "resolved": "\"automatic\" | \"manual\"",
                    "references": {
                        "IcActivationTypes": {
                            "location": "import",
                            "path": "../../utils/types",
                            "id": "src/utils/types.ts::IcActivationTypes"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Determines whether options manually set as values (by pressing 'Enter') when they receive focus using keyboard navigation."
                },
                "getter": false,
                "setter": false,
                "attribute": "activation-type",
                "reflect": false,
                "defaultValue": "\"automatic\""
            },
            "anchorEl": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "HTMLElement",
                    "resolved": "HTMLElement | undefined",
                    "references": {
                        "HTMLElement": {
                            "location": "global",
                            "id": "global::HTMLElement"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The reference to an anchor element the menu will position itself from when rendered."
                },
                "getter": false,
                "setter": false
            },
            "autofocusOnSelected": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "If `true`, autofocus will be applied on selected item when menu is open."
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "attribute": "autofocus-on-selected",
                "reflect": false,
                "defaultValue": "true"
            },
            "closeOnSelect": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If `true`, the menu will close when an option is selected."
                },
                "getter": false,
                "setter": false,
                "attribute": "close-on-select",
                "reflect": false,
                "defaultValue": "true"
            },
            "fullWidth": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If `true`, the menu will fill the width of the container."
                },
                "getter": false,
                "setter": false,
                "attribute": "full-width",
                "reflect": false,
                "defaultValue": "false"
            },
            "inputEl": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "HTMLElement",
                    "resolved": "HTMLElement | undefined",
                    "references": {
                        "HTMLElement": {
                            "location": "global",
                            "id": "global::HTMLElement"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The reference to the input element."
                },
                "getter": false,
                "setter": false
            },
            "inputLabel": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The label for the input element."
                },
                "getter": false,
                "setter": false,
                "attribute": "input-label",
                "reflect": false
            },
            "labelField": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The custom name for the label field for IcMenuOption."
                },
                "getter": false,
                "setter": false,
                "attribute": "label-field",
                "reflect": false,
                "defaultValue": "\"label\""
            },
            "menuId": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The ID of the menu."
                },
                "getter": false,
                "setter": false,
                "attribute": "menu-id",
                "reflect": false
            },
            "multiSelect": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "- flag to specify if menu is in a ic-select multiple."
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "attribute": "multi-select",
                "reflect": false,
                "defaultValue": "false"
            },
            "open": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If `true`, the menu will be displayed open."
                },
                "getter": false,
                "setter": false,
                "attribute": "open",
                "reflect": true
            },
            "parentEl": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "HTMLElement",
                    "resolved": "HTMLElement | undefined",
                    "references": {
                        "HTMLElement": {
                            "location": "global",
                            "id": "global::HTMLElement"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "- The parent element if ic-menu is nested inside another component."
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false
            },
            "searchableSelect": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "- flag to specify if menu is in a searchable ic-select."
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "attribute": "searchable-select",
                "reflect": false,
                "defaultValue": "false"
            },
            "searchBar": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "- flag to specify if menu is in a ic-search-bar."
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "attribute": "search-bar",
                "reflect": false,
                "defaultValue": "false"
            },
            "searchMode": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "IcSearchBarSearchModes",
                    "resolved": "\"navigation\" | \"query\"",
                    "references": {
                        "IcSearchBarSearchModes": {
                            "location": "import",
                            "path": "../ic-search-bar/ic-search-bar.types",
                            "id": "src/components/ic-search-bar/ic-search-bar.types.ts::IcSearchBarSearchModes"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Specify the mode search bar uses to search. `navigation` allows for quick lookups of a set of values, `query` allows for more general searches."
                },
                "getter": false,
                "setter": false,
                "attribute": "search-mode",
                "reflect": false,
                "defaultValue": "\"navigation\""
            },
            "selectOnEnter": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "If `true`, the icOptionSelect event will be fired on enter instead of ArrowUp and ArrowDown."
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "attribute": "select-on-enter",
                "reflect": false,
                "defaultValue": "false"
            },
            "size": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "IcSizes",
                    "resolved": "\"large\" | \"medium\" | \"small\"",
                    "references": {
                        "IcSizes": {
                            "location": "import",
                            "path": "../../utils/types",
                            "id": "src/utils/types.ts::IcSizes"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The size of the menu."
                },
                "getter": false,
                "setter": false,
                "attribute": "size",
                "reflect": false,
                "defaultValue": "\"medium\""
            },
            "options": {
                "type": "unknown",
                "mutable": false,
                "complexType": {
                    "original": "IcMenuOption[]",
                    "resolved": "IcMenuOption[]",
                    "references": {
                        "IcMenuOption": {
                            "location": "import",
                            "path": "../../utils/types",
                            "id": "src/utils/types.ts::IcMenuOption"
                        }
                    }
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The possible menu selection options."
                },
                "getter": false,
                "setter": false
            },
            "value": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string | string[]",
                    "resolved": "string | string[]",
                    "references": {}
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The value of the currently selected option - or array of values (if multiple options allowed)."
                },
                "getter": false,
                "setter": false,
                "attribute": "value",
                "reflect": false
            },
            "valueField": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The custom name for the value field for IcMenuOption."
                },
                "getter": false,
                "setter": false,
                "attribute": "value-field",
                "reflect": false,
                "defaultValue": "\"value\""
            },
            "allowMenuFocus": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "If `true`, allows the menu to receive focus when opened."
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "attribute": "allow-menu-focus",
                "reflect": false,
                "defaultValue": "true"
            }
        };
    }
    static get states() {
        return {
            "focusFromSearchKeypress": {},
            "initialOptionsListRender": {},
            "keyboardNav": {},
            "optionHighlighted": {},
            "preventIncorrectTabOrder": {},
            "menuOptions": {},
            "popperProps": {}
        };
    }
    static get events() {
        return [{
                "method": "icClear",
                "name": "icClear",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the clear all button is clicked."
                },
                "complexType": {
                    "original": "void",
                    "resolved": "void",
                    "references": {}
                }
            }, {
                "method": "menuKeyPress",
                "name": "menuKeyPress",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "Emitted when key is pressed while menu is open."
                        }],
                    "text": ""
                },
                "complexType": {
                    "original": "{ isNavKey: boolean; key: string }",
                    "resolved": "{ isNavKey: boolean; key: string; }",
                    "references": {}
                }
            }, {
                "method": "menuOptionId",
                "name": "menuOptionId",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "Emitted when an option has been highlighted."
                        }],
                    "text": ""
                },
                "complexType": {
                    "original": "IcMenuOptionIdEventDetail",
                    "resolved": "IcMenuOptionIdEventDetail",
                    "references": {
                        "IcMenuOptionIdEventDetail": {
                            "location": "import",
                            "path": "./ic-menu.types",
                            "id": "src/components/ic-menu/ic-menu.types.ts::IcMenuOptionIdEventDetail"
                        }
                    }
                }
            }, {
                "method": "menuOptionSelect",
                "name": "menuOptionSelect",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "Emitted when an option is selected."
                        }],
                    "text": ""
                },
                "complexType": {
                    "original": "IcOptionSelectEventDetail",
                    "resolved": "IcOptionSelectEventDetail",
                    "references": {
                        "IcOptionSelectEventDetail": {
                            "location": "import",
                            "path": "./ic-menu.types",
                            "id": "src/components/ic-menu/ic-menu.types.ts::IcOptionSelectEventDetail"
                        }
                    }
                }
            }, {
                "method": "menuOptionSelectAll",
                "name": "menuOptionSelectAll",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "Emitted when all options are selected or deselected."
                        }],
                    "text": ""
                },
                "complexType": {
                    "original": "{ select: boolean }",
                    "resolved": "{ select: boolean; }",
                    "references": {}
                }
            }, {
                "method": "menuStateChange",
                "name": "menuStateChange",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "Emitted when state of menu changes (i.e. open or closed)."
                        }],
                    "text": ""
                },
                "complexType": {
                    "original": "IcMenuChangeEventDetail",
                    "resolved": "IcMenuChangeEventDetail",
                    "references": {
                        "IcMenuChangeEventDetail": {
                            "location": "import",
                            "path": "./ic-menu.types",
                            "id": "src/components/ic-menu/ic-menu.types.ts::IcMenuChangeEventDetail"
                        }
                    }
                }
            }, {
                "method": "retryButtonClicked",
                "name": "retryButtonClicked",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "Emitted when the retry button is clicked."
                        }],
                    "text": ""
                },
                "complexType": {
                    "original": "IcMultiValueEventDetail",
                    "resolved": "IcMultiValueEventDetail",
                    "references": {
                        "IcMultiValueEventDetail": {
                            "location": "import",
                            "path": "../../utils/types",
                            "id": "src/utils/types.ts::IcMultiValueEventDetail"
                        }
                    }
                }
            }, {
                "method": "timeoutBlur",
                "name": "timeoutBlur",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "Emitted when the timeout menu loses focus."
                        }],
                    "text": ""
                },
                "complexType": {
                    "original": "{ ev: FocusEvent }",
                    "resolved": "{ ev: FocusEvent; }",
                    "references": {
                        "FocusEvent": {
                            "location": "global",
                            "id": "global::FocusEvent"
                        }
                    }
                }
            }, {
                "method": "ungroupedOptionsSet",
                "name": "ungroupedOptionsSet",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "Emitted when the ungrouped options have been set."
                        }],
                    "text": ""
                },
                "complexType": {
                    "original": "{ options: IcMenuOption[] }",
                    "resolved": "{ options: IcMenuOption[]; }",
                    "references": {
                        "IcMenuOption": {
                            "location": "import",
                            "path": "../../utils/types",
                            "id": "src/utils/types.ts::IcMenuOption"
                        }
                    }
                }
            }];
    }
    static get methods() {
        return {
            "handleClickOpen": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": "If menu is opened with the mouse, emit menuStateChange custom event."
                        }]
                }
            },
            "handleKeyboardOpen": {
                "complexType": {
                    "signature": "(event: KeyboardEvent) => Promise<void>",
                    "parameters": [{
                            "name": "event",
                            "type": "KeyboardEvent",
                            "docs": "The keyboard event which is available when handleKeyboardOpen is invoked."
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "KeyboardEvent": {
                            "location": "global",
                            "id": "global::KeyboardEvent"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Used alongside activationType\nIf menu is opened via keyboard navigation (i.e. Enter, ArrowUp or ArrowDown), emit optionSelect custom event.",
                    "tags": [{
                            "name": "param",
                            "text": "event The keyboard event which is available when handleKeyboardOpen is invoked."
                        }]
                }
            },
            "handleMenuKeyDown": {
                "complexType": {
                    "signature": "(event: KeyboardEvent) => Promise<void>",
                    "parameters": [{
                            "name": "event",
                            "type": "KeyboardEvent",
                            "docs": "The keyboard event which is available when handleMenuKeydown is invoked."
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "KeyboardEvent": {
                            "location": "global",
                            "id": "global::KeyboardEvent"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Used alongside activationType\nIf menu is open and user navigates options via keyboard, emit optionSelect custom event.",
                    "tags": [{
                            "name": "param",
                            "text": "event The keyboard event which is available when handleMenuKeydown is invoked."
                        }]
                }
            },
            "handleSetFirstOption": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": "Used to highlight the first option in the menu."
                        }]
                }
            },
            "initPopperJs": {
                "complexType": {
                    "signature": "(anchor: HTMLElement) => Promise<void>",
                    "parameters": [{
                            "name": "anchor",
                            "type": "HTMLElement",
                            "docs": ""
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "HTMLElement": {
                            "location": "global",
                            "id": "global::HTMLElement"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": "Used to initialize popperJS with an anchor element.\n5/12/2023: Tested with Floating UI, however, discovered inconsistent\nboundary behaviour so sticking with PopperJS."
                        }]
                }
            },
            "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 menu"
                        }, {
                            "name": "param",
                            "text": "props object - createPopper props set externally"
                        }]
                }
            }
        };
    }
    static get elementRef() { return "host"; }
    static get watchers() {
        return [{
                "propName": "open",
                "methodName": "watchOpenHandler"
            }, {
                "propName": "options",
                "methodName": "watchOptionsHandler"
            }];
    }
}
//# sourceMappingURL=ic-menu.js.map
