'use strict';

var index = require('./index-BjHIBY-I.js');
var dom = require('./dom-BWMDM6En.js');
var keycodes = require('./keycodes-B75-uKOK.js');
var randomString = require('./random-string-BTzDB2ee.js');
var getIconProps = require('./get-icon-props-CwpDdQDI.js');
var debounce = require('./debounce-DgDnRSlt.js');
require('./isObject-B6Osvvqp.js');
require('./toNumber-v-1DEwWD.js');
require('./isSymbol-DxAVNJfH.js');
require('./isObjectLike-Dlpn-j-1.js');

const pickerCss = () => `:host{position:relative;display:block}:host([hidden]){display:none}`;

const SEARCH_DEBOUNCE = 300;
const CHIP_SET_TAG_NAME = 'limel-chip-set';
const DEFAULT_SEARCHER_MAX_RESULTS = 20;
const Picker = class {
    constructor(hostRef) {
        index.registerInstance(this, hostRef);
        this.change = index.createEvent(this, "change");
        this.interact = index.createEvent(this, "interact");
        this.action = index.createEvent(this, "action");
        /**
         * True if the picker should be disabled
         */
        this.disabled = false;
        /**
         * Set to `true` to disable adding and removing items,
         * but allow interaction with existing items.
         */
        this.readonly = false;
        /**
         * True if the control requires a value
         */
        this.required = false;
        /**
         * Set to `true` to indicate that the current value of the input field is
         * invalid.
         */
        this.invalid = false;
        /**
         * Only used if no `searcher` is provided. The picker will then use a
         * default search function that filters the `allItems` based on the
         * `text` and `secondaryText` properties of the items.
         * This way, custom search functions are typically only needed when the
         * search is done on the server.
         * For performance reasons, the default searcher will never return more
         * than 20 items, but if there are more than 20 items, the rest can be
         * found by typing more characters in the search field.
         */
        this.allItems = [];
        /**
         * True if multiple values are allowed
         */
        this.multiple = false;
        /**
         * Sets delimiters between chips. Works only when `multiple` is `true`.
         */
        this.delimiter = null;
        /**
         * Static actions that can be clicked by the user.
         */
        this.actions = [];
        /**
         * Position of the custom static actions in the picker's results dropdown.
         * Can be set to `'top'` or `'bottom'`.
         */
        this.actionPosition = 'bottom';
        /**
         * Scroll behavior of the custom static actions, when user scrolls
         * in the picker's results dropdown. Can be set to `'scroll'` which means
         * the action items will scroll together with the list, or `'sticky'` which
         * retains their position at the top or bottom of the drop down while
         * scrolling.
         */
        this.actionScrollBehavior = 'sticky';
        /**
         * Whether badge icons should be used in the result list or not
         */
        this.badgeIcons = false;
        this.textValue = '';
        this.loading = false;
        this.chips = [];
        // Should NOT be decorated with State(), since this
        // should not trigger a re-render by itself.
        this.chipSetEditMode = false;
        this.getValueId = (item) => {
            const value = item.value;
            if (!!value && typeof value === 'object') {
                return value.id;
            }
            return value;
        };
        this.createChips = (value) => {
            if (!value) {
                return [];
            }
            if (this.multiple) {
                const listItems = value;
                return listItems.map(this.createChip);
            }
            const listItem = value;
            return [this.createChip(listItem)];
        };
        this.createChip = (listItem) => {
            const name = getIconProps.getIconName(listItem.icon);
            const color = getIconProps.getIconFillColor(listItem.icon, listItem.iconColor);
            const valueId = this.getValueId(listItem);
            return {
                id: `${valueId}`,
                text: listItem.text,
                removable: true,
                icon: name ? { name: name, color: color } : undefined,
                image: listItem.image,
                value: listItem,
                menuItems: listItem.actions,
            };
        };
        this.search = async (query) => {
            const timeoutId = setTimeout(() => {
                this.loading = true;
            });
            const searcher = this.searcher || this.defaultSearcher;
            const result = (await searcher(this.textValue));
            // If the search function resolves immediately,
            // the loading spinner will not be shown.
            clearTimeout(timeoutId);
            this.handleSearchResult(query, result);
        };
        this.defaultSearcher = async (query) => {
            if (query === '') {
                return this.allItems.slice(0, DEFAULT_SEARCHER_MAX_RESULTS);
            }
            const filteredItems = this.allItems.filter((item) => {
                let searchText = item.text.toLowerCase();
                if (item.secondaryText) {
                    searchText =
                        searchText + ' ' + item.secondaryText.toLowerCase();
                }
                return searchText.includes(query.toLowerCase());
            });
            return filteredItems.slice(0, DEFAULT_SEARCHER_MAX_RESULTS);
        };
        this.handleTextInput = this.handleTextInput.bind(this);
        this.handleInputKeyDown = this.handleInputKeyDown.bind(this);
        this.handleDropdownKeyDown = this.handleDropdownKeyDown.bind(this);
        this.handleInputFieldFocus = this.handleInputFieldFocus.bind(this);
        this.handleChange = this.handleChange.bind(this);
        this.handleInteract = this.handleInteract.bind(this);
        this.handleListChange = this.handleListChange.bind(this);
        this.handleActionListChange = this.handleActionListChange.bind(this);
        this.handleStopEditAndBlur = this.handleStopEditAndBlur.bind(this);
        this.handleCloseMenu = this.handleCloseMenu.bind(this);
        this.onListKeyDown = this.onListKeyDown.bind(this);
        this.portalId = randomString.createRandomString();
        this.debouncedSearch = debounce.debounce(this.search, SEARCH_DEBOUNCE);
    }
    componentWillLoad() {
        this.chips = this.createChips(this.value);
    }
    componentDidLoad() {
        this.chipSet = this.host.shadowRoot.querySelector(CHIP_SET_TAG_NAME);
        this.updateTabIndex();
    }
    disconnectedCallback() {
        this.debouncedSearch.cancel();
    }
    onDisabledChange() {
        this.updateTabIndex();
    }
    updateTabIndex() {
        if (this.disabled || this.readonly) {
            this.host.setAttribute('tabindex', '-1');
            return;
        }
        this.host.setAttribute('tabindex', '0');
    }
    async componentWillUpdate() {
        this.chipSetEditMode = false;
        if (this.chipSet) {
            this.chipSetEditMode = await this.chipSet.getEditMode();
        }
    }
    render() {
        const props = {};
        if (!this.multiple) {
            props.maxItems = 1;
        }
        return [
            index.h("limel-chip-set", Object.assign({ key: '4f760b3049b45f6db36e19fd776479dcef11403f', type: "input", inputType: "search", label: this.label, helperText: this.helperText, leadingIcon: this.leadingIcon, value: this.chips, disabled: this.disabled, invalid: this.invalid, delimiter: this.renderDelimiter(), readonly: this.readonly, required: this.required, searchLabel: this.searchLabel, onInput: this.handleTextInput, onKeyDown: this.handleInputKeyDown, onChange: this.handleChange, onInteract: this.handleInteract, onStartEdit: this.handleInputFieldFocus, onStopEdit: this.handleStopEditAndBlur, emptyInputOnBlur: false, clearAllButton: this.multiple && !this.chipSetEditMode }, props)),
            this.renderDropdown(),
        ];
    }
    onChangeValue() {
        this.chips = this.createChips(this.value);
    }
    renderDelimiter() {
        if (this.multiple) {
            return this.delimiter;
        }
        return null;
    }
    /**
     * Renders the dropdown with the items to pick from, or a spinner if the picker
     * is waiting for items to be received
     *
     * @returns picker dropdown
     */
    renderDropdown() {
        const dropDownContent = this.getDropdownContent();
        const content = [];
        if (this.shouldShowDropDownContent()) {
            const actionContent = this.getActionContent();
            if (this.actionPosition === 'top') {
                content.push(actionContent);
            }
            if (dropDownContent) {
                content.push(dropDownContent);
            }
            if (this.actionPosition === 'bottom') {
                content.push(actionContent);
            }
        }
        return this.renderPortal(content);
    }
    getActionContent() {
        var _a, _b;
        const actionCount = (_b = (_a = this.actions) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
        if (actionCount === 0) {
            return null;
        }
        return [
            index.h("limel-list", { class: {
                    'static-actions-list': true,
                    'is-on-top': this.actionPosition === 'top',
                    'is-at-bottom': this.actionPosition === 'bottom',
                    'has-position-sticky': this.actionScrollBehavior === 'sticky',
                }, badgeIcons: true, type: 'selectable', onChange: this.handleActionListChange, items: this.actions.map(this.removeUnusedPropertiesOnAction) }),
        ];
    }
    removeUnusedPropertiesOnAction(action) {
        return Object.assign(Object.assign({}, action), { actions: [] });
    }
    shouldShowDropDownContent() {
        if (this.isFull()) {
            return false;
        }
        return !!this.chipSetEditMode;
    }
    getDropdownContent() {
        var _a;
        if (!this.shouldShowDropDownContent()) {
            return;
        }
        if (this.loading) {
            return this.renderSpinner();
        }
        if (!((_a = this.items) === null || _a === void 0 ? void 0 : _a.length)) {
            return this.renderEmptyMessage();
        }
        return this.renderListResult();
    }
    /**
     * Returns true if the picker is "full"
     * The picker is considered to be full if it has a value and only one is allowed
     *
     * @returns true if the picker is full
     */
    isFull() {
        return !this.multiple && !!this.value;
    }
    renderSpinner() {
        return (index.h("div", { style: {
                width: '100%',
                display: 'flex',
                'align-items': 'center',
                'justify-content': 'center',
                padding: '1rem 0',
            } }, index.h("limel-spinner", { limeBranded: false })));
    }
    renderEmptyMessage() {
        if (!this.emptyResultMessage) {
            return;
        }
        const style = {
            color: 'rgb(var(--contrast-1100))',
            'text-align': 'center',
            margin: '0.5rem 1rem',
        };
        return index.h("p", { style: style }, this.emptyResultMessage);
    }
    renderListResult() {
        return (index.h("limel-list", { badgeIcons: this.badgeIcons, onChange: this.handleListChange, onKeyDown: this.onListKeyDown, type: "selectable", items: this.items }));
    }
    onListKeyDown(event) {
        const keyFound = [keycodes.TAB, keycodes.ESCAPE, keycodes.ENTER].includes(event.key);
        if (keyFound) {
            this.chipSet.setFocus();
        }
    }
    renderPortal(content = []) {
        const dropdownZIndex = getComputedStyle(this.host).getPropertyValue('--dropdown-z-index');
        return (index.h("limel-portal", { visible: content.length > 0, containerId: this.portalId, inheritParentWidth: true, containerStyle: { 'z-index': dropdownZIndex } }, index.h("limel-menu-surface", { open: content.length > 0, allowClicksElement: this.host, style: {
                '--menu-surface-width': '100%',
                'max-height': 'inherit',
                display: 'flex',
            }, onDismiss: this.handleCloseMenu }, content)));
    }
    /**
     * Check if a descendant still has focus. If not, reset text value and search result.
     */
    handleStopEditAndBlur() {
        // In browsers where shadow DOM is not supported activeElement on shadowRoot will return null
        // However, document.activeElement will return the actual focused element instead of the outermost shadow host
        const element = this.host.shadowRoot.activeElement || document.activeElement;
        const portalElement = document.querySelector(`#${this.portalId}`);
        if (dom.isDescendant(element, this.host) ||
            dom.isDescendant(element, portalElement)) {
            return;
        }
        this.clearInputField();
    }
    /**
     * Input handler for the input field
     *
     * @param event - event
     */
    async handleTextInput(event) {
        event.stopPropagation();
        const query = event.detail;
        this.textValue = query;
        this.debouncedSearch(query);
        // If the search-query is an empty string, bypass debouncing.
        if (query === '') {
            this.debouncedSearch.flush();
        }
    }
    /**
     * Change handler for the list
     *
     * @param event - event
     */
    handleListChange(event) {
        var _a;
        event.stopPropagation();
        if (!this.value || this.value !== event.detail) {
            let newValue = event.detail;
            if (this.multiple) {
                newValue = [
                    ...this.value,
                    event.detail,
                ];
            }
            this.change.emit(newValue);
            this.items = [];
        }
        if (this.multiple) {
            this.textValue = '';
            (_a = this.chipSet) === null || _a === void 0 ? void 0 : _a.setFocus(true);
        }
    }
    /**
     * Change handler for the list
     *
     * @param event - event
     */
    handleActionListChange(event) {
        event.stopPropagation();
        if (!event.detail) {
            return;
        }
        this.action.emit(event.detail.value);
        this.items = [];
    }
    /**
     * Focus handler for the chip set
     * Prevent focus if the picker has a value and does not support multiple values
     */
    handleInputFieldFocus() {
        const query = this.textValue;
        this.debouncedSearch(query);
    }
    handleChange(event) {
        event.stopPropagation();
        let newValue = null;
        if (this.multiple) {
            const chips = event.detail;
            newValue = chips.map((chip) => {
                return this.value.find((item) => {
                    const valueId = this.getValueId(item);
                    return `${valueId}` === chip.id;
                });
            });
        }
        this.change.emit(newValue);
    }
    handleInteract(event) {
        event.stopPropagation();
        this.interact.emit(event.detail ? event.detail.value : event.detail);
    }
    /**
     * Key handler for the input field
     * Will change focus to the first/last item in the dropdown list to enable selection with the keyboard
     *
     * @param event - event
     */
    handleInputKeyDown(event) {
        const isForwardTab = event.key === keycodes.TAB &&
            !event.altKey &&
            !event.metaKey &&
            !event.shiftKey;
        const isUp = event.key === keycodes.ARROW_UP;
        const isDown = event.key === keycodes.ARROW_DOWN;
        if (!isForwardTab && !isUp && !isDown) {
            return;
        }
        const list = document.querySelector(` #${this.portalId} limel-list`);
        if (!list) {
            return;
        }
        event.preventDefault();
        if (isForwardTab || isDown) {
            const listElement = list.shadowRoot.querySelector('.mdc-deprecated-list-item:first-child');
            listElement.focus();
            return;
        }
        if (isUp) {
            const listElement = list.shadowRoot.querySelector('.mdc-deprecated-list-item:last-child');
            listElement.focus();
        }
    }
    /**
     * Key handler for the dropdown
     *
     * @param event - event
     */
    handleDropdownKeyDown(event) {
        const isEscape = event.key === keycodes.ESCAPE;
        if (isEscape) {
            event.preventDefault();
            this.textValue = '';
            this.chipSet.setFocus(true);
        }
    }
    handleSearchResult(query, result) {
        if (query === this.textValue) {
            this.items = result;
            if (this.multiple) {
                const values = this.value;
                this.items = result.filter((item) => {
                    return !values.includes(item);
                });
            }
            this.loading = false;
        }
    }
    handleCloseMenu() {
        if (this.items.length > 0) {
            return;
        }
        this.clearInputField();
    }
    clearInputField() {
        this.chipSet.emptyInput();
        this.textValue = '';
        this.handleSearchResult('', []);
        this.debouncedSearch.cancel();
    }
    static get delegatesFocus() { return true; }
    get host() { return index.getElement(this); }
    static get watchers() { return {
        "disabled": [{
                "onDisabledChange": 0
            }],
        "value": [{
                "onChangeValue": 0
            }]
    }; }
};
Picker.style = pickerCss();

exports.limel_picker = Picker;
