import * as i0 from '@angular/core';
import { inject, ChangeDetectorRef, Pipe, input, output, model, computed, Component, signal } from '@angular/core';
import { Button } from '@masterteam/components/button';
import { map, tap, finalize, shareReplay, distinctUntilChanged, switchMap, filter, catchError } from 'rxjs/operators';
import { DomSanitizer } from '@angular/platform-browser';
import { Subscription, BehaviorSubject, of, finalize as finalize$1, catchError as catchError$1, throwError, take, forkJoin, map as map$1 } from 'rxjs';
import { HttpClient, HttpContext } from '@angular/common/http';
import { Avatar } from '@masterteam/components/avatar';
import * as i1 from '@jsverse/transloco';
import { TranslocoModule, TranslocoService } from '@jsverse/transloco';
import { Tooltip } from '@masterteam/components/tooltip';
import { Icon } from '@masterteam/icons';
import { Validators, NgControl } from '@angular/forms';
import { FieldValidation } from '@masterteam/components/field-validation';
import { Card } from '@masterteam/components/card';
import { ConfirmationService } from '@masterteam/components/confirmation';

class SecureImagePipe {
    static cachedBlobUrls = new Map();
    static pendingRequests = new Map();
    httpClient = inject(HttpClient);
    domSanitizer = inject(DomSanitizer);
    cdr = inject(ChangeDetectorRef);
    constructor() {
        this.setUpSubscription();
    }
    ngOnDestroy() {
        this.subscription.unsubscribe();
    }
    subscription = new Subscription();
    latestValue = '';
    transformValue = new BehaviorSubject(null);
    loading = false;
    transform(imagePath, wrapUrlOrContext, contextOrEndpoint, endPoint = 'uploader/') {
        const hasExtraArgs = arguments.length > 1;
        const isWrapFlag = typeof wrapUrlOrContext === 'boolean';
        let context;
        let wrapUrl = true;
        let useEndpoint = false;
        let endpoint = '';
        let sanitize = true;
        if (!hasExtraArgs || isWrapFlag) {
            // Backward compatible mode: (imagePath, wrapUrl?, context?, endPoint?)
            wrapUrl = isWrapFlag ? wrapUrlOrContext : false;
            useEndpoint = true;
            endpoint = endPoint;
            if (contextOrEndpoint instanceof HttpContext) {
                context = contextOrEndpoint;
            }
            else if (typeof contextOrEndpoint === 'string') {
                endpoint = contextOrEndpoint;
            }
            sanitize = false;
        }
        else {
            // Components mode: (imagePath, context)
            context = wrapUrlOrContext;
            wrapUrl = true;
            useEndpoint = false;
            endpoint = '';
            sanitize = true;
        }
        const fullPath = useEndpoint
            ? imagePath
                ? endpoint + imagePath
                : ''
            : imagePath;
        if (!fullPath || fullPath.includes('null')) {
            this.latestValue = '';
            this.loading = false;
            this.transformValue.next(null);
            return '';
        }
        this.transformValue.next({
            fullPath,
            cacheKey: SecureImagePipe.createCacheKey(fullPath, context),
            context,
            wrapUrl,
            useEndpoint,
            sanitize,
        });
        if (this.loading || !this.latestValue) {
            return '';
        }
        if (!useEndpoint || wrapUrl) {
            return this.latestValue;
        }
        return `url('${this.latestValue}')`;
    }
    static createCacheKey(fullPath, context) {
        if (!context) {
            return `default:${fullPath}`;
        }
        const contextSnapshot = Array.from(context.keys())
            .map((token) => SecureImagePipe.serializeContextValue(context.get(token)))
            .sort()
            .join('|');
        return `${contextSnapshot}:${fullPath}`;
    }
    static serializeContextValue(value) {
        if (value === null) {
            return 'null';
        }
        if (value === undefined) {
            return 'undefined';
        }
        if (typeof value !== 'object') {
            return String(value);
        }
        if (Array.isArray(value)) {
            return `[${value
                .map((item) => SecureImagePipe.serializeContextValue(item))
                .join(',')}]`;
        }
        const normalizedEntries = Object.entries(value)
            .sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey))
            .map(([key, entryValue]) => `${key}:${SecureImagePipe.serializeContextValue(entryValue)}`);
        return `{${normalizedEntries.join(',')}}`;
    }
    getOrLoadBlobUrl(request) {
        const cachedBlobUrl = SecureImagePipe.cachedBlobUrls.get(request.cacheKey);
        if (cachedBlobUrl) {
            return of(cachedBlobUrl);
        }
        const pendingRequest = SecureImagePipe.pendingRequests.get(request.cacheKey);
        if (pendingRequest) {
            return pendingRequest;
        }
        const request$ = this.httpClient
            .get(request.fullPath, {
            observe: 'response',
            responseType: 'blob',
            context: request.context,
        })
            .pipe(map((response) => response.body ? URL.createObjectURL(response.body) : ''), tap((blobUrl) => {
            if (blobUrl) {
                SecureImagePipe.cachedBlobUrls.set(request.cacheKey, blobUrl);
            }
        }), finalize(() => {
            SecureImagePipe.pendingRequests.delete(request.cacheKey);
        }), shareReplay(1));
        SecureImagePipe.pendingRequests.set(request.cacheKey, request$);
        return request$;
    }
    setUpSubscription() {
        const transformSubscription = this.transformValue
            .asObservable()
            .pipe(distinctUntilChanged((previous, current) => {
            if (previous === current) {
                return true;
            }
            if (!previous || !current) {
                return previous === current;
            }
            return (previous.cacheKey === current.cacheKey &&
                previous.wrapUrl === current.wrapUrl &&
                previous.useEndpoint === current.useEndpoint &&
                previous.sanitize === current.sanitize);
        }), switchMap((request) => {
            if (!request) {
                this.loading = false;
                return of('');
            }
            this.latestValue = '';
            this.loading = true;
            return this.getOrLoadBlobUrl(request).pipe(filter((blobUrl) => !!blobUrl), map((unsafeBlobUrl) => request.sanitize
                ? this.domSanitizer.bypassSecurityTrustUrl(unsafeBlobUrl)
                : unsafeBlobUrl), catchError(() => of('')), finalize(() => (this.loading = false)));
        }), tap((imagePath) => {
            this.latestValue = imagePath;
            this.cdr.markForCheck();
        }))
            .subscribe();
        this.subscription.add(transformSubscription);
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SecureImagePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
    static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.8", ngImport: i0, type: SecureImagePipe, isStandalone: true, name: "secureImage", pure: false });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: SecureImagePipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'secureImage',
                    pure: false,
                    standalone: true,
                }]
        }], ctorParameters: () => [] });

