// #region Imports
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 __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Themeable } from '../../../../Controls/Behaviors/Themeable';
import { Appearanceable } from '../../../Behaviors/Appearanceable';
import { Busyable } from '../../../Behaviors/Busyable';
import { Clearable } from '../../../Behaviors/Clearable';
import { Disableable } from '../../../Behaviors/Disableable';
import { Invalidable } from '../../../Behaviors/Invalidable';
import { Labelable } from '../../../Behaviors/Labelable';
import { Slottable } from '../../../Behaviors/Slottable';
import { Valueable } from '../../../Behaviors/Valueable';
import { Variantable } from '../../../Behaviors/Variantable';
import { KeyboardController } from '../../../Controllers/KeyboardController';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Component } from '../../../Decorators/ComponentDecorator';
import { Property } from '../../../Decorators/PropertyDecorator';
import { Key } from '../../../Types/Key';
import { ResizeMode } from '../../../Types/Resize';
import { TextBoxType } from '../../../Types/TextBoxType';
import { TextKeyboardMode } from '../../../Types/VirtualKeyboardMode';
import { ButtonElement } from '../../Buttons/Button/ButtonElement';
import { FocusRingElement } from '../../Primitives/FocusRing/FocusRingElement';
import { InputBaseElement } from '../Abstracts/InputBase';
import { textBoxElementJoyStyle } from './Themes/TextBoxElement.Joy';
import { textBoxElementMemphisStyle } from './Themes/TextBoxElement.Memphis';
import { textBoxElementTemplate } from './TextBoxElementTemplate';
import { textBoxElementCosmopolitanStyle } from './Themes/TextBoxElement.Cosmopolitan';
import { TextAlignment } from '../../../Types/TextAlignment';
// #endregion
/**
 * Text Box - A user interface component for entering single-line text.
 *
 * @description
 * The Text Box component is used to input single-line text or data. It provides a field where users can type or paste
 * information. Text Boxes are commonly used for various types of user input, such as usernames, search queries, or
 * short messages. It supports various input modes, validation, formatting, and accessibility features.
 *
 * @name Text Box
 * @element mosaik-textbox
 * @category Forms
 *
 * @fires cleared - Fired when the value is cleared.
 *
 * @slot prefix - The prefix slot.
 * @slot suffix - The suffix slot.
 * @slot label - The label slot.
 * @slot hint - The hint slot.
 *
 * @csspart focusRing - the focus ring part.
 * @csspart prefix - the prefix part.
 * @csspart inner - the inner part.
 * @csspart label - the label part.
 * @csspart input - the input part.
 * @csspart suffix - the suffix part.
 * @csspart hint - the hint part.
 *
 * @cssprop {String} --text-box-background-color - The background color.
 * @cssprop {String} --text-box-border-color - The border color.
 * @cssprop {String} --text-box-border-radius - The border radius.
 * @cssprop {String} --text-box-border-style - The border style.
 * @cssprop {String} --text-box-border-width - The border width.
 * @cssprop {String} --text-box-focus-ring-outward-offset - The focus ring outward offset.
 * @cssprop {String} --text-box-font-family - The font family.
 * @cssprop {String} --text-box-font-size - The font size.
 * @cssprop {String} --text-box-font-weight - The font weight.
 * @cssprop {String} --text-box-foreground-color - The foreground color.
 * @cssprop {String} --text-box-padding-top - The padding top.
 * @cssprop {String} --text-box-padding-right - The padding right.
 * @cssprop {String} --text-box-padding-bottom - The padding bottom.
 * @cssprop {String} --text-box-padding-left - The padding left.
 * @cssprop {String} --text-box-gap - The gap.
 * @cssprop {String} --text-box-transition-duration - The transition duration.
 * @cssprop {String} --text-box-transition-mode - The transition mode.
 * @cssprop {String} --text-box-transition-property - The transition property.
 * @cssprop {String} --text-box-shadow - The shadow.
 *
 * @dependency {ButtonElement} mosaik-button - The button element.
 * @dependency {FocusRingElement} mosaik-focus-ring - The focus ring element.
 *
 * @example
 * ```html
 * <mosaik-textbox label="Username" placeholder="Enter your username" required></mosaik-textbox>
 * ```
 *
 * @public
 */
