// #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 { Appearanceable } from '../../../Behaviors/Appearanceable';
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 { Themeable } from '../../../Behaviors/Themeable';
import { Valueable } from '../../../Behaviors/Valueable';
import { Variantable } from '../../../Behaviors/Variantable';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Component } from '../../../Decorators/ComponentDecorator';
import { ButtonElement } from '../../Buttons/Button/ButtonElement';
import { FocusRingElement } from '../../Primitives/FocusRing/FocusRingElement';
import { InputBaseElement } from '../Abstracts/InputBase';
import { durationBoxElementTemplate } from './DurationBoxElementTemplate';
import { durationBoxElementCosmopolitanStyle } from './Themes/DurationBoxElement.Cosmopolitan';
import { durationBoxElementJoyStyle } from './Themes/DurationBoxElement.Joy';
import { durationBoxElementMemphisStyle } from './Themes/DurationBoxElement.Memphis';
// #endregion
/**
 * Duration Box - A specialized input control for entering duration values in HH:MM:SS format.
 *
 * @description
 * The Duration Box component provides a user-friendly interface for inputting duration values
 * using three separate numeric segments for hours, minutes, and seconds. The component stores
 * the value as total seconds (number) and handles the conversion between the segmented display
 * and the numeric value internally. It supports keyboard navigation between segments, automatic
 * zero-padding on blur, validation of numeric input, and clearing. Ideal for time tracking,
 * scheduling, and any scenario requiring duration input.
 *
 * @name Duration Box
 * @element mosaik-durationbox
 * @category Inputs
 *
 * @slot prefix - Content placed before the input segments.
 * @slot suffix - Content placed after the input segments.
 *
 * @csspart clear - The clear button part.
 * @csspart focusRing - The focus ring indicator.
 * @csspart hours-segment segment - The hours-segment segment part.
 * @csspart inner - The inner container wrapper.
 * @csspart label - The floating label element.
 * @csspart minutes-segment segment - The minutes-segment segment part.
 * @csspart prefix - The prefix content container.
 * @csspart seconds-segment segment - The seconds-segment segment part.
 * @csspart segments - The container for the hour, minute, second segments.
 * @csspart separator - The colon separator between segments.
 * @csspart suffix - The suffix content container.
 *
 * @cssprop {String} --duration-box-background-color - The box background color CSS custom property.
 * @cssprop {String} --duration-box-border-color - The box border color CSS custom property.
 * @cssprop {String} --duration-box-border-radius - The box border radius CSS custom property.
 * @cssprop {String} --duration-box-border-style - The box border style CSS custom property.
 * @cssprop {String} --duration-box-border-width - The box border width CSS custom property.
 * @cssprop {String} --duration-box-font-family - The box font family CSS custom property.
 * @cssprop {String} --duration-box-font-letter-spacing - The box font letter spacing CSS custom property.
 * @cssprop {String} --duration-box-font-line-height - The box font line height CSS custom property.
 * @cssprop {String} --duration-box-font-size - The box font size CSS custom property.
 * @cssprop {String} --duration-box-font-text-decoration - The box font text decoration CSS custom property.
 * @cssprop {String} --duration-box-font-text-transform - The box font text transform CSS custom property.
 * @cssprop {String} --duration-box-font-weight - The box font weight CSS custom property.
 * @cssprop {String} --duration-box-foreground-color - The box foreground color CSS custom property.
 * @cssprop {String} --duration-box-gap - The box gap CSS custom property.
 * @cssprop {String} --duration-box-height - The box height CSS custom property.
 * @cssprop {String} --duration-box-padding-bottom - The box padding bottom CSS custom property.
 * @cssprop {String} --duration-box-padding-left - The box padding left CSS custom property.
 * @cssprop {String} --duration-box-padding-right - The box padding right CSS custom property.
 * @cssprop {String} --duration-box-padding-top - The box padding top CSS custom property.
 * @cssprop {String} --duration-box-shadow - The box shadow CSS custom property.
 * @cssprop {String} --duration-box-shadow-blur - The box shadow blur CSS custom property.
 * @cssprop {String} --duration-box-shadow-color - The box shadow color CSS custom property.
 * @cssprop {String} --duration-box-shadow-offset-x - The box shadow offset x CSS custom property.
 * @cssprop {String} --duration-box-shadow-offset-y - The box shadow offset y CSS custom property.
 * @cssprop {String} --duration-box-shadow-spread - The box shadow spread CSS custom property.
 * @cssprop {String} --duration-box-transition-duration - The box transition duration CSS custom property.
 * @cssprop {String} --duration-box-transition-mode - The box transition mode CSS custom property.
 * @cssprop {String} --duration-box-transition-property - The box transition property CSS custom property.
 * @cssprop {String} --duration-box-translate - The box translate CSS custom property.
 *
 * @fires cleared {ClearedEvent} - Fired when the value is cleared.
 * @fires change {PropertyChangedEvent} - Emitted when the value changes.
 * @fires input {PropertyChangedEvent} - Emitted when the value changes.
 * @fires focus - Emitted when the element receives focus.
 * @fires blur - Emitted when the element loses focus.
 *
 * @dependency mosaik-button - Used for the clear button.
 * @dependency mosaik-focus-ring - Used for focus indication.
 *
 * @example
 * Duration input for a time tracking application:
 * ```html
 * <mosaik-durationbox label="Duration" value="3661"></mosaik-durationbox>
 * ```
 *
 * @example
 * Required duration field in a task creation form:
 * ```html
 * <mosaik-durationbox label="Estimated Time" required placeholder="00:00:00"></mosaik-durationbox>
 * ```
 *
 * @public
 */
