'use client';
import { __decorate } from 'tslib';
import { html, nothing } from 'lit';
import { queryAssignedElements } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { ref } from 'lit/directives/ref.js';
import { SelectElement } from '../../base/select-element.js';
import css_248z from '../../styles/form-text-control.js';
import { watch } from '../../utils/watch.js';
import { SgdsIcon } from '../Icon/sgds-icon.js';
import css_248z$1 from './select.js';
import { SgdsSelectOption } from './sgds-select-option.js';
import { SgdsSpinner } from '../Spinner/sgds-spinner.js';

/**
 * @summary Select is used to make one selection from a list through keyboard or mouse actions
 *
 * @event sgds-select - Emitted when an option is selected.
 * @event sgds-change - Emitted when the select value changes.
 * @event sgds-focus -  Emitted when user input is focused.
 * @event sgds-blur -  Emitted when user input is blurred.
 *
 * @slot default - slot for sgds-select-option passed into select's menu
 */
class SgdsSelect extends SelectElement {
    constructor() {
        super(...arguments);
        this._blockInputKeydown = (e) => {
            if (e.key !== "Tab") {
                e.preventDefault();
            }
        };
    }
    connectedCallback() {
        super.connectedCallback();
        this.addEventListener("sgds-hide", async () => {
            const sgdsInput = await this._input;
            sgdsInput.focus();
        });
    }
    async firstUpdated(changedProperties) {
        super.firstUpdated(changedProperties);
        this._updateDisplayValue();
        this.input = await this._input;
        this._mixinValidate(this.input);
        if (this.menuIsOpen && !this.readonly) {
            this.showMenu();
        }
    }
    async _handleSlotChange(e) {
        const assignedElements = e.target.assignedElements({ flatten: true });
        assignedElements.forEach(el => el.addEventListener("click", (e) => {
            const option = e.target;
            if (option.disabled)
                return;
            this._handleItemSelected(e);
        }));
        assignedElements.forEach(el => el.addEventListener("keydown", (e) => {
            if (e.key === "Enter") {
                this._handleItemSelected(e);
            }
        }));
        this.menuList = await this._getMenuListFromOptions(assignedElements);
        this._updateDisplayValue();
        this.input = await this._input;
        this._mixinValidate(this.input);
    }
    _updateDisplayValue() {
        if (this.value && this.menuList.length > 0) {
            const initialSelectedItem = this.menuList.filter(({ value }) => value === this.value);
            this.displayValue = initialSelectedItem[0].label;
            this._setActiveToOption();
        }
    }
    _setActiveToOption() {
        const activeIndex = this.menuList.findIndex(item => item.value.toString() === this.value);
        this.options.forEach((option, index) => {
            option.active = index === activeIndex;
        });
    }
    async _handleValueChange() {
        this._setActiveToOption();
        // when value change, always emit a change event
        this.emit("sgds-change");
        if (this.value) {
            this.emit("sgds-select");
        }
        const sgdsInput = await this._input;
        this._mixinSetFormValue();
        this._mixinValidate(sgdsInput);
        this._updateDisplayValue();
        if (!this._isTouched && this.value === "")
            return;
        this.invalid = !this._mixinReportValidity();
    }
    async _handleItemSelected(e) {
        var _a, _b, _c;
        const itemEl = e.target;
        const itemLabel = (_b = (_a = itemEl.textContent) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : "";
        const itemValueAttr = (_c = itemEl.getAttribute("value")) !== null && _c !== void 0 ? _c : itemLabel;
        const foundItem = {
            label: itemLabel,
            value: itemValueAttr
        };
        this.value = foundItem.value.toString();
        this.displayValue = foundItem.label;
        this.hideMenu();
    }
    _handleFocus() {
        this.emit("sgds-focus");
    }
    async _handleInputBlur(e) {
        e.preventDefault();
        this.emit("sgds-blur");
    }
    /** For form reset  */
    async _mixinResetFormControl() {
        this.value = this.defaultValue;
        const initialItem = this.menuList.filter(({ value }) => value === this.value);
        if (initialItem.length <= 0) {
            this.displayValue = "";
        }
        else {
            this.displayValue = initialItem[0].label;
        }
        this._mixinResetValidity(await this._input);
    }
    /** Applicable for menuList prop only */
    _renderMenu() {
        const menu = this.menuList.map(item => {
            const isActive = item.value === this.value;
            return html `
        <sgds-select-option
          ?active=${isActive}
          value=${item.value}
          ?disabled=${item.disabled}
          @click=${item.disabled ? null : this._handleItemSelected}
          @keydown=${(e) => {
                if (e.key === "Enter") {
                    this._handleItemSelected(e);
                }
            }}
        >
          ${item.label}
        </sgds-select-option>
      `;
        });
        return this.menuList.length === 0 ? this._renderEmptyMenu() : menu;
    }
    _renderInput() {
        const wantFeedbackStyle = this.hasFeedback;
        return html `
      <div
        ${ref(this.myDropdown)}
        class="form-control-group ${classMap({
            disabled: this.disabled,
            readonly: this.readonly,
            "is-invalid": this.invalid && wantFeedbackStyle
        })}"
        @click=${this._handleClick}
      >
        <input
          class="form-control"
          type="text"
          id=${this._controlId}
          name=${ifDefined(this.name)}
          placeholder=${ifDefined(this.placeholder)}
          aria-invalid=${this.invalid ? "true" : "false"}
          ?autofocus=${this.autofocus}
          ?disabled=${this.disabled}
          ?readonly=${this.readonly}
          ?required=${this.required}
          .value=${this.displayValue}
          @blur=${this._handleInputBlur}
          @focus=${this._handleFocus}
          aria-describedby=${ifDefined(this.invalid && this.hasFeedback ? `${this._controlId}-invalid` : undefined)}
          aria-labelledby="${this._labelId} ${this._controlId}Help ${this.invalid && this.hasFeedback
            ? `${this._controlId}-invalid`
            : ""}"
          @keydown=${this._blockInputKeydown}
        />
        <sgds-icon name="chevron-down" size="md"></sgds-icon>
      </div>
    `;
    }
    render() {
        return html `
      <div
        class=${classMap({
            disabled: this.disabled,
            select: true,
            "form-control-container": true
        })}
      >
        ${this._renderLabel()}
        <!-- The input -->
        ${this._renderInput()} ${this._renderFeedback()}
        <ul id=${this.dropdownMenuId} class="dropdown-menu" part="menu" tabindex="-1" ${ref(this.menuRef)}>
          <slot id="default" class=${classMap({ "is-loading": this.loading })} @slotchange=${this._handleSlotChange}
            >${this._renderMenu()}</slot
          >
          ${this.loading ? this._renderLoadingMenu() : nothing}
        </ul>
      </div>
    `;
    }
}
SgdsSelect.styles = [...SelectElement.styles, css_248z, css_248z$1];
SgdsSelect.childName = "sgds-select-option";
/** @internal */
SgdsSelect.dependencies = {
    "sgds-icon": SgdsIcon,
    "sgds-spinner": SgdsSpinner,
    [SgdsSelect.childName]: SgdsSelectOption
};
__decorate([
    queryAssignedElements({ flatten: true, selector: "sgds-select-option" })
], SgdsSelect.prototype, "options", void 0);
__decorate([
    watch("value", { waitUntilFirstUpdate: true })
], SgdsSelect.prototype, "_handleValueChange", null);

export { SgdsSelect, SgdsSelect as default };
//# sourceMappingURL=sgds-select.js.map
