import { __decorate } from 'tslib';
import { nothing } from 'lit';
import { property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { live } from 'lit/directives/live.js';
import { html } from 'lit/static-html.js';
import FormControlElement from '../../base/form-control-element.js';
import css_248z$1 from '../../styles/form-placeholder.js';
import css_248z from '../../styles/form-text-control.js';
import { defaultValue } from '../../utils/defaultvalue.js';
import { SgdsFormValidatorMixin } from '../../utils/validatorMixin.js';
import { watch } from '../../utils/watch.js';
import { SgdsSpinner } from '../Spinner/sgds-spinner.js';
import css_248z$2 from './input.js';
import { SgdsIcon } from '../Icon/sgds-icon.js';

/**
 * @summary Text inputs allow your users to enter letters, numbers and symbols on a single line.
 *
 * @slot icon - The slot for leading icon of text input
 * @slot trailing-icon - The slot for trailing icon of text input. When present, it overrides valid icon and loading spinner rendered when valid prop or loading prop are true
 * @slot action - The slot for call to action of the text input. It is recommended to use sgds-icon-button within this slot
 * @event sgds-change - Emitted when an alteration to the control's value is committed by the user.
 * @event sgds-input - Emitted when the control receives input and its value changes.
 * @event sgds-focus - Emitted when input is in focus.
 * @event sgds-blur - Emitted when input is not in focus.
 * @event sgds-invalid - Emitted when input is invalid
 * @event sgds-valid - Emitted when input is valid
 *
 */
class SgdsInput extends SgdsFormValidatorMixin(FormControlElement) {
    constructor() {
        super(...arguments);
        this.type = "text";
        /** The input's placeholder text. */
        this.placeholder = "placeholder";
        /** Autofocus the input */
        this.autofocus = false;
        /** Makes the input readonly. */
        this.readonly = false;
        /**Gets or sets the default value used to reset this element. The initial value corresponds to the one originally specified in the HTML that created this element. */
        this.defaultValue = "";
        /** Marks the component as valid. */
        this.valid = false;
        /** Marks the component as loading. */
        this.loading = false;
        /** Makes the input a required field. */
        this.required = false;
        this.noValidate = false;
        /**The input's value attribute. */
        this.value = "";
        this._isTouched = false;
        this._showPassword = false;
    }
    /** Sets focus on the input. */
    focus(options) {
        this.input.focus(options);
    }
    /** Sets blur on the input. */
    blur() {
        this.input.blur();
    }
    /**
     * Checks for validity. Under the hood, HTMLFormElement's reportValidity method calls this method to check for component's validity state
     * Note that the native error popup is prevented for SGDS form components by default. Instead the validation message shows up in the feedback container of SgdsInput
     */
    reportValidity() {
        return this._mixinReportValidity();
    }
    /**
     * Checks for validity without any native error popup message
     */
    checkValidity() {
        return this._mixinCheckValidity();
    }
    /**
     * Checks for validity without any native error popup message
     */
    setValidity(flags, message, anchor) {
        return this._mixinSetValidity(flags, message, anchor);
    }
    /**
     * Returns the ValidityState object
     */
    get validity() {
        return this._mixinGetValidity();
    }
    /**
     * Returns the validation message based on the ValidityState
     */
    get validationMessage() {
        return this._mixinGetValidationMessage();
    }
    _handleFocus() {
        this.emit("sgds-focus");
    }
    _handleBlur() {
        const sgdsBlur = this.emit("sgds-blur", { cancelable: true });
        if (this._mixinShouldSkipSgdsValidation())
            return;
        if (sgdsBlur.defaultPrevented)
            return;
        this.setInvalid(!this._mixinCheckValidity());
        this._isTouched = true;
    }
    _handleClick() {
        this.focus();
    }
    _handleChange(e) {
        this.value = this.input.value;
        const sgdsChange = this.emit("sgds-change", { cancelable: true });
        if (this._mixinShouldSkipSgdsValidation())
            return;
        if (sgdsChange.defaultPrevented)
            return;
        super._mixinHandleChange(e);
    }
    _handleInputChange(e) {
        this.value = this.input.value;
        const sgdsInput = this.emit("sgds-input", { cancelable: true });
        if (this._mixinShouldSkipSgdsValidation())
            return;
        if (sgdsInput.defaultPrevented)
            return;
        super._mixinHandleInputChange(e);
    }
    /** @internal */
    _handleIsTouched() {
        if (this._mixinShouldSkipSgdsValidation())
            return;
        if (this._isTouched) {
            this.setInvalid(!this._mixinCheckValidity());
        }
    }
    _handleDisabledChange() {
        // Disabled form controls are always valid, so we need to recheck validity when the state changes
        this.setInvalid(false);
    }
    _renderInput() {
        const wantFeedbackStyle = this.hasFeedback === "both" || this.hasFeedback === "style";
        return html `
      <div
        class="form-control-group ${classMap({
            disabled: this.disabled,
            readonly: this.readonly,
            "is-invalid": this.invalid && wantFeedbackStyle
        })}"
        @click=${this._handleClick}
      >
        <slot name="icon"></slot>
        ${this.prefix ? html `<span class="form-control-prefix">${this.prefix}</span>` : nothing}
        <input
          class="form-control"
          type=${this._inputType()}
          id=${this._controlId}
          name=${ifDefined(this.name)}
          placeholder=${ifDefined(this.placeholder)}
          aria-invalid=${this.invalid ? "true" : "false"}
          pattern=${ifDefined(this.pattern)}
          ?autofocus=${this.autofocus}
          ?disabled=${this.disabled}
          ?readonly=${this.readonly}
          ?required=${this.required}
          .value=${live(this.value)}
          minlength=${ifDefined(this.minlength)}
          maxlength=${ifDefined(this.maxlength)}
          min=${ifDefined(this.min)}
          max=${ifDefined(this.max)}
          step=${ifDefined(this.step)}
          @input=${(e) => this._handleInputChange(e)}
          @change=${(e) => this._handleChange(e)}
          @invalid=${() => this.setInvalid(true)}
          @focus=${this._handleFocus}
          @blur=${this._handleBlur}
          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`
            : ""}"
        />
        ${this.type === "password" ? this._renderPasswordToggle() : nothing}
        ${this.suffix ? html `<span class="form-control-suffix">${this.suffix}</span>` : nothing}
        <slot name="trailing-icon">
          ${this.loading ? html `<sgds-spinner size="sm"></sgds-spinner>` : nothing}
          ${this.valid ? html `<sgds-icon name="check-circle-fill" class="valid-icon"></sgds-icon>` : nothing}
        </slot>
      </div>
    `;
    }
    _renderPasswordToggle() {
        return html `<sgds-icon
      tabIndex="0"
      role="button"
      name=${this._showPassword ? "eye-slash-fill" : "eye-fill"}
      @click=${() => (this._showPassword = !this._showPassword)}
    ></sgds-icon>`;
    }
    _inputType() {
        if (this.type === "password" && this._showPassword) {
            return "text";
        }
        return this.type;
    }
    _renderFeedback() {
        const wantFeedbackText = this.hasFeedback === "both" || this.hasFeedback === "text";
        return this.invalid && wantFeedbackText
            ? html ` <div class="invalid-feedback-container">
          <sgds-icon name="exclamation-circle-fill" size="md"></sgds-icon>
          <div id="${this._controlId}-invalid" class="invalid-feedback">
            ${this.invalidFeedback ? this.invalidFeedback : this.input.validationMessage}
          </div>
        </div>`
            : html `${this._renderHintText()}`;
    }
    _renderLabel() {
        const labelTemplate = html `
      <label
        for=${this._controlId}
        id=${this._labelId}
        class=${classMap({
            "form-label": true,
            required: this.required
        })}
        >${this.label}</label
      >
    `;
        return this.label && labelTemplate;
    }
    _renderHintText() {
        const hintTextTemplate = html ` <div id="${this._controlId}Help" class="form-text">${this.hintText}</div> `;
        return this.hintText && hintTextTemplate;
    }
    render() {
        return html `
      <div
        class="form-control-container ${classMap({
            disabled: this.disabled
        })}"
      >
        ${this._renderLabel()}
        <div class="form-control-row">
          ${this._renderInput()}
          <slot name="action"></slot>
        </div>
        ${this._renderFeedback()}
      </div>
    `;
    }
}
SgdsInput.styles = [...FormControlElement.styles, css_248z, css_248z$1, css_248z$2];
/** @internal */
SgdsInput.dependencies = {
    "sgds-spinner": SgdsSpinner,
    "sgds-icon": SgdsIcon
};
__decorate([
    property({ reflect: true })
], SgdsInput.prototype, "type", void 0);
__decorate([
    property({ type: String })
], SgdsInput.prototype, "prefix", void 0);
__decorate([
    property({ type: String })
], SgdsInput.prototype, "suffix", void 0);
__decorate([
    property({ type: Number, reflect: true })
], SgdsInput.prototype, "minlength", void 0);
__decorate([
    property({ type: Number, reflect: true })
], SgdsInput.prototype, "maxlength", void 0);
__decorate([
    property()
], SgdsInput.prototype, "min", void 0);
__decorate([
    property()
], SgdsInput.prototype, "max", void 0);
__decorate([
    property({ type: String, reflect: true })
], SgdsInput.prototype, "placeholder", void 0);
__decorate([
    property({ type: String })
], SgdsInput.prototype, "pattern", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], SgdsInput.prototype, "autofocus", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], SgdsInput.prototype, "readonly", void 0);
__decorate([
    property()
], SgdsInput.prototype, "step", void 0);
__decorate([
    property({ type: String, reflect: true })
], SgdsInput.prototype, "hasFeedback", void 0);
__decorate([
    property({ type: String, reflect: true })
], SgdsInput.prototype, "invalidFeedback", void 0);
__decorate([
    defaultValue()
], SgdsInput.prototype, "defaultValue", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], SgdsInput.prototype, "valid", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], SgdsInput.prototype, "loading", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], SgdsInput.prototype, "required", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], SgdsInput.prototype, "noValidate", void 0);
__decorate([
    property({ reflect: true })
], SgdsInput.prototype, "value", void 0);
__decorate([
    state()
], SgdsInput.prototype, "_isTouched", void 0);
__decorate([
    state()
], SgdsInput.prototype, "_showPassword", void 0);
__decorate([
    watch("_isTouched", { waitUntilFirstUpdate: true })
], SgdsInput.prototype, "_handleIsTouched", null);
__decorate([
    watch("disabled", { waitUntilFirstUpdate: true })
], SgdsInput.prototype, "_handleDisabledChange", null);

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