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 IgcSelectComponent_1;
import { html } from 'lit';
import { property, query, queryAssignedElements, state, } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { themes } from '../../theming/theming-decorator.js';
import { addKeybindings, altKey, arrowDown, arrowLeft, arrowRight, arrowUp, endKey, enterKey, escapeKey, homeKey, spaceBar, tabKey, } from '../common/controllers/key-bindings.js';
import { addRootScrollHandler } from '../common/controllers/root-scroll.js';
import { blazorAdditionalDependencies } from '../common/decorators/blazorAdditionalDependencies.js';
import { watch } from '../common/decorators/watch.js';
import { registerComponent } from '../common/definitions/register.js';
import { IgcBaseComboBoxLikeComponent, getActiveItems, getItems, getNextActiveItem, getPreviousActiveItem, setInitialSelectionState, } from '../common/mixins/combo-box.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 { findElementFromEventPath, isEmpty, isString, partNameMap, } 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 IgcSelectGroupComponent from './select-group.js';
import IgcSelectHeaderComponent from './select-header.js';
import IgcSelectItemComponent from './select-item.js';
import { styles } from './themes/select.base.css.js';
import { styles as shared } from './themes/shared/select.common.css.js';
import { all } from './themes/themes.js';
import { selectValidators } from './validators.js';
let IgcSelectComponent = IgcSelectComponent_1 = class IgcSelectComponent extends FormAssociatedRequiredMixin(EventEmitterMixin(IgcBaseComboBoxLikeComponent)) {
    static register() {
        registerComponent(IgcSelectComponent_1, IgcIconComponent, IgcInputComponent, IgcPopoverComponent, IgcSelectGroupComponent, IgcSelectHeaderComponent, IgcSelectItemComponent);
    }
    get _activeItems() {
        return Array.from(getActiveItems(this, IgcSelectItemComponent.tagName));
    }
    get __validators() {
        return selectValidators;
    }
    set value(value) {
        this._updateValue(value);
        const item = this.getItem(this._formValue.value);
        item ? this.setSelectedItem(item) : this.clearSelectedItem();
    }
    get value() {
        return this._formValue.value;
    }
    get items() {
        return Array.from(getItems(this, IgcSelectItemComponent.tagName));
    }
    get groups() {
        return Array.from(getItems(this, IgcSelectGroupComponent.tagName));
    }
    get selectedItem() {
        return this._selectedItem;
    }
    scrollStrategyChanged() {
        this._rootScrollController.update({ resetListeners: true });
    }
    openChange() {
        this._rootClickController.update();
        this._rootScrollController.update();
    }
    constructor() {
        super();
        this._searchTerm = '';
        this._lastKeyTime = 0;
        this._rootScrollController = addRootScrollHandler(this, {
            hideCallback: this.handleClosing,
        });
        this._selectedItem = null;
        this.outlined = false;
        this.distance = 0;
        this.placement = 'bottom-start';
        this.scrollStrategy = 'scroll';
        this._formValue = createFormValueState(this, {
            initialValue: undefined,
            transformers: {
                setValue: (value) => value || undefined,
                setDefaultValue: (value) => value || undefined,
            },
        });
        this._rootClickController.update({ hideCallback: this.handleClosing });
        addKeybindings(this, {
            skip: () => this.disabled,
            bindingDefaults: { preventDefault: true, triggers: ['keydownRepeat'] },
        })
            .set([altKey, arrowDown], this.altArrowDown)
            .set([altKey, arrowUp], this.altArrowUp)
            .set(arrowDown, this.onArrowDown)
            .set(arrowUp, this.onArrowUp)
            .set(arrowLeft, this.onArrowUp)
            .set(arrowRight, this.onArrowDown)
            .set(tabKey, this.onTabKey, { preventDefault: false })
            .set(escapeKey, this.onEscapeKey)
            .set(homeKey, this.onHomeKey)
            .set(endKey, this.onEndKey)
            .set(spaceBar, this.onSpaceBarKey)
            .set(enterKey, this.onEnterKey);
        this.addEventListener('keydown', this.handleSearch);
        this.addEventListener('focusin', this.handleFocusIn);
        this.addEventListener('focusout', this.handleFocusOut);
    }
    createRenderRoot() {
        const root = super.createRenderRoot();
        root.addEventListener('slotchange', () => this.requestUpdate());
        return root;
    }
    async firstUpdated() {
        await this.updateComplete;
        const selected = setInitialSelectionState(this.items);
        if (this.value && !selected) {
            this._selectItem(this.getItem(this.value), false);
        }
        if (selected && selected.value !== this.value) {
            this.defaultValue = selected.value;
            this._selectItem(selected, false);
        }
        if (this.autofocus) {
            this.focus();
        }
        this._updateValidity();
    }
    handleFocusIn({ relatedTarget }) {
        this._dirty = true;
        if (this.contains(relatedTarget) || this.open) {
            return;
        }
    }
    handleFocusOut({ relatedTarget }) {
        if (this.contains(relatedTarget)) {
            return;
        }
        this.checkValidity();
    }
    handleClick(event) {
        const item = findElementFromEventPath(IgcSelectItemComponent.tagName, event);
        if (item && this._activeItems.includes(item)) {
            this._selectItem(item);
        }
    }
    handleChange(item) {
        return this.emitEvent('igcChange', { detail: item });
    }
    handleSearch(event) {
        if (!/^.$/u.test(event.key)) {
            return;
        }
        event.preventDefault();
        const now = Date.now();
        if (now - this._lastKeyTime > 500) {
            this._searchTerm = '';
        }
        this._lastKeyTime = now;
        this._searchTerm += event.key.toLocaleLowerCase();
        const item = this._activeItems.find((item) => item.textContent?.trim().toLocaleLowerCase().startsWith(this._searchTerm));
        if (item) {
            this.open ? this.activateItem(item) : this._selectItem(item);
            this._activeItem.focus();
        }
    }
    handleAnchorClick() {
        super.handleAnchorClick();
        this.focusItemOnOpen();
    }
    onEnterKey() {
        this.open && this._activeItem
            ? this._selectItem(this._activeItem)
            : this.handleAnchorClick();
    }
    onSpaceBarKey() {
        if (!this.open) {
            this.handleAnchorClick();
        }
    }
    onArrowDown() {
        const item = getNextActiveItem(this.items, this._activeItem);
        this.open ? this._navigateToActiveItem(item) : this._selectItem(item);
    }
    onArrowUp() {
        const item = getPreviousActiveItem(this.items, this._activeItem);
        this.open ? this._navigateToActiveItem(item) : this._selectItem(item);
    }
    altArrowDown() {
        if (!this.open) {
            this._show(true);
            this.focusItemOnOpen();
        }
    }
    async altArrowUp() {
        if (this.open && (await this._hide(true))) {
            this._input.focus();
        }
    }
    async onEscapeKey() {
        if (await this._hide(true)) {
            this._input.focus();
        }
    }
    onTabKey(event) {
        if (this.open) {
            event.preventDefault();
            this._selectItem(this._activeItem ?? this._selectedItem);
            this._hide(true);
        }
    }
    onHomeKey() {
        const item = this._activeItems.at(0);
        this.open ? this._navigateToActiveItem(item) : this._selectItem(item);
    }
    onEndKey() {
        const item = this._activeItems.at(-1);
        this.open ? this._navigateToActiveItem(item) : this._selectItem(item);
    }
    handleClosing() {
        this._hide(true);
    }
    activateItem(item) {
        if (this._activeItem) {
            this._activeItem.active = false;
        }
        this._activeItem = item;
        this._activeItem.active = true;
    }
    setSelectedItem(item) {
        if (this._selectedItem) {
            this._selectedItem.selected = false;
        }
        this._selectedItem = item;
        this._selectedItem.selected = true;
        return this._selectedItem;
    }
    _selectItem(item, emit = true) {
        if (!item) {
            this.clearSelectedItem();
            this._updateValue();
            return null;
        }
        const shouldFocus = emit && this.open;
        const shouldHide = emit && !this.keepOpenOnSelect;
        if (this._selectedItem === item) {
            if (shouldFocus)
                this._input.focus();
            return this._selectedItem;
        }
        const newItem = this.setSelectedItem(item);
        this.activateItem(newItem);
        this._updateValue(newItem.value);
        if (emit)
            this.handleChange(newItem);
        if (shouldFocus)
            this._input.focus();
        if (shouldHide)
            this._hide(true);
        return this._selectedItem;
    }
    _navigateToActiveItem(item) {
        if (item) {
            this.activateItem(item);
            this._activeItem.focus({ preventScroll: true });
            item.scrollIntoView({ behavior: 'auto', block: 'nearest' });
        }
    }
    _updateValue(value) {
        this._formValue.setValueAndFormState(value);
        this._validate();
    }
    clearSelectedItem() {
        if (this._selectedItem) {
            this._selectedItem.selected = false;
        }
        this._selectedItem = null;
    }
    async focusItemOnOpen() {
        await this.updateComplete;
        (this._selectedItem || this._activeItem)?.focus();
    }
    getItem(value) {
        return this.items.find((item) => item.value === value);
    }
    focus(options) {
        this._input.focus(options);
    }
    blur() {
        this._input.blur();
    }
    reportValidity() {
        const valid = super.reportValidity();
        if (!valid)
            this._input.focus();
        return valid;
    }
    navigateTo(value) {
        const item = isString(value) ? this.getItem(value) : this.items[value];
        if (item) {
            this._navigateToActiveItem(item);
        }
        return item ?? null;
    }
    select(value) {
        const item = isString(value) ? this.getItem(value) : this.items[value];
        return item ? this._selectItem(item, false) : null;
    }
    clearSelection() {
        this._updateValue();
        this.clearSelectedItem();
    }
    renderInputSlots() {
        const prefixName = isEmpty(this._inputPrefix) ? '' : 'prefix';
        const suffixName = isEmpty(this._inputSuffix) ? '' : 'suffix';
        return html `
      <span slot=${prefixName}>
        <slot name="prefix"></slot>
      </span>

      <span slot=${suffixName}>
        <slot name="suffix"></slot>
      </span>
    `;
    }
    renderToggleIcon() {
        const parts = partNameMap({ 'toggle-icon': true, filled: this.value });
        const iconHidden = this.open && !isEmpty(this._expandedIconSlot);
        const iconExpandedHidden = !iconHidden;
        return html `
      <span slot="suffix" part=${parts} aria-hidden="true">
        <slot name="toggle-icon" ?hidden=${iconHidden}>
          <igc-icon
            name=${this.open ? 'input_collapse' : 'input_expand'}
            collection="default"
          ></igc-icon>
        </slot>
        <slot name="toggle-icon-expanded" ?hidden=${iconExpandedHidden}></slot>
      </span>
    `;
    }
    renderHelperText() {
        return IgcValidationContainerComponent.create(this, {
            id: 'select-helper-text',
            slot: 'anchor',
            hasHelperText: true,
        });
    }
    renderInputAnchor() {
        const value = this.selectedItem?.textContent?.trim();
        return html `
      <igc-input
        id="input"
        slot="anchor"
        role="combobox"
        readonly
        aria-controls="dropdown"
        aria-describedby="select-helper-text"
        aria-expanded=${this.open ? 'true' : 'false'}
        exportparts="container: input, input: native-input, label, prefix, suffix"
        tabIndex=${this.disabled ? -1 : 0}
        value=${ifDefined(value)}
        placeholder=${ifDefined(this.placeholder)}
        label=${ifDefined(this.label)}
        .disabled=${this.disabled}
        .required=${this.required}
        .invalid=${this.invalid}
        .outlined=${this.outlined}
        @click=${this.handleAnchorClick}
      >
        ${this.renderInputSlots()} ${this.renderToggleIcon()}
      </igc-input>

      ${this.renderHelperText()}
    `;
    }
    renderDropdown() {
        return html `<div part="base" .inert=${!this.open}>
      <div
        id="dropdown"
        role="listbox"
        part="list"
        aria-labelledby="input"
        @click=${this.handleClick}
      >
        <slot name="header"></slot>
        <slot></slot>
        <slot name="footer"></slot>
      </div>
    </div>`;
    }
    render() {
        return html `<igc-popover
      ?open=${this.open}
      flip
      shift
      same-width
      .offset=${this.distance}
      .placement=${this.placement}
      >${this.renderInputAnchor()} ${this.renderDropdown()}
    </igc-popover>`;
    }
};
IgcSelectComponent.tagName = 'igc-select';
IgcSelectComponent.styles = [styles, shared];
__decorate([
    state()
], IgcSelectComponent.prototype, "_selectedItem", void 0);
__decorate([
    state()
], IgcSelectComponent.prototype, "_activeItem", void 0);
__decorate([
    query(IgcInputComponent.tagName, true)
], IgcSelectComponent.prototype, "_input", void 0);
__decorate([
    queryAssignedElements({ slot: 'suffix' })
], IgcSelectComponent.prototype, "_inputSuffix", void 0);
__decorate([
    queryAssignedElements({ slot: 'prefix' })
], IgcSelectComponent.prototype, "_inputPrefix", void 0);
__decorate([
    queryAssignedElements({ slot: 'toggle-icon-expanded' })
], IgcSelectComponent.prototype, "_expandedIconSlot", void 0);
__decorate([
    property()
], IgcSelectComponent.prototype, "value", null);
__decorate([
    property({ reflect: true, type: Boolean })
], IgcSelectComponent.prototype, "outlined", void 0);
__decorate([
    property({ type: Boolean })
], IgcSelectComponent.prototype, "autofocus", void 0);
__decorate([
    property({ type: Number })
], IgcSelectComponent.prototype, "distance", void 0);
__decorate([
    property()
], IgcSelectComponent.prototype, "label", void 0);
__decorate([
    property()
], IgcSelectComponent.prototype, "placeholder", void 0);
__decorate([
    property()
], IgcSelectComponent.prototype, "placement", void 0);
__decorate([
    property({ attribute: 'scroll-strategy' })
], IgcSelectComponent.prototype, "scrollStrategy", void 0);
__decorate([
    watch('scrollStrategy', { waitUntilFirstUpdate: true })
], IgcSelectComponent.prototype, "scrollStrategyChanged", null);
__decorate([
    watch('open', { waitUntilFirstUpdate: true })
], IgcSelectComponent.prototype, "openChange", null);
IgcSelectComponent = IgcSelectComponent_1 = __decorate([
    themes(all),
    blazorAdditionalDependencies('IgcIconComponent, IgcInputComponent, IgcSelectGroupComponent, IgcSelectHeaderComponent, IgcSelectItemComponent')
], IgcSelectComponent);
export default IgcSelectComponent;
//# sourceMappingURL=select.js.map