var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var IgcComboComponent_1;
import { html, LitElement, nothing } from 'lit';
import { property, query, queryAssignedElements, state, } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { addThemingController } from '../../theming/theming-controller.js';
import { addRootClickController } from '../common/controllers/root-click.js';
import { blazorAdditionalDependencies } from '../common/decorators/blazorAdditionalDependencies.js';
import { blazorIndirectRender } from '../common/decorators/blazorIndirectRender.js';
import { watch } from '../common/decorators/watch.js';
import { registerComponent } from '../common/definitions/register.js';
import { EventEmitterMixin } from '../common/mixins/event-emitter.js';
import { FormAssociatedRequiredMixin } from '../common/mixins/forms/associated-required.js';
import { createFormValueState } from '../common/mixins/forms/form-value.js';
import { partMap } from '../common/part-map.js';
import { addSafeEventListener, asArray, equal, findElementFromEventPath, first, isEmpty, } from '../common/util.js';
import IgcIconComponent from '../icon/icon.js';
import IgcInputComponent from '../input/input.js';
import IgcPopoverComponent from '../popover/popover.js';
import IgcValidationContainerComponent from '../validation-container/validation-container.js';
import IgcComboHeaderComponent from './combo-header.js';
import IgcComboItemComponent from './combo-item.js';
import IgcComboListComponent from './combo-list.js';
import { DataController } from './controllers/data.js';
import { NavigationController } from './controllers/navigation.js';
import { SelectionController } from './controllers/selection.js';
import { styles } from './themes/combo.base.css.js';
import { styles as shared } from './themes/shared/combo.common.css.js';
import { all } from './themes/themes.js';
import { comboValidators } from './validators.js';
let IgcComboComponent = IgcComboComponent_1 = class IgcComboComponent extends FormAssociatedRequiredMixin(EventEmitterMixin(LitElement)) {
    static register() {
        registerComponent(IgcComboComponent_1, IgcIconComponent, IgcComboListComponent, IgcComboItemComponent, IgcComboHeaderComponent, IgcInputComponent, IgcPopoverComponent, IgcValidationContainerComponent);
    }
    get __validators() {
        return comboValidators;
    }
    set data(value) {
        if (this._data === value) {
            return;
        }
        this._data = asArray(value);
        const pristine = this._pristine;
        this.value = asArray(this.value);
        this._pristine = pristine;
        this._state.runPipeline();
    }
    get data() {
        return this._data;
    }
    set singleSelect(value) {
        if (this._singleSelect === Boolean(value)) {
            return;
        }
        this._singleSelect = Boolean(value);
        this._selection.clear();
        if (this.hasUpdated) {
            this.updateValue();
            this.resetSearchTerm();
            this._navigation.active = -1;
        }
    }
    get singleSelect() {
        return this._singleSelect;
    }
    set valueKey(value) {
        this._valueKey = value;
        this._displayKey = this._displayKey ?? this._valueKey;
    }
    get valueKey() {
        return this._valueKey;
    }
    set displayKey(value) {
        this._displayKey = value;
        if (!this.filteringOptions.filterKey) {
            this.filteringOptions = { filterKey: this.displayKey };
        }
    }
    get displayKey() {
        return this._displayKey ?? this._valueKey;
    }
    set groupKey(value) {
        if (this._groupKey !== value) {
            this._groupKey = value;
            this._state.runPipeline();
        }
    }
    get groupKey() {
        return this._groupKey;
    }
    set groupSorting(value) {
        if (this._groupSorting !== value) {
            this._groupSorting = value;
            this._state.runPipeline();
        }
    }
    get groupSorting() {
        return this._groupSorting;
    }
    set filteringOptions(value) {
        const options = { ...this._filteringOptions, ...value };
        if (!equal(options, this._filteringOptions)) {
            this._filteringOptions = options;
            this._state.runPipeline();
        }
    }
    get filteringOptions() {
        return this._filteringOptions;
    }
    set disableFiltering(value) {
        this._disableFiltering = value;
        this.resetSearchTerm();
    }
    get disableFiltering() {
        return this._disableFiltering;
    }
    set value(items) {
        this._formValue.value = items;
        if (this.hasUpdated) {
            this._updateSelection();
            this.updateValue();
        }
    }
    get value() {
        return this._formValue.value;
    }
    _updateSelection() {
        this._selection.deselect();
        if (!isEmpty(this.value)) {
            this._selection.select(this.value);
        }
    }
    toggleDirectiveChange() {
        this._rootClickController.update();
    }
    constructor() {
        super();
        this._rootClickController = addRootClickController(this, {
            onHide: async () => {
                if (!this.handleClosing()) {
                    return;
                }
                this.open = false;
                await this.updateComplete;
                this.emitEvent('igcClosed');
            },
        });
        this._formValue = createFormValueState(this, {
            initialValue: [],
            transformers: {
                setValue: asArray,
                setDefaultValue: asArray,
            },
        });
        this._data = [];
        this._disableFiltering = false;
        this._singleSelect = false;
        this._groupSorting = 'asc';
        this._filteringOptions = {
            filterKey: this.displayKey,
            caseSensitive: false,
            matchDiacritics: false,
        };
        this._displayValue = '';
        this._state = new DataController(this);
        this._selection = new SelectionController(this, this._state);
        this._navigation = new NavigationController(this, this._state);
        this.outlined = false;
        this.autofocusList = false;
        this.placeholderSearch = 'Search';
        this.open = false;
        this.caseSensitiveIcon = false;
        this.itemTemplate = ({ item }) => html `${this.displayKey ? item[this.displayKey] : item}`;
        this.groupHeaderTemplate = ({ item }) => html `${this.groupKey && item[this.groupKey]}`;
        this.itemRenderer = (item, index) => {
            if (!item) {
                return html `${nothing}`;
            }
            if (this.groupKey && item.header) {
                return html `
        <igc-combo-header part="group-header">
          ${this.groupHeaderTemplate({ item: item.value })}
        </igc-combo-header>
      `;
            }
            const { id, position } = this._getActiveDescendantId(index);
            const active = this._navigation.active === index;
            const selected = this._selection.has(this.data.at(item.dataIndex));
            if (active) {
                this._activeDescendant = id;
            }
            return html `
      <igc-combo-item
        id=${id}
        part=${partMap({ item: true, selected, active })}
        aria-setsize=${this._state.dataState.length}
        aria-posinset=${position}
        exportparts="checkbox, checkbox-indicator, checked"
        .index=${index}
        ?active=${active}
        ?selected=${selected}
        ?hide-checkbox=${this.singleSelect}
      >
        ${this.itemTemplate({ item: item.value })}
      </igc-combo-item>
    `;
        };
        addThemingController(this, all);
        addSafeEventListener(this, 'blur', this._handleBlur);
        addSafeEventListener(this, 'focusin', this._handleFocusIn);
        this.addEventListener('keydown', this._navigation.navigateHost.bind(this._navigation));
    }
    async firstUpdated() {
        await this.updateComplete;
        this._updateSelection();
        this.updateValue(this.hasUpdated);
        this._pristine = true;
        this._state.runPipeline();
    }
    _restoreDefaultValue() {
        this._formValue.value = this._formValue.defaultValue;
        this._updateSelection();
        this.updateValue(true);
        this._validate();
    }
    _setDefaultValue(current) {
        this.defaultValue = JSON.parse(current ?? '[]');
    }
    _setFormValue() {
        if (isEmpty(this.value)) {
            super._setFormValue(null);
            return;
        }
        if (this.singleSelect) {
            super._setFormValue(`${first(this.value)}`);
            return;
        }
        if (this.name) {
            const value = new FormData();
            for (const item of this.value) {
                value.append(this.name, `${item}`);
            }
            super._setFormValue(value);
        }
    }
    resetSearchTerm() {
        this._state.searchTerm = '';
    }
    updateValue(initial = false) {
        if (isEmpty(this.data)) {
            return;
        }
        this._formValue.value = this._selection.getSelectedValuesByKey(this.valueKey);
        this._displayValue = this._selection
            .getSelectedValuesByKey(this.displayKey)
            .join(', ');
        this._setFormValue();
        if (!initial) {
            this._validate();
            this._list.requestUpdate();
        }
    }
    focus(options) {
        this._input.focus(options);
    }
    blur() {
        this._input.blur();
    }
    get selection() {
        return this._selection.asArray;
    }
    select(items) {
        this._selection.select(items);
        this.updateValue();
    }
    deselect(items) {
        this._selection.deselect(items);
        this.updateValue();
    }
    async handleMainInput({ detail }) {
        this._setTouchedState();
        this._show();
        this._state.searchTerm = detail;
        await this.updateComplete;
        const matchIndex = this._state.dataState.findIndex((i) => !i.header);
        this._navigation.active = detail ? matchIndex : -1;
        this._list.requestUpdate();
        this.clearSingleSelection();
    }
    _handleFocusIn() {
        this._setTouchedState();
    }
    _handleBlur() {
        if (this._selection.isEmpty) {
            this._displayValue = '';
            this.resetSearchTerm();
        }
        super._handleBlur();
    }
    handleSearchInput({ detail }) {
        this._state.searchTerm = detail;
    }
    handleOpening() {
        return this.emitEvent('igcOpening', { cancelable: true });
    }
    handleClosing() {
        return this.emitEvent('igcClosing', { cancelable: true });
    }
    async _show(emitEvent = true) {
        if (this.open || (emitEvent && !this.handleOpening())) {
            return false;
        }
        this.open = true;
        await this.updateComplete;
        if (emitEvent) {
            this.emitEvent('igcOpened');
        }
        if (!this.singleSelect) {
            this._list.focus();
        }
        if (!this.autofocusList) {
            this._searchInput.focus();
        }
        return true;
    }
    async show() {
        return await this._show(false);
    }
    async _hide(emitEvent = true) {
        if (!this.open || (emitEvent && !this.handleClosing())) {
            return false;
        }
        this.open = false;
        await this.updateComplete;
        if (emitEvent) {
            this.emitEvent('igcClosed');
        }
        this._navigation.active = -1;
        return true;
    }
    async hide() {
        return await this._hide(false);
    }
    _toggle(emit = true) {
        return this.open ? this._hide(emit) : this._show(emit);
    }
    async toggle() {
        return await this._toggle(false);
    }
    _getActiveDescendantId(index) {
        const position = index + 1;
        const id = this.id ? `${this.id}-item-${position}` : `item-${position}`;
        return { id, position };
    }
    listKeydownHandler(event) {
        const target = findElementFromEventPath(IgcComboListComponent.tagName, event);
        if (target) {
            this._navigation.navigateList(event, target);
        }
    }
    itemClickHandler(event) {
        this._setTouchedState();
        const target = findElementFromEventPath(IgcComboItemComponent.tagName, event);
        if (!target) {
            return;
        }
        this.toggleSelect(target.index);
        if (this.singleSelect) {
            this._input.focus();
            this._hide();
        }
        else {
            this._searchInput.focus();
        }
    }
    toggleSelect(index) {
        const { dataIndex } = this._state.dataState.at(index);
        this._selection.changeSelection(dataIndex);
        this._navigation.active = index;
        this.updateValue();
    }
    selectByIndex(index) {
        const { dataIndex } = this._state.dataState.at(index);
        this._selection.selectByIndex(dataIndex);
        this._navigation.active = index;
        this.updateValue();
    }
    clearSingleSelection() {
        const _selection = this._selection.asArray;
        const selection = first(_selection);
        if (selection) {
            const item = this.valueKey ? selection[this.valueKey] : selection;
            this._selection.deselect(item, !isEmpty(_selection));
            this._formValue.value = [];
        }
    }
    handleClearIconClick(e) {
        e.stopPropagation();
        if (this.singleSelect) {
            this.resetSearchTerm();
            this.clearSingleSelection();
        }
        else {
            this._selection.deselect([], true);
        }
        this.updateValue();
        this._navigation.active = -1;
    }
    handleMainInputKeydown(e) {
        this._setTouchedState();
        this._navigation.navigateMainInput(e, this._list);
    }
    handleSearchInputKeydown(e) {
        this._navigation.navigateSearchInput(e, this._list);
    }
    toggleCaseSensitivity() {
        this.filteringOptions = {
            caseSensitive: !this.filteringOptions.caseSensitive,
        };
    }
    _stopPropagation(e) {
        e.stopPropagation();
    }
    renderToggleIcon() {
        return html `
      <span
        slot="suffix"
        part=${partMap({
            'toggle-icon': true,
            filled: !isEmpty(this.value),
        })}
      >
        <slot name="toggle-icon">
          <igc-icon
            name=${this.open ? 'input_collapse' : 'input_expand'}
            collection="default"
            aria-hidden="true"
          ></igc-icon>
        </slot>
      </span>
    `;
    }
    renderClearIcon() {
        return html `
      <span
        slot="suffix"
        part="clear-icon"
        @click=${this.handleClearIconClick}
        ?hidden=${this._selection.isEmpty}
      >
        <slot name="clear-icon">
          <igc-icon
            name="input_clear"
            collection="default"
            aria-hidden="true"
          ></igc-icon>
        </slot>
      </span>
    `;
    }
    renderMainInput() {
        return html `
      <igc-input
        id="target"
        slot="anchor"
        role="combobox"
        aria-controls="dropdown"
        aria-owns="dropdown"
        aria-expanded=${this.open}
        aria-describedby="combo-helper-text"
        aria-disabled=${this.disabled}
        exportparts="container: input, input: native-input, label, prefix, suffix"
        @click=${this._toggle}
        placeholder=${ifDefined(this.placeholder)}
        label=${ifDefined(this.label)}
        @igcChange=${this._stopPropagation}
        @igcInput=${this.handleMainInput}
        @keydown=${this.handleMainInputKeydown}
        .value=${this._displayValue}
        .disabled=${this.disabled}
        .required=${this.required}
        .invalid=${this.invalid}
        .outlined=${this.outlined}
        .autofocus=${this.autofocus}
        ?readonly=${!this.singleSelect}
      >
        <span slot=${!isEmpty(this.inputPrefix) && 'prefix'}>
          <slot name="prefix"></slot>
        </span>
        ${this.renderClearIcon()}
        <span slot=${!isEmpty(this.inputSuffix) && 'suffix'}>
          <slot name="suffix"></slot>
        </span>
        ${this.renderToggleIcon()}
      </igc-input>
    `;
    }
    renderSearchInput() {
        return html `
      <div
        part="filter-input"
        ?hidden=${this.disableFiltering || this.singleSelect}
      >
        <igc-input
          .value=${this._state.searchTerm}
          part="search-input"
          placeholder=${this.placeholderSearch}
          exportparts="input: search-input"
          @igcInput=${this.handleSearchInput}
          @keydown=${this.handleSearchInputKeydown}
        >
          <igc-icon
            slot=${this.caseSensitiveIcon && 'suffix'}
            name="case_sensitive"
            collection="default"
            part=${partMap({
            'case-icon': true,
            active: this.filteringOptions.caseSensitive ?? false,
        })}
            @click=${this.toggleCaseSensitivity}
          ></igc-icon>
        </igc-input>
      </div>
    `;
    }
    renderEmptyTemplate() {
        return html `
      <div part="empty" ?hidden=${!isEmpty(this._state.dataState)}>
        <slot name="empty">The list is empty</slot>
      </div>
    `;
    }
    renderList() {
        return html `
      <div
        .inert=${!this.open}
        @keydown=${this.listKeydownHandler}
        part="list-wrapper"
      >
        ${this.renderSearchInput()}
        <div part="header">
          <slot name="header"></slot>
        </div>
        <igc-combo-list
          aria-multiselectable=${!this.singleSelect}
          id="dropdown"
          part="list"
          role="listbox"
          tabindex="0"
          aria-labelledby="target"
          aria-activedescendant=${ifDefined(this._activeDescendant)}
          .items=${this._state.dataState}
          .renderItem=${this.itemRenderer}
          ?hidden=${isEmpty(this._state.dataState)}
          @click=${this.itemClickHandler}
        >
        </igc-combo-list>
        ${this.renderEmptyTemplate()}
        <div part="footer">
          <slot name="footer"></slot>
        </div>
      </div>
    `;
    }
    renderHelperText() {
        return IgcValidationContainerComponent.create(this, {
            id: 'combo-helper-text',
            hasHelperText: true,
        });
    }
    render() {
        return html `
      <igc-popover ?open=${this.open} flip shift same-width>
        ${this.renderMainInput()} ${this.renderList()}
      </igc-popover>
      ${this.renderHelperText()}
    `;
    }
};
IgcComboComponent.tagName = 'igc-combo';
IgcComboComponent.styles = [styles, shared];
__decorate([
    state()
], IgcComboComponent.prototype, "_activeDescendant", void 0);
__decorate([
    state()
], IgcComboComponent.prototype, "_displayValue", void 0);
__decorate([
    queryAssignedElements({ slot: 'suffix' })
], IgcComboComponent.prototype, "inputSuffix", void 0);
__decorate([
    queryAssignedElements({ slot: 'prefix' })
], IgcComboComponent.prototype, "inputPrefix", void 0);
__decorate([
    query('[part="search-input"]')
], IgcComboComponent.prototype, "_searchInput", void 0);
__decorate([
    query('#target', true)
], IgcComboComponent.prototype, "_input", void 0);
__decorate([
    query(IgcComboListComponent.tagName, true)
], IgcComboComponent.prototype, "_list", void 0);
__decorate([
    property({ attribute: false })
], IgcComboComponent.prototype, "data", null);
__decorate([
    property({ type: Boolean, reflect: true })
], IgcComboComponent.prototype, "outlined", void 0);
__decorate([
    property({ type: Boolean, reflect: true, attribute: 'single-select' })
], IgcComboComponent.prototype, "singleSelect", null);
__decorate([
    property({ type: Boolean })
], IgcComboComponent.prototype, "autofocus", void 0);
__decorate([
    property({ type: Boolean, attribute: 'autofocus-list' })
], IgcComboComponent.prototype, "autofocusList", void 0);
__decorate([
    property()
], IgcComboComponent.prototype, "label", void 0);
__decorate([
    property()
], IgcComboComponent.prototype, "placeholder", void 0);
__decorate([
    property({ attribute: 'placeholder-search' })
], IgcComboComponent.prototype, "placeholderSearch", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], IgcComboComponent.prototype, "open", void 0);
__decorate([
    property({ attribute: 'value-key' })
], IgcComboComponent.prototype, "valueKey", null);
__decorate([
    property({ attribute: 'display-key' })
], IgcComboComponent.prototype, "displayKey", null);
__decorate([
    property({ attribute: 'group-key' })
], IgcComboComponent.prototype, "groupKey", null);
__decorate([
    property({ attribute: 'group-sorting' })
], IgcComboComponent.prototype, "groupSorting", null);
__decorate([
    property({ type: Object, attribute: 'filtering-options' })
], IgcComboComponent.prototype, "filteringOptions", null);
__decorate([
    property({ type: Boolean, attribute: 'case-sensitive-icon' })
], IgcComboComponent.prototype, "caseSensitiveIcon", void 0);
__decorate([
    property({ type: Boolean, attribute: 'disable-filtering' })
], IgcComboComponent.prototype, "disableFiltering", null);
__decorate([
    property({ attribute: false })
], IgcComboComponent.prototype, "itemTemplate", void 0);
__decorate([
    property({ attribute: false })
], IgcComboComponent.prototype, "groupHeaderTemplate", void 0);
__decorate([
    property({ type: Array })
], IgcComboComponent.prototype, "value", null);
__decorate([
    watch('open')
], IgcComboComponent.prototype, "toggleDirectiveChange", null);
IgcComboComponent = IgcComboComponent_1 = __decorate([
    blazorAdditionalDependencies('IgcIconComponent, IgcInputComponent'),
    blazorIndirectRender
], IgcComboComponent);
export default IgcComboComponent;
//# sourceMappingURL=combo.js.map