let TextBoxElement = class TextBoxElement extends Themeable(Slottable(Clearable(Appearanceable(Variantable(Disableable(Labelable(Invalidable(Valueable(Busyable(InputBaseElement)))))))))) {
    // #region Fields
    _keyboardController;
    _inputElement;
    _value;
    _multiline;
    _multilineRows;
    _multilineMaxRows;
    _readonly;
    _required;
    _autofocus;
    _name;
    _keyboard;
    _type;
    _pattern;
    _placeholder;
    _autocomplete;
    _minlength;
    _maxlength;
    _resize;
    _textAlign;
    // #endregion
    // #region Ctor
    /**
     * @public
     */
    constructor() {
        super();
        this._value = '';
        this._multiline = false;
        this._multilineRows = 3;
        this._multilineMaxRows = null;
        this._readonly = false;
        this._required = false;
        this._autofocus = false;
        this._name = '';
        this._keyboard = TextKeyboardMode.Text;
        this._type = TextBoxType.Text;
        this._pattern = '';
        this._placeholder = '';
        this._autocomplete = false;
        this._minlength = null;
        this._maxlength = null;
        this._resize = ResizeMode.None;
        this._textAlign = TextAlignment.Left;
        this._keyboardController = new KeyboardController(this);
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `is` property.
     *
     * @public
     * @static
     * @readonly
    */
    static get is() {
        return 'mosaik-textbox';
    }
    /**
     * The value of the component.
     *
     * @public
     * @override
     */
    get value() {
        return this._value;
    }
    set value(value) {
        if (this._value !== value) {
            this._value = value;
            this.requestUpdate('value');
        }
    }
    /**
     * Determines whether the component is multiline or not.
     * If `true`, the component will be multiline able.
     *
     * @public
     * @attr
     */
    get multiline() {
        return this._multiline;
    }
    set multiline(value) {
        if (this._multiline !== value) {
            this._multiline = value;
            this.requestUpdate('multiline');
        }
    }
    /**
     * Determines the number of rows to display when `multiline` is `true`.
     *
     * @public
     * @attr
     */
    get multilineRows() {
        return this._multilineRows;
    }
    set multilineRows(value) {
        if (this._multilineRows !== value) {
            this._multilineRows = value;
            this.requestUpdate('multilineRows');
        }
    }
    /**
     * Determines the maximum number of rows to display when `multiline` is `true`.
     *
     * @public
     * @attr
     */
    get multilineMaxRows() {
        return this._multilineMaxRows;
    }
    set multilineMaxRows(value) {
        if (this._multilineMaxRows !== value) {
            this._multilineMaxRows = value;
            this.requestUpdate('multilineMaxRows');
        }
    }
    /**
     * Determines whether the component is readonly or not.
     * If `true`, the component will be readonly.
     *
     * @public
     * @attr
     */
    get readonly() {
        return this._readonly;
    }
    set readonly(value) {
        if (this._readonly !== value) {
            this._readonly = value;
            this.requestUpdate('readonly');
        }
    }
    /**
     * Determines whether the component is required or not.
     * If `true`, the component will require a value when submitted.
     *
     * @public
     * @attr
     */
    get required() {
        return this._required;
    }
    set required(value) {
        if (this._required !== value) {
            this._required = value;
            this.requestUpdate('required');
        }
    }
    /**
     * Determines whether the component is autofocus or not.
     * If `true`, the component will receive focus when the page loads.
     *
     * @public
     * @override
     */
    get autofocus() {
        return this._autofocus;
    }
    set autofocus(value) {
        if (this._autofocus !== value) {
            this._autofocus = value;
            this.requestUpdate('autofocus');
        }
    }
    /**
     * The name of the component.
     *
     * @public
     * @attr
     */
    get name() {
        return this._name;
    }
    set name(value) {
        if (this._name !== value) {
            this._name = value;
            this.requestUpdate('name');
        }
    }
    /**
     * Determines the virtual keyboard mode.
     * The virtual keyboard is used on mobile devices.
     * It displays a virtual keyboard that is optimized for entering
     *
     * @public
     * @attr
     */
    get keyboard() {
        return this._keyboard;
    }
    set keyboard(value) {
        if (this._keyboard !== value) {
            this._keyboard = value;
            this.requestUpdate('keyboard');
        }
    }
    /**
     * The type is determined how the validation is performed.
     *
     * @public
     * @attr
     */
    get type() {
        return this._type;
    }
    set type(value) {
        if (this._type !== value) {
            this._type = value;
            this.requestUpdate('type');
        }
    }
    /**
     * The pattern is used to validate the value of the component.
     *
     * @public
     * @attr
     */
    get pattern() {
        return this._pattern;
    }
    set pattern(value) {
        if (this._pattern !== value) {
            this._pattern = value;
            this.requestUpdate('pattern');
        }
    }
    /**
     * The placeholder is a short hint that is displayed in the component when it is empty.
     *
     * @public
     */
    get placeholder() {
        return this._placeholder;
    }
    set placeholder(value) {
        if (this._placeholder !== value) {
            this._placeholder = value;
            this.requestUpdate('placeholder');
        }
    }
    /**
     * The autocomplete property specifies whether the component should have autocomplete on or off.
     * If `true`, the component automatically complete values based on values that the user has entered before.
     *
     * @public
     * @attr
     */
    get autocomplete() {
        return this._autocomplete;
    }
    set autocomplete(value) {
        if (this._autocomplete !== value) {
            this._autocomplete = value;
            this.requestUpdate('autocomplete');
        }
    }
    /**
     * Determines the minimum length of the component value.
     *
     * @public
     * @attr
     */
    get minlength() {
        return this._minlength;
    }
    set minlength(value) {
        if (this._minlength !== value) {
            this._minlength = value;
            this.requestUpdate('minlength');
        }
    }
    /**
     * Determines the maximum length of the component value.
     *
     * @public
     * @attr
     */
    get maxlength() {
        return this._maxlength;
    }
    set maxlength(value) {
        if (this._maxlength !== value) {
            this._maxlength = value;
            this.requestUpdate('maxlength');
        }
    }
    /**
     * Gets or sets the `resize` property.
     *
     * @public
     * @attr
     */
    get resize() {
        return this._resize;
    }
    set resize(value) {
        if (this._resize !== value) {
            this._resize = value;
            this.requestUpdate('resize');
        }
    }
    /**
     * Determines the text alignment of the component.
     *
     * @public
     * @attr
     */
    get textAlign() {
        return this._textAlign;
    }
    set textAlign(value) {
        if (this._textAlign !== value) {
            this._textAlign = value;
            this.requestUpdate('textAlign');
        }
    }
    /**
     * Determines whether the element has a prefix or not.
     * The Prefix is a slot that is displayed before the input.
     *
     * @private
     * @readonly
     * @attr
     */
    get hasPrefix() {
        return this.hasSlotContent('prefix');
    }
    /**
     * Determines whether the element has a suffix or not.
     * The Suffix is a slot that is displayed after the input.
     *
     * @private
     * @readonly
     * @attr
     */
    get hasSuffix() {
        return this.hasSlotContent('suffix');
    }
    // #endregion
    // #region Methods
    /**
     * @public
     * @override
     */
    connectedCallback() {
        super.connectedCallback();
        this._keyboardController.add(Key.Escape, () => this.clear(), () => this.isClearable);
        this.on('click', () => this.focus());
    }
    /**
     * Sets focus to the element.
     *
     * @public
     * @override
     */
    focus() {
        this._inputElement.focus();
    }
    /**
     * Removes focus from the element.
     *
     * @public
     * @override
     */
    blur() {
        this._inputElement.blur();
    }
    /**
     * Resets the value, all kinds of validation and errors.
     *
     * @public
     * @override
     */
    reset() {
        super.reset();
        this.clear();
        this.invalid = false;
    }
    /**
     * Clears the value of the element but not the validation.
     *
     * @public
     * @override
     */
    clear(force) {
        const isCleared = super.clear(force);
        if (isCleared) {
            this.emit('input', {
                bubbles: true,
                composed: true
            });
            this.emit('change', {
                bubbles: true,
                composed: true
            });
        }
        return isCleared;
    }
    /**
     * Checks the validity of the element and returns `true` if it is valid; otherwise, `false`.
     *
     * @public
     * @override
     */
    checkValidity() {
        return this.shadowRoot
            ? this._inputElement.checkValidity()
            : true;
    }
    /**
     * @protected
     * @override
     */
    onApplyTemplate() {
        super.onApplyTemplate();
        this._inputElement = this.getTemplatePart('input');
        if (this.autofocus) {
            if (this.shadowRoot) {
                this._inputElement.focus();
            }
        }
    }
    /**
     * @protected
     * @template
     */
    onChange(event) {
        const inputValue = event.target.value;
        this.value = this.parser ? this.parser(inputValue) ?? '' : inputValue;
    }
    /**
     * @protected
     * @template
     * @override
     */
    onInput(event) {
        super.onInput(event);
        // if (this._maxlength && this.value.length > this._maxlength) {
        //     this.value = this.value.slice(0, this._maxlength);
        // }
        if (this.multiline) {
            this.adjustTextareaHeight();
        }
        const inputValue = event.target.value;
        this.value = this.parser ? this.parser(inputValue) ?? '' : inputValue;
    }
    /**
     * @protected
     * @template
     * @override
     */
    onFocus(event) {
        super.onFocus(event);
    }
    /**
     * @protected
     * @template
     * @override
     */
    onBlur(event) {
        super.onBlur(event);
    }
    /**
     * @protected
     * @template
     */
    onClear(event) {
        event.preventDefault();
        event.stopPropagation();
        this.clear();
    }
    /**
     * Adjust the height of the textarea based on content
     *
     * @private
     */
    adjustTextareaHeight() {
        const textarea = this._inputElement;
        if (!(textarea instanceof HTMLTextAreaElement)) {
            return;
        }
        textarea.style.height = 'auto';
        const scrollHeight = textarea.scrollHeight;
        const minHeight = this.getLineHeight() * this.multilineRows;
        const maxHeight = this.getLineHeight() * (this.multilineMaxRows ?? this.multilineRows);
        textarea.style.height = `${Math.min(Math.max(scrollHeight, minHeight), maxHeight)}px`;
    }
    /**
     * Get the line height of the textarea element
     *
     * @private
     */
    getLineHeight() {
        const textarea = this._inputElement;
        if (!(textarea instanceof HTMLTextAreaElement)) {
            return 20; // Default line height if not found
        }
        const computedStyle = window.getComputedStyle(textarea);
        const lineHeight = parseFloat(computedStyle.lineHeight);
        return lineHeight || 20; // Fallback if line-height is not a valid number
    }
};
__decorate([
    Property({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TextBoxElement.prototype, "value", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], TextBoxElement.prototype, "multiline", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], TextBoxElement.prototype, "multilineRows", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], TextBoxElement.prototype, "multilineMaxRows", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], TextBoxElement.prototype, "readonly", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], TextBoxElement.prototype, "required", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], TextBoxElement.prototype, "autofocus", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TextBoxElement.prototype, "name", null);
