import * as i0 from '@angular/core';
import { input, booleanAttribute, output, inject, ElementRef, LOCALE_ID, Directive, computed, viewChild, ChangeDetectionStrategy, Component, numberAttribute, ChangeDetectorRef, NgModule } from '@angular/core';
import { elementUpload, elementRedo, elementDocument, elementDelete, elementCancel } from '@siemens/element-icons';
import { addIcons, SiIconComponent, SiStatusIconComponent } from '@siemens/element-ng/icon';
import { t, SiTranslatePipe } from '@siemens/element-translate-ng/translate';
import { HttpHeaders, HttpClient, HttpRequest, HttpResponse, HttpEventType } from '@angular/common/http';
import { SiInlineNotificationComponent } from '@siemens/element-ng/inline-notification';
import { SiProgressbarComponent } from '@siemens/element-ng/progressbar';
import { retry } from 'rxjs/operators';

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
/**
 * Directive for handling file uploads with validation for file type and size.
 *
 * @example
 * ```html
 * <input
 *   #fileInput
 *   type="file"
 *   class="d-none"
 *   siFileUpload
 *   [accept]="accept()"
 *   [maxFileSize]="maxFileSize()"
 *   [multiple]="true"
 *   (validFiles)="onFilesAdded($event)"
 *   (fileError)="onFileError($event)"
 * />
 * ```
 */
