// #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 { Disableable } from '../../../Behaviors/Disableable';
import { TextFormattable } from '../../../Behaviors/TextFormattable';
import { Variantable } from '../../../Behaviors/Variantable';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Component } from '../../../Decorators/ComponentDecorator';
import { Property } from '../../../Decorators/PropertyDecorator';
import { Watch } from '../../../Decorators/WatchDecorator';
import { TextAlignment } from '../../../Types/TextAlignment';
import { CustomElement } from '../../Abstracts/CustomElement';
import { textElementTemplate } from './TextElementTemplate';
import { textElementJoyStyle } from './Themes/TextElement.Joy';
import { textElementRetroStyle } from './Themes/TextElement.Retro';
import { textElementCosmopolitanStyle } from './Themes/TextElement.Cosmopolitan';
import { Themeable } from '../../../Behaviors/Themeable';
// #endregion
/**
 * Text - A user interface component for displaying written content or information.
 *
 * @description
 * The Text component is used to display written content or information to users. It is a fundamental element for
 * presenting text-based content in various user interfaces, such as paragraphs, headings, labels, or descriptions.
 * Text components can include both plain text and formatted text, allowing developers to style and structure the
 * content as needed.
 *
 * @element mosaik-text
 * @category Display
 *
 * @slot text - The text slot.
 *
 * @example
 * ```html
 * <mosaik-text text="This is an example of a Text component.">
 * </mosaik-text>
 * ```
 *
 * @public
 */