class UploadFilePreview {
    value = input(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
    imgPath = input(...(ngDevMode ? [undefined, { debugName: "imgPath" }] : /* istanbul ignore next */ []));
    context = input(undefined, ...(ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []));
    loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
    uploadProgress = input(0, ...(ngDevMode ? [{ debugName: "uploadProgress" }] : /* istanbul ignore next */ []));
    onUploadInputClicked = output();
    ondDownloadFile = output();
    onDeleteFile = output();
    disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
    readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
    size = input(...(ngDevMode ? [undefined, { debugName: "size" }] : /* istanbul ignore next */ []));
    isImag = computed(() => {
        return this.value()?.contentType?.startsWith('image/');
    }, ...(ngDevMode ? [{ debugName: "isImag" }] : /* istanbul ignore next */ []));
    ngOnInit() {
        if (this.readonly()) {
            this.disabled.set(true);
        }
    }
    defaultIcon = computed(() => {
        switch (this.value()?.extension) {
            case '.pdf':
                return 'file.file-06';
            case '.docx':
            case '.doc':
                return 'file.file-06';
            case '.xlsx':
            case '.xls':
                return 'file.file-06';
            default:
                return 'image.image-03';
        }
    }, ...(ngDevMode ? [{ debugName: "defaultIcon" }] : /* istanbul ignore next */ []));
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UploadFilePreview, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: UploadFilePreview, isStandalone: true, selector: "mt-upload-file-preview", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, imgPath: { classPropertyName: "imgPath", publicName: "imgPath", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, uploadProgress: { classPropertyName: "uploadProgress", publicName: "uploadProgress", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onUploadInputClicked: "onUploadInputClicked", ondDownloadFile: "ondDownloadFile", onDeleteFile: "onDeleteFile", disabled: "disabledChange" }, ngImport: i0, template: "<div class=\"flex items-center justify-between gap-2 w-full p-2 overflow-hidden\">\r\n  <div class=\"flex gap-2 items-center flex-1 min-w-0 overflow-hidden\">\r\n    <mt-avatar\r\n      [size]=\"size()\"\r\n      [shape]=\"'square'\"\r\n      [image]=\"\r\n        isImag() && imgPath() ? (imgPath() | secureImage: context()) : ''\r\n      \"\r\n      [icon]=\"defaultIcon()\"\r\n      styleClass=\"text-2xl!\"\r\n    >\r\n    </mt-avatar>\r\n\r\n    <span class=\"truncate\" [mtTooltip]=\"value().name\" tooltipPosition=\"top\">\r\n      {{ value().name }}\r\n    </span>\r\n  </div>\r\n  <div class=\"flex items-center justify-center shrink-0\">\r\n    @if (!!value() && !loading() && (!disabled() || readonly())) {\r\n      <mt-button\r\n        variant=\"text\"\r\n        icon=\"general.download-01\"\r\n        [tooltip]=\"'components.upload.download' | transloco\"\r\n        (onClick)=\"ondDownloadFile.emit(value())\"\r\n        (click)=\"$event.stopPropagation()\"\r\n      >\r\n      </mt-button>\r\n    }\r\n    @if (!disabled() && !readonly() && !!value() && !loading()) {\r\n      <mt-button\r\n        variant=\"text\"\r\n        icon=\"general.trash-01\"\r\n        [tooltip]=\"'components.upload.delete' | transloco\"\r\n        severity=\"danger\"\r\n        (onClick)=\"onDeleteFile.emit($event)\"\r\n        (click)=\"$event.stopPropagation()\"\r\n      >\r\n      </mt-button>\r\n    }\r\n  </div>\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Avatar, selector: "mt-avatar", inputs: ["label", "icon", "image", "styleClass", "size", "shape", "badge", "badgeSize", "badgeSeverity"], outputs: ["onImageError"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "directive", type: Tooltip, selector: "[mtTooltip]" }, { kind: "pipe", type: SecureImagePipe, name: "secureImage" }, { kind: "pipe", type: i1.TranslocoPipe, name: "transloco" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UploadFilePreview, decorators: [{
            type: Component,
            args: [{ selector: 'mt-upload-file-preview', standalone: true, imports: [SecureImagePipe, Button, Avatar, TranslocoModule, Tooltip], template: "<div class=\"flex items-center justify-between gap-2 w-full p-2 overflow-hidden\">\r\n  <div class=\"flex gap-2 items-center flex-1 min-w-0 overflow-hidden\">\r\n    <mt-avatar\r\n      [size]=\"size()\"\r\n      [shape]=\"'square'\"\r\n      [image]=\"\r\n        isImag() && imgPath() ? (imgPath() | secureImage: context()) : ''\r\n      \"\r\n      [icon]=\"defaultIcon()\"\r\n      styleClass=\"text-2xl!\"\r\n    >\r\n    </mt-avatar>\r\n\r\n    <span class=\"truncate\" [mtTooltip]=\"value().name\" tooltipPosition=\"top\">\r\n      {{ value().name }}\r\n    </span>\r\n  </div>\r\n  <div class=\"flex items-center justify-center shrink-0\">\r\n    @if (!!value() && !loading() && (!disabled() || readonly())) {\r\n      <mt-button\r\n        variant=\"text\"\r\n        icon=\"general.download-01\"\r\n        [tooltip]=\"'components.upload.download' | transloco\"\r\n        (onClick)=\"ondDownloadFile.emit(value())\"\r\n        (click)=\"$event.stopPropagation()\"\r\n      >\r\n      </mt-button>\r\n    }\r\n    @if (!disabled() && !readonly() && !!value() && !loading()) {\r\n      <mt-button\r\n        variant=\"text\"\r\n        icon=\"general.trash-01\"\r\n        [tooltip]=\"'components.upload.delete' | transloco\"\r\n        severity=\"danger\"\r\n        (onClick)=\"onDeleteFile.emit($event)\"\r\n        (click)=\"$event.stopPropagation()\"\r\n      >\r\n      </mt-button>\r\n    }\r\n  </div>\r\n</div>\r\n" }]
        }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], imgPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "imgPath", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], uploadProgress: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadProgress", required: false }] }], onUploadInputClicked: [{ type: i0.Output, args: ["onUploadInputClicked"] }], ondDownloadFile: [{ type: i0.Output, args: ["ondDownloadFile"] }], onDeleteFile: [{ type: i0.Output, args: ["onDeleteFile"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });

class UploadUserPreview {
    value = input(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
    imgPath = input(...(ngDevMode ? [undefined, { debugName: "imgPath" }] : /* istanbul ignore next */ []));
    context = input(undefined, ...(ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []));
    loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
    uploadProgress = input(0, ...(ngDevMode ? [{ debugName: "uploadProgress" }] : /* istanbul ignore next */ []));
    isDragging = input(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : /* istanbul ignore next */ []));
    defaultIcon = signal('image.image-03', ...(ngDevMode ? [{ debugName: "defaultIcon" }] : /* istanbul ignore next */ []));
    onUploadInputClicked = output();
    ondDownloadFile = output();
    onDeleteFile = output();
    onDragOver = output();
    onDragLeave = output();
    onDrop = output();
    disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
    readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
    size = input(...(ngDevMode ? [undefined, { debugName: "size" }] : /* istanbul ignore next */ []));
    userImgClass = input('', ...(ngDevMode ? [{ debugName: "userImgClass" }] : /* istanbul ignore next */ []));
    OnUploadInputClicked() {
        if (!this.imgPath() && !this.loading() && !this.disabled()) {
            this.onUploadInputClicked.emit(true);
        }
    }
    ngOnInit() {
        if (this.readonly()) {
            this.disabled.set(true);
        }
    }
    OnDragOver(event) {
        this.onDragOver.emit(event);
    }
    OnDragLeave(event) {
        this.onDragLeave.emit(event);
    }
    OnDrop(event) {
        this.onDrop.emit(event);
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UploadUserPreview, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: UploadUserPreview, isStandalone: true, selector: "mt-upload-user-preview", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, imgPath: { classPropertyName: "imgPath", publicName: "imgPath", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, uploadProgress: { classPropertyName: "uploadProgress", publicName: "uploadProgress", isSignal: true, isRequired: false, transformFunction: null }, isDragging: { classPropertyName: "isDragging", publicName: "isDragging", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, userImgClass: { classPropertyName: "userImgClass", publicName: "userImgClass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onUploadInputClicked: "onUploadInputClicked", ondDownloadFile: "ondDownloadFile", onDeleteFile: "onDeleteFile", onDragOver: "onDragOver", onDragLeave: "onDragLeave", onDrop: "onDrop", disabled: "disabledChange" }, ngImport: i0, template: "<div\r\n  class=\"rounded-full p-1 w-fit\"\r\n  [style.background]=\"\r\n    'conic-gradient(var(--p-primary-300) ' +\r\n    uploadProgress() +\r\n    '%, transparent ' +\r\n    uploadProgress() +\r\n    '%)'\r\n  \"\r\n>\r\n  <div\r\n    class=\"relative rounded-full w-fit border-2 border-dashed border-gray-300 bg-white\"\r\n    [class.opacity-50]=\"isDragging()\"\r\n  >\r\n    <mt-avatar\r\n      [size]=\"size()\"\r\n      [image]=\"imgPath() ? (imgPath() | secureImage: context()) : ''\"\r\n      [icon]=\"defaultIcon()\"\r\n      [styleClass]=\"userImgClass()\"\r\n    >\r\n    </mt-avatar>\r\n\r\n    @if (!loading()) {\r\n      <div\r\n        class=\"absolute inset-0 flex items-center justify-center rounded-full bg-surface-400/50 opacity-0 hover:opacity-100 transition-opacity\"\r\n        [class]=\"!imgPath() && !disabled() ? 'cursor-pointer' : ''\"\r\n        (click)=\"OnUploadInputClicked()\"\r\n        (dragover)=\"OnDragOver($event)\"\r\n        (dragleave)=\"OnDragLeave($event)\"\r\n        (drop)=\"OnDrop($event)\"\r\n      >\r\n        @if (!disabled() && !!imgPath()) {\r\n          <mt-button\r\n            variant=\"text\"\r\n            icon=\"general.download-01\"\r\n            [tooltip]=\"'components.upload.download' | transloco\"\r\n            (onClick)=\"ondDownloadFile.emit(value())\"\r\n          >\r\n          </mt-button>\r\n          <mt-button\r\n            variant=\"text\"\r\n            icon=\"general.trash-01\"\r\n            [tooltip]=\"'components.upload.delete' | transloco\"\r\n            severity=\"danger\"\r\n            (onClick)=\"onDeleteFile.emit($event)\"\r\n          >\r\n          </mt-button>\r\n        }\r\n        @if (!imgPath() && !disabled()) {\r\n          <mt-icon\r\n            icon=\"general.upload-01\"\r\n            class=\"text-primary-400 text-xl\"\r\n          ></mt-icon>\r\n        }\r\n      </div>\r\n    } @else if (loading()) {\r\n      <div\r\n        class=\"absolute inset-0 flex items-center justify-center rounded-full bg-surface-400/50\"\r\n      >\r\n        @if (uploadProgress() === 100) {\r\n          <mt-icon\r\n            icon=\"general.check\"\r\n            class=\"text-primary-400 text-2xl\"\r\n          ></mt-icon>\r\n        } @else {\r\n          <small class=\"text-primary-300 font-bold text-lg\">{{\r\n            uploadProgress() + \"%\"\r\n          }}</small>\r\n        }\r\n      </div>\r\n    }\r\n  </div>\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Avatar, selector: "mt-avatar", inputs: ["label", "icon", "image", "styleClass", "size", "shape", "badge", "badgeSize", "badgeSeverity"], outputs: ["onImageError"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "pipe", type: SecureImagePipe, name: "secureImage" }, { kind: "pipe", type: i1.TranslocoPipe, name: "transloco" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UploadUserPreview, decorators: [{
            type: Component,
            args: [{ selector: 'mt-upload-user-preview', standalone: true, imports: [Icon, SecureImagePipe, Button, Icon, Avatar, TranslocoModule], template: "<div\r\n  class=\"rounded-full p-1 w-fit\"\r\n  [style.background]=\"\r\n    'conic-gradient(var(--p-primary-300) ' +\r\n    uploadProgress() +\r\n    '%, transparent ' +\r\n    uploadProgress() +\r\n    '%)'\r\n  \"\r\n>\r\n  <div\r\n    class=\"relative rounded-full w-fit border-2 border-dashed border-gray-300 bg-white\"\r\n    [class.opacity-50]=\"isDragging()\"\r\n  >\r\n    <mt-avatar\r\n      [size]=\"size()\"\r\n      [image]=\"imgPath() ? (imgPath() | secureImage: context()) : ''\"\r\n      [icon]=\"defaultIcon()\"\r\n      [styleClass]=\"userImgClass()\"\r\n    >\r\n    </mt-avatar>\r\n\r\n    @if (!loading()) {\r\n      <div\r\n        class=\"absolute inset-0 flex items-center justify-center rounded-full bg-surface-400/50 opacity-0 hover:opacity-100 transition-opacity\"\r\n        [class]=\"!imgPath() && !disabled() ? 'cursor-pointer' : ''\"\r\n        (click)=\"OnUploadInputClicked()\"\r\n        (dragover)=\"OnDragOver($event)\"\r\n        (dragleave)=\"OnDragLeave($event)\"\r\n        (drop)=\"OnDrop($event)\"\r\n      >\r\n        @if (!disabled() && !!imgPath()) {\r\n          <mt-button\r\n            variant=\"text\"\r\n            icon=\"general.download-01\"\r\n            [tooltip]=\"'components.upload.download' | transloco\"\r\n            (onClick)=\"ondDownloadFile.emit(value())\"\r\n          >\r\n          </mt-button>\r\n          <mt-button\r\n            variant=\"text\"\r\n            icon=\"general.trash-01\"\r\n            [tooltip]=\"'components.upload.delete' | transloco\"\r\n            severity=\"danger\"\r\n            (onClick)=\"onDeleteFile.emit($event)\"\r\n          >\r\n          </mt-button>\r\n        }\r\n        @if (!imgPath() && !disabled()) {\r\n          <mt-icon\r\n            icon=\"general.upload-01\"\r\n            class=\"text-primary-400 text-xl\"\r\n          ></mt-icon>\r\n        }\r\n      </div>\r\n    } @else if (loading()) {\r\n      <div\r\n        class=\"absolute inset-0 flex items-center justify-center rounded-full bg-surface-400/50\"\r\n      >\r\n        @if (uploadProgress() === 100) {\r\n          <mt-icon\r\n            icon=\"general.check\"\r\n            class=\"text-primary-400 text-2xl\"\r\n          ></mt-icon>\r\n        } @else {\r\n          <small class=\"text-primary-300 font-bold text-lg\">{{\r\n            uploadProgress() + \"%\"\r\n          }}</small>\r\n        }\r\n      </div>\r\n    }\r\n  </div>\r\n</div>\r\n" }]
        }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], imgPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "imgPath", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], uploadProgress: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadProgress", required: false }] }], isDragging: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDragging", required: false }] }], onUploadInputClicked: [{ type: i0.Output, args: ["onUploadInputClicked"] }], ondDownloadFile: [{ type: i0.Output, args: ["ondDownloadFile"] }], onDeleteFile: [{ type: i0.Output, args: ["onDeleteFile"] }], onDragOver: [{ type: i0.Output, args: ["onDragOver"] }], onDragLeave: [{ type: i0.Output, args: ["onDragLeave"] }], onDrop: [{ type: i0.Output, args: ["onDrop"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], userImgClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "userImgClass", required: false }] }] } });