class SiFileUploadDirective {
    /**
     * Text or translation key of message title if incorrect file type is dragged / dropped.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.ERROR_FILE_TYPE:Incorrect file type selected`)
     * ```
     */
    errorTextFileType = input(t(() => $localize `:@@SI_FILE_UPLOADER.ERROR_FILE_TYPE:Incorrect file type selected`), ...(ngDevMode ? [{ debugName: "errorTextFileType" }] : []));
    /**
     * Message or translation key if file exceeds the maximum file size limit.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.ERROR_FILE_SIZE_EXCEEDED:File exceeds allowed maximum size`)
     * ```
     */
    errorTextFileMaxSize = input(t(() => $localize `:@@SI_FILE_UPLOADER.ERROR_FILE_SIZE_EXCEEDED:File exceeds allowed maximum size`), ...(ngDevMode ? [{ debugName: "errorTextFileMaxSize" }] : []));
    /**
     * Define which file types are suggested in file browser.
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#attr-accept
     */
    accept = input(...(ngDevMode ? [undefined, { debugName: "accept" }] : []));
    /**
     * Define maximal allowed file size in bytes.
     */
    maxFileSize = input(...(ngDevMode ? [undefined, { debugName: "maxFileSize" }] : []));
    /**
     * Defines whether the file input allows selecting multiple files.
     * When {@link directoryUpload} is enabled, this will have no effect.
     *
     * @defaultValue false
     */
    multiple = input(false, { ...(ngDevMode ? { debugName: "multiple" } : {}), transform: booleanAttribute });
    /**
     * Enable directory upload.
     *
     * @defaultValue false
     */
    directoryUpload = input(false, { ...(ngDevMode ? { debugName: "directoryUpload" } : {}), transform: booleanAttribute });
    /**
     * Event emitted when valid files are added.
     * Invalid files (due to size or type) will be ignored and instead the {@link fileError} event will be emitted.
     */
    validFiles = output();
    /**
     * Event emitted when valid files are added.
     * Also includes invalid files, but with status 'invalid' and an errorText describing why they were ignored.
     */
    filesAdded = output();
    /**
     * Event emitted when file validation errors occur, including files that were ignored due to size or type.
     */
    fileError = output();
    elementRef = inject((ElementRef));
    locale = inject(LOCALE_ID).toString();
    numberFormat = new Intl.NumberFormat(this.locale, { maximumFractionDigits: 2 });
    onInputChange(event) {
        const inputElement = event.target;
        this.handleFiles(inputElement.files);
    }
    /**
     * Handle files from input or drag and drop
     */
    handleFiles(files) {
        if (!files?.length) {
            return;
        }
        const newFiles = [];
        const validFiles = [];
        // eslint-disable-next-line @typescript-eslint/prefer-for-of
        for (let i = 0; i < files.length; i++) {
            const uploadFile = this.makeUploadFile(files[i]);
            newFiles.push(uploadFile);
            if (uploadFile.status === 'invalid' && uploadFile.errorText) {
                this.fileError.emit(uploadFile);
            }
            else if (uploadFile.status === 'added') {
                validFiles.push(uploadFile);
            }
        }
        if (newFiles.length > 0) {
            newFiles.sort((a, b) => a.fileName.localeCompare(b.fileName));
            this.filesAdded.emit(newFiles);
        }
        if (validFiles.length > 0) {
            validFiles.sort((a, b) => a.fileName.localeCompare(b.fileName));
            this.validFiles.emit(validFiles);
        }
        this.reset();
    }
    /**
     * Handle directory entries for drag and drop
     */
    handleItems(items) {
        const newFiles = [];
        let pendingEntries = 0;
        const traverseFileTree = (item) => {
            if (item.isFile) {
                item.file(file => {
                    const uploadFile = this.makeUploadFile(file);
                    newFiles.push(uploadFile);
                    if (uploadFile.status === 'invalid' && uploadFile.errorText) {
                        this.fileError.emit(uploadFile);
                    }
                    if (--pendingEntries === 0) {
                        if (newFiles.length > 0) {
                            this.filesAdded.emit(newFiles);
                        }
                        const validFiles = newFiles.filter(f => f.status === 'added');
                        if (validFiles.length > 0) {
                            this.filesAdded.emit(validFiles);
                        }
                        this.reset();
                    }
                });
            }
            else if (item.isDirectory) {
                const dirReader = item.createReader();
                dirReader.readEntries(entries => {
                    for (const entry of entries) {
                        pendingEntries++;
                        traverseFileTree(entry);
                    }
                    if (--pendingEntries === 0) {
                        if (newFiles.length > 0) {
                            this.filesAdded.emit(newFiles);
                        }
                        const validFiles = newFiles.filter(f => f.status === 'added');
                        if (validFiles.length > 0) {
                            this.filesAdded.emit(validFiles);
                        }
                        this.reset();
                    }
                });
            }
        };
        // items is not an array but of type DataTransferItemList
        // eslint-disable-next-line @typescript-eslint/prefer-for-of
        for (let i = 0; i < items.length; i++) {
            const item = items[i].webkitGetAsEntry();
            if (item) {
                pendingEntries++;
                traverseFileTree(item);
            }
        }
    }
    /**
     * Reset the file input value
     */
    reset() {
        this.elementRef.nativeElement.value = '';
    }
    /**
     * Trigger the file input click
     */
    triggerClick() {
        this.elementRef.nativeElement.click();
    }
    makeUploadFile(file) {
        const uploadFile = {
            fileName: file.name,
            file,
            size: this.fileSizeToString(file.size),
            progress: 0,
            status: 'added'
        };
        // use MIME type of file if set. Otherwise fall back to file name ending
        const ext = '.' + uploadFile.file.name.split('.').pop();
        if (!this.verifyFileType(uploadFile.file.type, ext)) {
            uploadFile.status = 'invalid';
            uploadFile.errorText = this.errorTextFileType();
        }
        else if (!this.verifyFileSize(uploadFile.file.size)) {
            uploadFile.status = 'invalid';
            uploadFile.errorText = this.errorTextFileMaxSize();
        }
        return uploadFile;
    }
    verifyFileSize(size) {
        const maxFileSize = this.maxFileSize();
        return !maxFileSize || size <= maxFileSize;
    }
    verifyFileType(fileType, ext) {
        const accept = this.accept();
        if (!accept) {
            return true;
        }
        if (fileType === undefined && ext === undefined) {
            return false;
        }
        // Spec says that comma is the delimiter for filetypes. Also allow pipe for compatibility
        return accept.split(/,|\|/).some(acceptedType => {
            // convert accept glob into regex (example: images/* --> images/.*)
            const acceptedRegexStr = acceptedType.replace(/\./g, '\\.').replace('*', '.*').trim();
            const acceptedRegex = new RegExp(acceptedRegexStr, 'i');
            // if fileType is set and accepted type looks like a MIME type, match that otherwise extension
            if (fileType && acceptedType.includes('/')) {
                return !!fileType.match(acceptedRegex);
            }
            return !!ext?.match(acceptedRegex);
        });
    }
    fileSizeToString(num) {
        return SiFileUploadDirective.formatFileSize(num, this.numberFormat);
    }
    static formatFileSize(num, formatter) {
        const numberFormat = formatter ?? new Intl.NumberFormat('en-US', { maximumFractionDigits: 2 });
        let suffix = 'B';
        if (num >= 1_073_741_824) {
            num /= 1_073_741_824;
            suffix = 'GB';
        }
        else if (num >= 1_048_576) {
            num /= 1_048_576;
            suffix = 'MB';
        }
        else if (num >= 1_024) {
            num /= 1_024;
            suffix = 'KB';
        }
        return numberFormat.format(num) + suffix;
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiFileUploadDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.8", type: SiFileUploadDirective, isStandalone: true, selector: "input[type=\"file\"][siFileUpload]", inputs: { errorTextFileType: { classPropertyName: "errorTextFileType", publicName: "errorTextFileType", isSignal: true, isRequired: false, transformFunction: null }, errorTextFileMaxSize: { classPropertyName: "errorTextFileMaxSize", publicName: "errorTextFileMaxSize", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, directoryUpload: { classPropertyName: "directoryUpload", publicName: "directoryUpload", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { validFiles: "validFiles", filesAdded: "filesAdded", fileError: "fileError" }, host: { listeners: { "change": "onInputChange($event)" }, properties: { "attr.accept": "accept()", "multiple": "directoryUpload() || multiple()", "attr.webkitdirectory": "directoryUpload() ? \"\" : null" } }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiFileUploadDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: 'input[type="file"][siFileUpload]',
                    host: {
                        '[attr.accept]': 'accept()',
                        '[multiple]': 'directoryUpload() || multiple()',
                        '[attr.webkitdirectory]': 'directoryUpload() ? "" : null',
                        '(change)': 'onInputChange($event)'
                    }
                }]
        }], propDecorators: { errorTextFileType: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorTextFileType", required: false }] }], errorTextFileMaxSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorTextFileMaxSize", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], directoryUpload: [{ type: i0.Input, args: [{ isSignal: true, alias: "directoryUpload", required: false }] }], validFiles: [{ type: i0.Output, args: ["validFiles"] }], filesAdded: [{ type: i0.Output, args: ["filesAdded"] }], fileError: [{ type: i0.Output, args: ["fileError"] }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiFileDropzoneComponent {
    /**
     * Text or translation key of the input file selector (is combined with the `uploadTextRest`).
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.FILE_SELECT:click to upload`)
     * ```
     */
    uploadTextFileSelect = input(t(() => $localize `:@@SI_FILE_UPLOADER.FILE_SELECT:click to upload`), ...(ngDevMode ? [{ debugName: "uploadTextFileSelect" }] : []));
    /**
     * Text or translation key of the drag&drop field (is combined with the `uploadTextFileSelect`).
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.DROP:Drop files here or`)
     * ```
     */
    uploadDropText = input(t(() => $localize `:@@SI_FILE_UPLOADER.DROP:Drop files here or`), ...(ngDevMode ? [{ debugName: "uploadDropText" }] : []));
    /**
     * Text or translation key for max file size.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.MAX_SIZE:Max. {{maxFileSize}} upload size.`)
     * ```
     */
    maxFileSizeText = input(t(() => $localize `:@@SI_FILE_UPLOADER.MAX_SIZE:Max. {{maxFileSize}} upload size.`), ...(ngDevMode ? [{ debugName: "maxFileSizeText" }] : []));
    /**
     * Text or translation key for accepted types.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.ACCEPTED_FILE_TYPES:Accepted file types: {{accept}}.`)
     * ```
     */
    acceptText = input(t(() => $localize `:@@SI_FILE_UPLOADER.ACCEPTED_FILE_TYPES:Accepted file types: {{accept}}.`), ...(ngDevMode ? [{ debugName: "acceptText" }] : []));
    /**
     * Text or translation key of message title if incorrect file type is dragged / dropped.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.ERROR_FILE_TYPE:Incorrect file type selected`)
     * ```
     */
    errorTextFileType = input(t(() => $localize `:@@SI_FILE_UPLOADER.ERROR_FILE_TYPE:Incorrect file type selected`), ...(ngDevMode ? [{ debugName: "errorTextFileType" }] : []));
    /**
     * Message or translation key if file exceeds the maximum file size limit.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.ERROR_FILE_SIZE_EXCEEDED:File exceeds allowed maximum size`)
     * ```
     */
    errorTextFileMaxSize = input(t(() => $localize `:@@SI_FILE_UPLOADER.ERROR_FILE_SIZE_EXCEEDED:File exceeds allowed maximum size`), ...(ngDevMode ? [{ debugName: "errorTextFileMaxSize" }] : []));
    /**
     * Define which file types are suggested in file browser.
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#attr-accept
     */
    accept = input(...(ngDevMode ? [undefined, { debugName: "accept" }] : []));
    /**
     * Define maximal allowed file size in bytes.
     */
    maxFileSize = input(...(ngDevMode ? [undefined, { debugName: "maxFileSize" }] : []));
    /**
     * Defines whether the file input allows selecting multiple files.
     * When {@link directoryUpload} is enabled, this will have no effect.
     *
     * @defaultValue false
     */
    multiple = input(false, { ...(ngDevMode ? { debugName: "multiple" } : {}), transform: booleanAttribute });
    /**
     * Event emitted when valid files are added.
     * Invalid files are also included here, but with status 'invalid' and an errorText describing why they were ignored.
     */
    filesAdded = output();
    /**
     * Event emitted when file validation errors occur, including files that were ignored due to size or type.
     */
    fileError = output();
    /**
     * Enable directory upload.
     *
     * @defaultValue false
     */
    directoryUpload = input(false, { ...(ngDevMode ? { debugName: "directoryUpload" } : {}), transform: booleanAttribute });
    maxFileSizeString = computed(() => {
        const maxFileSize = this.maxFileSize();
        return maxFileSize ? this.fileUploadDirective().fileSizeToString(maxFileSize) : '';
    }, ...(ngDevMode ? [{ debugName: "maxFileSizeString" }] : []));
    icons = addIcons({ elementUpload });
    dragOver = false;
    fileUploadDirective = viewChild.required(SiFileUploadDirective);
    dropHandler(event) {
        event.preventDefault();
        if (this.directoryUpload()) {
            this.fileUploadDirective().handleItems(event.dataTransfer.items);
        }
        else {
            this.fileUploadDirective().handleFiles(event.dataTransfer.files);
        }
        this.dragOver = false;
    }
    dragOverHandler(event) {
        event.preventDefault();
        event.stopPropagation();
        this.dragOver = true;
    }
    inputEnterHandler() {
        this.fileUploadDirective().triggerClick();
    }
    onFilesAdded(files) {
        this.filesAdded.emit(files);
    }
    onFileError(error) {
        this.fileError.emit(error);
    }
    /**
     * Reset all the files inside the native file input (and therefore the dropzone).
     */
    reset() {
        this.fileUploadDirective().reset();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiFileDropzoneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: SiFileDropzoneComponent, isStandalone: true, selector: "si-file-dropzone", inputs: { uploadTextFileSelect: { classPropertyName: "uploadTextFileSelect", publicName: "uploadTextFileSelect", isSignal: true, isRequired: false, transformFunction: null }, uploadDropText: { classPropertyName: "uploadDropText", publicName: "uploadDropText", isSignal: true, isRequired: false, transformFunction: null }, maxFileSizeText: { classPropertyName: "maxFileSizeText", publicName: "maxFileSizeText", isSignal: true, isRequired: false, transformFunction: null }, acceptText: { classPropertyName: "acceptText", publicName: "acceptText", isSignal: true, isRequired: false, transformFunction: null }, errorTextFileType: { classPropertyName: "errorTextFileType", publicName: "errorTextFileType", isSignal: true, isRequired: false, transformFunction: null }, errorTextFileMaxSize: { classPropertyName: "errorTextFileMaxSize", publicName: "errorTextFileMaxSize", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, directoryUpload: { classPropertyName: "directoryUpload", publicName: "directoryUpload", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filesAdded: "filesAdded", fileError: "fileError" }, viewQueries: [{ propertyName: "fileUploadDirective", first: true, predicate: SiFileUploadDirective, descendants: true, isSignal: true }], ngImport: i0, template: "<div\n  class=\"drag-and-drop rounded p-6\"\n  [class.drag-over]=\"dragOver\"\n  (drop)=\"dropHandler($event)\"\n  (dragover)=\"dragOverHandler($event)\"\n  (dragleave)=\"dragOver = false\"\n>\n  <si-icon class=\"mb-6 si-display-bold\" [icon]=\"icons.elementUpload\" />\n  <span class=\"drag-and-drop-description si-h5 d-flex\">\n    <span>{{ uploadDropText() | translate }}</span>\n    &nbsp;\n    <label class=\"select-file si-h5 mb-0\">\n      <span tabindex=\"0\" (keydown.enter)=\"inputEnterHandler()\">{{\n        uploadTextFileSelect() | translate\n      }}</span>\n      <input\n        #fileInput\n        type=\"file\"\n        tabindex=\"-1\"\n        class=\"d-none\"\n        siFileUpload\n        [accept]=\"accept()\"\n        [maxFileSize]=\"maxFileSize()\"\n        [multiple]=\"multiple()\"\n        [directoryUpload]=\"directoryUpload()\"\n        [errorTextFileType]=\"errorTextFileType()\"\n        [errorTextFileMaxSize]=\"errorTextFileMaxSize()\"\n        (filesAdded)=\"onFilesAdded($event)\"\n        (fileError)=\"onFileError($event)\"\n        (cancel)=\"$event.stopPropagation()\"\n      />\n    </label>\n  </span>\n  @if (maxFileSize() || accept()) {\n    <div class=\"allowed si-caption mt-6 text-center\">\n      @if (maxFileSize()) {\n        {{ maxFileSizeText() | translate: { maxFileSize: maxFileSizeString() } }}\n      }\n      @if (accept()) {\n        {{ acceptText() | translate: { accept: accept() } }}\n      }\n    </div>\n  }\n</div>\n", styles: [":host{display:block}.select-file{margin-block-end:0;cursor:pointer;color:var(--element-ui-0)}.select-file:hover,.select-file:active{text-decoration:underline}.drag-and-drop{background-color:var(--element-base-1);border:1px dashed var(--element-ui-2);display:flex;flex-direction:column;justify-content:center;align-items:center}.drag-and-drop.drag-over{border:1px solid var(--element-focus-default);box-shadow:0 0 0 1px var(--element-focus-default)}\n"], dependencies: [{ kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "directive", type: SiFileUploadDirective, selector: "input[type=\"file\"][siFileUpload]", inputs: ["errorTextFileType", "errorTextFileMaxSize", "accept", "maxFileSize", "multiple", "directoryUpload"], outputs: ["validFiles", "filesAdded", "fileError"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiFileDropzoneComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-file-dropzone', imports: [SiIconComponent, SiTranslatePipe, SiFileUploadDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n  class=\"drag-and-drop rounded p-6\"\n  [class.drag-over]=\"dragOver\"\n  (drop)=\"dropHandler($event)\"\n  (dragover)=\"dragOverHandler($event)\"\n  (dragleave)=\"dragOver = false\"\n>\n  <si-icon class=\"mb-6 si-display-bold\" [icon]=\"icons.elementUpload\" />\n  <span class=\"drag-and-drop-description si-h5 d-flex\">\n    <span>{{ uploadDropText() | translate }}</span>\n    &nbsp;\n    <label class=\"select-file si-h5 mb-0\">\n      <span tabindex=\"0\" (keydown.enter)=\"inputEnterHandler()\">{{\n        uploadTextFileSelect() | translate\n      }}</span>\n      <input\n        #fileInput\n        type=\"file\"\n        tabindex=\"-1\"\n        class=\"d-none\"\n        siFileUpload\n        [accept]=\"accept()\"\n        [maxFileSize]=\"maxFileSize()\"\n        [multiple]=\"multiple()\"\n        [directoryUpload]=\"directoryUpload()\"\n        [errorTextFileType]=\"errorTextFileType()\"\n        [errorTextFileMaxSize]=\"errorTextFileMaxSize()\"\n        (filesAdded)=\"onFilesAdded($event)\"\n        (fileError)=\"onFileError($event)\"\n        (cancel)=\"$event.stopPropagation()\"\n      />\n    </label>\n  </span>\n  @if (maxFileSize() || accept()) {\n    <div class=\"allowed si-caption mt-6 text-center\">\n      @if (maxFileSize()) {\n        {{ maxFileSizeText() | translate: { maxFileSize: maxFileSizeString() } }}\n      }\n      @if (accept()) {\n        {{ acceptText() | translate: { accept: accept() } }}\n      }\n    </div>\n  }\n</div>\n", styles: [":host{display:block}.select-file{margin-block-end:0;cursor:pointer;color:var(--element-ui-0)}.select-file:hover,.select-file:active{text-decoration:underline}.drag-and-drop{background-color:var(--element-base-1);border:1px dashed var(--element-ui-2);display:flex;flex-direction:column;justify-content:center;align-items:center}.drag-and-drop.drag-over{border:1px solid var(--element-focus-default);box-shadow:0 0 0 1px var(--element-focus-default)}\n"] }]
        }], propDecorators: { uploadTextFileSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadTextFileSelect", required: false }] }], uploadDropText: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadDropText", required: false }] }], maxFileSizeText: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSizeText", required: false }] }], acceptText: [{ type: i0.Input, args: [{ isSignal: true, alias: "acceptText", required: false }] }], errorTextFileType: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorTextFileType", required: false }] }], errorTextFileMaxSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorTextFileMaxSize", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], filesAdded: [{ type: i0.Output, args: ["filesAdded"] }], fileError: [{ type: i0.Output, args: ["fileError"] }], directoryUpload: [{ type: i0.Input, args: [{ isSignal: true, alias: "directoryUpload", required: false }] }], fileUploadDirective: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SiFileUploadDirective), { isSignal: true }] }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiFileUploaderComponent {
    /**
     * Text of the link to open the file select dialog (follows `uploadDropText`).
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.FILE_SELECT:click to upload`)
     * ```
     */
    uploadTextFileSelect = input(t(() => $localize `:@@SI_FILE_UPLOADER.FILE_SELECT:click to upload`), ...(ngDevMode ? [{ debugName: "uploadTextFileSelect" }] : []));
    /**
     * Text instructing a user to drop the files inside the dropzone.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.DROP:Drop files here or`)
     * ```
     */
    uploadDropText = input(t(() => $localize `:@@SI_FILE_UPLOADER.DROP:Drop files here or`), ...(ngDevMode ? [{ debugName: "uploadDropText" }] : []));
    /**
     * Text to describe the maximum file size.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.MAX_SIZE:Max. {{maxFileSize}} upload size.`)
     * ```
     */
    maxFileSizeText = input(t(() => $localize `:@@SI_FILE_UPLOADER.MAX_SIZE:Max. {{maxFileSize}} upload size.`), ...(ngDevMode ? [{ debugName: "maxFileSizeText" }] : []));
    /**
     * Error message shown when the maximum number of files are reached.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.MAX_FILE_REACHED:Max. {{maxFiles}} files`)
     * ```
     */
    maxFilesReachedText = input(t(() => $localize `:@@SI_FILE_UPLOADER.MAX_FILE_REACHED:Max. {{maxFiles}} files`), ...(ngDevMode ? [{ debugName: "maxFilesReachedText" }] : []));
    /**
     * Text for the accepted file types.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.ACCEPTED_FILE_TYPES:Accepted file types: {{accept}}.`)
     * ```
     */
    acceptText = input(t(() => $localize `:@@SI_FILE_UPLOADER.ACCEPTED_FILE_TYPES:Accepted file types: {{accept}}.`), ...(ngDevMode ? [{ debugName: "acceptText" }] : []));
    /**
     * Text used inside the upload button.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.UPLOAD:Upload`)
     * ```
     */
    uploadButtonText = input(t(() => $localize `:@@SI_FILE_UPLOADER.UPLOAD:Upload`), ...(ngDevMode ? [{ debugName: "uploadButtonText" }] : []));
    /**
     * Text used inside the clear button.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.CLEAR:Clear`)
     * ```
     */
    clearButtonText = input(t(() => $localize `:@@SI_FILE_UPLOADER.CLEAR:Clear`), ...(ngDevMode ? [{ debugName: "clearButtonText" }] : []));
    /**
     * Text shown during the file upload.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.UPLOADING:Uploading`)
     * ```
     */
    uploadingText = input(t(() => $localize `:@@SI_FILE_UPLOADER.UPLOADING:Uploading`), ...(ngDevMode ? [{ debugName: "uploadingText" }] : []));
    /**
     * Text shown to remove a file from the file list. Required for a11y.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.REMOVE:Remove`)
     * ```
     */
    removeButtonText = input(t(() => $localize `:@@SI_FILE_UPLOADER.REMOVE:Remove`), ...(ngDevMode ? [{ debugName: "removeButtonText" }] : []));
    /**
     * Text of cancel button. Shown during upload. Required for a11y.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.CANCEL:Cancel`)
     * ```
     */
    cancelButtonText = input(t(() => $localize `:@@SI_FILE_UPLOADER.CANCEL:Cancel`), ...(ngDevMode ? [{ debugName: "cancelButtonText" }] : []));
    /**
     * Text shown if the upload was successful.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.UPLOAD_COMPLETED:Upload completed`)
     * ```
     */
    successTextTitle = input(t(() => $localize `:@@SI_FILE_UPLOADER.UPLOAD_COMPLETED:Upload completed`), ...(ngDevMode ? [{ debugName: "successTextTitle" }] : []));
    /**
     * Text shown if the upload failed.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.UPLOAD_FAILED:Upload failed`)
     * ```
     */
    errorUploadFailed = input(t(() => $localize `:@@SI_FILE_UPLOADER.UPLOAD_FAILED:Upload failed`), ...(ngDevMode ? [{ debugName: "errorUploadFailed" }] : []));
    /**
     * On failed upload, show the error received from the server.
     *
     * @defaultValue false
     */
    showHttpError = input(false, { ...(ngDevMode ? { debugName: "showHttpError" } : {}), transform: booleanAttribute });
    /**
     * Text shown to indicate that an incorrect file type was added to file list.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.ERROR_FILE_TYPE:Incorrect file type selected`)
     * ```
     */
    errorTextFileType = input(t(() => $localize `:@@SI_FILE_UPLOADER.ERROR_FILE_TYPE:Incorrect file type selected`), ...(ngDevMode ? [{ debugName: "errorTextFileType" }] : []));
    /**
     * Message or translation key if file exceeds the maximum file size limit.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_FILE_UPLOADER.ERROR_FILE_SIZE_EXCEEDED:File exceeds allowed maximum size`)
     * ```
     */
    errorTextFileMaxSize = input(t(() => $localize `:@@SI_FILE_UPLOADER.ERROR_FILE_SIZE_EXCEEDED:File exceeds allowed maximum size`), ...(ngDevMode ? [{ debugName: "errorTextFileMaxSize" }] : []));
    /**
     * Config for HTTP request to upload file.
     *
     * @defaultValue
     * ```
     * {
     *     headers: new HttpHeaders({ 'Accept': 'application/json' }),
     *     method: 'POST',
     *     url: '',
     *     fieldName: 'upload_file',
     *     responseType: 'json'
     *   }
     * ```
     */
    uploadConfig = input({
        headers: new HttpHeaders({ 'Accept': 'application/json' }),
        method: 'POST',
        url: '',
        fieldName: 'upload_file',
        responseType: 'json'
    }, ...(ngDevMode ? [{ debugName: "uploadConfig" }] : []));
    /**
     * Define which file types are suggested in file browser.
     * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#attr-accept
     */
    accept = input(...(ngDevMode ? [undefined, { debugName: "accept" }] : []));
    /**
     * Define maximal allowed file size in bytes.
     *
     * @defaultValue undefined
     */
    maxFileSize = input(undefined, { ...(ngDevMode ? { debugName: "maxFileSize" } : {}), transform: numberAttribute });
    /**
     * Define maximal allowed number of files.
     * When {@link directoryUpload} is enabled, this will have no effect.
     * @defaultValue 10
     */
    maxFiles = input(10, { ...(ngDevMode ? { debugName: "maxFiles" } : {}), transform: numberAttribute });
    /**
     * Maximum number of concurrent uploads.
     *
     * @defaultValue 3
     */
    maxConcurrentUploads = input(3, { ...(ngDevMode ? { debugName: "maxConcurrentUploads" } : {}), transform: numberAttribute });
    /**
     * Numbers of retries for failed uploads.
     *
     * @defaultValue 0
     */
    retries = input(0, { ...(ngDevMode ? { debugName: "retries" } : {}), transform: numberAttribute });
    /**
     * Auto-upload mode - automatically start upload once files are added.
     *
     * @defaultValue false
     */
    autoUpload = input(false, { ...(ngDevMode ? { debugName: "autoUpload" } : {}), transform: booleanAttribute });
    /**
     * Disable the upload button.
     *
     * @defaultValue false
     */
    disableUpload = input(false, { ...(ngDevMode ? { debugName: "disableUpload" } : {}), transform: booleanAttribute });
    /**
     * Enable directory upload mode.
     * When enabled, the file input will accept directories and upload all files within as a flat list.
     * The hierarchy of the directory will not be preserved.
     * The `maxFiles` property will have no effect when `directoryUpload` is enabled.
     *
     * **Note:** This feature is not yet available for safari (iOS)
     *
     * @defaultValue false
     */
    directoryUpload = input(false, { ...(ngDevMode ? { debugName: "directoryUpload" } : {}), transform: booleanAttribute });
    /**
     * Emits when a user press cancel during upload. The event provides the file details.
     */
    uploadCanceled = output();
    /**
     * Output callback event will provide you if upload is finished. If an error
     * occurred it will be emitted.
     */
    uploadCompleted = output();
    /**
     * Output which fires whenever new files are added to or removed from the uploader.
     */
    filesChanges = output();
    icons = addIcons({
        elementCancel,
        elementDelete,
        elementDocument,
        elementRedo
    });
    files = [];
    pending = 0;
    uploading = 0;
    uploadEnabled = false;
    maxFilesReached = false;
    dropZone = viewChild.required('dropZone');
    cdRef = inject(ChangeDetectorRef);
    http = inject(HttpClient, { optional: true });
    ngOnChanges(changes) {
        if (changes.maxFiles || changes.disableUpload) {
            this.updateStates();
        }
    }
    handleFiles(files) {
        if (!files?.length) {
            return;
        }
        const maxFiles = this.maxFiles();
        // for single-file case, replace exiting file if any
        if (maxFiles === 1 && this.files.length) {
            this.reset(false);
        }
        let numValid = this.countValid();
        for (const file of files) {
            const duplicate = this.isDuplicate(file);
            if (duplicate) {
                // in case this is duplicated: reset if already uploaded or not handled yet
                if (duplicate.status !== 'uploading' && duplicate.status !== 'queued') {
                    Object.assign(duplicate, file);
                }
                continue;
            }
            const canAdd = numValid + 1 <= maxFiles;
            const valid = file.status === 'added';
            if (valid && !canAdd) {
                this.maxFilesReached = true;
                break;
            }
            else if (valid) {
                numValid++;
            }
            this.files.push(file);
        }
        this.files.sort((a, b) => a.fileName.localeCompare(b.fileName));
        this.filesChanges.emit(this.files.slice());
        this.updateStates();
        // needed for drag drop of directory
        this.cdRef.markForCheck();
        if (this.autoUpload()) {
            // allow concurrent uploads for auto upload mode.
            this.uploadEnabled = true;
            this.fileUpload(false);
        }
    }
    removeFile(index) {
        if (index >= 0) {
            this.files.splice(index, 1);
            this.filesChanges.emit(this.files.slice());
            this.dropZone().reset();
            this.updateStates();
        }
    }
    cancelUpload(file) {
        if (file.subscription) {
            file.subscription.unsubscribe();
            file.subscription = undefined;
            this.uploading--;
        }
        this.pending--;
        file.status = 'added';
        file.progress = 0;
        this.updateStates();
        const { status, fileName, size, progress } = file;
        this.uploadCanceled.emit({
            status,
            fileName,
            size,
            progress,
            file: file.file
        });
    }
    retryUpload(file) {
        file.status = 'added';
        this.doUpload([file], true);
    }
    /**
     * Reset the state.
     */
    reset(emit = true) {
        this.files.forEach(f => f.subscription?.unsubscribe());
        this.files = [];
        this.dropZone().reset();
        this.updateStates();
        if (emit) {
            this.filesChanges.emit([]);
        }
    }
    /**
     * Uploads the file
     */
    fileUpload(doRetry = true) {
        if (!this.uploadEnabled) {
            return;
        }
        this.uploadEnabled = false;
        this.doUpload(this.files, doRetry);
    }
    doUpload(files, doRetry) {
        for (const file of files) {
            if (file.status !== 'added' && (!doRetry || file.status !== 'error')) {
                continue;
            }
            this.pending++;
            file.status = 'queued';
        }
        this.processQueue();
    }
    processQueue() {
        for (let i = 0; i < this.files.length && this.uploading < this.maxConcurrentUploads(); i++) {
            const file = this.files[i];
            if (file.status === 'queued') {
                this.uploading++;
                this.uploadOneFile(file);
            }
        }
    }
    uploadOneFile(file) {
        let formData;
        const config = this.uploadConfig();
        if (!config.sendBinary) {
            formData = new FormData();
            if (config.additionalFields) {
                Object.keys(config.additionalFields).forEach(key => {
                    formData.append(key, config.additionalFields[key]);
                });
            }
            // this needs to be last for AWS
            formData.append(config.fieldName, file.file, file.fileName);
        }
        const headers = config.headers instanceof HttpHeaders ? config.headers : new HttpHeaders(config.headers);
        const req = new HttpRequest(config.method, config.url, formData ?? file.file, {
            headers,
            responseType: config.responseType,
            reportProgress: true
        });
        file.status = 'uploading';
        file.errorText = undefined;
        file.httpErrorText = undefined;
        const requestHandler = config.handler ??
            (this.http ? (r) => this.http.request(r) : undefined);
        if (!requestHandler) {
            return;
        }
        file.subscription = requestHandler(req)
            .pipe(retry(this.retries()))
            .subscribe({
            next: event => this.handleUploadEvent(file, event),
            error: (error) => this.handleUploadError(file, error),
            complete: () => this.handleUploadComplete(file)
        });
    }
    // this is a light check for duplicate file - name and size only, not content!
    isDuplicate(file) {
        for (const uploadFile of this.files) {
            if (uploadFile.file.name === file.file.name && uploadFile.file.size === file.file.size) {
                return uploadFile;
            }
        }
        return null;
    }
    handleUploadEvent(file, httpEvent) {
        if (httpEvent instanceof HttpResponse) {
            file.successResponse = httpEvent;
        }
        else if (httpEvent.type === HttpEventType.UploadProgress && httpEvent.total) {
            file.progress = Math.floor((100 * httpEvent.loaded) / httpEvent.total);
            this.cdRef.markForCheck();
        }
    }
    handleUploadError(file, error) {
        this.uploadCompleted.emit({ file: file.fileName, error });
        file.status = 'error';
        file.errorText = this.errorUploadFailed();
        if (this.showHttpError() && error.status && error.statusText) {
            file.httpErrorText = `${error.status}: ${error.statusText}`;
        }
        this.oneUploadDone(file);
    }
    handleUploadComplete(file) {
        this.uploadCompleted.emit({ file: file.fileName, response: file.successResponse });
        file.status = 'success';
        file.progress = 100;
        file.successResponse = undefined;
        if (this.autoUpload()) {
            this.fadeOut(file);
        }
        this.oneUploadDone(file);
    }
    oneUploadDone(file) {
        file.subscription = undefined;
        this.pending--;
        this.uploading--;
        this.updateStates();
        this.processQueue();
    }
    fadeOut(file) {
        setTimeout(() => {
            file.fadeOut = true;
            this.cdRef.markForCheck();
            setTimeout(() => {
                this.removeFile(this.files.indexOf(file));
                this.cdRef.markForCheck();
            }, 500);
            this.cdRef.markForCheck();
        }, 3500);
    }
    updateStates() {
        this.uploadEnabled =
            !this.disableUpload() &&
                !this.pending &&
                this.files.some(f => f.status === 'added' || f.status === 'error');
        if (this.maxFilesReached && this.countValid() < this.maxFiles()) {
            this.maxFilesReached = false;
        }
    }
    countValid() {
        return this.files.reduce((acc, f) => acc + (f.status !== 'invalid' ? 1 : 0), 0);
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiFileUploaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: SiFileUploaderComponent, isStandalone: true, selector: "si-file-uploader", inputs: { uploadTextFileSelect: { classPropertyName: "uploadTextFileSelect", publicName: "uploadTextFileSelect", isSignal: true, isRequired: false, transformFunction: null }, uploadDropText: { classPropertyName: "uploadDropText", publicName: "uploadDropText", isSignal: true, isRequired: false, transformFunction: null }, maxFileSizeText: { classPropertyName: "maxFileSizeText", publicName: "maxFileSizeText", isSignal: true, isRequired: false, transformFunction: null }, maxFilesReachedText: { classPropertyName: "maxFilesReachedText", publicName: "maxFilesReachedText", isSignal: true, isRequired: false, transformFunction: null }, acceptText: { classPropertyName: "acceptText", publicName: "acceptText", isSignal: true, isRequired: false, transformFunction: null }, uploadButtonText: { classPropertyName: "uploadButtonText", publicName: "uploadButtonText", isSignal: true, isRequired: false, transformFunction: null }, clearButtonText: { classPropertyName: "clearButtonText", publicName: "clearButtonText", isSignal: true, isRequired: false, transformFunction: null }, uploadingText: { classPropertyName: "uploadingText", publicName: "uploadingText", isSignal: true, isRequired: false, transformFunction: null }, removeButtonText: { classPropertyName: "removeButtonText", publicName: "removeButtonText", isSignal: true, isRequired: false, transformFunction: null }, cancelButtonText: { classPropertyName: "cancelButtonText", publicName: "cancelButtonText", isSignal: true, isRequired: false, transformFunction: null }, successTextTitle: { classPropertyName: "successTextTitle", publicName: "successTextTitle", isSignal: true, isRequired: false, transformFunction: null }, errorUploadFailed: { classPropertyName: "errorUploadFailed", publicName: "errorUploadFailed", isSignal: true, isRequired: false, transformFunction: null }, showHttpError: { classPropertyName: "showHttpError", publicName: "showHttpError", isSignal: true, isRequired: false, transformFunction: null }, errorTextFileType: { classPropertyName: "errorTextFileType", publicName: "errorTextFileType", isSignal: true, isRequired: false, transformFunction: null }, errorTextFileMaxSize: { classPropertyName: "errorTextFileMaxSize", publicName: "errorTextFileMaxSize", isSignal: true, isRequired: false, transformFunction: null }, uploadConfig: { classPropertyName: "uploadConfig", publicName: "uploadConfig", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, maxFiles: { classPropertyName: "maxFiles", publicName: "maxFiles", isSignal: true, isRequired: false, transformFunction: null }, maxConcurrentUploads: { classPropertyName: "maxConcurrentUploads", publicName: "maxConcurrentUploads", isSignal: true, isRequired: false, transformFunction: null }, retries: { classPropertyName: "retries", publicName: "retries", isSignal: true, isRequired: false, transformFunction: null }, autoUpload: { classPropertyName: "autoUpload", publicName: "autoUpload", isSignal: true, isRequired: false, transformFunction: null }, disableUpload: { classPropertyName: "disableUpload", publicName: "disableUpload", isSignal: true, isRequired: false, transformFunction: null }, directoryUpload: { classPropertyName: "directoryUpload", publicName: "directoryUpload", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { uploadCanceled: "uploadCanceled", uploadCompleted: "uploadCompleted", filesChanges: "filesChanges" }, viewQueries: [{ propertyName: "dropZone", first: true, predicate: ["dropZone"], descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<si-file-dropzone\n  #dropZone\n  [class]=\"autoUpload() ? 'mb-8' : 'mb-4'\"\n  [uploadTextFileSelect]=\"uploadTextFileSelect()\"\n  [uploadDropText]=\"uploadDropText()\"\n  [multiple]=\"maxFiles() > 1\"\n  [directoryUpload]=\"directoryUpload()\"\n  [maxFileSizeText]=\"maxFileSizeText()\"\n  [acceptText]=\"acceptText()\"\n  [errorTextFileType]=\"errorTextFileType()\"\n  [errorTextFileMaxSize]=\"errorTextFileMaxSize()\"\n  [accept]=\"accept()\"\n  [maxFileSize]=\"maxFileSize()\"\n  (filesAdded)=\"handleFiles($event)\"\n/>\n\n@if (maxFilesReached) {\n  <si-inline-notification\n    class=\"mb-4\"\n    severity=\"info\"\n    [message]=\"maxFilesReachedText()\"\n    [translationParams]=\"{ maxFiles: maxFiles() }\"\n  />\n}\n\n<div class=\"file-list\">\n  @for (file of files; track file) {\n    <div [class]=\"`file d-flex ${autoUpload() ? 'mb-8' : 'mb-4'}`\" [class.fade-out]=\"file.fadeOut\">\n      <si-icon class=\"icon align-self-center ms-6 me-4\" [icon]=\"icons.elementDocument\" />\n      <div class=\"flex-fill overflow-hidden\">\n        <div class=\"file-info\">\n          <div class=\"file-name text-truncate si-h5\">{{ file.fileName }}</div>\n          <div class=\"file-size text-secondary\">{{ file.size }}</div>\n        </div>\n        @if (file.errorText) {\n          <div\n            class=\"error text-truncate d-flex align-items-center\"\n            [class.text-warning]=\"file.status === 'invalid'\"\n            [class.text-danger]=\"file.status === 'error'\"\n          >\n            <si-status-icon\n              class=\"icon-sm my-n2 me-2\"\n              [status]=\"file.status === 'invalid' ? 'warning' : 'danger'\"\n            />\n            {{ file.errorText | translate }}\n            @if (file.httpErrorText) {\n              : {{ file.httpErrorText }}\n            }\n          </div>\n        } @else {\n          <div class=\"position-relative\">\n            <div class=\"position-absolute si-caption end-0 mt-n8\">{{ file.progress }} %</div>\n            <si-progressbar\n              height=\"small\"\n              [value]=\"file.progress\"\n              [ariaLabel]=\"uploadingText() | translate\"\n            />\n          </div>\n        }\n      </div>\n      <div class=\"status align-self-center text-nowrap ps-4 pe-6\">\n        @if (file.status === 'error') {\n          <button\n            type=\"button\"\n            class=\"btn btn-circle btn-tertiary me-4\"\n            [disabled]=\"!uploadEnabled\"\n            [title]=\"uploadButtonText() | translate\"\n            [attr.aria-label]=\"uploadButtonText() | translate\"\n            (click)=\"retryUpload(file)\"\n          >\n            <si-icon [icon]=\"icons.elementRedo\" />\n          </button>\n        }\n        @if (file.status === 'added' || file.status === 'error' || file.status === 'invalid') {\n          <button\n            type=\"button\"\n            class=\"btn btn-circle btn-ghost\"\n            [title]=\"removeButtonText() | translate\"\n            [attr.aria-label]=\"removeButtonText() | translate\"\n            (click)=\"removeFile($index)\"\n          >\n            <si-icon [icon]=\"icons.elementDelete\" />\n          </button>\n        }\n        @if (file.status === 'uploading' || file.status === 'queued') {\n          <button\n            type=\"button\"\n            class=\"btn btn-circle btn-tertiary\"\n            [title]=\"cancelButtonText() | translate\"\n            [attr.aria-label]=\"cancelButtonText() | translate\"\n            (click)=\"cancelUpload(file)\"\n          >\n            <si-icon [icon]=\"icons.elementCancel\" />\n          </button>\n        }\n        @if (file.status === 'success') {\n          <si-status-icon class=\"icon mx-2\" status=\"success\" />\n        }\n      </div>\n    </div>\n  }\n</div>\n\n@if (!autoUpload()) {\n  <div class=\"buttons text-end\">\n    <button\n      type=\"button\"\n      class=\"btn btn-secondary me-4\"\n      [disabled]=\"pending || !files.length\"\n      (click)=\"reset()\"\n      >{{ clearButtonText() | translate }}</button\n    >\n    <button\n      type=\"button\"\n      class=\"btn btn-primary\"\n      [disabled]=\"!uploadEnabled\"\n      (click)=\"fileUpload()\"\n      >{{ uploadButtonText() | translate }}</button\n    >\n  </div>\n}\n", styles: [":host{display:flex;flex-direction:column;justify-content:center;align-items:stretch}:host>*{min-inline-size:320px;max-inline-size:680px;inline-size:100%;align-self:center}.file-list{overflow-y:auto}.file-info{display:flex;justify-content:center;flex-direction:column;block-size:56px}.file{min-block-size:72px;transition:opacity calc(.5s * var(--element-animations-enabled, 1))}.fade-out{opacity:0}\n"], dependencies: [{ kind: "component", type: SiStatusIconComponent, selector: "si-status-icon", inputs: ["status"] }, { kind: "component", type: SiFileDropzoneComponent, selector: "si-file-dropzone", inputs: ["uploadTextFileSelect", "uploadDropText", "maxFileSizeText", "acceptText", "errorTextFileType", "errorTextFileMaxSize", "accept", "maxFileSize", "multiple", "directoryUpload"], outputs: ["filesAdded", "fileError"] }, { kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "component", type: SiInlineNotificationComponent, selector: "si-inline-notification", inputs: ["severity", "heading", "message", "action", "translationParams", "embedded"] }, { kind: "component", type: SiProgressbarComponent, selector: "si-progressbar", inputs: ["ariaLabel", "max", "value", "heading", "progress", "height"] }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiFileUploaderComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-file-uploader', imports: [
                        SiStatusIconComponent,
                        SiFileDropzoneComponent,
                        SiIconComponent,
                        SiInlineNotificationComponent,
                        SiProgressbarComponent,
                        SiTranslatePipe
                    ], template: "<si-file-dropzone\n  #dropZone\n  [class]=\"autoUpload() ? 'mb-8' : 'mb-4'\"\n  [uploadTextFileSelect]=\"uploadTextFileSelect()\"\n  [uploadDropText]=\"uploadDropText()\"\n  [multiple]=\"maxFiles() > 1\"\n  [directoryUpload]=\"directoryUpload()\"\n  [maxFileSizeText]=\"maxFileSizeText()\"\n  [acceptText]=\"acceptText()\"\n  [errorTextFileType]=\"errorTextFileType()\"\n  [errorTextFileMaxSize]=\"errorTextFileMaxSize()\"\n  [accept]=\"accept()\"\n  [maxFileSize]=\"maxFileSize()\"\n  (filesAdded)=\"handleFiles($event)\"\n/>\n\n@if (maxFilesReached) {\n  <si-inline-notification\n    class=\"mb-4\"\n    severity=\"info\"\n    [message]=\"maxFilesReachedText()\"\n    [translationParams]=\"{ maxFiles: maxFiles() }\"\n  />\n}\n\n<div class=\"file-list\">\n  @for (file of files; track file) {\n    <div [class]=\"`file d-flex ${autoUpload() ? 'mb-8' : 'mb-4'}`\" [class.fade-out]=\"file.fadeOut\">\n      <si-icon class=\"icon align-self-center ms-6 me-4\" [icon]=\"icons.elementDocument\" />\n      <div class=\"flex-fill overflow-hidden\">\n        <div class=\"file-info\">\n          <div class=\"file-name text-truncate si-h5\">{{ file.fileName }}</div>\n          <div class=\"file-size text-secondary\">{{ file.size }}</div>\n        </div>\n        @if (file.errorText) {\n          <div\n            class=\"error text-truncate d-flex align-items-center\"\n            [class.text-warning]=\"file.status === 'invalid'\"\n            [class.text-danger]=\"file.status === 'error'\"\n          >\n            <si-status-icon\n              class=\"icon-sm my-n2 me-2\"\n              [status]=\"file.status === 'invalid' ? 'warning' : 'danger'\"\n            />\n            {{ file.errorText | translate }}\n            @if (file.httpErrorText) {\n              : {{ file.httpErrorText }}\n            }\n          </div>\n        } @else {\n          <div class=\"position-relative\">\n            <div class=\"position-absolute si-caption end-0 mt-n8\">{{ file.progress }} %</div>\n            <si-progressbar\n              height=\"small\"\n              [value]=\"file.progress\"\n              [ariaLabel]=\"uploadingText() | translate\"\n            />\n          </div>\n        }\n      </div>\n      <div class=\"status align-self-center text-nowrap ps-4 pe-6\">\n        @if (file.status === 'error') {\n          <button\n            type=\"button\"\n            class=\"btn btn-circle btn-tertiary me-4\"\n            [disabled]=\"!uploadEnabled\"\n            [title]=\"uploadButtonText() | translate\"\n            [attr.aria-label]=\"uploadButtonText() | translate\"\n            (click)=\"retryUpload(file)\"\n          >\n            <si-icon [icon]=\"icons.elementRedo\" />\n          </button>\n        }\n        @if (file.status === 'added' || file.status === 'error' || file.status === 'invalid') {\n          <button\n            type=\"button\"\n            class=\"btn btn-circle btn-ghost\"\n            [title]=\"removeButtonText() | translate\"\n            [attr.aria-label]=\"removeButtonText() | translate\"\n            (click)=\"removeFile($index)\"\n          >\n            <si-icon [icon]=\"icons.elementDelete\" />\n          </button>\n        }\n        @if (file.status === 'uploading' || file.status === 'queued') {\n          <button\n            type=\"button\"\n            class=\"btn btn-circle btn-tertiary\"\n            [title]=\"cancelButtonText() | translate\"\n            [attr.aria-label]=\"cancelButtonText() | translate\"\n            (click)=\"cancelUpload(file)\"\n          >\n            <si-icon [icon]=\"icons.elementCancel\" />\n          </button>\n        }\n        @if (file.status === 'success') {\n          <si-status-icon class=\"icon mx-2\" status=\"success\" />\n        }\n      </div>\n    </div>\n  }\n</div>\n\n@if (!autoUpload()) {\n  <div class=\"buttons text-end\">\n    <button\n      type=\"button\"\n      class=\"btn btn-secondary me-4\"\n      [disabled]=\"pending || !files.length\"\n      (click)=\"reset()\"\n      >{{ clearButtonText() | translate }}</button\n    >\n    <button\n      type=\"button\"\n      class=\"btn btn-primary\"\n      [disabled]=\"!uploadEnabled\"\n      (click)=\"fileUpload()\"\n      >{{ uploadButtonText() | translate }}</button\n    >\n  </div>\n}\n", styles: [":host{display:flex;flex-direction:column;justify-content:center;align-items:stretch}:host>*{min-inline-size:320px;max-inline-size:680px;inline-size:100%;align-self:center}.file-list{overflow-y:auto}.file-info{display:flex;justify-content:center;flex-direction:column;block-size:56px}.file{min-block-size:72px;transition:opacity calc(.5s * var(--element-animations-enabled, 1))}.fade-out{opacity:0}\n"] }]
        }], propDecorators: { uploadTextFileSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadTextFileSelect", required: false }] }], uploadDropText: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadDropText", required: false }] }], maxFileSizeText: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSizeText", required: false }] }], maxFilesReachedText: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFilesReachedText", required: false }] }], acceptText: [{ type: i0.Input, args: [{ isSignal: true, alias: "acceptText", required: false }] }], uploadButtonText: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadButtonText", required: false }] }], clearButtonText: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearButtonText", required: false }] }], uploadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadingText", required: false }] }], removeButtonText: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeButtonText", required: false }] }], cancelButtonText: [{ type: i0.Input, args: [{ isSignal: true, alias: "cancelButtonText", required: false }] }], successTextTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "successTextTitle", required: false }] }], errorUploadFailed: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorUploadFailed", required: false }] }], showHttpError: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHttpError", required: false }] }], errorTextFileType: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorTextFileType", required: false }] }], errorTextFileMaxSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorTextFileMaxSize", required: false }] }], uploadConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadConfig", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], maxFiles: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFiles", required: false }] }], maxConcurrentUploads: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxConcurrentUploads", required: false }] }], retries: [{ type: i0.Input, args: [{ isSignal: true, alias: "retries", required: false }] }], autoUpload: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoUpload", required: false }] }], disableUpload: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableUpload", required: false }] }], directoryUpload: [{ type: i0.Input, args: [{ isSignal: true, alias: "directoryUpload", required: false }] }], uploadCanceled: [{ type: i0.Output, args: ["uploadCanceled"] }], uploadCompleted: [{ type: i0.Output, args: ["uploadCompleted"] }], filesChanges: [{ type: i0.Output, args: ["filesChanges"] }], dropZone: [{ type: i0.ViewChild, args: ['dropZone', { isSignal: true }] }] } });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiFileUploaderModule {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiFileUploaderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
    static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.0.8", ngImport: i0, type: SiFileUploaderModule, imports: [SiFileDropzoneComponent, SiFileUploaderComponent, SiFileUploadDirective], exports: [SiFileDropzoneComponent, SiFileUploaderComponent, SiFileUploadDirective] });
    static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiFileUploaderModule, imports: [SiFileDropzoneComponent, SiFileUploaderComponent] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiFileUploaderModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [SiFileDropzoneComponent, SiFileUploaderComponent, SiFileUploadDirective],
                    exports: [SiFileDropzoneComponent, SiFileUploaderComponent, SiFileUploadDirective]
                }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */

/**
 * Generated bundle index. Do not edit.
 */

export { SiFileDropzoneComponent, SiFileUploadDirective, SiFileUploaderComponent, SiFileUploaderModule };
//# sourceMappingURL=siemens-element-ng-file-uploader.mjs.map
