@tft/crispr-forms 13.0.0 → 13.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -69
- package/esm2020/lib/material/image-upload-field/image-upload-field.component.mjs +60 -23
- package/esm2020/lib/models/file-upload-field.config.mjs +1 -1
- package/esm2020/lib/models/image-upload-field.config.mjs +1 -1
- package/fesm2015/tft-crispr-forms.mjs +63 -24
- package/fesm2015/tft-crispr-forms.mjs.map +1 -1
- package/fesm2020/tft-crispr-forms.mjs +61 -23
- package/fesm2020/tft-crispr-forms.mjs.map +1 -1
- package/lib/material/image-upload-field/image-upload-field.component.d.ts +9 -2
- package/lib/models/file-upload-field.config.d.ts +1 -1
- package/lib/models/image-upload-field.config.d.ts +7 -1
- package/package.json +3 -4
- package/tft-crispr-forms-13.0.4.tgz +0 -0
- package/tft-crispr-forms-13.0.0.tgz +0 -0
|
@@ -1127,7 +1127,6 @@ function convertBytesToMb(bytes) {
|
|
|
1127
1127
|
|
|
1128
1128
|
const ImageUploadFieldMixin = crisprControlMixin(CrisprFieldComponent);
|
|
1129
1129
|
class ImageUploadFieldComponent extends ImageUploadFieldMixin {
|
|
1130
|
-
// ngControl: NgControl = null;
|
|
1131
1130
|
constructor(ngControl, domSanitizer, cdr) {
|
|
1132
1131
|
super();
|
|
1133
1132
|
this.ngControl = ngControl;
|
|
@@ -1148,48 +1147,61 @@ class ImageUploadFieldComponent extends ImageUploadFieldMixin {
|
|
|
1148
1147
|
minCompressionThresholdMb: .6,
|
|
1149
1148
|
useWebWorker: true,
|
|
1150
1149
|
};
|
|
1150
|
+
/**
|
|
1151
|
+
* The url mapped from initial input value, consumers can us mapInputValueToUrl in config to transform their input value into a src url for the image element
|
|
1152
|
+
*/
|
|
1153
|
+
// inputValueUrl: string | undefined;
|
|
1151
1154
|
this.inputImageFileSubject = new Subject();
|
|
1152
1155
|
this.inputImageFile$ = this.inputImageFileSubject.asObservable().pipe(shareReplay(1));
|
|
1153
1156
|
this.compressedFile$ = this.inputImageFile$.pipe(switchMap(async (file) => {
|
|
1154
|
-
if (!file)
|
|
1157
|
+
if (!file || !(file instanceof File))
|
|
1155
1158
|
return null;
|
|
1156
|
-
if (typeof file === 'string')
|
|
1157
|
-
return file;
|
|
1158
1159
|
const { compressImage, targetCompressedImageFileSizeMb, minCompressionThresholdMb, maxWidthOrHeight, useWebWorker } = this.config;
|
|
1159
1160
|
const fileSizeMb = convertBytesToMb(file.size);
|
|
1160
|
-
const shouldCompress = compressImage
|
|
1161
|
+
const shouldCompress = compressImage
|
|
1162
|
+
&& targetCompressedImageFileSizeMb < fileSizeMb
|
|
1163
|
+
&& minCompressionThresholdMb < fileSizeMb;
|
|
1161
1164
|
if (shouldCompress) {
|
|
1162
1165
|
const options = {
|
|
1163
1166
|
// Use maxWidthOrHeight if it was provided, else use target compressed size
|
|
1164
1167
|
...(maxWidthOrHeight ? { maxWidthOrHeight } : { maxSizeMB: targetCompressedImageFileSizeMb }),
|
|
1165
1168
|
useWebWorker,
|
|
1166
1169
|
maxIterations: 30,
|
|
1167
|
-
onProgress: (
|
|
1168
|
-
this.progress =
|
|
1170
|
+
onProgress: (progress) => {
|
|
1171
|
+
this.progress = progress;
|
|
1169
1172
|
this.cdr.detectChanges();
|
|
1170
1173
|
}
|
|
1171
1174
|
};
|
|
1172
|
-
|
|
1173
|
-
return compressedFile;
|
|
1175
|
+
return await imageCompression(file, options);
|
|
1174
1176
|
}
|
|
1175
1177
|
else
|
|
1176
1178
|
return file;
|
|
1179
|
+
}), map((compressedFile) => {
|
|
1180
|
+
if (!compressedFile)
|
|
1181
|
+
return compressedFile;
|
|
1182
|
+
const { type, name, lastModified } = compressedFile;
|
|
1183
|
+
return new File([compressedFile], this.config.fileName || name, {
|
|
1184
|
+
type,
|
|
1185
|
+
lastModified
|
|
1186
|
+
});
|
|
1177
1187
|
}), tap(file => {
|
|
1178
|
-
|
|
1188
|
+
// only set the value if there is a file because resetToInitialValue sets the control value
|
|
1189
|
+
// to initial value and clears the compressed image, so setting it to null here would undo that
|
|
1190
|
+
if (file) {
|
|
1191
|
+
this.control.setValue(file);
|
|
1192
|
+
}
|
|
1179
1193
|
if (file || this.value) {
|
|
1180
1194
|
this.control.markAsTouched();
|
|
1181
1195
|
setTimeout(() => {
|
|
1182
1196
|
this.cdr.detectChanges();
|
|
1183
1197
|
}, 100);
|
|
1184
1198
|
}
|
|
1185
|
-
}),
|
|
1199
|
+
}), shareReplay(1));
|
|
1186
1200
|
this.compressedImageUrlString$ = this.compressedFile$.pipe(switchMap(async (file) => {
|
|
1187
1201
|
if (!file)
|
|
1188
1202
|
return null;
|
|
1189
1203
|
const compressedStringImage = await imageCompression.getDataUrlFromFile(file);
|
|
1190
|
-
return
|
|
1191
|
-
? this.domSanitizer.bypassSecurityTrustResourceUrl(compressedStringImage)
|
|
1192
|
-
: compressedStringImage;
|
|
1204
|
+
return this.domSanitizer.bypassSecurityTrustResourceUrl(compressedStringImage);
|
|
1193
1205
|
}), shareReplay(1));
|
|
1194
1206
|
this.isUploaded = false;
|
|
1195
1207
|
if (this.ngControl != null) {
|
|
@@ -1200,11 +1212,18 @@ class ImageUploadFieldComponent extends ImageUploadFieldMixin {
|
|
|
1200
1212
|
}
|
|
1201
1213
|
ngOnInit() {
|
|
1202
1214
|
super.ngOnInit();
|
|
1215
|
+
// this.inputValueUrl = this.value && this.config.mapInputValueToUrl?.(this.value) || this.value;
|
|
1203
1216
|
this.imageSrcUrl$ = combineLatest([
|
|
1204
1217
|
this.compressedImageUrlString$.pipe(startWith(null)),
|
|
1205
|
-
this.control.valueChanges.pipe(startWith(this.value))
|
|
1218
|
+
this.control.valueChanges.pipe(startWith(this.value), map((controlValue) => {
|
|
1219
|
+
if (!controlValue)
|
|
1220
|
+
return null;
|
|
1221
|
+
if (controlValue instanceof File)
|
|
1222
|
+
return null;
|
|
1223
|
+
return this.config.mapInputValueToUrl?.(controlValue) || controlValue;
|
|
1224
|
+
}))
|
|
1206
1225
|
]).pipe(map(([compressedImageUrlString, controlUrl]) => {
|
|
1207
|
-
return compressedImageUrlString ||
|
|
1226
|
+
return compressedImageUrlString || controlUrl || null;
|
|
1208
1227
|
}));
|
|
1209
1228
|
this.disabled$ = this.config.disabledCallback
|
|
1210
1229
|
? this.config.disabledCallback(this.group, this.config)
|
|
@@ -1213,6 +1232,10 @@ class ImageUploadFieldComponent extends ImageUploadFieldMixin {
|
|
|
1213
1232
|
filesChanged(files) {
|
|
1214
1233
|
if (files && files.length > 0) {
|
|
1215
1234
|
const imageFile = files[0];
|
|
1235
|
+
// We clear the control here so that it is invalid while compressing
|
|
1236
|
+
// the input pipeline will take care of resetting it
|
|
1237
|
+
this.control.patchValue(null);
|
|
1238
|
+
// this.control.setErrors({compressing: {loadingMessage: 'Please wait while file compresses'}});
|
|
1216
1239
|
this.control.markAsTouched();
|
|
1217
1240
|
this.inputImageFileSubject.next(imageFile);
|
|
1218
1241
|
}
|
|
@@ -1225,8 +1248,8 @@ class ImageUploadFieldComponent extends ImageUploadFieldMixin {
|
|
|
1225
1248
|
this.isUploaded = false;
|
|
1226
1249
|
}
|
|
1227
1250
|
resetToInitialValue(initialValue) {
|
|
1228
|
-
this.inputImageFileSubject.next(
|
|
1229
|
-
|
|
1251
|
+
this.inputImageFileSubject.next(null);
|
|
1252
|
+
this.control.patchValue(initialValue);
|
|
1230
1253
|
this.isUploaded = false;
|
|
1231
1254
|
}
|
|
1232
1255
|
writeValue(value) { }
|
|
@@ -1236,10 +1259,10 @@ class ImageUploadFieldComponent extends ImageUploadFieldMixin {
|
|
|
1236
1259
|
registerOnTouched(fn) { }
|
|
1237
1260
|
}
|
|
1238
1261
|
ImageUploadFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: ImageUploadFieldComponent, deps: [{ token: i4$1.NgControl, optional: true, self: true }, { token: i2$3.DomSanitizer }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
1239
|
-
ImageUploadFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: ImageUploadFieldComponent, selector: "crispr-image-upload-field", viewQueries: [{ propertyName: "fileInputRef", first: true, predicate: ["fileInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n\n <mat-form-field floatLabel=\"always\"\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 <crispr-selected-file\n *ngIf=\"(progress < 100) && inputImageFile$ | async as file; else dropzoneOrPreview\"\n [color]=\"config.color === 'primary' ? 'accent' : 'primary'\"\n [fileName]=\"'Compressing: ' + file.name\"\n [showProgress]=\"true\"\n [progress]=\"progress\">\n </crispr-selected-file>\n\n <ng-template #dropzoneOrPreview>\n <!-- <img *ngIf=\"(initialUrlString$ | async) as initialUrlString;\" [src]=\"initialUrlString\" alt=\"\"> -->\n <img *ngIf=\"imageSrcUrl$ | async as srcUrl; else noImage\" [src]=\"srcUrl\" alt=\"\">\n <ng-template #noImage>\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 </ng-template>\n\n </ng-template>\n </div>\n\n\n\n <!-- </ng-template> -->\n <div class=\"button-container\" *ngIf=\"true\">\n\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\n <button\n *ngIf=\"value\"\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 </div>\n\n </mat-form-field>\n\n</crispr-field-container>\n", styles: [":host ::ng-deep .mat-form-field .mat-form-field-infix{padding-top:0}:host ::ng-deep .mat-form-field .mat-button-wrapper{display:flex;flex-direction:column;align-items:center;padding-top:8px}:host .ui-container{display:flex;flex-direction:column}:host .ui-container .image-preview{display:flex;flex-direction:column;align-content:space-between;justify-content:center;align-items:center;margin:8px 0;flex-grow:1}:host .ui-container .image-preview crispr-selected-file{width:100%}:host .ui-container .image-preview .drop-container{display:flex;flex-direction:column;align-items:center;border:3px dashed gray;height:100%;width:100%;align-content:center;justify-content:center;border-radius:8px}:host .ui-container .image-preview .drop-container .drop-icon{height:32px;width:32px;font-size:36px}:host .ui-container .image-preview .drop-container .mat-h2{margin:0}:host .ui-container .image-preview img{height:inherit;max-width:100%}:host .ui-container .button-container{display:flex;flex-direction:var(--image-upload-button-container-direction);justify-content:flex-end}:host .ui-container .button-container button{margin-left:8px}:host input{position:absolute;max-height:0;visibility:hidden}\n"], components: [{ type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: SelectedFileComponent, selector: "crispr-selected-file", inputs: ["fileName", "progress", "showProgress", "color"] }, { type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i1.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i4$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { type: i2$1.MatLabel, selector: "mat-label" }, { type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i4$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i4$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i5.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: FileDropzoneDirective, selector: "[crisprFileDropzone]", inputs: ["crisprFileDropzone"], outputs: ["fileDrop"] }], pipes: { "async": i2.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
|
|
1262
|
+
ImageUploadFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: ImageUploadFieldComponent, selector: "crispr-image-upload-field", viewQueries: [{ propertyName: "fileInputRef", first: true, predicate: ["fileInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n\n <mat-form-field floatLabel=\"always\"\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 <crispr-selected-file\n *ngIf=\"(progress < 100) && inputImageFile$ | async as file; else dropzoneOrPreview\"\n [color]=\"config.color === 'primary' ? 'accent' : 'primary'\"\n [fileName]=\"'Compressing: ' + file.name\"\n [showProgress]=\"true\"\n [progress]=\"progress\">\n </crispr-selected-file>\n\n <ng-template #dropzoneOrPreview>\n <!-- <img *ngIf=\"(initialUrlString$ | async) as initialUrlString;\" [src]=\"initialUrlString\" alt=\"\"> -->\n <img *ngIf=\"imageSrcUrl$ | async as srcUrl; else noImage\" [src]=\"srcUrl\" alt=\"\">\n <ng-template #noImage>\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 </ng-template>\n\n </ng-template>\n </div>\n\n\n\n <!-- </ng-template> -->\n <div class=\"button-container\" *ngIf=\"true\">\n\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\n <button\n *ngIf=\"value\"\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 </div>\n\n </mat-form-field>\n\n</crispr-field-container>\n", styles: [":host ::ng-deep .mat-form-field .mat-form-field-infix{padding-top:0}:host ::ng-deep .mat-form-field .mat-button-wrapper{display:flex;flex-direction:column;align-items:center;padding-top:8px}:host .ui-container{display:flex;flex-direction:column}:host .ui-container .image-preview{display:flex;flex-direction:column;align-content:space-between;justify-content:center;align-items:center;margin:8px 0;flex-grow:1}:host .ui-container .image-preview crispr-selected-file{width:100%}:host .ui-container .image-preview .drop-container{display:flex;box-sizing:border-box;flex-direction:column;align-items:center;border:3px dashed gray;height:100%;width:100%;align-content:center;justify-content:center;border-radius:8px}:host .ui-container .image-preview .drop-container .drop-icon{height:32px;width:32px;font-size:36px}:host .ui-container .image-preview .drop-container .mat-h2{margin:0}:host .ui-container .image-preview img{height:inherit;max-width:100%}:host .ui-container .button-container{display:flex;flex-direction:var(--image-upload-button-container-direction);justify-content:flex-end}:host .ui-container .button-container button{margin-left:8px}:host input{position:absolute;max-height:0;visibility:hidden}\n"], components: [{ type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: SelectedFileComponent, selector: "crispr-selected-file", inputs: ["fileName", "progress", "showProgress", "color"] }, { type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i1.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i4$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { type: i2$1.MatLabel, selector: "mat-label" }, { type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i4$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i4$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i5.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: FileDropzoneDirective, selector: "[crisprFileDropzone]", inputs: ["crisprFileDropzone"], outputs: ["fileDrop"] }], pipes: { "async": i2.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
|
|
1240
1263
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: ImageUploadFieldComponent, decorators: [{
|
|
1241
1264
|
type: Component,
|
|
1242
|
-
args: [{ selector: 'crispr-image-upload-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n\n <mat-form-field floatLabel=\"always\"\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 <crispr-selected-file\n *ngIf=\"(progress < 100) && inputImageFile$ | async as file; else dropzoneOrPreview\"\n [color]=\"config.color === 'primary' ? 'accent' : 'primary'\"\n [fileName]=\"'Compressing: ' + file.name\"\n [showProgress]=\"true\"\n [progress]=\"progress\">\n </crispr-selected-file>\n\n <ng-template #dropzoneOrPreview>\n <!-- <img *ngIf=\"(initialUrlString$ | async) as initialUrlString;\" [src]=\"initialUrlString\" alt=\"\"> -->\n <img *ngIf=\"imageSrcUrl$ | async as srcUrl; else noImage\" [src]=\"srcUrl\" alt=\"\">\n <ng-template #noImage>\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 </ng-template>\n\n </ng-template>\n </div>\n\n\n\n <!-- </ng-template> -->\n <div class=\"button-container\" *ngIf=\"true\">\n\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\n <button\n *ngIf=\"value\"\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 </div>\n\n </mat-form-field>\n\n</crispr-field-container>\n", styles: [":host ::ng-deep .mat-form-field .mat-form-field-infix{padding-top:0}:host ::ng-deep .mat-form-field .mat-button-wrapper{display:flex;flex-direction:column;align-items:center;padding-top:8px}:host .ui-container{display:flex;flex-direction:column}:host .ui-container .image-preview{display:flex;flex-direction:column;align-content:space-between;justify-content:center;align-items:center;margin:8px 0;flex-grow:1}:host .ui-container .image-preview crispr-selected-file{width:100%}:host .ui-container .image-preview .drop-container{display:flex;flex-direction:column;align-items:center;border:3px dashed gray;height:100%;width:100%;align-content:center;justify-content:center;border-radius:8px}:host .ui-container .image-preview .drop-container .drop-icon{height:32px;width:32px;font-size:36px}:host .ui-container .image-preview .drop-container .mat-h2{margin:0}:host .ui-container .image-preview img{height:inherit;max-width:100%}:host .ui-container .button-container{display:flex;flex-direction:var(--image-upload-button-container-direction);justify-content:flex-end}:host .ui-container .button-container button{margin-left:8px}:host input{position:absolute;max-height:0;visibility:hidden}\n"] }]
|
|
1265
|
+
args: [{ selector: 'crispr-image-upload-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n\n <mat-form-field floatLabel=\"always\"\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 <crispr-selected-file\n *ngIf=\"(progress < 100) && inputImageFile$ | async as file; else dropzoneOrPreview\"\n [color]=\"config.color === 'primary' ? 'accent' : 'primary'\"\n [fileName]=\"'Compressing: ' + file.name\"\n [showProgress]=\"true\"\n [progress]=\"progress\">\n </crispr-selected-file>\n\n <ng-template #dropzoneOrPreview>\n <!-- <img *ngIf=\"(initialUrlString$ | async) as initialUrlString;\" [src]=\"initialUrlString\" alt=\"\"> -->\n <img *ngIf=\"imageSrcUrl$ | async as srcUrl; else noImage\" [src]=\"srcUrl\" alt=\"\">\n <ng-template #noImage>\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 </ng-template>\n\n </ng-template>\n </div>\n\n\n\n <!-- </ng-template> -->\n <div class=\"button-container\" *ngIf=\"true\">\n\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\n <button\n *ngIf=\"value\"\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 </div>\n\n </mat-form-field>\n\n</crispr-field-container>\n", styles: [":host ::ng-deep .mat-form-field .mat-form-field-infix{padding-top:0}:host ::ng-deep .mat-form-field .mat-button-wrapper{display:flex;flex-direction:column;align-items:center;padding-top:8px}:host .ui-container{display:flex;flex-direction:column}:host .ui-container .image-preview{display:flex;flex-direction:column;align-content:space-between;justify-content:center;align-items:center;margin:8px 0;flex-grow:1}:host .ui-container .image-preview crispr-selected-file{width:100%}:host .ui-container .image-preview .drop-container{display:flex;box-sizing:border-box;flex-direction:column;align-items:center;border:3px dashed gray;height:100%;width:100%;align-content:center;justify-content:center;border-radius:8px}:host .ui-container .image-preview .drop-container .drop-icon{height:32px;width:32px;font-size:36px}:host .ui-container .image-preview .drop-container .mat-h2{margin:0}:host .ui-container .image-preview img{height:inherit;max-width:100%}:host .ui-container .button-container{display:flex;flex-direction:var(--image-upload-button-container-direction);justify-content:flex-end}:host .ui-container .button-container button{margin-left:8px}:host input{position:absolute;max-height:0;visibility:hidden}\n"] }]
|
|
1243
1266
|
}], ctorParameters: function () { return [{ type: i4$1.NgControl, decorators: [{
|
|
1244
1267
|
type: Optional
|
|
1245
1268
|
}, {
|
|
@@ -1299,14 +1322,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImpor
|
|
|
1299
1322
|
function maxFileSizeValidator(maxFileSize) {
|
|
1300
1323
|
return (control) => {
|
|
1301
1324
|
const controlValue = control.value;
|
|
1302
|
-
if (!(controlValue instanceof
|
|
1325
|
+
if (!(controlValue instanceof File)) {
|
|
1303
1326
|
return null;
|
|
1327
|
+
}
|
|
1304
1328
|
const actualFileSize = +convertBytesToMb(controlValue.size).toPrecision(3);
|
|
1305
1329
|
if (maxFileSize > actualFileSize)
|
|
1306
1330
|
return null;
|
|
1307
|
-
control.setErrors({ maxFileSize: { maxFileSize, actualFileSize } });
|
|
1308
1331
|
return { maxFileSize: { maxFileSize, actualFileSize } };
|
|
1309
1332
|
};
|
|
1333
|
+
}
|
|
1334
|
+
function allowedFileExtValidator(allowedFileExtensions, onlyAllowFiles = true) {
|
|
1335
|
+
return (control) => {
|
|
1336
|
+
const controlValue = control.value;
|
|
1337
|
+
const isFile = controlValue instanceof File;
|
|
1338
|
+
if (!onlyAllowFiles && !isFile)
|
|
1339
|
+
return null;
|
|
1340
|
+
const actualExtension = isFile ? controlValue.name.split('.').pop().toLocaleLowerCase() : 'Not a file';
|
|
1341
|
+
const isAllowedExtension = allowedFileExtensions.includes(actualExtension);
|
|
1342
|
+
if (isAllowedExtension) {
|
|
1343
|
+
return null;
|
|
1344
|
+
}
|
|
1345
|
+
return { allowedExtension: { allowedFileExtensions, actualExtension } };
|
|
1346
|
+
};
|
|
1310
1347
|
}
|
|
1311
1348
|
|
|
1312
1349
|
// TODO: Should we import UI library?
|
|
@@ -1487,6 +1524,7 @@ var index$2 = /*#__PURE__*/Object.freeze({
|
|
|
1487
1524
|
ImageUploadFieldComponent: ImageUploadFieldComponent,
|
|
1488
1525
|
ImageUploadFieldModule: ImageUploadFieldModule,
|
|
1489
1526
|
maxFileSizeValidator: maxFileSizeValidator,
|
|
1527
|
+
allowedFileExtValidator: allowedFileExtValidator,
|
|
1490
1528
|
FileDropzoneDirective: FileDropzoneDirective,
|
|
1491
1529
|
FileUploadFieldComponent: FileUploadFieldComponent,
|
|
1492
1530
|
FileUploadFieldModule: FileUploadFieldModule,
|
|
@@ -1871,5 +1909,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImpor
|
|
|
1871
1909
|
* Generated bundle index. Do not edit.
|
|
1872
1910
|
*/
|
|
1873
1911
|
|
|
1874
|
-
export { AbstractAutocompleteComponent, AutocompleteChiplistFieldComponent, AutocompleteFieldComponent, ButtonComponent, CheckboxFieldComponent, ControlType, CrisprFieldComponent, CrisprFormComponent, CrisprFormsModule, DEFAULT_EMPTY_OPTIONS_MESSAGE, DatepickerFieldComponent, DividerComponent, FieldContainerComponent, FieldContainerModule, FileDropzoneDirective, FileUploadFieldComponent, FileUploadFieldModule, HeadingComponent, HeadingModule, ImageUploadFieldComponent, ImageUploadFieldModule, InputFieldComponent, MaterialModule, OptionComponent, RadioFieldComponent, SelectFieldComponent, SliderFieldComponent, TextareaFieldComponent, UnitConversionFieldComponent, buildFormGroupFromConfig, callOptionsIfFunction, checkControlForValues, checkControlsForValues, computeValueFromFields, createControlForType, crisprControlMixin, filterOptionsByLabel, isControlConfig, maxFileSizeValidator, observablifyOptions };
|
|
1912
|
+
export { AbstractAutocompleteComponent, AutocompleteChiplistFieldComponent, AutocompleteFieldComponent, ButtonComponent, CheckboxFieldComponent, ControlType, CrisprFieldComponent, CrisprFormComponent, CrisprFormsModule, DEFAULT_EMPTY_OPTIONS_MESSAGE, DatepickerFieldComponent, DividerComponent, FieldContainerComponent, FieldContainerModule, FileDropzoneDirective, FileUploadFieldComponent, FileUploadFieldModule, HeadingComponent, HeadingModule, ImageUploadFieldComponent, ImageUploadFieldModule, InputFieldComponent, MaterialModule, OptionComponent, RadioFieldComponent, SelectFieldComponent, SliderFieldComponent, TextareaFieldComponent, UnitConversionFieldComponent, allowedFileExtValidator, buildFormGroupFromConfig, callOptionsIfFunction, checkControlForValues, checkControlsForValues, computeValueFromFields, createControlForType, crisprControlMixin, filterOptionsByLabel, isControlConfig, maxFileSizeValidator, observablifyOptions };
|
|
1875
1913
|
//# sourceMappingURL=tft-crispr-forms.mjs.map
|