const ACCEPT_TYPE_LABELS = {
    'image/*': 'Images',
    'application/pdf': 'PDF',
    '.mpp': 'MPP',
    '.xer': 'XER',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'Word',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'Excel',
    'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'PowerPoint',
    '.eml': 'EML',
    '.doc': 'DOC',
    '.docx': 'DOCX',
    '.ppt': 'PPT',
    '.pptx': 'PPTX',
    '.xls': 'XLS',
    '.xlsx': 'XLSX',
    '.csv': 'CSV',
    '.mp4': 'MP4',
    '.mov': 'MOV',
    '.wmv': 'WMV',
    '.avi': 'AVI',
    '.mkv': 'MKV',
    '.msg': 'MSG',
    '.zip': 'ZIP',
    '.rar': 'RAR',
    '.7z': '7Z',
    '.gz': 'GZ',
    '.gzip': 'GZIP',
};
class UploadField {
    transloco = inject(TranslocoService);
    confirmationService = inject(ConfirmationService);
    label = input(...(ngDevMode ? [undefined, { debugName: "label" }] : /* istanbul ignore next */ []));
    title = input(this.transloco.translate('components.uploadField.uploadFile'), ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
    description = input(this.transloco.translate('components.uploadField.clickOrDrop'), ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
    endPoint = input('uploader', ...(ngDevMode ? [{ debugName: "endPoint" }] : /* istanbul ignore next */ []));
    size = input(...(ngDevMode ? [undefined, { debugName: "size" }] : /* istanbul ignore next */ []));
    userImgClass = input('w-25! h-25! text-4xl! text-gray-400!', ...(ngDevMode ? [{ debugName: "userImgClass" }] : /* istanbul ignore next */ []));
    shape = input('field', ...(ngDevMode ? [{ debugName: "shape" }] : /* istanbul ignore next */ []));
    multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
    accept = input('.pdf,.doc,.docx,.xlsx,image/*', ...(ngDevMode ? [{ debugName: "accept" }] : /* istanbul ignore next */ []));
    isDragging = model(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : /* istanbul ignore next */ []));
    fileSizeLimit = input(...(ngDevMode ? [undefined, { debugName: "fileSizeLimit" }] : /* istanbul ignore next */ []));
    readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
    context = input(undefined, ...(ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []));
    isMultipleEnabled = computed(() => this.shape() !== 'circle' && this.multiple(), ...(ngDevMode ? [{ debugName: "isMultipleEnabled" }] : /* istanbul ignore next */ []));
    /**
     * The native `accept` attribute is only a UI hint — users can switch the OS
     * file dialog to "All files" and pick anything. This is the spec we re-check
     * every selected/dropped file against before uploading to the backend.
     */
    effectiveAccept = computed(() => {
        if (this.shape() === 'circle') {
            return 'image/*';
        }
        return normalizeAcceptSpec(this.accept());
    }, ...(ngDevMode ? [{ debugName: "effectiveAccept" }] : /* istanbul ignore next */ []));
    /**
     * Human-friendly, de-duplicated list of accepted types shown next to the
     * upload prompt so the user knows what to pick before opening the dialog
     * (e.g. ".pdf,.doc,image/*" -> "PDF, DOC, Images"). Empty when everything
     * is allowed, so the hint can be hidden entirely.
     */
    acceptedTypesLabel = computed(() => {
        const spec = this.effectiveAccept().trim();
        if (!spec || spec === '*' || spec === '*/*') {
            return '';
        }
        const labels = spec
            .split(',')
            .map((token) => token.trim().toLowerCase())
            .filter((token) => token.length > 0 && token !== '*' && token !== '*/*')
            .map((token) => {
            if (ACCEPT_TYPE_LABELS[token]) {
                return ACCEPT_TYPE_LABELS[token];
            }
            if (token.startsWith('.')) {
                return token.slice(1).toUpperCase();
            }
            const [group, subtype] = token.split('/');
            if (subtype === '*') {
                const key = `components.upload.fileGroups.${group}`;
                const translated = this.transloco.translate(key);
                // Transloco echoes the key back when it has no entry for it.
                return translated === key
                    ? group.charAt(0).toUpperCase() + group.slice(1)
                    : translated;
            }
            return (subtype ?? group).toUpperCase();
        })
            .filter((label) => !!label);
        return Array.from(new Set(labels)).join(', ');
    }, ...(ngDevMode ? [{ debugName: "acceptedTypesLabel" }] : /* istanbul ignore next */ []));
    onChange = output();
    requiredValidator = Validators.required;
    value = signal(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
    files = computed(() => {
        const value = this.value();
        if (Array.isArray(value)) {
            return value.filter((item) => item != null);
        }
        return value ? [value] : [];
    }, ...(ngDevMode ? [{ debugName: "files" }] : /* istanbul ignore next */ []));
    primaryFile = computed(() => this.files()[0] ?? null, ...(ngDevMode ? [{ debugName: "primaryFile" }] : /* istanbul ignore next */ []));
    imgPath = computed(() => this.resolveImgPath(this.primaryFile()), ...(ngDevMode ? [{ debugName: "imgPath" }] : /* istanbul ignore next */ []));
    disabled = signal(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
    uploadProgress = signal(0, ...(ngDevMode ? [{ debugName: "uploadProgress" }] : /* istanbul ignore next */ []));
    loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
    httpClient = inject(HttpClient);
    pendingUploads = signal(0, ...(ngDevMode ? [{ debugName: "pendingUploads" }] : /* istanbul ignore next */ []));
    onTouched = () => { };
    onModelChange = () => { };
    ngControl = inject(NgControl, { self: true });
    constructor() {
        if (this.ngControl) {
            this.ngControl.valueAccessor = this;
        }
    }
    writeValue(value) {
        if (Array.isArray(value)) {
            const normalized = value.filter((item) => item != null);
            const fileIds = normalized.filter((item) => typeof item === 'string' && item.trim().length > 0);
            const files = normalized.filter((item) => !!item && typeof item === 'object');
            if (fileIds.length) {
                this.fetchMetadata(fileIds, files, true);
                return;
            }
            this.value.set(normalized);
            return;
        }
        if (typeof value === 'string' && value.trim().length > 0) {
            this.fetchMetadata([value], [], false);
            return;
        }
        this.value.set(value ?? null);
    }
    registerOnChange(fn) {
        this.onModelChange = fn;
    }
    registerOnTouched(fn) {
        this.onTouched = fn;
    }
    setDisabledState(disabled) {
        this.disabled.set(disabled);
    }
    onAdd(item) {
        if (this.disabled()) {
            return;
        }
        const nextValue = this.isMultipleEnabled() ? [...this.files(), item] : item;
        this.value.set(nextValue);
        this.onModelChange(nextValue);
        this.onChange.emit(nextValue);
    }
    onDelete(item, event) {
        if (this.disabled()) {
            return;
        }
        this.confirmationService.confirmDelete({
            type: 'popup',
            event,
            accept: () => this.performDelete(item),
        });
    }
    performDelete(item) {
        if (!this.isMultipleEnabled()) {
            this.value.set(null);
            this.onModelChange(null);
            this.onChange.emit(null);
            return;
        }
        const nextValue = this.files().filter((file) => !isSameFile(file, item));
        const resolvedValue = nextValue.length ? nextValue : null;
        this.value.set(resolvedValue);
        this.onModelChange(resolvedValue);
        this.onChange.emit(resolvedValue);
    }
    onFileSelect(event) {
        const input = event.target;
        const selectedFiles = Array.from(input?.files ?? []);
        if (!selectedFiles.length) {
            return;
        }
        if (!this.isMultipleEnabled()) {
            this.value.set(null);
        }
        this.prepareFiles(selectedFiles);
        if (input) {
            input.value = '';
        }
    }
    prepareFiles(files) {
        this.ngControl.control?.setErrors({ uploading: true });
        const accept = this.effectiveAccept();
        const rejected = files.filter((file) => !isFileAccepted(file, accept));
        if (rejected.length) {
            this.ngControl.control?.setErrors({
                invalidFileType: {
                    message: this.transloco.translate('components.validation.invalidFileType', { types: this.acceptedTypesLabel() || accept }),
                },
            });
            return;
        }
        const filesToUpload = this.isMultipleEnabled() ? files : [files[0]];
        filesToUpload.forEach((file) => this.uploadFile(file));
    }
    uploadFile(file) {
        this.pendingUploads.update((count) => count + 1);
        this.loading.set(true);
        this.uploadProgress.set(10);
        const formData = new FormData();
        formData.append('file', file);
        this.httpClient
            .post(this.endPoint(), formData, {
            reportProgress: true,
            observe: 'events',
            context: this.context(),
        })
            .pipe(finalize$1(() => {
            const pending = Math.max(this.pendingUploads() - 1, 0);
            this.pendingUploads.set(pending);
            if (!pending) {
                setTimeout(() => {
                    this.uploadProgress.set(0);
                    this.loading.set(false);
                }, 700);
            }
        }), catchError$1(() => {
            this.uploadProgress.set(0);
            return throwError(() => new Error('Upload failed'));
        }))
            .subscribe((event) => {
            if (!event?.body) {
                if (event.total) {
                    this.uploadProgress.set(Math.round((100 * event.loaded) / event.total));
                }
                return;
            }
            this.uploadProgress.set(100);
            this.handleUploadDone({ ...event.body?.data, size: file.size });
        });
    }
    handleUploadDone(file) {
        if (!file) {
            return;
        }
        this.onAdd(file);
        if (this.fileSizeLimit() && file.size > this.fileSizeLimit()) {
            this.ngControl.control?.setErrors({ fileSizeLimited: true });
            return;
        }
        if (this.pendingUploads() <= 1) {
            this.ngControl.control?.setErrors(null);
        }
    }
    downloadFile(value) {
        const downloadUrl = this.resolveImgPath(value);
        const downloadFileName = value?.name;
        const mimeType = value?.contentType;
        if (!downloadUrl || !mimeType || !downloadFileName) {
            console.error('File metadata is incomplete. Cannot download.');
            return;
        }
        this.httpClient
            .get(downloadUrl, {
            responseType: 'blob',
            context: this.context(),
        })
            .pipe(take(1))
            .subscribe((res) => {
            const blob = new Blob([res], { type: mimeType });
            const data = window.URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.href = data;
            link.download = downloadFileName;
            link.click();
            window.URL.revokeObjectURL(data);
        });
    }
    onDragOver(event) {
        event.preventDefault();
        event.stopPropagation();
        if (!this.disabled()) {
            this.isDragging.set(true);
        }
    }
    onDragLeave(event) {
        event.preventDefault();
        event.stopPropagation();
        this.isDragging.set(false);
    }
    onDrop(event) {
        event.preventDefault();
        event.stopPropagation();
        this.isDragging.set(false);
        if (this.disabled()) {
            return;
        }
        const files = Array.from(event.dataTransfer?.files ?? []);
        if (!files.length) {
            return;
        }
        if (!this.isMultipleEnabled()) {
            this.value.set(null);
        }
        this.prepareFiles(files);
    }
    resolveImgPath(value) {
        return value?.fileName ? `${this.endPoint()}/${value.fileName}` : undefined;
    }
    fetchMetadata(fileIds, existingFiles = [], forceArray = false) {
        const normalizedIds = fileIds
            .map((fileId) => fileId.trim())
            .filter((fileId) => fileId.length > 0);
        if (!normalizedIds.length) {
            this.value.set(forceArray ? existingFiles : (existingFiles[0] ?? null));
            return;
        }
        this.loading.set(true);
        forkJoin(normalizedIds.map((fileId) => this.httpClient
            .get(`${this.endPoint()}/${fileId}/metaData`, {
            context: this.context(),
        })
            .pipe(take(1), map$1((response) => response.data), catchError$1((error) => {
            console.error('Failed to fetch file metadata:', error);
            return of({
                id: fileId,
                name: fileId,
                fileName: fileId,
                contentType: '',
                extension: '',
            });
        }))))
            .pipe(finalize$1(() => this.loading.set(false)))
            .subscribe((files) => {
            const resolvedFiles = [...existingFiles, ...files];
            const resolvedValue = forceArray || this.isMultipleEnabled() || resolvedFiles.length > 1
                ? resolvedFiles
                : (resolvedFiles[0] ?? null);
            this.value.set(resolvedValue);
        });
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UploadField, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: UploadField, isStandalone: true, selector: "mt-upload-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, endPoint: { classPropertyName: "endPoint", publicName: "endPoint", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, userImgClass: { classPropertyName: "userImgClass", publicName: "userImgClass", isSignal: true, isRequired: false, transformFunction: null }, shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, isDragging: { classPropertyName: "isDragging", publicName: "isDragging", isSignal: true, isRequired: false, transformFunction: null }, fileSizeLimit: { classPropertyName: "fileSizeLimit", publicName: "fileSizeLimit", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isDragging: "isDraggingChange", onChange: "onChange" }, ngImport: i0, template: "<input\r\n  #uploadInput\r\n  type=\"file\"\r\n  name=\"file[]\"\r\n  (change)=\"onFileSelect($event)\"\r\n  style=\"display: none\"\r\n  [multiple]=\"isMultipleEnabled()\"\r\n  [accept]=\"effectiveAccept()\"\r\n/>\r\n\r\n@if (shape() === \"circle\") {\r\n  <div class=\"flex flex-col items-center gap-2 w-full\">\r\n    <div class=\"flex\">\r\n      <div class=\"flex flex-col items-center\">\r\n        <mt-upload-user-preview\r\n          [value]=\"primaryFile()\"\r\n          [imgPath]=\"imgPath()\"\r\n          [disabled]=\"disabled()\"\r\n          [readonly]=\"readonly()\"\r\n          [loading]=\"loading()\"\r\n          [size]=\"size()\"\r\n          [context]=\"context()\"\r\n          [userImgClass]=\"userImgClass()\"\r\n          [isDragging]=\"isDragging()\"\r\n          [uploadProgress]=\"uploadProgress()\"\r\n          (onUploadInputClicked)=\"uploadInput.click()\"\r\n          (ondDownloadFile)=\"downloadFile($event)\"\r\n          (onDeleteFile)=\"onDelete(primaryFile(), $event)\"\r\n          (onDragOver)=\"onDragOver($event)\"\r\n          (onDragLeave)=\"onDragLeave($event)\"\r\n          (onDrop)=\"onDrop($event)\"\r\n        ></mt-upload-user-preview>\r\n        @if (label()) {\r\n          <label\r\n            [class.required]=\"\r\n              ngControl?.control?.hasValidator(requiredValidator)\r\n            \"\r\n            [for]=\"ngControl?.name || label()\"\r\n            >{{ label() }}</label\r\n          >\r\n        }\r\n        @if (acceptedTypesLabel()) {\r\n          <span class=\"mt-1 text-xs text-surface-400\">\r\n            {{\r\n              \"components.upload.allowedTypes\"\r\n                | transloco: { types: acceptedTypesLabel() }\r\n            }}\r\n          </span>\r\n        }\r\n      </div>\r\n    </div>\r\n  </div>\r\n} @else if (shape() === \"card\") {\r\n  <mt-card\r\n    headless\r\n    class=\"border-2 border-dashed border-gray-300 rounded-lg cursor-pointer hover:bg-gray-50\"\r\n  >\r\n    <div class=\"content flex flex-col gap-5 items-center text-center\">\r\n      @if (!files().length && !loading()) {\r\n        <div class=\"flex flex-col gap-1\">\r\n          @if (title()) {\r\n            <div class=\"title text-lg font-semibold\">\r\n              {{ title() }}\r\n            </div>\r\n          }\r\n          @if (description()) {\r\n            <div\r\n              class=\"description text-sm text-muted-foreground secondary text-surface-500\"\r\n            >\r\n              {{ description() }}\r\n            </div>\r\n          }\r\n          @if (acceptedTypesLabel()) {\r\n            <div class=\"mt-1 flex items-center justify-center gap-1.5\">\r\n              <mt-icon\r\n                icon=\"general.info-circle\"\r\n                class=\"text-xs text-surface-400\"\r\n              />\r\n              <span class=\"text-xs text-surface-400\">\r\n                {{\r\n                  \"components.upload.allowedTypes\"\r\n                    | transloco: { types: acceptedTypesLabel() }\r\n                }}\r\n              </span>\r\n            </div>\r\n          }\r\n        </div>\r\n      }\r\n\r\n      @if (files().length) {\r\n        <div class=\"flex w-full flex-col gap-2\">\r\n          @for (file of files(); track $index) {\r\n            <mt-upload-file-preview\r\n              style=\"width: 100%\"\r\n              [value]=\"file\"\r\n              [imgPath]=\"resolveImgPath(file)\"\r\n              [disabled]=\"disabled()\"\r\n              [readonly]=\"readonly()\"\r\n              [loading]=\"loading()\"\r\n              [context]=\"context()\"\r\n              [uploadProgress]=\"uploadProgress()\"\r\n              (onUploadInputClicked)=\"uploadInput.click()\"\r\n              (ondDownloadFile)=\"downloadFile(file)\"\r\n              (onDeleteFile)=\"onDelete(file, $event)\"\r\n            />\r\n          }\r\n          @if (\r\n            isMultipleEnabled() && !disabled() && !readonly() && !loading()\r\n          ) {\r\n            <div class=\"flex flex-col items-center gap-1\">\r\n              <mt-button\r\n                [size]=\"'small'\"\r\n                [label]=\"'components.upload.addMore' | transloco\"\r\n                [icon]=\"'general.upload-01'\"\r\n                (onClick)=\"uploadInput.click()\"\r\n              />\r\n              @if (acceptedTypesLabel()) {\r\n                <span class=\"text-xs text-surface-400\">\r\n                  {{\r\n                    \"components.upload.allowedTypes\"\r\n                      | transloco: { types: acceptedTypesLabel() }\r\n                  }}\r\n                </span>\r\n              }\r\n            </div>\r\n          } @else if (acceptedTypesLabel()) {\r\n            <span class=\"text-xs text-surface-400\">\r\n              {{\r\n                \"components.upload.allowedTypes\"\r\n                  | transloco: { types: acceptedTypesLabel() }\r\n              }}\r\n            </span>\r\n          }\r\n        </div>\r\n      } @else if (loading()) {\r\n        <div class=\"w-full flex gap-3 items-center justify-center p-3\">\r\n          <p class=\"text-lg text-gray-500\">\r\n            {{\r\n              (\"components.upload.uploading\" | transloco) +\r\n                uploadProgress() +\r\n                \"%\"\r\n            }}\r\n          </p>\r\n        </div>\r\n      } @else {\r\n        <mt-button\r\n          [size]=\"'small'\"\r\n          [label]=\"'components.upload.upload' | transloco\"\r\n          [icon]=\"'general.upload-01'\"\r\n          (onClick)=\"\r\n            !loading() && !disabled() && !readonly() ? uploadInput.click() : ''\r\n          \"\r\n          [disabled]=\"disabled() || loading() || readonly()\"\r\n        />\r\n      }\r\n    </div>\r\n  </mt-card>\r\n} @else {\r\n  <div class=\"flex flex-col items-start gap-2 w-full\">\r\n    @if (label()) {\r\n      <label\r\n        [class.required]=\"ngControl?.control?.hasValidator(requiredValidator)\"\r\n        [for]=\"ngControl?.name || label()\"\r\n        >{{ label() }}</label\r\n      >\r\n    }\r\n\r\n    <div\r\n      class=\"w-full flex gap-3 items-center justify-center border-2 border-dashed border-gray-300 rounded-lg cursor-pointer hover:bg-gray-50\"\r\n      [class]=\"disabled() ? 'bg-gray-50' : ''\"\r\n      (click)=\"\r\n        !loading() && !disabled() && !readonly() ? uploadInput.click() : ''\r\n      \"\r\n      [class.border-blue-500]=\"isDragging()\"\r\n      [class.bg-blue-50]=\"isDragging()\"\r\n      (dragover)=\"onDragOver($event)\"\r\n      (dragleave)=\"onDragLeave($event)\"\r\n      (drop)=\"onDrop($event)\"\r\n    >\r\n      @if (files().length) {\r\n        <div\r\n          class=\"flex w-full flex-col gap-2 p-2\"\r\n          (click)=\"$event.stopPropagation()\"\r\n        >\r\n          @for (file of files(); track $index) {\r\n            <mt-upload-file-preview\r\n              style=\"width: 100%\"\r\n              [value]=\"file\"\r\n              [imgPath]=\"resolveImgPath(file)\"\r\n              [disabled]=\"disabled()\"\r\n              [readonly]=\"readonly()\"\r\n              [loading]=\"loading()\"\r\n              [context]=\"context()\"\r\n              [uploadProgress]=\"uploadProgress()\"\r\n              (onUploadInputClicked)=\"uploadInput.click()\"\r\n              (ondDownloadFile)=\"downloadFile(file)\"\r\n              (onDeleteFile)=\"onDelete(file, $event)\"\r\n            />\r\n          }\r\n          @if (\r\n            isMultipleEnabled() && !disabled() && !readonly() && !loading()\r\n          ) {\r\n            <div\r\n              class=\"flex w-full flex-col border-t border-dashed border-gray-300\"\r\n            >\r\n              <div\r\n                class=\"w-full flex gap-2 items-center justify-center p-2 cursor-pointer hover:bg-gray-100 rounded-b-lg transition-colors\"\r\n                (click)=\"uploadInput.click()\"\r\n              >\r\n                <mt-icon icon=\"general.upload-01\" />\r\n                <span class=\"text-sm text-gray-500\">\r\n                  {{ \"components.upload.addMore\" | transloco }}\r\n                </span>\r\n              </div>\r\n              @if (acceptedTypesLabel()) {\r\n                <span class=\"px-2 pb-2 text-center text-xs text-surface-400\">\r\n                  {{\r\n                    \"components.upload.allowedTypes\"\r\n                      | transloco: { types: acceptedTypesLabel() }\r\n                  }}\r\n                </span>\r\n              }\r\n            </div>\r\n          } @else if (acceptedTypesLabel()) {\r\n            <span class=\"px-2 pb-2 text-center text-xs text-surface-400\">\r\n              {{\r\n                \"components.upload.allowedTypes\"\r\n                  | transloco: { types: acceptedTypesLabel() }\r\n              }}\r\n            </span>\r\n          }\r\n        </div>\r\n      } @else if (loading()) {\r\n        <div class=\"w-full flex gap-3 items-center justify-center p-3\">\r\n          <p class=\"text-lg text-gray-500\">\r\n            {{\r\n              (\"components.upload.uploading\" | transloco) +\r\n                uploadProgress() +\r\n                \"%\"\r\n            }}\r\n          </p>\r\n        </div>\r\n      } @else {\r\n        <div class=\"w-full flex flex-col gap-1 items-center justify-center p-3\">\r\n          <div class=\"flex gap-3 items-center\">\r\n            <mt-icon icon=\"general.upload-01\" />\r\n            <p class=\"text-lg text-gray-500\">\r\n              {{ \"components.upload.clickOrDrop\" | transloco }}\r\n            </p>\r\n          </div>\r\n          @if (acceptedTypesLabel()) {\r\n            <span class=\"text-xs text-surface-400\">\r\n              {{\r\n                \"components.upload.allowedTypes\"\r\n                  | transloco: { types: acceptedTypesLabel() }\r\n              }}\r\n            </span>\r\n          }\r\n        </div>\r\n      }\r\n    </div>\r\n  </div>\r\n}\r\n<mt-field-validation [control]=\"ngControl?.control\"></mt-field-validation>\r\n", dependencies: [{ kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: UploadUserPreview, selector: "mt-upload-user-preview", inputs: ["value", "imgPath", "context", "loading", "uploadProgress", "isDragging", "disabled", "readonly", "size", "userImgClass"], outputs: ["onUploadInputClicked", "ondDownloadFile", "onDeleteFile", "onDragOver", "onDragLeave", "onDrop", "disabledChange"] }, { kind: "component", type: UploadFilePreview, selector: "mt-upload-file-preview", inputs: ["value", "imgPath", "context", "loading", "uploadProgress", "disabled", "readonly", "size"], outputs: ["onUploadInputClicked", "ondDownloadFile", "onDeleteFile", "disabledChange"] }, { kind: "component", type: FieldValidation, selector: "mt-field-validation", inputs: ["control", "touched"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "pipe", type: i1.TranslocoPipe, name: "transloco" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UploadField, decorators: [{
            type: Component,
            args: [{ selector: 'mt-upload-field', standalone: true, imports: [
                        Icon,
                        UploadUserPreview,
                        UploadFilePreview,
                        FieldValidation,
                        Card,
                        Button,
                        TranslocoModule,
                    ], template: "<input\r\n  #uploadInput\r\n  type=\"file\"\r\n  name=\"file[]\"\r\n  (change)=\"onFileSelect($event)\"\r\n  style=\"display: none\"\r\n  [multiple]=\"isMultipleEnabled()\"\r\n  [accept]=\"effectiveAccept()\"\r\n/>\r\n\r\n@if (shape() === \"circle\") {\r\n  <div class=\"flex flex-col items-center gap-2 w-full\">\r\n    <div class=\"flex\">\r\n      <div class=\"flex flex-col items-center\">\r\n        <mt-upload-user-preview\r\n          [value]=\"primaryFile()\"\r\n          [imgPath]=\"imgPath()\"\r\n          [disabled]=\"disabled()\"\r\n          [readonly]=\"readonly()\"\r\n          [loading]=\"loading()\"\r\n          [size]=\"size()\"\r\n          [context]=\"context()\"\r\n          [userImgClass]=\"userImgClass()\"\r\n          [isDragging]=\"isDragging()\"\r\n          [uploadProgress]=\"uploadProgress()\"\r\n          (onUploadInputClicked)=\"uploadInput.click()\"\r\n          (ondDownloadFile)=\"downloadFile($event)\"\r\n          (onDeleteFile)=\"onDelete(primaryFile(), $event)\"\r\n          (onDragOver)=\"onDragOver($event)\"\r\n          (onDragLeave)=\"onDragLeave($event)\"\r\n          (onDrop)=\"onDrop($event)\"\r\n        ></mt-upload-user-preview>\r\n        @if (label()) {\r\n          <label\r\n            [class.required]=\"\r\n              ngControl?.control?.hasValidator(requiredValidator)\r\n            \"\r\n            [for]=\"ngControl?.name || label()\"\r\n            >{{ label() }}</label\r\n          >\r\n        }\r\n        @if (acceptedTypesLabel()) {\r\n          <span class=\"mt-1 text-xs text-surface-400\">\r\n            {{\r\n              \"components.upload.allowedTypes\"\r\n                | transloco: { types: acceptedTypesLabel() }\r\n            }}\r\n          </span>\r\n        }\r\n      </div>\r\n    </div>\r\n  </div>\r\n} @else if (shape() === \"card\") {\r\n  <mt-card\r\n    headless\r\n    class=\"border-2 border-dashed border-gray-300 rounded-lg cursor-pointer hover:bg-gray-50\"\r\n  >\r\n    <div class=\"content flex flex-col gap-5 items-center text-center\">\r\n      @if (!files().length && !loading()) {\r\n        <div class=\"flex flex-col gap-1\">\r\n          @if (title()) {\r\n            <div class=\"title text-lg font-semibold\">\r\n              {{ title() }}\r\n            </div>\r\n          }\r\n          @if (description()) {\r\n            <div\r\n              class=\"description text-sm text-muted-foreground secondary text-surface-500\"\r\n            >\r\n              {{ description() }}\r\n            </div>\r\n          }\r\n          @if (acceptedTypesLabel()) {\r\n            <div class=\"mt-1 flex items-center justify-center gap-1.5\">\r\n              <mt-icon\r\n                icon=\"general.info-circle\"\r\n                class=\"text-xs text-surface-400\"\r\n              />\r\n              <span class=\"text-xs text-surface-400\">\r\n                {{\r\n                  \"components.upload.allowedTypes\"\r\n                    | transloco: { types: acceptedTypesLabel() }\r\n                }}\r\n              </span>\r\n            </div>\r\n          }\r\n        </div>\r\n      }\r\n\r\n      @if (files().length) {\r\n        <div class=\"flex w-full flex-col gap-2\">\r\n          @for (file of files(); track $index) {\r\n            <mt-upload-file-preview\r\n              style=\"width: 100%\"\r\n              [value]=\"file\"\r\n              [imgPath]=\"resolveImgPath(file)\"\r\n              [disabled]=\"disabled()\"\r\n              [readonly]=\"readonly()\"\r\n              [loading]=\"loading()\"\r\n              [context]=\"context()\"\r\n              [uploadProgress]=\"uploadProgress()\"\r\n              (onUploadInputClicked)=\"uploadInput.click()\"\r\n              (ondDownloadFile)=\"downloadFile(file)\"\r\n              (onDeleteFile)=\"onDelete(file, $event)\"\r\n            />\r\n          }\r\n          @if (\r\n            isMultipleEnabled() && !disabled() && !readonly() && !loading()\r\n          ) {\r\n            <div class=\"flex flex-col items-center gap-1\">\r\n              <mt-button\r\n                [size]=\"'small'\"\r\n                [label]=\"'components.upload.addMore' | transloco\"\r\n                [icon]=\"'general.upload-01'\"\r\n                (onClick)=\"uploadInput.click()\"\r\n              />\r\n              @if (acceptedTypesLabel()) {\r\n                <span class=\"text-xs text-surface-400\">\r\n                  {{\r\n                    \"components.upload.allowedTypes\"\r\n                      | transloco: { types: acceptedTypesLabel() }\r\n                  }}\r\n                </span>\r\n              }\r\n            </div>\r\n          } @else if (acceptedTypesLabel()) {\r\n            <span class=\"text-xs text-surface-400\">\r\n              {{\r\n                \"components.upload.allowedTypes\"\r\n                  | transloco: { types: acceptedTypesLabel() }\r\n              }}\r\n            </span>\r\n          }\r\n        </div>\r\n      } @else if (loading()) {\r\n        <div class=\"w-full flex gap-3 items-center justify-center p-3\">\r\n          <p class=\"text-lg text-gray-500\">\r\n            {{\r\n              (\"components.upload.uploading\" | transloco) +\r\n                uploadProgress() +\r\n                \"%\"\r\n            }}\r\n          </p>\r\n        </div>\r\n      } @else {\r\n        <mt-button\r\n          [size]=\"'small'\"\r\n          [label]=\"'components.upload.upload' | transloco\"\r\n          [icon]=\"'general.upload-01'\"\r\n          (onClick)=\"\r\n            !loading() && !disabled() && !readonly() ? uploadInput.click() : ''\r\n          \"\r\n          [disabled]=\"disabled() || loading() || readonly()\"\r\n        />\r\n      }\r\n    </div>\r\n  </mt-card>\r\n} @else {\r\n  <div class=\"flex flex-col items-start gap-2 w-full\">\r\n    @if (label()) {\r\n      <label\r\n        [class.required]=\"ngControl?.control?.hasValidator(requiredValidator)\"\r\n        [for]=\"ngControl?.name || label()\"\r\n        >{{ label() }}</label\r\n      >\r\n    }\r\n\r\n    <div\r\n      class=\"w-full flex gap-3 items-center justify-center border-2 border-dashed border-gray-300 rounded-lg cursor-pointer hover:bg-gray-50\"\r\n      [class]=\"disabled() ? 'bg-gray-50' : ''\"\r\n      (click)=\"\r\n        !loading() && !disabled() && !readonly() ? uploadInput.click() : ''\r\n      \"\r\n      [class.border-blue-500]=\"isDragging()\"\r\n      [class.bg-blue-50]=\"isDragging()\"\r\n      (dragover)=\"onDragOver($event)\"\r\n      (dragleave)=\"onDragLeave($event)\"\r\n      (drop)=\"onDrop($event)\"\r\n    >\r\n      @if (files().length) {\r\n        <div\r\n          class=\"flex w-full flex-col gap-2 p-2\"\r\n          (click)=\"$event.stopPropagation()\"\r\n        >\r\n          @for (file of files(); track $index) {\r\n            <mt-upload-file-preview\r\n              style=\"width: 100%\"\r\n              [value]=\"file\"\r\n              [imgPath]=\"resolveImgPath(file)\"\r\n              [disabled]=\"disabled()\"\r\n              [readonly]=\"readonly()\"\r\n              [loading]=\"loading()\"\r\n              [context]=\"context()\"\r\n              [uploadProgress]=\"uploadProgress()\"\r\n              (onUploadInputClicked)=\"uploadInput.click()\"\r\n              (ondDownloadFile)=\"downloadFile(file)\"\r\n              (onDeleteFile)=\"onDelete(file, $event)\"\r\n            />\r\n          }\r\n          @if (\r\n            isMultipleEnabled() && !disabled() && !readonly() && !loading()\r\n          ) {\r\n            <div\r\n              class=\"flex w-full flex-col border-t border-dashed border-gray-300\"\r\n            >\r\n              <div\r\n                class=\"w-full flex gap-2 items-center justify-center p-2 cursor-pointer hover:bg-gray-100 rounded-b-lg transition-colors\"\r\n                (click)=\"uploadInput.click()\"\r\n              >\r\n                <mt-icon icon=\"general.upload-01\" />\r\n                <span class=\"text-sm text-gray-500\">\r\n                  {{ \"components.upload.addMore\" | transloco }}\r\n                </span>\r\n              </div>\r\n              @if (acceptedTypesLabel()) {\r\n                <span class=\"px-2 pb-2 text-center text-xs text-surface-400\">\r\n                  {{\r\n                    \"components.upload.allowedTypes\"\r\n                      | transloco: { types: acceptedTypesLabel() }\r\n                  }}\r\n                </span>\r\n              }\r\n            </div>\r\n          } @else if (acceptedTypesLabel()) {\r\n            <span class=\"px-2 pb-2 text-center text-xs text-surface-400\">\r\n              {{\r\n                \"components.upload.allowedTypes\"\r\n                  | transloco: { types: acceptedTypesLabel() }\r\n              }}\r\n            </span>\r\n          }\r\n        </div>\r\n      } @else if (loading()) {\r\n        <div class=\"w-full flex gap-3 items-center justify-center p-3\">\r\n          <p class=\"text-lg text-gray-500\">\r\n            {{\r\n              (\"components.upload.uploading\" | transloco) +\r\n                uploadProgress() +\r\n                \"%\"\r\n            }}\r\n          </p>\r\n        </div>\r\n      } @else {\r\n        <div class=\"w-full flex flex-col gap-1 items-center justify-center p-3\">\r\n          <div class=\"flex gap-3 items-center\">\r\n            <mt-icon icon=\"general.upload-01\" />\r\n            <p class=\"text-lg text-gray-500\">\r\n              {{ \"components.upload.clickOrDrop\" | transloco }}\r\n            </p>\r\n          </div>\r\n          @if (acceptedTypesLabel()) {\r\n            <span class=\"text-xs text-surface-400\">\r\n              {{\r\n                \"components.upload.allowedTypes\"\r\n                  | transloco: { types: acceptedTypesLabel() }\r\n              }}\r\n            </span>\r\n          }\r\n        </div>\r\n      }\r\n    </div>\r\n  </div>\r\n}\r\n<mt-field-validation [control]=\"ngControl?.control\"></mt-field-validation>\r\n" }]
        }], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], endPoint: [{ type: i0.Input, args: [{ isSignal: true, alias: "endPoint", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], userImgClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "userImgClass", required: false }] }], shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], isDragging: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDragging", required: false }] }, { type: i0.Output, args: ["isDraggingChange"] }], fileSizeLimit: [{ type: i0.Input, args: [{ isSignal: true, alias: "fileSizeLimit", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }], onChange: [{ type: i0.Output, args: ["onChange"] }] } });
