// #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 { HTMLElementEventEmitter } from '@breadstone/mosaik-elements';
import { DomServiceLocator } from '../../../../Dom/Dom';
import { Emit } from '../../../../events/Decorators/EmitDecorator';
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 { Property } from '../../../Decorators/PropertyDecorator';
import { ButtonElement } from '../../Buttons/Button/ButtonElement';
import { FocusRingElement } from '../../Primitives/FocusRing/FocusRingElement';
import { InputBaseElement } from '../Abstracts/InputBase';
import { fileBoxElementTemplate } from './FileBoxElementTemplate';
import { fileBoxElementCosmopolitanStyle } from './Themes/FileBoxElement.Cosmopolitan';
import { fileBoxElementJoyStyle } from './Themes/FileBoxElement.Joy';
import { fileBoxElementMemphisStyle } from './Themes/FileBoxElement.Memphis';
// #endregion
/**
 * File Box - A text-box-styled file input control with a trailing browse button.
 *
 * @description
 * The File Box component provides a familiar text-box appearance for file selection.
 * It displays the selected file name(s) in a readonly text input and offers a trailing
 * browse button to open the native file picker dialog. Supports single and multiple file
 * selection, directory selection, file type filtering via accept attribute, clearable state,
 * and form integration through value accessors. Bridges the gap between the primitive
 * FilePicker and the complex FileUpload component.
 *
 * @name File Box
 * @element mosaik-filebox
 * @category Inputs
 *
 * @slot prefix - Content placed before the input field.
 * @slot suffix - Content placed after the input field.
 *
 * @csspart browse - The browse button.
 * @csspart clear - The clear button.
 * @csspart fileInput - The fileInput part.
 * @csspart focusRing - The focus ring indicator.
 * @csspart inner - The inner container wrapper.
 * @csspart input - The readonly text input showing file names.
 * @csspart label - The floating label element.
 * @csspart prefix - The prefix content container.
 * @csspart suffix - The suffix content container.
 *
 * @cssprop {String} --file-box-background-color - The box background color CSS custom property.
 * @cssprop {String} --file-box-border-color - The box border color CSS custom property.
 * @cssprop {String} --file-box-border-radius - The box border radius CSS custom property.
 * @cssprop {String} --file-box-border-style - The box border style CSS custom property.
 * @cssprop {String} --file-box-border-width - The box border width CSS custom property.
 * @cssprop {String} --file-box-focus-ring-width - The box focus ring width CSS custom property.
 * @cssprop {String} --file-box-font-family - The box font family CSS custom property.
 * @cssprop {String} --file-box-font-letter-spacing - The box font letter spacing CSS custom property.
 * @cssprop {String} --file-box-font-line-height - The box font line height CSS custom property.
 * @cssprop {String} --file-box-font-size - The box font size CSS custom property.
 * @cssprop {String} --file-box-font-text-decoration - The box font text decoration CSS custom property.
 * @cssprop {String} --file-box-font-text-transform - The box font text transform CSS custom property.
 * @cssprop {String} --file-box-font-weight - The box font weight CSS custom property.
 * @cssprop {String} --file-box-foreground-color - The box foreground color CSS custom property.
 * @cssprop {String} --file-box-gap - The box gap CSS custom property.
 * @cssprop {String} --file-box-height - The box height CSS custom property.
 * @cssprop {String} --file-box-padding-bottom - The box padding bottom CSS custom property.
 * @cssprop {String} --file-box-padding-left - The box padding left CSS custom property.
 * @cssprop {String} --file-box-padding-right - The box padding right CSS custom property.
 * @cssprop {String} --file-box-padding-top - The box padding top CSS custom property.
 * @cssprop {String} --file-box-shadow - The box shadow CSS custom property.
 * @cssprop {String} --file-box-shadow-blur - The box shadow blur CSS custom property.
 * @cssprop {String} --file-box-shadow-color - The box shadow color CSS custom property.
 * @cssprop {String} --file-box-shadow-offset-x - The box shadow offset x CSS custom property.
 * @cssprop {String} --file-box-shadow-offset-y - The box shadow offset y CSS custom property.
 * @cssprop {String} --file-box-shadow-spread - The box shadow spread CSS custom property.
 * @cssprop {String} --file-box-transition-duration - The box transition duration CSS custom property.
 * @cssprop {String} --file-box-transition-mode - The box transition mode CSS custom property.
 * @cssprop {String} --file-box-transition-property - The box transition property CSS custom property.
 * @cssprop {String} --file-box-translate - The box translate CSS custom property.
 *
 * @fires cleared {ClearedEvent} - Fired when the file selection is cleared.
 * @fires filesSelected {FilesSelectedEvent} - Fired when files are selected.
 *
 * @dependency mosaik-button - Used for the browse button.
 * @dependency mosaik-focus-ring - Used for focus indication.
 *
 * @example
 * ```html
 * <mosaik-filebox
 *   placeholder="Choose a file..."
 *   accept=".pdf,.doc,.docx">
 * </mosaik-filebox>
 * ```
 *
 * @public
 */