let TextElement = class TextElement extends Themeable(Variantable(Disableable(TextFormattable(CustomElement)))) {
    // #region Fields
    _text;
    _truncate;
    _wrap;
    _maxLength;
    _maxLines;
    _readonly;
    _alignment;
    _marker;
    // #endregion
    // #region Ctor
    /**
     * Constructs a new instance of the `TextElement` class.
     *
     * @public
     */
    constructor() {
        super();
        this._text = {
            rawValue: '',
            value: ''
        };
        this._truncate = false;
        this._wrap = false;
        this._maxLength = null;
        this._maxLines = null;
        this._readonly = false;
        this._alignment = TextAlignment.Left;
        this._marker = null;
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `is` property.
     *
     * @public
     * @static
     * @readonly
    */
    static get is() {
        return 'mosaik-text';
    }
    /**
     * Gets or sets the `text` property.
     *
     * @public
     */
    get text() {
        return this._text.value;
    }
    set text(value) {
        if (this._text.rawValue !== value) {
            this._text.rawValue = value ?? '';
            this.requestUpdate('text');
        }
    }
    /**
     * Gets or sets the `truncate` property.
     *
     * @public
     * @attr
     */
    get truncate() {
        return this._truncate;
    }
    set truncate(value) {
        if (this._truncate !== value) {
            this._truncate = value;
            this.requestUpdate('truncate');
        }
    }
    /**
     * Gets or sets the `wrap` property.
     *
     * @public
     * @attr
     */
    get wrap() {
        return this._wrap;
    }
    set wrap(value) {
        if (this._wrap !== value) {
            this._wrap = value;
            this.requestUpdate('wrap');
        }
    }
    /**
     * Gets or sets the `maxLength` property.
     *
     * @public
     * @attr
     */
    get maxLength() {
        return this._maxLength;
    }
    set maxLength(value) {
        if (this._maxLength !== value) {
            this._maxLength = value;
            this.requestUpdate('maxLength');
        }
    }
    /**
     * Gets or sets the `maxLines` property.
     *
     * @public
     * @attr
     */
    get maxLines() {
        return this._maxLines;
    }
    set maxLines(value) {
        if (this._maxLines !== value) {
            this._maxLines = value;
            this.requestUpdate('maxLines');
        }
    }
    /**
     * Gets or sets the `readonly` property.
     *
     * @public
     * @attr
     */
    get readonly() {
        return this._readonly;
    }
    set readonly(value) {
        if (this._readonly !== value) {
            this._readonly = value;
            this.requestUpdate('readonly');
        }
    }
    /**
     * Gets or sets the `alignment` property.
     *
     * Possible values are:
     * * `center`
     * * `justify`
     * * `left`
     * * `right`
     *
     * @public
     * @attr
     */
    get alignment() {
        return this._alignment;
    }
    set alignment(value) {
        if (this._alignment !== value) {
            this._alignment = value;
            this.requestUpdate('alignment');
        }
    }
    /**
     * Gets or sets the `marker` property.
     *
     * @public
     * @attr
     */
    get marker() {
        return this._marker;
    }
    set marker(value) {
        if (this._marker !== value) {
            this._marker = value;
            this.requestUpdate('marker');
        }
    }
    // #endregion
    // #region Methods
    /**
     * Mark the `text` by the given `value`. If the value is a boolean `true`, the text will be marked completely.
     *
     * @public
     */
    mark(value) {
        if (typeof value === 'boolean') {
            this.text = `<mark part="marker">${this._text.value}</mark>`;
        }
        else {
            this.text = this._text.value.replace(new RegExp(value, 'gi'), '<mark part="marker">$&</mark>');
        }
    }
    /**
     * Trim the `text` by the given `maxLength`.
     *
     * @template
     * @private
     */
    tryTrim() {
        if (!this._text.rawValue) {
            return '';
        }
        if (this._maxLength === null) {
            return this._text.value;
        }
        if (this.formatter) {
            const text = this._text.value;
            const truncatedText = this._maxLength === undefined || this._maxLength === null
                ? text
                : text.substring(0, this._maxLength);
            // Check for incomplete HTML tags at the end
            const match = (/<[^>]*$/).exec(truncatedText);
            if (match) {
                // If there's an incomplete HTML tag, remove it to maintain valid HTML structure
                return truncatedText.substring(0, truncatedText.lastIndexOf(match[0]));
            }
        }
        const text = this._text.value;
        return this._maxLength === undefined || this._maxLength === null
            ? text
            : text.length <= this._maxLength
                ? text
                : text.substring(0, this._maxLength).trim();
    }
    /**
     * @protected
     */
    onTextPropertyChanged(_prev, _next) {
        const fn = this.formatter;
        this._text.value = this.formatter
            ? fn(this._text.rawValue)
            : this._text.rawValue;
    }
    /**
     * @protected
     */
    onFormatterPropertyChanged(_prev, next) {
        if (next) {
            const fn = next;
            this._text.value = fn(this._text.rawValue);
        }
    }
    /**
     * @protected
     */
    onMarkerPropertyChanged(_prev, next) {
        this.mark(next ?? true);
    }
};
__decorate([
    Property({ type: String }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], TextElement.prototype, "text", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], TextElement.prototype, "truncate", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], TextElement.prototype, "wrap", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], TextElement.prototype, "maxLength", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], TextElement.prototype, "maxLines", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], TextElement.prototype, "readonly", null);
__decorate([
    Attribute({ type: TextAlignment }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TextElement.prototype, "alignment", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], TextElement.prototype, "marker", null);
__decorate([
    Watch('text'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, String]),
    __metadata("design:returntype", void 0)
], TextElement.prototype, "onTextPropertyChanged", null);
__decorate([
    Watch('formatter'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object]),
    __metadata("design:returntype", void 0)
], TextElement.prototype, "onFormatterPropertyChanged", null);
__decorate([
    Watch('marker'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object, Object]),
    __metadata("design:returntype", void 0)
], TextElement.prototype, "onMarkerPropertyChanged", null);
TextElement = __decorate([
    Component({
        selector: 'mosaik-text',
        template: textElementTemplate,
        themes: {
            joy: textElementJoyStyle,
            retro: textElementRetroStyle,
            cosmopolitan: textElementCosmopolitanStyle
        },
        host: {
            role: 'text'
        },
        imports: []
    }),
    __metadata("design:paramtypes", [])
], TextElement);
export { TextElement };
//# sourceMappingURL=TextElement.js.map