{"version":3,"file":"tft-crispr-forms-index-IyuNneu2.mjs","sources":["../../../../libs/crispr-forms/src/lib/ui/image-upload-field/image-upload-field.component.ts","../../../../libs/crispr-forms/src/lib/ui/image-upload-field/image-upload-field.component.html"],"sourcesContent":["/* eslint-disable @nx/enforce-module-boundaries */\nimport { CommonModule } from '@angular/common';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, inject, OnInit, ViewChild } from '@angular/core';\nimport {\n  ControlValueAccessor,\n  NgControl,\n  ReactiveFormsModule,\n} from '@angular/forms';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatInputModule } from '@angular/material/input';\nimport { DomSanitizer } from '@angular/platform-browser';\nimport imageCompression from 'browser-image-compression';\nimport { combineLatest, Observable, of, Subject } from 'rxjs';\nimport { map, shareReplay, startWith, switchMap, tap } from 'rxjs/operators';\nimport { FormValidationHandlerModule } from '@tft/form-validation-handler';\nimport { FileDropzoneDirective } from '../file-dropzone';\nimport { SelectedFileComponent } from '../selected-file';\nimport { FieldContainerComponent } from '../field-container';\nimport {\n  convertBytesToMb,\n  ImageUploadFieldConfig,\n} from '../../utils';\nimport { CrisprControlComponent } from '../../utils/abstracts/crispr-control.abstract';\n\n@Component({\n    selector: 'crispr-image-upload-field',\n    templateUrl: './image-upload-field.component.html',\n    styleUrls: ['./image-upload-field.component.scss'],\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    imports: [\n        CommonModule,\n        FieldContainerComponent,\n        ReactiveFormsModule,\n        MatIconModule,\n        MatButtonModule,\n        MatFormFieldModule,\n        MatInputModule,\n        SelectedFileComponent,\n        FileDropzoneDirective,\n        FormValidationHandlerModule,\n    ],\n    standalone: true\n})\nexport class ImageUploadFieldComponent\n  extends CrisprControlComponent<ImageUploadFieldConfig>\n  implements OnInit, ControlValueAccessor\n{\n  ngControl = inject(NgControl, { optional: true, self: true });\n  private domSanitizer = inject(DomSanitizer);\n  private cdr = inject(ChangeDetectorRef);\n\n  onChange: () => void;\n\n  defaultConfig: Partial<ImageUploadFieldConfig> = {\n    // allowMultipleFiles: false,\n    acceptedTypes: 'image/*',\n    dropZoneText: 'DROP FILE HERE',\n    selectFilesButtonType: 'button',\n    selectButtonText: 'SELECT',\n    showClearFilesButton: true,\n    clearFilesButtonText: 'CLEAR',\n    resetFilesButtonText: 'RESET',\n    imagePreviewHeight: '250px',\n    compressImage: false,\n    targetCompressedImageFileSizeMb: 0.4,\n    minCompressionThresholdMb: 0.6,\n    useWebWorker: true,\n  };\n\n  private inputImageFileSubject = new Subject<File | null>();\n  inputImageFile$ = this.inputImageFileSubject\n    .asObservable()\n    .pipe(shareReplay(1));\n  /**\n   * the compression progress\n   */\n  progress: number | undefined;\n\n  compressedFile$: Observable<File> = this.inputImageFile$.pipe(\n    switchMap(async (file) => {\n      if (!file || !(file instanceof File)) return null;\n      const {\n        compressImage,\n        targetCompressedImageFileSizeMb,\n        minCompressionThresholdMb,\n        maxWidthOrHeight,\n        useWebWorker,\n      } = this.config();\n      const fileSizeMb = convertBytesToMb(file.size);\n      const shouldCompress =\n        compressImage &&\n        targetCompressedImageFileSizeMb < fileSizeMb &&\n        minCompressionThresholdMb < fileSizeMb;\n      if (shouldCompress) {\n        const options = {\n          // Use maxWidthOrHeight if it was provided, else use target compressed size\n          ...(maxWidthOrHeight\n            ? { maxWidthOrHeight }\n            : { maxSizeMB: targetCompressedImageFileSizeMb }),\n          useWebWorker,\n          maxIterations: 30,\n          onProgress: (progress: number) => {\n            this.progress = progress;\n            this.cdr.markForCheck();\n          },\n        };\n        return await imageCompression(file, options);\n      } else return file;\n    }),\n    map((compressedFile: File) => {\n      if (!compressedFile) return compressedFile;\n      const { type, name, lastModified } = compressedFile;\n      return new File([compressedFile], this.config().fileName || name, {\n        type,\n        lastModified,\n      });\n    }),\n    tap((file) => {\n      // only set the value if there is a file because resetToInitialValue sets the control value\n      // to initial value and clears the compressed image, so setting it to null here would undo that\n      if (file) {\n        this.control().setValue(file);\n      }\n      if (file || this.value()) {\n        this.control().markAsTouched();\n        this.cdr.markForCheck();\n      }\n    }),\n    shareReplay(1)\n  );\n\n  compressedImageUrlString$: Observable<string | null> =\n    this.compressedFile$.pipe(\n      switchMap(async (file) => {\n        if (!file) return null;\n        const compressedStringImage = await imageCompression.getDataUrlFromFile(\n          file\n        );\n        return this.domSanitizer.bypassSecurityTrustResourceUrl(\n          compressedStringImage\n        ) as string;\n      }),\n      shareReplay(1)\n    );\n\n  // This is what is displayed by the image preview\n  imageSrcUrl$: Observable<string | null>;\n\n  @ViewChild('fileInput') fileInputRef: ElementRef;\n\n  selectedFiles: FileList;\n\n  isUploaded = false;\n\n  disabled$: Observable<boolean>;\n\n  constructor() {\n    super();\n    const ngControl = this.ngControl;\n\n    if (this.ngControl != null) {\n      // Setting the value accessor directly (instead of using\n      // the providers) to avoid running into a circular import.\n      ngControl.valueAccessor = this;\n    }\n  }\n\n  ngOnInit() {\n    super.ngOnInit();\n    this.imageSrcUrl$ = combineLatest([\n      this.compressedImageUrlString$.pipe(startWith(null)),\n      this.control().valueChanges.pipe(\n        startWith(this.value()),\n        map((controlValue): string => {\n          if (!controlValue) return null;\n          if (controlValue instanceof File) return null;\n          return (\n            this.config().mapInputValueToUrl?.(controlValue) ||\n            (controlValue as string)\n          );\n        })\n      ),\n    ]).pipe(\n      map(([compressedImageUrlString, controlUrl]) => {\n        return compressedImageUrlString || controlUrl || null;\n      })\n    );\n    this.disabled$ = this.config().disabledCallback\n      ? this.config().disabledCallback(this.group())\n      : of(false);\n  }\n\n  filesChanged(files: FileList): void {\n    if (files && files.length > 0) {\n      const imageFile = files[0];\n      // We clear the control here so that it is invalid while compressing\n      // the input pipeline will take care of resetting it\n      this.control().patchValue(null);\n      // this.control().setErrors({compressing: {loadingMessage: 'Please wait while file compresses'}});\n      this.control().markAsTouched();\n      this.inputImageFileSubject.next(imageFile);\n    }\n  }\n\n  clearFileInput(): void {\n    this.inputImageFileSubject.next(null);\n    this.fileInputRef.nativeElement.value = '';\n    this.control().patchValue(null);\n    this.control().markAsTouched();\n    this.isUploaded = false;\n  }\n\n  resetToInitialValue(initialValue: string): void {\n    this.inputImageFileSubject.next(null);\n    this.control().patchValue(initialValue);\n    this.isUploaded = false;\n  }\n\n  writeValue(value: null) {}\n\n  registerOnChange(fn: () => void) {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: () => void) {}\n}\n","<crispr-field-container\n  [config]=\"config()\"\n  [group]=\"group()\">\n\n  <mat-form-field floatLabel=\"always\"\n    [attr.data-testid]=\"testId()\"\n    [color]=\"config().color\"\n    [appearance]=\"config().appearance\"\n    [formGroup]=\"group()\">\n    <mat-label>{{config().label}}</mat-label>\n    <input [formControlName]=\"config().controlName\" matInput type=\"text\"/>\n    <input\n      #fileInput\n      type=\"file\"\n      [accept]=\"config().acceptedTypes\"\n      (change)=\"filesChanged($event.target.files)\"/>\n    <div class=\"ui-container\">\n\n      <div class=\"image-preview\" [style.height]=\"config().imagePreviewHeight\">\n        @if ((progress < 100) && inputImageFile$ | async; as file) {\n          <crispr-selected-file\n            [color]=\"config().color === 'primary' ? 'accent' : 'primary'\"\n            [fileName]=\"'Compressing: ' + file.name\"\n            [showProgress]=\"true\"\n            [progress]=\"progress\">\n          </crispr-selected-file>\n        } @else {\n          <!-- <img *ngIf=\"(initialUrlString$ | async) as initialUrlString;\" [src]=\"initialUrlString\" alt=\"\"> -->\n          @if (imageSrcUrl$ | async; as srcUrl) {\n            <img [src]=\"srcUrl\" alt=\"\">\n          } @else {\n            <div class=\"drop-container\"\n              [crisprFileDropzone]=\"!(disabled$ | async)\"\n              (fileDrop)=\"filesChanged($event)\">\n              <mat-icon class=\"drop-icon\" inline=\"true\">cloud_upload</mat-icon>\n              <h2 class=\"mat-h2\">{{config().dropZoneText}}</h2>\n            </div>\n          }\n        }\n\n      </div>\n\n\n\n    <!-- </ng-template> -->\n    @if (true) {\n      <div class=\"button-container\">\n        <button\n          mat-button\n          (click)=\"clearFileInput()\"\n          type=\"button\"\n          [disabled]=\"(disabled$ | async)\"\n          aria-label=\"Remove Selected File(s)\">\n          <mat-icon>delete</mat-icon>\n          {{config().clearFilesButtonText}}\n        </button>\n        @if (value()) {\n          <button\n            mat-button\n            (click)=\"resetToInitialValue(value())\"\n            type=\"button\"\n            [disabled]=\"(disabled$ | async)\"\n            aria-label=\"Remove Selected File(s)\">\n            <mat-icon>replay</mat-icon>\n            {{config().resetFilesButtonText}}\n          </button>\n        }\n        <button\n          mat-button\n          type=\"button\"\n          color=\"primary\"\n          [disabled]=\"(disabled$ | async)\"\n          (click)=\"fileInput.click()\"\n          [attr.aria-label]=\"config().controlName\">\n          <mat-icon>\n            camera\n          </mat-icon>\n          SELECT\n        </button>\n      </div>\n    }\n  </div>\n\n  @if (config().hint && (control().valid || !control().touched)) {<mat-hint>{{config().hint}}</mat-hint>}\n\n</mat-form-field>\n\n</crispr-field-container>\n"],"names":["i3","i4","i7"],"mappings":"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"}