/**
 * Re-validates a picked/dropped file against the `accept` spec on the client,
 * since the native picker's accept filter can be bypassed by the user.
 * Supports the full HTML accept syntax: extensions (`.pdf`), exact MIME
 * (`application/pdf`), wildcard MIME (`image/*`), and catch-all (`*` / `*\/*`).
 */
function isFileAccepted(file, accept) {
    const spec = (accept ?? '').trim();
    // No restriction configured, or explicitly allowing every file.
    if (!spec || spec === '*' || spec === '*/*') {
        return true;
    }
    const fileName = (file?.name ?? '').toLowerCase();
    const fileType = (file?.type ?? '').toLowerCase();
    return spec
        .split(',')
        .map((token) => token.trim().toLowerCase())
        .filter((token) => token.length > 0)
        .some((token) => {
        // Catch-all token.
        if (token === '*' || token === '*/*') {
            return true;
        }
        // Extension token, e.g. ".pdf" — the only reliable check when the
        // browser cannot resolve a MIME type (common for .docx/.xlsx).
        if (token.startsWith('.')) {
            return fileName.endsWith(token);
        }
        // Wildcard MIME token, e.g. "image/*".
        if (token.endsWith('/*')) {
            const group = token.slice(0, token.indexOf('/') + 1);
            return !!fileType && fileType.startsWith(group);
        }
        // Exact MIME token, e.g. "application/pdf".
        return !!fileType && fileType === token;
    });
}
function normalizeAcceptSpec(accept) {
    if (Array.isArray(accept)) {
        return accept
            .map((token) => token.trim())
            .filter(Boolean)
            .join(',');
    }
    return accept?.trim() ?? '';
}
function isSameFile(source, target) {
    if (!source || !target) {
        return source === target;
    }
    return (source === target ||
        (source.id && target.id && source.id === target.id) ||
        (source.fileName && target.fileName && source.fileName === target.fileName));
}

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

export { SecureImagePipe, UploadField };
//# sourceMappingURL=masterteam-components-upload-field.mjs.map
