import * as i0 from '@angular/core';
import { ChangeDetectionStrategy, Component, input, booleanAttribute, model, viewChild, signal, computed, inject } from '@angular/core';
import { NgTemplateOutlet } from '@angular/common';
import { DomSanitizer } from '@angular/platform-browser';
import { elementStateExclamationMark, elementCircleFilled, elementCancel } from '@siemens/element-icons';
import * as i1 from '@siemens/element-ng/avatar';
import { SiAvatarBackgroundColorDirective } from '@siemens/element-ng/avatar';
import { addIcons, SiIconComponent } from '@siemens/element-ng/icon';
import { SiModalService } from '@siemens/element-ng/modal';
import { t, SiTranslatePipe } from '@siemens/element-translate-ng/translate';
import { ImageCropperComponent } from 'ngx-image-cropper';

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class SiImageCropperStyleComponent {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiImageCropperStyleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.8", type: SiImageCropperStyleComponent, isStandalone: true, selector: "si-image-cropper-style", ngImport: i0, template: '<ng-content />', isInline: true, styles: [":host ::ng-deep image-cropper{max-block-size:70vh;--image-cropper-outline-color: var(--element-base-translucent-1);--cropper-outline-color: var(--image-cropper-outline-color);--cropper-overlay-color: var(--element-ui-5)}:host ::ng-deep image-cropper .ngx-ic-square{background:var(--element-ui-0)!important}:host ::ng-deep image-cropper .ngx-ic-cropper.ngx-ic-cropper{outline:2px solid var(--element-ui-0)!important}:host ::ng-deep image-cropper .ngx-ic-cropper.ngx-ic-cropper:after{z-index:0;border:unset;box-shadow:0 0 0 9999px var(--cropper-outline-color)}:host ::ng-deep image-cropper .ngx-ic-cropper.ngx-ic-cropper .ngx-ic-move.ngx-ic-move{position:relative;overflow:hidden;border:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiImageCropperStyleComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-image-cropper-style', template: '<ng-content />', changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host ::ng-deep image-cropper{max-block-size:70vh;--image-cropper-outline-color: var(--element-base-translucent-1);--cropper-outline-color: var(--image-cropper-outline-color);--cropper-overlay-color: var(--element-ui-5)}:host ::ng-deep image-cropper .ngx-ic-square{background:var(--element-ui-0)!important}:host ::ng-deep image-cropper .ngx-ic-cropper.ngx-ic-cropper{outline:2px solid var(--element-ui-0)!important}:host ::ng-deep image-cropper .ngx-ic-cropper.ngx-ic-cropper:after{z-index:0;border:unset;box-shadow:0 0 0 9999px var(--cropper-outline-color)}:host ::ng-deep image-cropper .ngx-ic-cropper.ngx-ic-cropper .ngx-ic-move.ngx-ic-move{position:relative;overflow:hidden;border:0}\n"] }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
/**
 * A component used to upload, edit, and delete a user's photo. The user can upload
 * a photo either via file browser or a URL to the photo. You can set the source
 * photo with the `sourcePhoto` Data URL input or the `sourcePhotoUrl` URL input.
 * If you already have a cropped image you can set it with the `croppedPhoto` input.
 * Cropping changes are emitted via the `croppedPhotoChange` output.
 */
class SiPhotoUploadComponent {
    static idCounter = 0;
    /**
     * Indicate that changing or uploads are disabled.
     *
     * @defaultValue false
     */
    readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : {}), transform: booleanAttribute });
    /**
     * Optionally disable image cropping.
     *
     * @defaultValue false
     */
    disabledCropping = input(false, { ...(ngDevMode ? { debugName: "disabledCropping" } : {}), transform: booleanAttribute });
    /**
     * Accepted image formats for the file selection dialog.
     *
     * @defaultValue '.png, .jpg, .jpeg'
     *
     * @see
     *
     * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#attr-accept
     */
    acceptedUploadFormats = input('.png, .jpg, .jpeg', ...(ngDevMode ? [{ debugName: "acceptedUploadFormats" }] : []));
    /**
     * Maximum allowed file size of the uploaded file in kilobytes.
     *
     * @defaultValue 2048
     */
    maxFileSize = input(2048, ...(ngDevMode ? [{ debugName: "maxFileSize" }] : []));
    /**
     * If the uploaded file is of an unsupported type, this
     * error message will be displayed to the user.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_PHOTO_UPLOAD.ERROR_FILE_TYPE:The image file is not valid. Please upload a PNG or JP(E)G.`)
     * ```
     */
    uploadErrorWrongType = input(t(() => $localize `:@@SI_PHOTO_UPLOAD.ERROR_FILE_TYPE:The image file is not valid. Please upload a PNG or JP(E)G.`), ...(ngDevMode ? [{ debugName: "uploadErrorWrongType" }] : []));
    /**
     * If the uploaded file exceeds the allowed upload size, this
     * error message will be displayed to the user.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_PHOTO_UPLOAD.ERROR_FILE_SIZE_EXCEEDED:The actual file size {{mb}} MB exceeds the {{maxSizeMb}} MB limit.`)
     * ```
     */
    uploadErrorTooBig = input(t(() => $localize `:@@SI_PHOTO_UPLOAD.ERROR_FILE_SIZE_EXCEEDED:The actual file size {{mb}} MB exceeds the {{maxSizeMb}} MB limit.`), ...(ngDevMode ? [{ debugName: "uploadErrorTooBig" }] : []));
    /**
     * Alternative text for the photo.
     *
     * @defaultValue ''
     */
    photoAltText = input('', ...(ngDevMode ? [{ debugName: "photoAltText" }] : []));
    /**
     * Alternative text for the photo´s placeholder.
     * The value will be used to calculate the background color when `autoColor` is true.
     *
     * @defaultValue ''
     */
    placeholderAltText = input('', ...(ngDevMode ? [{ debugName: "placeholderAltText" }] : []));
    /**
     * Text for the button changing the photo.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_PHOTO_UPLOAD.CHANGE_PHOTO:Change`)
     * ```
     */
    changePhotoText = input(t(() => $localize `:@@SI_PHOTO_UPLOAD.CHANGE_PHOTO:Change`), ...(ngDevMode ? [{ debugName: "changePhotoText" }] : []));
    /**
     * Cropper frame aria label.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_PHOTO_UPLOAD.CROPPER_FRAME_LABEL:Crop photo`)
     * ```
     */
    cropperFrameAriaLabel = input(t(() => $localize `:@@SI_PHOTO_UPLOAD.CROPPER_FRAME_LABEL:Crop photo`), ...(ngDevMode ? [{ debugName: "cropperFrameAriaLabel" }] : []));
    /**
     * Text for the button uploading a photo.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_PHOTO_UPLOAD.UPLOAD_PHOTO:Upload photo`)
     * ```
     */
    uploadPhotoText = input(t(() => $localize `:@@SI_PHOTO_UPLOAD.UPLOAD_PHOTO:Upload photo`), ...(ngDevMode ? [{ debugName: "uploadPhotoText" }] : []));
    /**
     * Text for the button removing the photo.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_PHOTO_UPLOAD.REMOVE:Remove`)
     * ```
     */
    removePhotoText = input(t(() => $localize `:@@SI_PHOTO_UPLOAD.REMOVE:Remove`), ...(ngDevMode ? [{ debugName: "removePhotoText" }] : []));
    /**
     * Text for the button cancelling the editing process.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_PHOTO_UPLOAD.CANCEL:Cancel`)
     * ```
     */
    cancelEditText = input(t(() => $localize `:@@SI_PHOTO_UPLOAD.CANCEL:Cancel`), ...(ngDevMode ? [{ debugName: "cancelEditText" }] : []));
    /**
     * Text for the button applying the edited photo.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_PHOTO_UPLOAD.APPLY_PHOTO:Apply`)
     * ```
     */
    applyEditText = input(t(() => $localize `:@@SI_PHOTO_UPLOAD.APPLY_PHOTO:Apply`), ...(ngDevMode ? [{ debugName: "applyEditText" }] : []));
    /**
     * Text displayed as header of the editing modal.
     *
     * @defaultValue
     * ```
     * t(() => $localize`:@@SI_PHOTO_UPLOAD.MODAL_TITLE:Avatar photo`)
     * ```
     */
    modalHeader = input(t(() => $localize `:@@SI_PHOTO_UPLOAD.MODAL_TITLE:Avatar photo`), ...(ngDevMode ? [{ debugName: "modalHeader" }] : []));
    /**
     * Text displayed as description of the editing modal.
     */
    modalDescription = input(...(ngDevMode ? [undefined, { debugName: "modalDescription" }] : []));
    /**
     * Output format of the edited image.
     *
     * @defaultValue 'jpeg'
     */
    cropperImageFormat = input('jpeg', ...(ngDevMode ? [{ debugName: "cropperImageFormat" }] : []));
    /**
     * The width / height ratio (e.g. 1 / 1 for a square, 4 / 3, 16 / 9 ...).
     *
     * @defaultValue 1
     */
    cropperAspectRatio = input(1, ...(ngDevMode ? [{ debugName: "cropperAspectRatio" }] : []));
    /**
     * Whether to keep the width and height of the cropped image equal according
     * to the aspectRatio.
     *
     * @defaultValue true
     */
    cropperMaintainAspectRatio = input(true, { ...(ngDevMode ? { debugName: "cropperMaintainAspectRatio" } : {}), transform: booleanAttribute });
    /**
     * When set to true, padding will be added around the image to make it fit to
     * the aspect ratio. Be aware that this transformation will cause the loaded
     * image to be a png file with an increased base64 string payload.
     *
     * @defaultValue false
     */
    cropperContainWithinAspectRatio = input(false, { ...(ngDevMode ? { debugName: "cropperContainWithinAspectRatio" } : {}), transform: booleanAttribute });
    /**
     * The cropper´s width cannot be made smaller than this number of pixels
     * (relative to original image´s size). (0 = disabled).
     *
     * @defaultValue 50
     */
    cropperMinWidth = input(50, ...(ngDevMode ? [{ debugName: "cropperMinWidth" }] : []));
    /**
     * The cropper´s height cannot be made smaller than this number of pixels
     * (relative to original image´s size). Will be ignored if
     * `cropperMaintainAspectRatio` is set. (0 = disabled).
     *
     * @defaultValue 50
     */
    cropperMinHeight = input(50, ...(ngDevMode ? [{ debugName: "cropperMinHeight" }] : []));
    /**
     * The cropper´s width cannot be made bigger than this number of pixels.
     * Default is 0 (disabled).
     *
     * @defaultValue 0
     */
    cropperMaxWidth = input(0, ...(ngDevMode ? [{ debugName: "cropperMaxWidth" }] : []));
    /**
     * The cropper´s height cannot be made bigger than this number of pixels.
     * Default is 0 (disabled).
     *
     * @defaultValue 0
     */
    cropperMaxHeight = input(0, ...(ngDevMode ? [{ debugName: "cropperMaxHeight" }] : []));
    /**
     * Set this to true for a round cropper. Resulting image will still
     * be square, but visually clipped with a border-radius: 50% on the
     * resulting image to show it as round.
     *
     * @defaultValue true
     */
    roundImage = input(true, { ...(ngDevMode ? { debugName: "roundImage" } : {}), transform: booleanAttribute });
    /**
     * The input photo to be used for cropping. A string in [Data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs) format
     * with base64 encoding.
     */
    sourcePhoto = model(...(ngDevMode ? [undefined, { debugName: "sourcePhoto" }] : []));
    /**
     * URL to a photo to be used for cropping.
     */
    sourcePhotoUrl = input(...(ngDevMode ? [undefined, { debugName: "sourcePhotoUrl" }] : []));
    /**
     * The photo to be displayed and edited (when not readonly).
     */
    croppedPhoto = model(...(ngDevMode ? [undefined, { debugName: "croppedPhoto" }] : []));
    editPhotoTemplate = viewChild.required('editPhotoTemplate');
    fileInput = viewChild.required('fileInput');
    imageCropper = viewChild('imageCropper', ...(ngDevMode ? [{ debugName: "imageCropper" }] : []));
    // used to label the dialog
    titleId = `__si-photo-upload-${SiPhotoUploadComponent.idCounter++}`;
    /**
     * The trusted photo url string which is used to display the photo.
     */
    sanitizedPhotoUrl = signal(undefined, ...(ngDevMode ? [{ debugName: "sanitizedPhotoUrl" }] : []));
    /**
     * The appropriate error message displayed to the user. Might be
     * `uploadErrorWrongType` or `uploadErrorTooBig`.
     */
    uploadErrorMessage = signal(undefined, ...(ngDevMode ? [{ debugName: "uploadErrorMessage" }] : []));
    editButtonText = computed(() => this.sanitizedPhotoUrl() ? this.changePhotoText() : this.uploadPhotoText(), ...(ngDevMode ? [{ debugName: "editButtonText" }] : []));
    currentFileSizeKilobytes = signal(-1, ...(ngDevMode ? [{ debugName: "currentFileSizeKilobytes" }] : []));
    currentFileSizeMegabytes = signal(-1, ...(ngDevMode ? [{ debugName: "currentFileSizeMegabytes" }] : []));
    maxSizeMb = computed(() => this.maxFileSize() / 1024, ...(ngDevMode ? [{ debugName: "maxSizeMb" }] : []));
    /**
     * The photo instance to be used in the image cropper. We need a different
     * reference than `sourcePhoto` to support the cancel after uploading
     * a new photo. While `sourcePhoto` is A and image cropper uploads B,
     * we should not replace `sourcePhoto` A until user presses apply.
     */
    imageCropperPhoto = signal(undefined, ...(ngDevMode ? [{ debugName: "imageCropperPhoto" }] : []));
    icons = addIcons({
        elementCancel,
        elementCircleFilled,
        elementStateExclamationMark
    });
    /**
     * Reference to the modal displaying the photo to edit.
     */
    modalRef;
    /**
     * The last cropped event of the image cropper component.
     * Will be set on every mouse drag of the user. It contains
     * the cropped image and the position. When user completes
     * the cropping, the data from the last event is used.
     */
    imageCroppedEvent;
    /**
     * Applied cropper position necessary to restore the cropper position when the use press the Change button.
     */
    cropperPosition;
    sanitizer = inject(DomSanitizer);
    modalService = inject(SiModalService);
    autoBackgroundColorDirective = inject(SiAvatarBackgroundColorDirective);
    ngOnChanges(changes) {
        if (changes.readonly) {
            this.resetErrorMessage();
            this.resetFileInputValue();
        }
        if (changes.sourcePhotoUrl) {
            this.setPhoto(this.sourcePhotoUrl());
            this.cropperPosition = undefined;
            this.croppedPhoto.set(undefined);
        }
        if (changes.sourcePhoto?.currentValue !== this.imageCropperPhoto()) {
            const sourcePhoto = this.sourcePhoto();
            this.setPhoto(sourcePhoto);
            this.cropperPosition = undefined;
            this.croppedPhoto.set(undefined);
            this.imageCropperPhoto.set(sourcePhoto);
        }
        if (changes.croppedPhoto &&
            (changes.croppedPhoto?.previousValue?.length ?? 0) > 0 &&
            changes.croppedPhoto.previousValue !== changes.croppedPhoto.currentValue) {
            this.setPhoto(this.croppedPhoto());
        }
        if (changes.placeholderAltText) {
            this.autoBackgroundColorDirective.calculateColorFromInitials(this.placeholderAltText());
        }
    }
    ngOnDestroy() {
        this.modalRef?.detach();
    }
    /**
     * Opens a modal dialog with the cropping component.
     */
    showCroppingDialog() {
        if (this.modalRef) {
            return;
        }
        if (this.disabledCropping()) {
            this.sourcePhoto.set(this.imageCropperPhoto());
            const sourcePhoto = this.sourcePhoto();
            this.updateCroppedPhoto(sourcePhoto ?? '');
            return;
        }
        this.modalRef = this.modalService.show(this.editPhotoTemplate(), {
            ignoreBackdropClick: false,
            keyboard: true,
            class: 'modal-dialog-centered',
            ariaLabelledBy: this.titleId
        }, 'cancel');
        this.resetErrorMessage();
        this.modalRef.hidden.subscribe(() => {
            this.resetErrorMessage();
            this.resetFileInputValue();
            this.modalRef = undefined;
        });
    }
    fileUpload(event) {
        // Initially reset a possible error message
        this.resetErrorMessage();
        const files = event.target.files;
        const file = files && files.length > 0 ? files[0] : undefined;
        if (!file) {
            return;
        }
        const fileType = file.type;
        const allowedFileTypes = this.acceptedUploadFormats()
            .split(',')
            .map(type => type.trim().replace('.', 'image/'));
        const fileTypeWrong = !allowedFileTypes.includes(fileType);
        if (fileTypeWrong) {
            this.uploadErrorMessage.set(this.uploadErrorWrongType());
            return;
        }
        const sizeInKb = file.size / 1024;
        this.currentFileSizeKilobytes.set(Math.round(sizeInKb * 10) / 10);
        this.currentFileSizeMegabytes.set(Math.round((sizeInKb / 1024) * 1000) / 1000);
        const fileSizeTooBig = sizeInKb > this.maxFileSize();
        if (fileSizeTooBig) {
            this.uploadErrorMessage.set(this.uploadErrorTooBig());
            return;
        }
        const reader = new FileReader();
        reader.addEventListener('loadend', () => {
            if (typeof reader.result === 'string') {
                this.cropperPosition = undefined;
                this.imageCropperPhoto.set(reader.result);
                // Bring up the editing modal if not already present
                this.showCroppingDialog();
            }
        });
        reader.readAsDataURL(file);
    }
    updateCroppedPhoto(croppedPhoto, position) {
        this.croppedPhoto.set(croppedPhoto);
        this.setPhoto(this.croppedPhoto());
        this.cropperPosition = position;
    }
    removePhoto() {
        // We emit undefined to notify consumers that the cropped
        // images is removed. This is a kind of special crop event.
        this.croppedPhoto.set(undefined);
        this.imageCropperPhoto.set(undefined);
        this.setPhoto(undefined);
        this.cropperPosition = undefined;
        this.resetFileInputValue();
        this.sourcePhoto.set(undefined);
    }
    /**
     * Invoked when user cropped the photo and pressed apply button.
     * Updates the current photo by the selected cropped photo and
     * closes the modal dialog.
     */
    imageCropperApplied() {
        if (this.imageCroppedEvent) {
            this.sourcePhoto.set(this.imageCropperPhoto());
            this.updateCroppedPhoto(this.imageCroppedEvent.base64.toString(), this.imageCroppedEvent.cropperPosition);
        }
        this.modalRef?.hide();
    }
    imageCropperCanceled() {
        this.imageCropperPhoto.set(this.sourcePhoto());
        this.modalRef?.hide('cancel');
    }
    /**
     * Callback from the image cropper on every mouse drag invoking a cropping.
     *
     * @param event - Event containing the cropped image and the image cropped position.
     *
     */
    cropperImageCropped(event) {
        this.imageCroppedEvent = event;
    }
    /**
     * Lifecycle hook from the image cropper component. Informs
     * us when initialized and ready.
     */
    cropperReady() {
        // When the user opens cropper dialog multiple times we need to
        // apply existing cropper position.
        const imageCropper = this.imageCropper();
        if (this.cropperPosition && imageCropper) {
            imageCropper.cropper = { ...this.cropperPosition };
            imageCropper.crop();
        }
    }
    resetFileInputValue() {
        if (this.fileInput()) {
            // Remove fileInput value to allow for selecting the same
            // file for being uploaded again.
            this.fileInput().nativeElement.value = null;
        }
    }
    resetErrorMessage() {
        this.uploadErrorMessage.set(undefined);
    }
    setPhoto(photo) {
        this.resetErrorMessage();
        this.sanitizedPhotoUrl.set(photo ? this.sanitizer.bypassSecurityTrustResourceUrl(photo) : undefined);
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiPhotoUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: SiPhotoUploadComponent, isStandalone: true, selector: "si-photo-upload", inputs: { readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabledCropping: { classPropertyName: "disabledCropping", publicName: "disabledCropping", isSignal: true, isRequired: false, transformFunction: null }, acceptedUploadFormats: { classPropertyName: "acceptedUploadFormats", publicName: "acceptedUploadFormats", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, uploadErrorWrongType: { classPropertyName: "uploadErrorWrongType", publicName: "uploadErrorWrongType", isSignal: true, isRequired: false, transformFunction: null }, uploadErrorTooBig: { classPropertyName: "uploadErrorTooBig", publicName: "uploadErrorTooBig", isSignal: true, isRequired: false, transformFunction: null }, photoAltText: { classPropertyName: "photoAltText", publicName: "photoAltText", isSignal: true, isRequired: false, transformFunction: null }, placeholderAltText: { classPropertyName: "placeholderAltText", publicName: "placeholderAltText", isSignal: true, isRequired: false, transformFunction: null }, changePhotoText: { classPropertyName: "changePhotoText", publicName: "changePhotoText", isSignal: true, isRequired: false, transformFunction: null }, cropperFrameAriaLabel: { classPropertyName: "cropperFrameAriaLabel", publicName: "cropperFrameAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, uploadPhotoText: { classPropertyName: "uploadPhotoText", publicName: "uploadPhotoText", isSignal: true, isRequired: false, transformFunction: null }, removePhotoText: { classPropertyName: "removePhotoText", publicName: "removePhotoText", isSignal: true, isRequired: false, transformFunction: null }, cancelEditText: { classPropertyName: "cancelEditText", publicName: "cancelEditText", isSignal: true, isRequired: false, transformFunction: null }, applyEditText: { classPropertyName: "applyEditText", publicName: "applyEditText", isSignal: true, isRequired: false, transformFunction: null }, modalHeader: { classPropertyName: "modalHeader", publicName: "modalHeader", isSignal: true, isRequired: false, transformFunction: null }, modalDescription: { classPropertyName: "modalDescription", publicName: "modalDescription", isSignal: true, isRequired: false, transformFunction: null }, cropperImageFormat: { classPropertyName: "cropperImageFormat", publicName: "cropperImageFormat", isSignal: true, isRequired: false, transformFunction: null }, cropperAspectRatio: { classPropertyName: "cropperAspectRatio", publicName: "cropperAspectRatio", isSignal: true, isRequired: false, transformFunction: null }, cropperMaintainAspectRatio: { classPropertyName: "cropperMaintainAspectRatio", publicName: "cropperMaintainAspectRatio", isSignal: true, isRequired: false, transformFunction: null }, cropperContainWithinAspectRatio: { classPropertyName: "cropperContainWithinAspectRatio", publicName: "cropperContainWithinAspectRatio", isSignal: true, isRequired: false, transformFunction: null }, cropperMinWidth: { classPropertyName: "cropperMinWidth", publicName: "cropperMinWidth", isSignal: true, isRequired: false, transformFunction: null }, cropperMinHeight: { classPropertyName: "cropperMinHeight", publicName: "cropperMinHeight", isSignal: true, isRequired: false, transformFunction: null }, cropperMaxWidth: { classPropertyName: "cropperMaxWidth", publicName: "cropperMaxWidth", isSignal: true, isRequired: false, transformFunction: null }, cropperMaxHeight: { classPropertyName: "cropperMaxHeight", publicName: "cropperMaxHeight", isSignal: true, isRequired: false, transformFunction: null }, roundImage: { classPropertyName: "roundImage", publicName: "roundImage", isSignal: true, isRequired: false, transformFunction: null }, sourcePhoto: { classPropertyName: "sourcePhoto", publicName: "sourcePhoto", isSignal: true, isRequired: false, transformFunction: null }, sourcePhotoUrl: { classPropertyName: "sourcePhotoUrl", publicName: "sourcePhotoUrl", isSignal: true, isRequired: false, transformFunction: null }, croppedPhoto: { classPropertyName: "croppedPhoto", publicName: "croppedPhoto", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sourcePhoto: "sourcePhotoChange", croppedPhoto: "croppedPhotoChange" }, viewQueries: [{ propertyName: "editPhotoTemplate", first: true, predicate: ["editPhotoTemplate"], descendants: true, isSignal: true }, { propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true, isSignal: true }, { propertyName: "imageCropper", first: true, predicate: ["imageCropper"], descendants: true, isSignal: true }], usesOnChanges: true, hostDirectives: [{ directive: i1.SiAvatarBackgroundColorDirective, inputs: ["color", "color", "autoColor", "autoColor"] }], ngImport: i0, template: "<div class=\"photo-upload d-flex flex-column p-6\">\n  <!-- File upload -->\n  <input\n    #fileInput\n    type=\"file\"\n    class=\"d-none\"\n    [accept]=\"acceptedUploadFormats()\"\n    (change)=\"fileUpload($event)\"\n  />\n\n  <!-- Image -->\n  @if (sanitizedPhotoUrl()) {\n    <img\n      class=\"photo-upload-photo\"\n      [class.round]=\"roundImage()\"\n      [src]=\"sanitizedPhotoUrl()\"\n      [alt]=\"photoAltText() | translate\"\n    />\n  } @else {\n    <span\n      class=\"photo-upload-placeholder d-flex align-items-center justify-content-center flex-none\"\n      [class.round]=\"roundImage()\"\n    >\n      {{ placeholderAltText() | translate }}\n    </span>\n  }\n  <!-- Buttons -->\n  @if (!readonly()) {\n    <div class=\"d-flex justify-content-center gap-6 mt-8\">\n      <button\n        type=\"button\"\n        class=\"btn btn-secondary\"\n        (click)=\"\n          (sourcePhoto() || sourcePhotoUrl()) && !disabledCropping()\n            ? showCroppingDialog()\n            : fileInput.click()\n        \"\n      >\n        {{ editButtonText() | translate }}\n      </button>\n      @if (sanitizedPhotoUrl()) {\n        <button type=\"button\" class=\"btn btn-danger\" (click)=\"removePhoto()\">\n          {{ removePhotoText() | translate }}\n        </button>\n      }\n    </div>\n  }\n\n  <!-- Error message -->\n  @if (uploadErrorMessage() && !modalRef) {\n    <div class=\"mt-6\">\n      <ng-container [ngTemplateOutlet]=\"errorMessageTemplate\" />\n    </div>\n  }\n</div>\n\n<!-- Template: modal -->\n<ng-template #editPhotoTemplate>\n  <!-- Header -->\n  <div class=\"modal-header\">\n    <h4 class=\"modal-title\" [id]=\"titleId\">{{ modalHeader() | translate }}</h4>\n    <button\n      type=\"button\"\n      class=\"btn btn-circle btn-ghost\"\n      [attr.aria-label]=\"cancelEditText() | translate\"\n      (click)=\"imageCropperCanceled()\"\n    >\n      <si-icon [icon]=\"icons.elementCancel\" />\n    </button>\n  </div>\n  <!-- Content -->\n  <div class=\"modal-body\">\n    @if (modalDescription()) {\n      <div class=\"mb-4\">\n        <span class=\"text-secondary\">{{ modalDescription() | translate }}</span>\n      </div>\n    }\n    <ng-container [ngTemplateOutlet]=\"imageCropperTemplate\" />\n    @if (uploadErrorMessage()) {\n      <div class=\"d-flex mt-4\">\n        <ng-container [ngTemplateOutlet]=\"errorMessageTemplate\" />\n      </div>\n    }\n  </div>\n  <!-- Footer -->\n  <div class=\"modal-footer\">\n    <button type=\"button\" class=\"btn btn-secondary me-auto\" (click)=\"fileInput.click()\">\n      {{ changePhotoText() | translate }}\n    </button>\n    <div class=\"d-flex gap-6\">\n      <button type=\"button\" class=\"btn btn-secondary\" (click)=\"imageCropperCanceled()\">\n        {{ cancelEditText() | translate }}\n      </button>\n      <button type=\"button\" class=\"btn btn-primary\" (click)=\"imageCropperApplied()\">\n        {{ applyEditText() | translate }}\n      </button>\n    </div>\n  </div>\n</ng-template>\n\n<!-- Template: error message -->\n<ng-template #errorMessageTemplate>\n  <div class=\"d-flex align-items-center\">\n    <span class=\"icon-sm icon-stack d-inline-block my-n2 me-2\">\n      <si-icon class=\"status-danger\" [icon]=\"icons.elementCircleFilled\" />\n      <si-icon class=\"status-danger-contrast\" [icon]=\"icons.elementStateExclamationMark\" />\n    </span>\n    <span class=\"text-danger\">{{\n      uploadErrorMessage()\n        | translate\n          : {\n              mb: currentFileSizeMegabytes(),\n              kb: currentFileSizeKilobytes(),\n              maxSizeMb: maxSizeMb()\n            }\n    }}</span>\n  </div>\n</ng-template>\n\n<!-- Template: image cropper -->\n<ng-template #imageCropperTemplate>\n  <si-image-cropper-style>\n    <image-cropper\n      #imageCropper\n      output=\"base64\"\n      [aspectRatio]=\"cropperAspectRatio()\"\n      [containWithinAspectRatio]=\"cropperContainWithinAspectRatio()\"\n      [cropperMinWidth]=\"cropperMinWidth()\"\n      [cropperMinHeight]=\"cropperMinHeight()\"\n      [cropperMaxWidth]=\"cropperMaxWidth()\"\n      [cropperMaxHeight]=\"cropperMaxHeight()\"\n      [cropperFrameAriaLabel]=\"cropperFrameAriaLabel() | translate\"\n      [format]=\"cropperImageFormat()\"\n      [imageBase64]=\"imageCropperPhoto()\"\n      [imageURL]=\"sourcePhotoUrl()\"\n      [maintainAspectRatio]=\"cropperMaintainAspectRatio()\"\n      [onlyScaleDown]=\"true\"\n      [roundCropper]=\"roundImage()\"\n      (cropperReady)=\"cropperReady()\"\n      (imageCropped)=\"cropperImageCropped($event)\"\n    />\n  </si-image-cropper-style>\n</ng-template>\n", styles: [":host{--si-photo-upload-photo-width: 200px;--si-photo-upload-photo-height: 200px}.photo-upload{box-sizing:content-box;max-inline-size:var(--si-photo-upload-photo-width)}.photo-upload-photo,.photo-upload-placeholder{display:block;margin:auto;inline-size:var(--si-photo-upload-photo-width);max-inline-size:100%;block-size:var(--si-photo-upload-photo-height);object-fit:cover}.photo-upload-photo.round,.photo-upload-placeholder.round{border-radius:50%}.photo-upload-placeholder{background-color:var(--background);color:var(--element-ui-5);font-size:3rem;text-align:center;overflow:hidden;word-break:break-all;-webkit-user-select:none;user-select:none}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ImageCropperComponent, selector: "image-cropper", inputs: ["imageChangedEvent", "imageURL", "imageBase64", "imageFile", "imageAltText", "options", "cropperFrameAriaLabel", "output", "format", "autoCrop", "cropper", "transform", "maintainAspectRatio", "aspectRatio", "resetCropOnAspectRatioChange", "resizeToWidth", "resizeToHeight", "cropperMinWidth", "cropperMinHeight", "cropperMaxHeight", "cropperMaxWidth", "cropperStaticWidth", "cropperStaticHeight", "canvasRotation", "initialStepSize", "roundCropper", "onlyScaleDown", "imageQuality", "backgroundColor", "containWithinAspectRatio", "hideResizeSquares", "allowMoveImage", "checkImageType", "alignImage", "disabled", "hidden"], outputs: ["imageCropped", "startCropImage", "imageLoaded", "cropperReady", "loadImageFailed", "transformChange", "cropperChange"] }, { kind: "component", type: SiIconComponent, selector: "si-icon", inputs: ["icon"] }, { kind: "component", type: SiImageCropperStyleComponent, selector: "si-image-cropper-style" }, { kind: "pipe", type: SiTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiPhotoUploadComponent, decorators: [{
            type: Component,
            args: [{ selector: 'si-photo-upload', imports: [
                        NgTemplateOutlet,
                        ImageCropperComponent,
                        SiIconComponent,
                        SiImageCropperStyleComponent,
                        SiTranslatePipe
                    ], changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [
                        {
                            directive: SiAvatarBackgroundColorDirective,
                            inputs: ['color', 'autoColor']
                        }
                    ], template: "<div class=\"photo-upload d-flex flex-column p-6\">\n  <!-- File upload -->\n  <input\n    #fileInput\n    type=\"file\"\n    class=\"d-none\"\n    [accept]=\"acceptedUploadFormats()\"\n    (change)=\"fileUpload($event)\"\n  />\n\n  <!-- Image -->\n  @if (sanitizedPhotoUrl()) {\n    <img\n      class=\"photo-upload-photo\"\n      [class.round]=\"roundImage()\"\n      [src]=\"sanitizedPhotoUrl()\"\n      [alt]=\"photoAltText() | translate\"\n    />\n  } @else {\n    <span\n      class=\"photo-upload-placeholder d-flex align-items-center justify-content-center flex-none\"\n      [class.round]=\"roundImage()\"\n    >\n      {{ placeholderAltText() | translate }}\n    </span>\n  }\n  <!-- Buttons -->\n  @if (!readonly()) {\n    <div class=\"d-flex justify-content-center gap-6 mt-8\">\n      <button\n        type=\"button\"\n        class=\"btn btn-secondary\"\n        (click)=\"\n          (sourcePhoto() || sourcePhotoUrl()) && !disabledCropping()\n            ? showCroppingDialog()\n            : fileInput.click()\n        \"\n      >\n        {{ editButtonText() | translate }}\n      </button>\n      @if (sanitizedPhotoUrl()) {\n        <button type=\"button\" class=\"btn btn-danger\" (click)=\"removePhoto()\">\n          {{ removePhotoText() | translate }}\n        </button>\n      }\n    </div>\n  }\n\n  <!-- Error message -->\n  @if (uploadErrorMessage() && !modalRef) {\n    <div class=\"mt-6\">\n      <ng-container [ngTemplateOutlet]=\"errorMessageTemplate\" />\n    </div>\n  }\n</div>\n\n<!-- Template: modal -->\n<ng-template #editPhotoTemplate>\n  <!-- Header -->\n  <div class=\"modal-header\">\n    <h4 class=\"modal-title\" [id]=\"titleId\">{{ modalHeader() | translate }}</h4>\n    <button\n      type=\"button\"\n      class=\"btn btn-circle btn-ghost\"\n      [attr.aria-label]=\"cancelEditText() | translate\"\n      (click)=\"imageCropperCanceled()\"\n    >\n      <si-icon [icon]=\"icons.elementCancel\" />\n    </button>\n  </div>\n  <!-- Content -->\n  <div class=\"modal-body\">\n    @if (modalDescription()) {\n      <div class=\"mb-4\">\n        <span class=\"text-secondary\">{{ modalDescription() | translate }}</span>\n      </div>\n    }\n    <ng-container [ngTemplateOutlet]=\"imageCropperTemplate\" />\n    @if (uploadErrorMessage()) {\n      <div class=\"d-flex mt-4\">\n        <ng-container [ngTemplateOutlet]=\"errorMessageTemplate\" />\n      </div>\n    }\n  </div>\n  <!-- Footer -->\n  <div class=\"modal-footer\">\n    <button type=\"button\" class=\"btn btn-secondary me-auto\" (click)=\"fileInput.click()\">\n      {{ changePhotoText() | translate }}\n    </button>\n    <div class=\"d-flex gap-6\">\n      <button type=\"button\" class=\"btn btn-secondary\" (click)=\"imageCropperCanceled()\">\n        {{ cancelEditText() | translate }}\n      </button>\n      <button type=\"button\" class=\"btn btn-primary\" (click)=\"imageCropperApplied()\">\n        {{ applyEditText() | translate }}\n      </button>\n    </div>\n  </div>\n</ng-template>\n\n<!-- Template: error message -->\n<ng-template #errorMessageTemplate>\n  <div class=\"d-flex align-items-center\">\n    <span class=\"icon-sm icon-stack d-inline-block my-n2 me-2\">\n      <si-icon class=\"status-danger\" [icon]=\"icons.elementCircleFilled\" />\n      <si-icon class=\"status-danger-contrast\" [icon]=\"icons.elementStateExclamationMark\" />\n    </span>\n    <span class=\"text-danger\">{{\n      uploadErrorMessage()\n        | translate\n          : {\n              mb: currentFileSizeMegabytes(),\n              kb: currentFileSizeKilobytes(),\n              maxSizeMb: maxSizeMb()\n            }\n    }}</span>\n  </div>\n</ng-template>\n\n<!-- Template: image cropper -->\n<ng-template #imageCropperTemplate>\n  <si-image-cropper-style>\n    <image-cropper\n      #imageCropper\n      output=\"base64\"\n      [aspectRatio]=\"cropperAspectRatio()\"\n      [containWithinAspectRatio]=\"cropperContainWithinAspectRatio()\"\n      [cropperMinWidth]=\"cropperMinWidth()\"\n      [cropperMinHeight]=\"cropperMinHeight()\"\n      [cropperMaxWidth]=\"cropperMaxWidth()\"\n      [cropperMaxHeight]=\"cropperMaxHeight()\"\n      [cropperFrameAriaLabel]=\"cropperFrameAriaLabel() | translate\"\n      [format]=\"cropperImageFormat()\"\n      [imageBase64]=\"imageCropperPhoto()\"\n      [imageURL]=\"sourcePhotoUrl()\"\n      [maintainAspectRatio]=\"cropperMaintainAspectRatio()\"\n      [onlyScaleDown]=\"true\"\n      [roundCropper]=\"roundImage()\"\n      (cropperReady)=\"cropperReady()\"\n      (imageCropped)=\"cropperImageCropped($event)\"\n    />\n  </si-image-cropper-style>\n</ng-template>\n", styles: [":host{--si-photo-upload-photo-width: 200px;--si-photo-upload-photo-height: 200px}.photo-upload{box-sizing:content-box;max-inline-size:var(--si-photo-upload-photo-width)}.photo-upload-photo,.photo-upload-placeholder{display:block;margin:auto;inline-size:var(--si-photo-upload-photo-width);max-inline-size:100%;block-size:var(--si-photo-upload-photo-height);object-fit:cover}.photo-upload-photo.round,.photo-upload-placeholder.round{border-radius:50%}.photo-upload-placeholder{background-color:var(--background);color:var(--element-ui-5);font-size:3rem;text-align:center;overflow:hidden;word-break:break-all;-webkit-user-select:none;user-select:none}\n"] }]
        }], propDecorators: { readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], disabledCropping: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledCropping", required: false }] }], acceptedUploadFormats: [{ type: i0.Input, args: [{ isSignal: true, alias: "acceptedUploadFormats", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], uploadErrorWrongType: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadErrorWrongType", required: false }] }], uploadErrorTooBig: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadErrorTooBig", required: false }] }], photoAltText: [{ type: i0.Input, args: [{ isSignal: true, alias: "photoAltText", required: false }] }], placeholderAltText: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholderAltText", required: false }] }], changePhotoText: [{ type: i0.Input, args: [{ isSignal: true, alias: "changePhotoText", required: false }] }], cropperFrameAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "cropperFrameAriaLabel", required: false }] }], uploadPhotoText: [{ type: i0.Input, args: [{ isSignal: true, alias: "uploadPhotoText", required: false }] }], removePhotoText: [{ type: i0.Input, args: [{ isSignal: true, alias: "removePhotoText", required: false }] }], cancelEditText: [{ type: i0.Input, args: [{ isSignal: true, alias: "cancelEditText", required: false }] }], applyEditText: [{ type: i0.Input, args: [{ isSignal: true, alias: "applyEditText", required: false }] }], modalHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "modalHeader", required: false }] }], modalDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "modalDescription", required: false }] }], cropperImageFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "cropperImageFormat", required: false }] }], cropperAspectRatio: [{ type: i0.Input, args: [{ isSignal: true, alias: "cropperAspectRatio", required: false }] }], cropperMaintainAspectRatio: [{ type: i0.Input, args: [{ isSignal: true, alias: "cropperMaintainAspectRatio", required: false }] }], cropperContainWithinAspectRatio: [{ type: i0.Input, args: [{ isSignal: true, alias: "cropperContainWithinAspectRatio", required: false }] }], cropperMinWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "cropperMinWidth", required: false }] }], cropperMinHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "cropperMinHeight", required: false }] }], cropperMaxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "cropperMaxWidth", required: false }] }], cropperMaxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "cropperMaxHeight", required: false }] }], roundImage: [{ type: i0.Input, args: [{ isSignal: true, alias: "roundImage", required: false }] }], sourcePhoto: [{ type: i0.Input, args: [{ isSignal: true, alias: "sourcePhoto", required: false }] }, { type: i0.Output, args: ["sourcePhotoChange"] }], sourcePhotoUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "sourcePhotoUrl", required: false }] }], croppedPhoto: [{ type: i0.Input, args: [{ isSignal: true, alias: "croppedPhoto", required: false }] }, { type: i0.Output, args: ["croppedPhotoChange"] }], editPhotoTemplate: [{ type: i0.ViewChild, args: ['editPhotoTemplate', { isSignal: true }] }], fileInput: [{ type: i0.ViewChild, args: ['fileInput', { isSignal: true }] }], imageCropper: [{ type: i0.ViewChild, args: ['imageCropper', { isSignal: true }] }] } });

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

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

export { SiImageCropperStyleComponent, SiPhotoUploadComponent };
//# sourceMappingURL=siemens-element-ng-photo-upload.mjs.map