__decorate([
    Attribute({ type: TextKeyboardMode }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TextBoxElement.prototype, "keyboard", null);
__decorate([
    Attribute({ type: TextBoxType }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TextBoxElement.prototype, "type", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TextBoxElement.prototype, "pattern", null);
__decorate([
    Property({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TextBoxElement.prototype, "placeholder", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], TextBoxElement.prototype, "autocomplete", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], TextBoxElement.prototype, "minlength", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], TextBoxElement.prototype, "maxlength", null);
__decorate([
    Attribute({ type: ResizeMode }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TextBoxElement.prototype, "resize", null);
__decorate([
    Attribute({ type: TextAlignment }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TextBoxElement.prototype, "textAlign", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [])
], TextBoxElement.prototype, "hasPrefix", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [])
], TextBoxElement.prototype, "hasSuffix", null);
TextBoxElement = __decorate([
    Component({
        selector: 'mosaik-textbox',
        template: textBoxElementTemplate,
        themes: {
            joy: textBoxElementJoyStyle,
            memphis: textBoxElementMemphisStyle,
            cosmopolitan: textBoxElementCosmopolitanStyle
        },
        host: {
            'tabIndex': '0',
            'attr.exportparts': 'input:textbox-input, prefix:textbox-prefix, suffix:textbox-suffix, clear:textbox-clear'
        },
        options: {
            mode: 'open',
            delegatesFocus: true
        },
        imports: [
            FocusRingElement,
            ButtonElement
        ]
    }),
    __metadata("design:paramtypes", [])
], TextBoxElement);
export { TextBoxElement };
export function clearCheckFn(e) {
    return !e.disabled && !e.readonly && !!e.value && e.isClearable && !e.isBusy;
}
//# sourceMappingURL=TextBoxElement.js.map