let FileBoxElement = class FileBoxElement extends Themeable(Slottable(Clearable(Disableable(Invalidable(Valueable(Variantable(Labelable(Appearanceable(InputBaseElement))))))))) {
    // #region Fields
    _filesSelected;
    _fileInputElement;
    _value;
    _readonly;
    _required;
    _autofocus;
    _name;
    _placeholder;
    _multiple;
    _accept;
    _directory;
    _files;
    // #endregion
    // #region Ctor
    /**
     * @public
     */
    constructor() {
        super();
        this._value = '';
        this._readonly = false;
        this._required = false;
        this._autofocus = false;
        this._name = '';
        this._placeholder = '';
        this._multiple = false;
        this._accept = [];
        this._directory = false;
        this._files = [];
        this._filesSelected = new HTMLElementEventEmitter(this, 'filesSelected');
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `is` property.
     * The `is` property represents natural name of this element.
     *
     * @public
     * @static
     * @readonly
     */
    static get is() {
        return 'mosaik-filebox';
    }
    /**
     * Gets or sets the `value` property.
     * The value represents the display text of the selected file(s).
     *
     * @public
     * @override
     */
    get value() {
        return this._value;
    }
    set value(value) {
        if (this._value !== value) {
            this._value = value;
            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
     * @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 or sets the `multiple` property.
     * When true, allows selecting multiple files.
     *
     * @public
     * @attr
     */
    get multiple() {
        return this._multiple;
    }
    set multiple(value) {
        if (this._multiple !== value) {
            this._multiple = value;
            this.requestUpdate('multiple');
        }
    }
    /**
     * Gets or sets the `accept` property.
     * Specifies the file types that the file input should accept.
     *
     * @public
     * @attr
     */
    get accept() {
        return this._accept;
    }
    set accept(value) {
        if (this._accept !== value) {
            this._accept = value;
            this.requestUpdate('accept');
        }
    }
    /**
     * Gets or sets the `directory` property.
     * When true, allows selecting directories instead of files.
     *
     * @public
     * @attr
     */
    get directory() {
        return this._directory;
    }
    set directory(value) {
        if (this._directory !== value) {
            this._directory = value;
            this.requestUpdate('directory');
        }
    }
    /**
     * Gets or sets the selected files.
     *
     * @public
     * @readonly
     */
    get files() {
        return this._files;
    }
    set files(value) {
        if (this._files !== value) {
            this._files = value;
            this.requestUpdate('files');
        }
    }
    /**
     * 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');
    }
    /**
     * Called when files are selected.
     * Provides reference to `IFilesSelectedEventDetail` as event detail.
     *
     * @public
     * @readonly
     * @eventProperty
     */
    get filesSelected() {
        return this._filesSelected;
    }
    // #endregion
    // #region Methods
    /**
     * @public
     * @override
     */
    focus() {
        if (this.shadowRoot) {
            DomServiceLocator.current.findDescendant(this.shadowRoot, 'input')?.focus();
        }
    }
    /**
     * @public
     * @override
     */
    blur() {
        if (this.shadowRoot) {
            DomServiceLocator.current.findDescendant(this.shadowRoot, 'input')?.blur();
        }
    }
    /**
     * Opens the native file picker dialog.
     *
     * @public
     */
    browse() {
        if (!this.disabled && !this.readonly) {
            this._fileInputElement.click();
        }
    }
    /**
     * Clears the selected files and value.
     *
     * @public
     * @override
     */
    clear(force) {
        const isCleared = super.clear(force);
        if (isCleared) {
            this._files = [];
            this._fileInputElement.value = '';
            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.
     *
     * @public
     * @override
     */
    checkValidity() {
        if (this.required && this._files.length === 0) {
            return false;
        }
        return true;
    }
    /**
     * Handles file input change events.
     *
     * @public
     */
    onFileChange(event) {
        const input = event.target;
        const fileList = input.files;
        if (fileList && fileList.length > 0) {
            const selectedFiles = Array.from(fileList);
            this._files = selectedFiles;
            this.value = selectedFiles.map((file) => file.name).join(', ');
            this.onFilesSelected({ files: selectedFiles });
            this.emit('change', {
                bubbles: true,
                composed: true
            });
        }
        // Reset file input to allow re-selecting the same file
        input.value = '';
    }
    /**
     * @template
     * @protected
     * @override
     */
    onFocus(event) {
        super.onFocus(event);
        this.emit('focus', { detail: event });
    }
    /**
     * @template
     * @protected
     * @override
     */
    onBlur(event) {
        super.onBlur(event);
        this.emit('blur', { detail: event });
    }
    /**
     * @protected
     * @override
     */
    onApplyTemplate() {
        super.onApplyTemplate();
        this._fileInputElement = this.getTemplatePart('fileInput');
    }
    /**
     * Emits the `filesSelected` event.
     *
     * @protected
     */
    onFilesSelected(args) {
        this._filesSelected.emit(args);
    }
};
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], FileBoxElement.prototype, "value", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], FileBoxElement.prototype, "readonly", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], FileBoxElement.prototype, "required", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], FileBoxElement.prototype, "autofocus", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], FileBoxElement.prototype, "name", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], FileBoxElement.prototype, "placeholder", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], FileBoxElement.prototype, "multiple", null);
__decorate([
    Property({ type: Array }),
    __metadata("design:type", Array),
    __metadata("design:paramtypes", [Array])
], FileBoxElement.prototype, "accept", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], FileBoxElement.prototype, "directory", null);
__decorate([
    Property({ type: Array }),
    __metadata("design:type", Array),
    __metadata("design:paramtypes", [Array])
], FileBoxElement.prototype, "files", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [])
], FileBoxElement.prototype, "hasPrefix", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [])
], FileBoxElement.prototype, "hasSuffix", null);
__decorate([
    Emit({ eventName: 'filesSelected' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], FileBoxElement.prototype, "filesSelected", null);
FileBoxElement = __decorate([
    Component({
        selector: 'mosaik-filebox',
        template: fileBoxElementTemplate,
        themes: {
            joy: fileBoxElementJoyStyle,
            memphis: fileBoxElementMemphisStyle,
            cosmopolitan: fileBoxElementCosmopolitanStyle
        },
        host: {
            tabIndex: '0'
        },
        options: {
            mode: 'open',
            delegatesFocus: true
        },
        imports: [
            FocusRingElement,
            ButtonElement
        ]
    }),
    __metadata("design:paramtypes", [])
], FileBoxElement);
export { FileBoxElement };
//# sourceMappingURL=FileBoxElement.js.map