let DurationBoxElement = class DurationBoxElement extends Themeable(Slottable(Clearable(Appearanceable(Disableable(Invalidable(Valueable(Variantable(Labelable(InputBaseElement))))))))) {
    // #region Fields
    _hoursInputElement;
    _minutesInputElement;
    _secondsInputElement;
    _value;
    _readonly;
    _required;
    _autofocus;
    _name;
    _placeholder;
    _hours;
    _minutes;
    _seconds;
    // #endregion
    // #region Ctor
    /**
     * @public
     */
    constructor() {
        super();
        this._value = null;
        this._readonly = false;
        this._required = false;
        this._autofocus = false;
        this._name = '';
        this._placeholder = '';
        this._hours = '';
        this._minutes = '';
        this._seconds = '';
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `is` property.
     * The `is` property represents natural name of this element.
     *
     * @public
     * @static
     * @readonly
     */
    static get is() {
        return 'mosaik-durationbox';
    }
    /**
     * Gets or sets the `value` property.
     * The value is stored as total seconds.
     *
     * @public
     * @attr
     * @override
     */
    get value() {
        return this._value;
    }
    set value(value) {
        if (!isValidValue(value)) {
            value = null;
        }
        if (this._value !== value) {
            this._value = value;
            this.syncSegmentsFromValue();
            this.requestUpdate('value');
        }
    }
    /**
     * 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 `required` property.
     *
     * @public
     * @attr
     */
    get required() {
        return this._required;
    }
    set required(value) {
        if (this._required !== value) {
            this._required = value;
            this.requestUpdate('required');
        }
    }
    /**
     * Gets or sets the `autofocus` property.
     *
     * @public
     * @attr
     * @override
     */
    get autofocus() {
        return this._autofocus;
    }
    set autofocus(value) {
        if (this._autofocus !== value) {
            this._autofocus = value;
            this.requestUpdate('autofocus');
        }
    }
    /**
     * Gets or sets the `name` property.
     *
     * @public
     * @attr
     */
    get name() {
        return this._name;
    }
    set name(value) {
        if (this._name !== value) {
            this._name = value;
            this.requestUpdate('name');
        }
    }
    /**
     * Gets or sets the `placeholder` property.
     *
     * @public
     * @attr
     */
    get placeholder() {
        return this._placeholder;
    }
    set placeholder(value) {
        if (this._placeholder !== value) {
            this._placeholder = value;
            this.requestUpdate('placeholder');
        }
    }
    /**
     * Gets the hours segment value.
     *
     * @public
     * @readonly
     */
    get hours() {
        return this._hours;
    }
    /**
     * Gets the minutes segment value.
     *
     * @public
     * @readonly
     */
    get minutes() {
        return this._minutes;
    }
    /**
     * Gets the seconds segment value.
     *
     * @public
     * @readonly
     */
    get seconds() {
        return this._seconds;
    }
    /**
     * Determines whether the element has a prefix or not.
     *
     * @private
     * @readonly
     * @attr
     */
    get hasPrefix() {
        return this.hasSlotContent('prefix');
    }
    /**
     * Determines whether the element has a suffix or not.
     *
     * @private
     * @readonly
     * @attr
     */
    get hasSuffix() {
        return this.hasSlotContent('suffix');
    }
    /**
     * Determines whether the element has a label or not.
     *
     * @private
     * @readonly
     * @attr
     */
    get hasLabel() {
        return !!this.label;
    }
    // #endregion
    // #region Methods
    /**
     * @public
     * @override
     */
    focus() {
        if (this.shadowRoot) {
            this._hoursInputElement.focus();
        }
    }
    /**
     * @public
     * @override
     */
    blur() {
        if (this.shadowRoot) {
            const activeElement = this.shadowRoot.activeElement;
            if (activeElement instanceof HTMLElement) {
                activeElement.blur();
            }
        }
    }
    /**
     * Clears the value of the element but not the validation.
     *
     * @public
     * @override
     */
    clear(force) {
        const isCleared = super.clear(force);
        if (isCleared) {
            this._hours = '';
            this._minutes = '';
            this._seconds = '';
            this.requestUpdate('value');
            this.emit('input', {
                bubbles: true,
                composed: true
            });
            this.emit('change', {
                bubbles: true,
                composed: true
            });
        }
        return isCleared;
    }
    /**
     * Resets the value, all kinds of validation and errors.
     *
     * @public
     * @override
     */
    reset() {
        super.reset();
        this.clear();
        this.invalid = false;
    }
    /**
     * Checks the validity of the element and returns `true` if it is valid; otherwise, `false`.
     *
     * @public
     * @override
     */
    checkValidity() {
        if (this.required && this.value === null) {
            return false;
        }
        return true;
    }
    /**
     * Handles the input event on a segment.
     *
     * @private
     * @hidden
     * @template
     */
    onSegmentInput(segment, event) {
        if (!event.target) {
            return;
        }
        const input = event.target;
        const raw = input.value.replace(/\D/g, '');
        const maxLength = segment === 'hours' ? 3 : 2;
        const clampedValue = raw.slice(0, maxLength);
        input.value = clampedValue;
        switch (segment) {
            case 'hours':
                this._hours = clampedValue;
                break;
            case 'minutes':
                this._minutes = clampedValue;
                break;
            case 'seconds':
                this._seconds = clampedValue;
                break;
        }
        this.updateValueFromSegments();
        this.emit('input', { detail: this.value });
    }
    /**
     * Handles the change event on a segment.
     *
     * @private
     * @hidden
     * @template
     */
    onSegmentChange(segment, event) {
        if (!event.target) {
            return;
        }
        const input = event.target;
        const raw = input.value.replace(/\D/g, '');
        const maxLength = segment === 'hours' ? 3 : 2;
        const clampedValue = raw.slice(0, maxLength);
        switch (segment) {
            case 'hours':
                this._hours = clampedValue;
                break;
            case 'minutes':
                this._minutes = clampedValue;
                break;
            case 'seconds':
                this._seconds = clampedValue;
                break;
        }
        this.updateValueFromSegments();
        this.emit('change', { detail: this.value });
    }
    /**
     * Handles the focus event on a segment. Selects all text.
     *
     * @private
     * @hidden
     * @template
     */
    onSegmentFocus(event) {
        super.onFocus(event);
        const target = event.target;
        target.select();
        this.emit('focus', { detail: event });
    }
    /**
     * Handles the blur event on a segment. Pads values with zeros.
     *
     * @private
     * @hidden
     * @template
     */
    onSegmentBlur(segment, event) {
        super.onBlur(event);
        switch (segment) {
            case 'hours':
                if (this._hours.length > 0) {
                    this._hours = this._hours.padStart(2, '0');
                }
                break;
            case 'minutes':
                if (this._minutes.length > 0) {
                    const minuteValue = Math.min(parseInt(this._minutes, 10) || 0, 59);
                    this._minutes = minuteValue.toString().padStart(2, '0');
                }
                break;
            case 'seconds':
                if (this._seconds.length > 0) {
                    const secondValue = Math.min(parseInt(this._seconds, 10) || 0, 59);
                    this._seconds = secondValue.toString().padStart(2, '0');
                }
                break;
        }
        this.updateValueFromSegments();
        this.requestUpdate('value');
        this.emit('blur', { detail: event });
    }
    /**
     * Handles keydown events for Tab navigation between segments.
     *
     * @private
     * @hidden
     * @template
     */
    onSegmentKeyDown(segment, event) {
        if (event.key === 'Tab' && !event.shiftKey) {
            if (segment === 'hours' && this._minutesInputElement) {
                event.preventDefault();
                this._minutesInputElement.focus();
            }
            else if (segment === 'minutes' && this._secondsInputElement) {
                event.preventDefault();
                this._secondsInputElement.focus();
            }
        }
        else if (event.key === 'Tab' && event.shiftKey) {
            if (segment === 'seconds' && this._minutesInputElement) {
                event.preventDefault();
                this._minutesInputElement.focus();
            }
            else if (segment === 'minutes' && this._hoursInputElement) {
                event.preventDefault();
                this._hoursInputElement.focus();
            }
        }
    }
    /**
     * @protected
     * @override
     */
    onApplyTemplate() {
        super.onApplyTemplate();
        this._hoursInputElement = this.getTemplatePart('hours-segment');
        this._minutesInputElement = this.getTemplatePart('minutes-segment');
        this._secondsInputElement = this.getTemplatePart('seconds-segment');
    }
    syncSegmentsFromValue() {
        if (this._value === null || this._value === undefined) {
            this._hours = '';
            this._minutes = '';
            this._seconds = '';
        }
        else {
            const totalSeconds = Math.max(0, Math.floor(this._value));
            const hours = Math.floor(totalSeconds / 3600);
            const minutes = Math.floor((totalSeconds % 3600) / 60);
            const seconds = totalSeconds % 60;
            this._hours = hours.toString().padStart(2, '0');
            this._minutes = minutes.toString().padStart(2, '0');
            this._seconds = seconds.toString().padStart(2, '0');
        }
    }
    updateValueFromSegments() {
        const hours = parseInt(this._hours, 10) || 0;
        const minutes = parseInt(this._minutes, 10) || 0;
        const seconds = parseInt(this._seconds, 10) || 0;
        if (this._hours === '' && this._minutes === '' && this._seconds === '') {
            this._value = null;
        }
        else {
            this._value = (hours * 3600) + (minutes * 60) + seconds;
        }
    }
};
__decorate([
    Attribute({
        type: Number,
        converter: {
            fromAttribute: (value) => {
                const parsedValue = Number.parseInt(value, 10);
                return isNaN(parsedValue) ? null : parsedValue;
            },
            toAttribute: (value) => value !== null ? value.toString() : null
        }
    }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], DurationBoxElement.prototype, "value", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], DurationBoxElement.prototype, "readonly", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], DurationBoxElement.prototype, "required", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], DurationBoxElement.prototype, "autofocus", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], DurationBoxElement.prototype, "name", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], DurationBoxElement.prototype, "placeholder", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [])
], DurationBoxElement.prototype, "hasPrefix", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [])
], DurationBoxElement.prototype, "hasSuffix", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [])
], DurationBoxElement.prototype, "hasLabel", null);
DurationBoxElement = __decorate([
    Component({
        selector: 'mosaik-durationbox',
        template: durationBoxElementTemplate,
        themes: {
            joy: durationBoxElementJoyStyle,
            memphis: durationBoxElementMemphisStyle,
            cosmopolitan: durationBoxElementCosmopolitanStyle
        },
        host: {
            tabIndex: '0'
        },
        options: {
            mode: 'open',
            delegatesFocus: true
        },
        imports: [
            FocusRingElement,
            ButtonElement
        ]
    }),
    __metadata("design:paramtypes", [])
], DurationBoxElement);
export { DurationBoxElement };
/**
 * Checks if the provided value is valid for a duration input.
 * A valid value can be a number or null.
 *
 * @private
 * @param value - The value to check.
 */
function isValidValue(value) {
    return typeof value === 'number' || value === null;
}
//# sourceMappingURL=DurationBoxElement.js.map