/*!
 * Custom elements for Nanopore-Digital Web applications
 */
import { Host, writeTask, Build, } from "@stencil/core";
import { h, transformTag } from "../../utils/renderer";
import { getActiveElement } from "../../utils/active-element";
import { debounce } from "../../utils/throttle";
import { getDirectChildren } from "../../utils/dom";
function findLabel(formCtrl) {
    let foundLabel;
    if (formCtrl.id) {
        foundLabel = document.querySelector(`label[for='${formCtrl.id}']`);
    }
    if (!foundLabel) {
        foundLabel = formCtrl.closest('label');
    }
    return foundLabel;
}
let listIds = 0;
/**
 * Represents a permissible or recommended list of options available to choose from within other controls.
 *
 * @version 2.0.0
 * @status stable
 *
 * @slot - use `<nano-option>` elements for more complex html. Alternatively use the `options` prop
 * @slot list-top - shows at the top of the list when there are options present
 * @slot list-bottom - shows at the bottom of the list when there are options present
 * @slot no-result - shown when there are no results otherwise nothing will be shown
 *
 * @part dropdown - the wrapping `nano-dropdown` element
 * @part main-menu - the main `nano-menu` element that holds the options
 * @part no-result-menu - the `nano-menu` element that holds the no results content
 */
export class DataList {
    // Private State
    isNanoInput = false;
    typeToSelect = '';
    typeToSelectTimeout;
    nanoDropdown;
    listBox;
    mo;
    listId = `nano-datalist-${listIds++}`;
    isFiltered = false;
    shouldFocus = false;
    // all potential option eles. Set via slot or `options` prop.
    // Some may get hidden due to filtering
    get allOptEles() {
        return this._allOptEles;
    }
    set allOptEles(opts) {
        // when allOptEles are initially set (on slot change / options) -
        // add options to 'selected' and fire selected event *if*
        // value isn't set on the input
        this._allOptEles = opts;
        if (this.connectedInput?.value)
            return;
        opts.forEach((opt) => {
            if (opt.selected && !this.selected.includes(opt.value)) {
                this.changeInputValue(opt);
            }
        });
    }
    _allOptEles = [];
    host;
    // active option eles that are not hidden.
    actvOptEles = [];
    connectedInput;
    inputLabel;
    hasNoResult;
    shouldOpen;
    canOpen = true;
    optionIds = [];
    constructor() {
        this.inputChange = debounce(this.inputChange.bind(this), 50);
    }
    // Public API
    /** By default, items in the list will appear 'selected' when the value in the linked input control matches.
     * However you can add other selected options via the the selected prop. */
    selected = [];
    /** nano-dropdown config options you can pass to the nested dropdown component */
    get dropDownConfig() {
        return this._dropDownConfig;
    }
    set dropDownConfig(ddc) {
        this._dropDownConfig = { ...this._dropDownConfig, ...ddc };
    }
    _dropDownConfig = {
        skidding: -1,
    };
    /** Provide an option list.
     * Options can be defined declaratively by nesting `<nano-option>` elements or imperatively using this prop */
    options = [];
    /** A selector to a HTMLInputElement */
    input;
    /** Tweaks the datalist behaviour and linked control semantics and behaviour.
     * e.g. 'select' will make the linked input control `readonly`.
     */
    type = 'input';
    /** return all the active options currently within the datalist. Can be useful for validation */
    get activeOptions() {
        return this.allOptEles;
    }
    /** Force datalist open */
    open = false;
    openWatcher() {
        writeTask(() => {
            if (this.open && this.nanoDropdown.tetherTo) {
                const { height, top } = this.nanoDropdown.tetherTo.getBoundingClientRect();
                this.nanoDropdown.style.setProperty('--max-height', `max(${window.innerHeight - (height + top + 40)}px, 48vw)`);
            }
            this.nanoDropdown.open = this.open;
            if (this.connectedInput) {
                this.connectedInput.setAttribute('aria-expanded', this.open.toString());
            }
        });
    }
    /** Use this option to disable to default filtering. This is useful if filtering happens
     * externally via another method (e.g. via ajax)
     */
    disableFilter = false;
    /** Activate / deactivate the datalist control */
    disabled = false;
    // State change watchers
    async watchInputChange() {
        let nanoInput;
        if ((nanoInput = this.host.closest(transformTag('nano-input')))) {
            this.isNanoInput = true;
            this.connectedInput = await nanoInput.getInputElement();
        }
        else if (this.input &&
            typeof this.input === 'string' &&
            (nanoInput = document.querySelector(this.input))) {
            this.isNanoInput = false;
            this.connectedInput = nanoInput;
        }
        else if (typeof this.input === 'object') {
            this.connectedInput = this.input;
        }
    }
    handleOptionsChange() {
        if (!this.host)
            return;
        getDirectChildren(this.host, ':not(nano-nav-item):not(nano-option):not([role])', true).forEach((el) => el.setAttribute('role', 'none'));
        // we're not using `options` - setup new MO
        if ((!this.options || !this.options.length) && !this.mo) {
            if (Build.isBrowser) {
                const mo = (this.mo = new MutationObserver(() => this.processSlottedContent()));
                mo.observe(this.host, { childList: true, subtree: true });
            }
            this.processSlottedContent();
            return;
        }
        // we're using `options` - trash current MO
        if (this.options?.length) {
            if (this.mo) {
                this.mo.disconnect();
                this.mo = undefined;
            }
            const previousOptions = this.host.querySelectorAll(transformTag('nano-option'));
            // add imperative `options`
            writeTask(() => {
                // clear all previous
                if (previousOptions?.length)
                    previousOptions.forEach((internalOpt) => internalOpt.remove());
                this.allOptEles = this.options.flatMap((option, i) => {
                    if (option.value || option.label) {
                        const opt = Object.assign(document.createElement(transformTag('nano-option')), {
                            label: option.label,
                            value: option.value,
                            ariaPosinset: i,
                            ariaSetsize: this.options.length,
                            selected: option.selected,
                            id: this.listId + '-option-' + i,
                            textContent: option.label ? option.label : option.value,
                            slot: 'internal-opts',
                        });
                        this.host.append(opt);
                        return opt;
                    }
                });
                if (this.connectedInput?.value.length && this.type !== 'select') {
                    this.inputChange();
                }
                else {
                    this.actvOptEles = [...this.allOptEles];
                }
            });
        }
        // forceUpdate(this.host);
    }
    watchTypeChange() {
        if (!this.connectedInput || this.disabled)
            return;
        let dwConfig = { closeOnSelect: false };
        let autocompleteType = 'both';
        let readonly = false;
        switch (this.type) {
            case 'input':
                dwConfig = { closeOnSelect: true };
                break;
            case 'select':
                autocompleteType = 'list';
                readonly = true;
                dwConfig = { closeOnSelect: true };
                break;
        }
        if (!this.isNanoInput) {
            dwConfig.tetherTo = this.connectedInput;
        }
        this.dropDownConfig = { ...this.dropDownConfig, ...dwConfig };
        this.connectedInput.setAttribute('aria-autocomplete', autocompleteType);
        this.connectedInput.readOnly = readonly;
    }
    manageInputEvents(newInput, oldInput) {
        if (oldInput) {
            const nanoInput = oldInput.closest(transformTag('nano-input'));
            if (nanoInput) {
                nanoInput.removeEventListener('nanoChange', this.inputChange);
            }
            this.removeEventListeners(oldInput);
            this.inputLabel = null;
            writeTask(() => {
                oldInput.removeAttribute('role');
                oldInput.removeAttribute('aria-expanded');
                oldInput.removeAttribute('aria-controls');
                oldInput.removeAttribute('aria-owns');
                oldInput.removeAttribute('aria-haspopup');
                oldInput.removeAttribute('aria-autocomplete');
                oldInput.removeAttribute('autocomplete');
            });
        }
        if (newInput) {
            const nanoInput = newInput.closest(transformTag('nano-input'));
            if (nanoInput) {
                nanoInput.addEventListener('nanoChange', this.inputChange);
            }
            newInput.addEventListener('change', this.inputChange);
            newInput.addEventListener('click', this.inputClick);
            newInput.addEventListener('keydown', this.inputKeydown);
            newInput.addEventListener('input', this.inputChange);
            this.listId = this.host.id || this.listId;
            this.inputLabel = newInput?.labels?.item(0) || findLabel(newInput);
            writeTask(() => {
                this.host.id = this.listId;
                newInput.setAttribute('role', 'combobox');
                newInput.setAttribute('aria-expanded', 'false');
                newInput.setAttribute('aria-controls', this.listId);
                newInput.setAttribute('aria-owns', this.listId);
                newInput.setAttribute('aria-haspopup', 'listbox');
                newInput.setAttribute('autocomplete', 'off');
            });
        }
    }
    watchActvOptChange() {
        let c = 0;
        const val = this.connectedInput?.value || '';
        const optIds = [];
        writeTask(() => {
            this.allOptEles.forEach((opt, i) => {
                if (this.actvOptEles.includes(opt)) {
                    c++;
                    opt.setAttribute('aria-posinset', c + '');
                    opt.setAttribute('aria-setsize', this.actvOptEles.length + '');
                    opt.hidden = false;
                    this.isSelected(opt, val);
                }
                else {
                    opt.removeAttribute('aria-posinset');
                    opt.removeAttribute('aria-setsize');
                    opt.hidden = true;
                    opt.selected = false;
                }
                opt.id = this.listId + '-option-' + i;
                optIds.push(opt.id);
            });
            this.optionIds = optIds;
        });
    }
    manageCanOpen() {
        if (this.actvOptEles.length || this.hasNoResult)
            this.canOpen = true;
        else
            this.canOpen = false;
    }
    /**
     * Opens the dropdown if it can, it should and there are items to display.
     */
    manageDropdownDisplay() {
        if (this.shouldOpen && this.canOpen && !this.disabled)
            this.open = true;
        if (!this.shouldOpen || !this.canOpen)
            this.open = false;
        this.openWatcher();
    }
    fireActiveOptsEvent() {
        this.nanoOptionsUpdated.emit(this.actvOptEles);
    }
    // Events
    /** Fired when an item is selected. */
    nanoSelect;
    /** Fired when a currently selected item is reselected. */
    nanoDeselect;
    /** Fired when active options change */
    nanoOptionsUpdated;
    // Private logic
    isSelected(opt, val) {
        if (!opt)
            return;
        if (val === opt.value || this.selected.includes(opt.value)) {
            opt.selected = true;
        }
        else
            opt.selected = false;
    }
    get dropwdownOpen() {
        if (!this.nanoDropdown || !this.open)
            return false;
        return true;
    }
    get exactMatch() {
        return this.allOptEles.find((opt) => this.connectedInput.value === opt.value);
    }
    /** reflect value back to the connected input unless the event is cancelled */
    changeInputValue(opt) {
        let nanoSelected;
        if (this.selected.includes(opt.value)) {
            // deselect option
            this.selected = this.selected.filter((val) => val !== opt.value);
            nanoSelected = this.nanoDeselect.emit(opt);
        }
        else {
            // select new option
            this.selected = [...this.selected];
            nanoSelected = this.nanoSelect.emit(opt);
        }
        if (!nanoSelected.defaultPrevented) {
            if (this.connectedInput)
                this.connectedInput.value = opt.value;
            const event = new window.Event('change');
            this.connectedInput?.dispatchEvent(event);
        }
    }
    // a new option has been picked
    optSelected = (e) => {
        e.stopPropagation();
        this.changeInputValue(e.detail);
        requestAnimationFrame(() => this.inputChange());
        if (this.type !== 'selectMulti')
            this.shouldOpen = false;
    };
    // this is for type="select" only.
    // Filter options that start with text - aggregates letters (as opposed to getting the value from input)
    setOptStartsWith() {
        const attrFind = (toFind) => toFind.toLowerCase().substring(0, this.typeToSelect.length) ===
            this.typeToSelect;
        const foundEle = this.allOptEles.find((opt) => opt.value.trim().length > 0 &&
            !opt.disabled &&
            (attrFind(opt.textContent) ||
                attrFind(opt.value) ||
                attrFind(opt.label) ||
                attrFind(opt.filterMeta)));
        if (foundEle)
            this.changeInputValue(foundEle);
    }
    // Event handlers
    removeEventListeners(oldInput) {
        const nanoInput = oldInput.closest(transformTag('nano-input'));
        if (nanoInput) {
            nanoInput.removeEventListener('nanoChange', this.inputChange);
        }
        oldInput.removeEventListener('change', this.inputChange);
        oldInput.removeEventListener('click', this.inputClick);
        oldInput.removeEventListener('keydown', this.inputKeydown);
        oldInput.removeEventListener('input', this.inputChange);
    }
    processSlottedContent() {
        requestAnimationFrame(() => {
            this.allOptEles = Array.from(this.host.querySelectorAll(transformTag('nano-option')));
            this.hasNoResult = !!this.host.querySelector('[slot="no-result"]');
            if (this.connectedInput?.value.length && this.type !== 'select') {
                this.inputChange();
            }
            else
                this.actvOptEles = this.allOptEles;
        });
    }
    // sets focus immediately on open when 'select' - mirroring native behaviour
    handleShow = async () => {
        if (this.shouldFocus) {
            this.shouldFocus = false;
            this.listBox.setFocus();
        }
        else if (this.type === 'select')
            this.listBox.showActiveElement();
    };
    handleHide = () => {
        this.open = false;
        const activeElement = getActiveElement();
        if (activeElement.closest(this.host.tagName.toLowerCase())) {
            this.connectedInput.select();
        }
    };
    // any changes to the connected input value will filter the list of active options
    inputChange() {
        if (!this.connectedInput)
            return;
        if (this.disableFilter) {
            this.actvOptEles = this.allOptEles;
            return;
        }
        const val = this.connectedInput?.value;
        const valStr = val.trim().toLowerCase();
        let exactMatch = false;
        const activeEles = [];
        const attrFind = (toFind) => toFind.toLowerCase().indexOf(valStr) > -1;
        this.allOptEles.forEach((opt) => {
            if ((val === opt.value || val === opt.label) &&
                this.type !== 'selectMulti') {
                opt.selected = true;
                exactMatch = true;
            }
            else
                this.isSelected(opt, val);
        });
        this.allOptEles.forEach((opt) => {
            if (!valStr.length || exactMatch) {
                activeEles.push(opt);
            }
            else if (opt.value.trim().length > 0 &&
                !opt.disabled &&
                (attrFind(opt.textContent) ||
                    attrFind(opt.value) ||
                    attrFind(opt.label) ||
                    attrFind(opt.filterMeta))) {
                activeEles.push(opt);
            }
        });
        this.isFiltered = valStr.length && !exactMatch;
        this.actvOptEles = activeEles;
    }
    inputClick = () => {
        if (this.open)
            return;
        this.shouldOpen = true;
        // open dropdown if possible
        this.manageDropdownDisplay();
    };
    inputKeydown = (e) => {
        const ignoreKeys = ['Shift', 'ArrowRight', 'ArrowLeft', 'Escape', 'Tab'];
        if (ignoreKeys.includes(e.key)) {
            if (e.key === 'Tab')
                this.shouldOpen = false;
            return;
        }
        // When select, mirror native select behaviour. Search on closed list
        if (this.type === 'select' &&
            !['ArrowDown', 'ArrowUp', 'Enter'].includes(e.key) &&
            (e.key !== ' ' || this.typeToSelectTimeout)) {
            if (e.key === ' ' || /^[a-zA0-9]+$/i.test(e.key)) {
                clearTimeout(this.typeToSelectTimeout);
                this.typeToSelectTimeout = window.setTimeout(() => {
                    this.typeToSelect = '';
                    this.typeToSelectTimeout = 0;
                }, 750);
                this.typeToSelect += e.key;
                this.setOptStartsWith();
            }
            return;
        }
        if (this.open && ['ArrowDown', 'ArrowUp'].includes(e.key)) {
            this.listBox.setFocus();
            return;
        }
        this.shouldOpen = true;
        // open dropdown if possible
        this.manageDropdownDisplay();
        if (['ArrowDown', 'ArrowUp', 'Enter'].includes(e.key)) {
            e.preventDefault();
            this.shouldFocus = true;
        }
    };
    // handles key down on options. Either 'picks'
    // an option or passes event back to input for search / filter
    optionKeyDown = (e) => {
        const ignoreKeys = [
            'Shift',
            'ArrowUp',
            'ArrowDown',
            'Escape',
            'Enter',
            'Tab',
            'Space',
            'PageUp',
            'PageDown',
            'Home',
            'End',
            ' ',
        ];
        if (ignoreKeys.includes(e.key)) {
            if (e.key === 'Escape')
                this.connectedInput.focus();
            return;
        }
        const deleteKeys = ['Delete', 'Backspace'];
        // this passes whatever's typed back to our input control
        if (this.type !== 'select' &&
            (!this.exactMatch || deleteKeys.includes(e.key))) {
            this.connectedInput.focus();
        }
    };
    // Component lifecycle
    connectedCallback() {
        this.watchInputChange();
    }
    componentDidLoad() {
        this.handleOptionsChange();
        this.openWatcher();
    }
    componentDidRender() {
        setTimeout(() => {
            if (!this.connectedInput && this.host.isConnected)
                console.warn('no `nano-input` found. `nano-datalist` should be nested within an `nano-input` or linked via `input` prop', this.host);
        }, 500);
    }
    disconnectedCallback() {
        if (this.mo) {
            this.mo.disconnect();
            this.mo = undefined;
        }
        if (this.connectedInput) {
            this.connectedInput = undefined;
        }
    }
    render() {
        return (h(Host, { key: '8acb3be76246d665171db96444cff3a5141e1132', class: "nano-datalist", role: this.actvOptEles.length ? 'listbox' : undefined, "aria-owns": this.optionIds.length ? this.optionIds.join(' ') : undefined, "aria-label": this.optionIds.length
                ? 'Select options from the list below'
                : undefined }, h("nano-dropdown", { key: '56c051873a20a3dab17a36eec1a2f040f83247fa', part: "dropdown", exportparts: "trigger:dropdown__trigger, panel:dropdown__panel", ...this.dropDownConfig, ref: (el) => (this.nanoDropdown = el), dialogTitle: "Select options from the list below", class: {
                dlist__dropdown: true,
                'dlist--isfiltered': this.isFiltered,
            }, onNanoAfterShow: this.handleShow, onNanoAfterHide: this.handleHide, role: "group" }, h("nano-menu", { key: '7559b648617c8d32f61c670e4dc78c0d60d36dc4', part: "main-menu", ref: (el) => (this.listBox = el), hidden: !this.actvOptEles.length, type: "listbox", label: this.inputLabel ? this.inputLabel.textContent : undefined, class: {
                dlist__menu: true,
                'dlist__menu--open': this.dropwdownOpen,
            }, tabIndex: -1, onNanoSelect: this.optSelected, onKeyDown: this.optionKeyDown }, h("slot", { key: '02bd8ba511db314637e8991d29234a22967cf27d', name: "list-top" }), h("slot", { key: 'cb0234e0dd103293c1f1292af62575dd766af730' }), h("slot", { key: '0adac42b20ee0338de74217e6e91c00be6b5b6a7', name: "internal-opts" }), h("slot", { key: '906255e4e6fdc87fa8bf6e278ad076f179553925', name: "list-bottom" })), h("nano-menu", { key: '9aa978054227c9bb928c06ce93303ceda48cbf29', part: "no-result-menu", type: "listbox", label: "No results found", hidden: !!this.actvOptEles.length, class: {
                dlist__menu: true,
                'dlist__menu--open': this.dropwdownOpen,
            } }, h("slot", { key: '4e2ce9dcb39d0c823ed27f13dc8c9a8873f0ca9f', name: "no-result" })), !!this.actvOptEles && (h("div", { key: 'c6bf0c88d7b1fcd24b2882c7db851ffca2e77ba3', class: "dlist__status" }, this.actvOptEles.length, " result", this.actvOptEles.length > 1 ? 's' : '', " available.")))));
    }
    static get is() { return "nano-datalist"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() {
        return {
            "$": ["datalist.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["datalist.css"]
        };
    }
    static get properties() {
        return {
            "selected": {
                "type": "unknown",
                "attribute": "selected",
                "mutable": true,
                "complexType": {
                    "original": "string[]",
                    "resolved": "string[]",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "By default, items in the list will appear 'selected' when the value in the linked input control matches.\nHowever you can add other selected options via the the selected prop."
                },
                "getter": false,
                "setter": false,
                "defaultValue": "[]"
            },
            "dropDownConfig": {
                "type": "unknown",
                "attribute": "drop-down-config",
                "mutable": false,
                "complexType": {
                    "original": "Partial<Dropdown>",
                    "resolved": "{ host?: HTMLNanoDropdownElement; autoOpen?: boolean; open?: boolean; handleOpenChange?: () => void; closeOnSelect?: boolean; containingElement?: HTMLElement; tetherTo?: HTMLElement; handleTetherToChange?: () => void; placement?: PopoverPlacement; distance?: number; skidding?: number; hoist?: boolean; handlePopoverOptionsChange?: () => void; dialogTitle?: string; nanoShow?: EventEmitter<any>; nanoAfterShow?: EventEmitter<any>; nanoHide?: EventEmitter<any>; nanoAfterHide?: EventEmitter<any>; eventType?: EventEmitter<any>; secondaryOpen?: (ev: CustomEvent<any>) => void; secondaryClose?: (ev: CustomEvent<any>) => void; handlePanelSelect?: (event: CustomEvent<any>) => void; show?: () => Promise<void>; hide?: () => Promise<void>; connectedCallback?: () => void; componentDidLoad?: () => void; disconnectedCallback?: () => void; render?: () => any; }",
                    "references": {
                        "Partial": {
                            "location": "global",
                            "id": "global::Partial"
                        },
                        "Dropdown": {
                            "location": "import",
                            "path": "../dropdown/dropdown",
                            "id": "src/components/dropdown/dropdown.tsx::Dropdown"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "nano-dropdown config options you can pass to the nested dropdown component"
                },
                "getter": true,
                "setter": true,
                "defaultValue": "{\n    skidding: -1,\n  }"
            },
            "options": {
                "type": "unknown",
                "attribute": "options",
                "mutable": false,
                "complexType": {
                    "original": "OptionInterface[]",
                    "resolved": "OptionInterface[]",
                    "references": {
                        "OptionInterface": {
                            "location": "import",
                            "path": "../option/option-interface",
                            "id": "src/components/option/option-interface.d.ts::OptionInterface"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Provide an option list.\nOptions can be defined declaratively by nesting `<nano-option>` elements or imperatively using this prop"
                },
                "getter": false,
                "setter": false,
                "defaultValue": "[]"
            },
            "input": {
                "type": "string",
                "attribute": "input",
                "mutable": false,
                "complexType": {
                    "original": "string | HTMLInputElement",
                    "resolved": "HTMLInputElement | string",
                    "references": {
                        "HTMLInputElement": {
                            "location": "global",
                            "id": "global::HTMLInputElement"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "A selector to a HTMLInputElement"
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "type": {
                "type": "string",
                "attribute": "type",
                "mutable": false,
                "complexType": {
                    "original": "'select' | 'selectMulti' | 'input'",
                    "resolved": "\"input\" | \"select\" | \"selectMulti\"",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Tweaks the datalist behaviour and linked control semantics and behaviour.\ne.g. 'select' will make the linked input control `readonly`."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "'input'"
            },
            "activeOptions": {
                "type": "unknown",
                "attribute": "active-options",
                "mutable": false,
                "complexType": {
                    "original": "HTMLNanoOptionElement[]",
                    "resolved": "HTMLNanoOptionElement[]",
                    "references": {
                        "HTMLNanoOptionElement": {
                            "location": "global",
                            "id": "global::HTMLNanoOptionElement"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "return all the active options currently within the datalist. Can be useful for validation"
                },
                "getter": true,
                "setter": false
            },
            "open": {
                "type": "boolean",
                "attribute": "open",
                "mutable": true,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Force datalist open"
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "defaultValue": "false"
            },
            "disableFilter": {
                "type": "boolean",
                "attribute": "disable-filter",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Use this option to disable to default filtering. This is useful if filtering happens\nexternally via another method (e.g. via ajax)"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "false"
            },
            "disabled": {
                "type": "boolean",
                "attribute": "disabled",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Activate / deactivate the datalist control"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "false"
            }
        };
    }
    static get states() {
        return {
            "actvOptEles": {},
            "connectedInput": {},
            "inputLabel": {},
            "hasNoResult": {},
            "shouldOpen": {},
            "canOpen": {},
            "optionIds": {}
        };
    }
    static get events() {
        return [{
                "method": "nanoSelect",
                "name": "nanoSelect",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Fired when an item is selected."
                },
                "complexType": {
                    "original": "HTMLNanoOptionElement",
                    "resolved": "HTMLNanoOptionElement",
                    "references": {
                        "HTMLNanoOptionElement": {
                            "location": "global",
                            "id": "global::HTMLNanoOptionElement"
                        }
                    }
                }
            }, {
                "method": "nanoDeselect",
                "name": "nanoDeselect",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Fired when a currently selected item is reselected."
                },
                "complexType": {
                    "original": "HTMLNanoOptionElement",
                    "resolved": "HTMLNanoOptionElement",
                    "references": {
                        "HTMLNanoOptionElement": {
                            "location": "global",
                            "id": "global::HTMLNanoOptionElement"
                        }
                    }
                }
            }, {
                "method": "nanoOptionsUpdated",
                "name": "nanoOptionsUpdated",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Fired when active options change"
                },
                "complexType": {
                    "original": "HTMLNanoOptionElement[]",
                    "resolved": "HTMLNanoOptionElement[]",
                    "references": {
                        "HTMLNanoOptionElement": {
                            "location": "global",
                            "id": "global::HTMLNanoOptionElement"
                        }
                    }
                }
            }];
    }
    static get elementRef() { return "host"; }
    static get watchers() {
        return [{
                "propName": "open",
                "methodName": "openWatcher"
            }, {
                "propName": "input",
                "methodName": "watchInputChange"
            }, {
                "propName": "options",
                "methodName": "handleOptionsChange"
            }, {
                "propName": "type",
                "methodName": "watchTypeChange"
            }, {
                "propName": "connectedInput",
                "methodName": "watchTypeChange"
            }, {
                "propName": "disabled",
                "methodName": "watchTypeChange"
            }, {
                "propName": "connectedInput",
                "methodName": "manageInputEvents"
            }, {
                "propName": "selected",
                "methodName": "watchActvOptChange"
            }, {
                "propName": "actvOptEles",
                "methodName": "watchActvOptChange"
            }, {
                "propName": "actvOptEles",
                "methodName": "manageCanOpen"
            }, {
                "propName": "hasNoResult",
                "methodName": "manageCanOpen"
            }, {
                "propName": "shouldOpen",
                "methodName": "manageDropdownDisplay"
            }, {
                "propName": "canOpen",
                "methodName": "manageDropdownDisplay"
            }, {
                "propName": "actvOptEles",
                "methodName": "fireActiveOptsEvent"
            }];
    }
}
