@tft/crispr-forms 21.0.18 → 21.1.0

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.
Files changed (39) hide show
  1. package/README.md +21 -4
  2. package/fesm2022/tft-crispr-forms.mjs +2071 -1
  3. package/fesm2022/tft-crispr-forms.mjs.map +1 -1
  4. package/package.json +7 -7
  5. package/types/tft-crispr-forms.d.ts +238 -212
  6. package/fesm2022/tft-crispr-forms-autocomplete-field.component-BgQZYqB0.mjs +0 -95
  7. package/fesm2022/tft-crispr-forms-autocomplete-field.component-BgQZYqB0.mjs.map +0 -1
  8. package/fesm2022/tft-crispr-forms-index-3aw152gK.mjs +0 -18
  9. package/fesm2022/tft-crispr-forms-index-3aw152gK.mjs.map +0 -1
  10. package/fesm2022/tft-crispr-forms-index-BFzx83fR.mjs +0 -39
  11. package/fesm2022/tft-crispr-forms-index-BFzx83fR.mjs.map +0 -1
  12. package/fesm2022/tft-crispr-forms-index-BMZQakFs.mjs +0 -88
  13. package/fesm2022/tft-crispr-forms-index-BMZQakFs.mjs.map +0 -1
  14. package/fesm2022/tft-crispr-forms-index-B_lhA83w.mjs +0 -2
  15. package/fesm2022/tft-crispr-forms-index-B_lhA83w.mjs.map +0 -1
  16. package/fesm2022/tft-crispr-forms-index-BawhjTMp.mjs +0 -183
  17. package/fesm2022/tft-crispr-forms-index-BawhjTMp.mjs.map +0 -1
  18. package/fesm2022/tft-crispr-forms-index-CXXD0vdZ.mjs +0 -172
  19. package/fesm2022/tft-crispr-forms-index-CXXD0vdZ.mjs.map +0 -1
  20. package/fesm2022/tft-crispr-forms-index-CmVahfkJ.mjs +0 -24
  21. package/fesm2022/tft-crispr-forms-index-CmVahfkJ.mjs.map +0 -1
  22. package/fesm2022/tft-crispr-forms-index-CoUwTugQ.mjs +0 -309
  23. package/fesm2022/tft-crispr-forms-index-CoUwTugQ.mjs.map +0 -1
  24. package/fesm2022/tft-crispr-forms-index-D99OHDPc.mjs +0 -40
  25. package/fesm2022/tft-crispr-forms-index-D99OHDPc.mjs.map +0 -1
  26. package/fesm2022/tft-crispr-forms-index-DYWkX7D3.mjs +0 -83
  27. package/fesm2022/tft-crispr-forms-index-DYWkX7D3.mjs.map +0 -1
  28. package/fesm2022/tft-crispr-forms-index-DysioRya.mjs +0 -39
  29. package/fesm2022/tft-crispr-forms-index-DysioRya.mjs.map +0 -1
  30. package/fesm2022/tft-crispr-forms-index-GlYQbbbv.mjs +0 -36
  31. package/fesm2022/tft-crispr-forms-index-GlYQbbbv.mjs.map +0 -1
  32. package/fesm2022/tft-crispr-forms-index-UX-Wdyk1.mjs +0 -40
  33. package/fesm2022/tft-crispr-forms-index-UX-Wdyk1.mjs.map +0 -1
  34. package/fesm2022/tft-crispr-forms-index-bTdYHJPk.mjs +0 -68
  35. package/fesm2022/tft-crispr-forms-index-bTdYHJPk.mjs.map +0 -1
  36. package/fesm2022/tft-crispr-forms-index-kah2HT_N.mjs +0 -54
  37. package/fesm2022/tft-crispr-forms-index-kah2HT_N.mjs.map +0 -1
  38. package/fesm2022/tft-crispr-forms-tft-crispr-forms-8liD7eof.mjs +0 -943
  39. package/fesm2022/tft-crispr-forms-tft-crispr-forms-8liD7eof.mjs.map +0 -1
@@ -1,309 +0,0 @@
1
- import * as i1$2 from '@angular/common';
2
- import { CommonModule } from '@angular/common';
3
- import * as i0 from '@angular/core';
4
- import { inject, ChangeDetectorRef, signal, untracked, ViewChild, ChangeDetectionStrategy, Component } from '@angular/core';
5
- import * as i1 from '@angular/forms';
6
- import { NgControl, ReactiveFormsModule } from '@angular/forms';
7
- import * as i1$1 from '@angular/material/button';
8
- import { MatButtonModule } from '@angular/material/button';
9
- import * as i2$1 from '@angular/material/form-field';
10
- import { MatFormFieldModule } from '@angular/material/form-field';
11
- import * as i2 from '@angular/material/icon';
12
- import { MatIconModule } from '@angular/material/icon';
13
- import * as i3 from '@angular/material/input';
14
- import { MatInputModule } from '@angular/material/input';
15
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
16
- import { DomSanitizer } from '@angular/platform-browser';
17
- import imageCompression from 'browser-image-compression';
18
- import { Subject, Observable, concat, of, from, combineLatest, defer } from 'rxjs';
19
- import { shareReplay, switchMap, tap, map, startWith } from 'rxjs/operators';
20
- import * as i6 from '@tft/form-validation-handler';
21
- import { FormValidationHandlerModule } from '@tft/form-validation-handler';
22
- import { a as CrisprControlComponent, e as convertBytesToMb, F as FieldContainerComponent, S as SelectedFileComponent, f as FileDropzoneDirective } from './tft-crispr-forms-tft-crispr-forms-8liD7eof.mjs';
23
-
24
- /* eslint-disable @nx/enforce-module-boundaries */
25
- class ImageUploadFieldComponent extends CrisprControlComponent {
26
- /** Compresses (when configured) and wraps a file. Never rejects, failures are returned. */
27
- async processFile(file, signal) {
28
- if (!file || !(file instanceof File))
29
- return { file: null };
30
- try {
31
- const { compressImage, targetCompressedImageFileSizeMb, minCompressionThresholdMb, maxWidthOrHeight, useWebWorker, } = this.config();
32
- const fileSizeMb = convertBytesToMb(file.size);
33
- const shouldCompress = compressImage &&
34
- targetCompressedImageFileSizeMb < fileSizeMb &&
35
- minCompressionThresholdMb < fileSizeMb;
36
- let processed = file;
37
- if (shouldCompress) {
38
- const options = {
39
- // Use maxWidthOrHeight if it was provided, else use target compressed size
40
- ...(maxWidthOrHeight
41
- ? { maxWidthOrHeight }
42
- : { maxSizeMB: targetCompressedImageFileSizeMb }),
43
- useWebWorker,
44
- maxIterations: 30,
45
- signal,
46
- onProgress: (progress) => {
47
- // ignore progress from a compression that a newer selection has superseded
48
- if (this.destroyed || this.latestFile !== file)
49
- return;
50
- this.progress.set(progress);
51
- },
52
- };
53
- processed = await imageCompression(file, options);
54
- }
55
- const { type, name, lastModified } = processed;
56
- return {
57
- file: new File([processed], this.config().fileName || name, {
58
- type,
59
- lastModified,
60
- }),
61
- };
62
- }
63
- catch {
64
- return { file: null, failed: file };
65
- }
66
- }
67
- async toImageUrl(file) {
68
- try {
69
- const compressedStringImage = await imageCompression.getDataUrlFromFile(file);
70
- return this.domSanitizer.bypassSecurityTrustResourceUrl(compressedStringImage);
71
- }
72
- catch {
73
- return null;
74
- }
75
- }
76
- constructor() {
77
- super();
78
- this.ngControl = inject(NgControl, { optional: true, self: true });
79
- this.domSanitizer = inject(DomSanitizer);
80
- this.cdr = inject(ChangeDetectorRef);
81
- this.defaultConfig = {
82
- // allowMultipleFiles: false,
83
- acceptedTypes: 'image/*',
84
- dropZoneText: 'DROP FILE HERE',
85
- selectFilesButtonType: 'button',
86
- selectButtonText: 'SELECT',
87
- showClearFilesButton: true,
88
- clearFilesButtonText: 'CLEAR',
89
- resetFilesButtonText: 'RESET',
90
- imagePreviewHeight: '250px',
91
- compressImage: false,
92
- targetCompressedImageFileSizeMb: 0.4,
93
- minCompressionThresholdMb: 0.6,
94
- useWebWorker: true,
95
- };
96
- this.inputImageFileSubject = new Subject();
97
- this.inputImageFile$ = this.inputImageFileSubject
98
- .asObservable()
99
- .pipe(shareReplay(1));
100
- /**
101
- * The compression progress (0-100), undefined when nothing is compressing
102
- */
103
- this.progress = signal(undefined, ...(ngDevMode ? [{ debugName: "progress" }] : []));
104
- /**
105
- * Whether the field is idle, processing (compressing) a selected image, or failed to process it.
106
- * While `processing` or `failed` the control is invalid.
107
- */
108
- this.processingState = signal('idle', ...(ngDevMode ? [{ debugName: "processingState" }] : []));
109
- /** The message describing why processing failed, null unless `processingState` is `failed` */
110
- this.failureMessage = signal(null, ...(ngDevMode ? [{ debugName: "failureMessage" }] : []));
111
- /** The name of the file currently being processed */
112
- this.processingFileName = signal('', ...(ngDevMode ? [{ debugName: "processingFileName" }] : []));
113
- /**
114
- * The most recently selected file (null once cleared/reset). Used to ignore progress
115
- * reports from compressions that were superseded by a newer selection.
116
- */
117
- this.latestFile = null;
118
- /** Set on destroy so that an in-flight compression can no longer touch the control or call back */
119
- this.destroyed = false;
120
- /**
121
- * Makes the control invalid while an image is processing or after processing failed.
122
- * Implemented as a validator because Angular clears manually set errors whenever
123
- * the control's validity is recalculated.
124
- */
125
- this.imageProcessingValidator = () =>
126
- // untracked: this runs inside effects (e.g. setControlValue) which must not depend on the state
127
- untracked(() => {
128
- switch (this.processingState()) {
129
- case 'processing':
130
- return { imageProcessing: true };
131
- case 'failed':
132
- return {
133
- imageProcessingFailed: {
134
- message: this.failureMessage() ||
135
- 'The image could not be processed. Please try a different image.',
136
- },
137
- };
138
- default:
139
- return null;
140
- }
141
- });
142
- /**
143
- * Compresses (when configured) and wraps each selected file. Failures are caught inside the
144
- * switchMap so that one bad file never errors out, and so kills, the stream.
145
- */
146
- this.compressedFile$ = this.inputImageFile$.pipe(
147
- // Each selection gets its own AbortController. switchMap unsubscribing (new selection, clear,
148
- // reset) runs the teardown below which aborts the superseded compression, and an aborted
149
- // compression never emits so it can not produce a `failed` state.
150
- switchMap((file) => new Observable((subscriber) => {
151
- const controller = new AbortController();
152
- let finished = false;
153
- this.processFile(file, controller.signal).then((result) => {
154
- if (controller.signal.aborted)
155
- return;
156
- finished = true;
157
- subscriber.next(result);
158
- subscriber.complete();
159
- });
160
- return () => {
161
- if (!finished)
162
- controller.abort();
163
- };
164
- })),
165
- // unsubscribing from the switchMap on destroy aborts any in-flight compression
166
- takeUntilDestroyed(),
167
- // switchMap has already discarded results of superseded selections, so state
168
- // transitions made here always belong to the latest selection
169
- tap(({ file, failed }) => {
170
- if (this.destroyed)
171
- return;
172
- const control = this.control();
173
- if (failed) {
174
- this.progress.set(undefined);
175
- this.setProcessingState('failed', `Unable to process "${failed.name}". Please try a different image.`, () => control.updateValueAndValidity());
176
- }
177
- else if (file) {
178
- this.progress.set(undefined);
179
- // only set the value if there is a file because resetToInitialValue sets the control value
180
- // to initial value and clears the compressed image, so setting it to null here would undo that
181
- this.setProcessingState('idle', null, () => control.setValue(file));
182
- this.config().filesChanged?.(this.group(), file);
183
- }
184
- if (file || this.value()) {
185
- control.markAsTouched();
186
- this.cdr.markForCheck();
187
- }
188
- }), map(({ file }) => file), shareReplay(1));
189
- this.compressedImageUrlString$ = this.compressedFile$.pipe(
190
- // null is emitted synchronously whenever a file starts (or no file is left) so that a
191
- // resubscribing template (shareReplay replays the latest value) can never see the url of a
192
- // previous file, or of one that has since been cleared or failed, while the new url is pending
193
- switchMap((file) => file ? concat(of(null), from(this.toImageUrl(file))) : of(null)), shareReplay(1));
194
- const ngControl = this.ngControl;
195
- if (this.ngControl != null) {
196
- // Setting the value accessor directly (instead of using
197
- // the providers) to avoid running into a circular import.
198
- ngControl.valueAccessor = this;
199
- }
200
- }
201
- ngOnInit() {
202
- super.ngOnInit();
203
- const control = this.control();
204
- control.addValidators(this.imageProcessingValidator);
205
- this.destroyRef.onDestroy(() => {
206
- this.destroyed = true;
207
- this.inputImageFileSubject.complete();
208
- control.removeValidators(this.imageProcessingValidator);
209
- // a destroyed field must not leave the form invalid because of a processing/failed state
210
- control.updateValueAndValidity();
211
- if (this.processingState() !== 'idle') {
212
- this.processingState.set('idle');
213
- this.failureMessage.set(null);
214
- this.config().processingStateChange?.('idle', this.group());
215
- }
216
- });
217
- this.imageSrcUrl$ = combineLatest([
218
- this.compressedImageUrlString$.pipe(startWith(null)),
219
- // defer: start with the control's value at subscribe time, the template resubscribes after
220
- // every processing phase and must not replay the value the control had at init
221
- defer(() => this.control().valueChanges.pipe(startWith(this.control().value), map((controlValue) => {
222
- if (!controlValue)
223
- return null;
224
- if (controlValue instanceof File)
225
- return null;
226
- return (this.config().mapInputValueToUrl?.(controlValue) ||
227
- controlValue);
228
- }))),
229
- ]).pipe(map(([compressedImageUrlString, controlUrl]) => {
230
- return compressedImageUrlString || controlUrl || null;
231
- }));
232
- this.disabled$ = this.config().disabledCallback
233
- ? this.config().disabledCallback(this.group())
234
- : of(false);
235
- }
236
- filesChanged(files) {
237
- if (files && files.length > 0) {
238
- const imageFile = files[0];
239
- this.latestFile = imageFile;
240
- this.progress.set(undefined);
241
- this.processingFileName.set(imageFile.name);
242
- // We clear the control here and flag the field as processing so that the control is invalid
243
- // while compressing, the input pipeline will take care of setting the processed value
244
- this.setProcessingState('processing', null, () => {
245
- this.control().patchValue(null);
246
- this.control().markAsTouched();
247
- });
248
- this.inputImageFileSubject.next(imageFile);
249
- }
250
- }
251
- clearFileInput() {
252
- this.latestFile = null;
253
- this.inputImageFileSubject.next(null);
254
- this.fileInputRef.nativeElement.value = '';
255
- this.progress.set(undefined);
256
- this.setProcessingState('idle', null, () => {
257
- this.control().patchValue(null);
258
- this.control().markAsTouched();
259
- });
260
- }
261
- resetToInitialValue(initialValue) {
262
- this.latestFile = null;
263
- this.inputImageFileSubject.next(null);
264
- this.progress.set(undefined);
265
- this.setProcessingState('idle', null, () => this.control().patchValue(initialValue));
266
- }
267
- /**
268
- * Transitions the processing state. `applyValue` updates the control (which revalidates it),
269
- * so validity is current before `processingStateChange` is called. The callback only fires
270
- * when the state actually changes.
271
- */
272
- setProcessingState(state, message, applyValue) {
273
- const changed = this.processingState() !== state || this.failureMessage() !== message;
274
- this.processingState.set(state);
275
- this.failureMessage.set(message);
276
- applyValue();
277
- if (changed) {
278
- this.config().processingStateChange?.(state, this.group());
279
- }
280
- }
281
- writeValue(value) { }
282
- registerOnChange(fn) {
283
- this.onChange = fn;
284
- }
285
- registerOnTouched(fn) { }
286
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ImageUploadFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
287
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: ImageUploadFieldComponent, isStandalone: true, 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 [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 (processingState() === 'processing') {\n <crispr-selected-file\n data-testid=\"image-processing\"\n [color]=\"config().color === 'primary' ? 'accent' : 'primary'\"\n [fileName]=\"(config().compressImage ? 'Compressing: ' : 'Processing: ') + processingFileName()\"\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 @if (processingState() === 'failed') {\n <p class=\"processing-failed mat-body-2\" role=\"alert\" data-testid=\"image-processing-failed\">\n <mat-icon inline=\"true\">error</mat-icon>\n {{failureMessage()}}\n </p>\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", styles: [":host ::ng-deep .mat-mdc-form-field .mat-mdc-form-field-infix{padding-top:0}:host ::ng-deep .mat-mdc-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 .processing-failed{display:flex;align-items:center;gap:4px;margin:8px 0 0;color:var(--mat-sys-error, #b3261e)}: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"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: SelectedFileComponent, selector: "crispr-selected-file", inputs: ["fileName", "progress", "showProgress", "color"] }, { kind: "directive", type: FileDropzoneDirective, selector: "[crisprFileDropzone]", inputs: ["crisprFileDropzone"], outputs: ["fileDrop"] }, { kind: "ngmodule", type: FormValidationHandlerModule }, { kind: "directive", type: i6.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { kind: "directive", type: i6.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { kind: "pipe", type: i1$2.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true }); }
288
- }
289
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: ImageUploadFieldComponent, decorators: [{
290
- type: Component,
291
- args: [{ selector: 'crispr-image-upload-field', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
292
- CommonModule,
293
- FieldContainerComponent,
294
- ReactiveFormsModule,
295
- MatIconModule,
296
- MatButtonModule,
297
- MatFormFieldModule,
298
- MatInputModule,
299
- SelectedFileComponent,
300
- FileDropzoneDirective,
301
- FormValidationHandlerModule,
302
- ], standalone: true, template: "<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 (processingState() === 'processing') {\n <crispr-selected-file\n data-testid=\"image-processing\"\n [color]=\"config().color === 'primary' ? 'accent' : 'primary'\"\n [fileName]=\"(config().compressImage ? 'Compressing: ' : 'Processing: ') + processingFileName()\"\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 @if (processingState() === 'failed') {\n <p class=\"processing-failed mat-body-2\" role=\"alert\" data-testid=\"image-processing-failed\">\n <mat-icon inline=\"true\">error</mat-icon>\n {{failureMessage()}}\n </p>\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", styles: [":host ::ng-deep .mat-mdc-form-field .mat-mdc-form-field-infix{padding-top:0}:host ::ng-deep .mat-mdc-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 .processing-failed{display:flex;align-items:center;gap:4px;margin:8px 0 0;color:var(--mat-sys-error, #b3261e)}: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"] }]
303
- }], ctorParameters: () => [], propDecorators: { fileInputRef: [{
304
- type: ViewChild,
305
- args: ['fileInput']
306
- }] } });
307
-
308
- export { ImageUploadFieldComponent };
309
- //# sourceMappingURL=tft-crispr-forms-index-CoUwTugQ.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tft-crispr-forms-index-CoUwTugQ.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, signal, untracked, ViewChild } from '@angular/core';\nimport {\n ControlValueAccessor,\n NgControl,\n ReactiveFormsModule,\n ValidationErrors,\n ValidatorFn,\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 { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { DomSanitizer } from '@angular/platform-browser';\nimport imageCompression from 'browser-image-compression';\nimport { combineLatest, concat, defer, from, 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 ImageProcessingState,\n ImageUploadFieldConfig,\n} from '../../utils';\nimport { CrisprControlComponent } from '../../utils/abstracts/crispr-control.abstract';\n\n/** The outcome of processing one selected file */\ninterface ProcessedImage {\n /** The processed file, null when there is no file or processing failed */\n file: File | null;\n /** The selected file that could not be processed */\n failed?: File;\n}\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 /**\n * The compression progress (0-100), undefined when nothing is compressing\n */\n progress = signal<number | undefined>(undefined);\n\n /**\n * Whether the field is idle, processing (compressing) a selected image, or failed to process it.\n * While `processing` or `failed` the control is invalid.\n */\n processingState = signal<ImageProcessingState>('idle');\n\n /** The message describing why processing failed, null unless `processingState` is `failed` */\n failureMessage = signal<string | null>(null);\n\n /** The name of the file currently being processed */\n processingFileName = signal<string>('');\n\n /**\n * The most recently selected file (null once cleared/reset). Used to ignore progress\n * reports from compressions that were superseded by a newer selection.\n */\n private latestFile: File | null = null;\n\n /** Set on destroy so that an in-flight compression can no longer touch the control or call back */\n private destroyed = false;\n\n /**\n * Makes the control invalid while an image is processing or after processing failed.\n * Implemented as a validator because Angular clears manually set errors whenever\n * the control's validity is recalculated.\n */\n private imageProcessingValidator: ValidatorFn = (): ValidationErrors | null =>\n // untracked: this runs inside effects (e.g. setControlValue) which must not depend on the state\n untracked(() => {\n switch (this.processingState()) {\n case 'processing':\n return { imageProcessing: true };\n case 'failed':\n return {\n imageProcessingFailed: {\n message:\n this.failureMessage() ||\n 'The image could not be processed. Please try a different image.',\n },\n };\n default:\n return null;\n }\n });\n\n /**\n * Compresses (when configured) and wraps each selected file. Failures are caught inside the\n * switchMap so that one bad file never errors out, and so kills, the stream.\n */\n compressedFile$: Observable<File | null> = this.inputImageFile$.pipe(\n // Each selection gets its own AbortController. switchMap unsubscribing (new selection, clear,\n // reset) runs the teardown below which aborts the superseded compression, and an aborted\n // compression never emits so it can not produce a `failed` state.\n switchMap((file) =>\n new Observable<ProcessedImage>((subscriber) => {\n const controller = new AbortController();\n let finished = false;\n this.processFile(file, controller.signal).then((result) => {\n if (controller.signal.aborted) return;\n finished = true;\n subscriber.next(result);\n subscriber.complete();\n });\n return () => {\n if (!finished) controller.abort();\n };\n })\n ),\n // unsubscribing from the switchMap on destroy aborts any in-flight compression\n takeUntilDestroyed(),\n // switchMap has already discarded results of superseded selections, so state\n // transitions made here always belong to the latest selection\n tap(({ file, failed }) => {\n if (this.destroyed) return;\n const control = this.control();\n if (failed) {\n this.progress.set(undefined);\n this.setProcessingState(\n 'failed',\n `Unable to process \"${failed.name}\". Please try a different image.`,\n () => control.updateValueAndValidity()\n );\n } else if (file) {\n this.progress.set(undefined);\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 this.setProcessingState('idle', null, () => control.setValue(file));\n this.config().filesChanged?.(this.group(), file);\n }\n if (file || this.value()) {\n control.markAsTouched();\n this.cdr.markForCheck();\n }\n }),\n map(({ file }) => file),\n shareReplay(1)\n );\n\n compressedImageUrlString$: Observable<string | null> =\n this.compressedFile$.pipe(\n // null is emitted synchronously whenever a file starts (or no file is left) so that a\n // resubscribing template (shareReplay replays the latest value) can never see the url of a\n // previous file, or of one that has since been cleared or failed, while the new url is pending\n switchMap((file) =>\n file ? concat(of(null), from(this.toImageUrl(file))) : of(null)\n ),\n shareReplay(1)\n );\n\n /** Compresses (when configured) and wraps a file. Never rejects, failures are returned. */\n private async processFile(\n file: File | null,\n signal: AbortSignal\n ): Promise<ProcessedImage> {\n if (!file || !(file instanceof File)) return { file: null };\n try {\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 let processed: File = file;\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 signal,\n onProgress: (progress: number) => {\n // ignore progress from a compression that a newer selection has superseded\n if (this.destroyed || this.latestFile !== file) return;\n this.progress.set(progress);\n },\n };\n processed = await imageCompression(file, options);\n }\n const { type, name, lastModified } = processed;\n return {\n file: new File([processed], this.config().fileName || name, {\n type,\n lastModified,\n }),\n };\n } catch {\n return { file: null, failed: file };\n }\n }\n\n private async toImageUrl(file: File): Promise<string | null> {\n try {\n const compressedStringImage = await imageCompression.getDataUrlFromFile(\n file\n );\n return this.domSanitizer.bypassSecurityTrustResourceUrl(\n compressedStringImage\n ) as string;\n } catch {\n return null;\n }\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 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 const control = this.control();\n control.addValidators(this.imageProcessingValidator);\n this.destroyRef.onDestroy(() => {\n this.destroyed = true;\n this.inputImageFileSubject.complete();\n control.removeValidators(this.imageProcessingValidator);\n // a destroyed field must not leave the form invalid because of a processing/failed state\n control.updateValueAndValidity();\n if (this.processingState() !== 'idle') {\n this.processingState.set('idle');\n this.failureMessage.set(null);\n this.config().processingStateChange?.('idle', this.group());\n }\n });\n this.imageSrcUrl$ = combineLatest([\n this.compressedImageUrlString$.pipe(startWith(null)),\n // defer: start with the control's value at subscribe time, the template resubscribes after\n // every processing phase and must not replay the value the control had at init\n defer(() => this.control().valueChanges.pipe(\n startWith(this.control().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 this.latestFile = imageFile;\n this.progress.set(undefined);\n this.processingFileName.set(imageFile.name);\n // We clear the control here and flag the field as processing so that the control is invalid\n // while compressing, the input pipeline will take care of setting the processed value\n this.setProcessingState('processing', null, () => {\n this.control().patchValue(null);\n this.control().markAsTouched();\n });\n this.inputImageFileSubject.next(imageFile);\n }\n }\n\n clearFileInput(): void {\n this.latestFile = null;\n this.inputImageFileSubject.next(null);\n this.fileInputRef.nativeElement.value = '';\n this.progress.set(undefined);\n this.setProcessingState('idle', null, () => {\n this.control().patchValue(null);\n this.control().markAsTouched();\n });\n }\n\n resetToInitialValue(initialValue: string): void {\n this.latestFile = null;\n this.inputImageFileSubject.next(null);\n this.progress.set(undefined);\n this.setProcessingState('idle', null, () =>\n this.control().patchValue(initialValue)\n );\n }\n\n /**\n * Transitions the processing state. `applyValue` updates the control (which revalidates it),\n * so validity is current before `processingStateChange` is called. The callback only fires\n * when the state actually changes.\n */\n private setProcessingState(\n state: ImageProcessingState,\n message: string | null,\n applyValue: () => void\n ): void {\n const changed =\n this.processingState() !== state || this.failureMessage() !== message;\n this.processingState.set(state);\n this.failureMessage.set(message);\n applyValue();\n if (changed) {\n this.config().processingStateChange?.(state, this.group());\n }\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 (processingState() === 'processing') {\n <crispr-selected-file\n data-testid=\"image-processing\"\n [color]=\"config().color === 'primary' ? 'accent' : 'primary'\"\n [fileName]=\"(config().compressImage ? 'Compressing: ' : 'Processing: ') + processingFileName()\"\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 @if (processingState() === 'failed') {\n <p class=\"processing-failed mat-body-2\" role=\"alert\" data-testid=\"image-processing-failed\">\n <mat-icon inline=\"true\">error</mat-icon>\n {{failureMessage()}}\n </p>\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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"}
@@ -1,40 +0,0 @@
1
- import * as i0 from '@angular/core';
2
- import { ChangeDetectionStrategy, Component } from '@angular/core';
3
- import * as i2 from '@angular/material/radio';
4
- import { MatRadioModule } from '@angular/material/radio';
5
- import * as i1 from '@angular/forms';
6
- import { ReactiveFormsModule } from '@angular/forms';
7
- import * as i1$1 from '@angular/common';
8
- import { CommonModule } from '@angular/common';
9
- import * as i6 from '@tft/form-validation-handler';
10
- import { FormValidationHandlerModule } from '@tft/form-validation-handler';
11
- import { a as CrisprControlComponent, o as observablifyOptions, F as FieldContainerComponent } from './tft-crispr-forms-tft-crispr-forms-8liD7eof.mjs';
12
-
13
- /* eslint-disable @nx/enforce-module-boundaries */
14
- class RadioFieldComponent extends CrisprControlComponent {
15
- constructor() {
16
- super(...arguments);
17
- this.defaultConfig = {};
18
- }
19
- ngOnInit() {
20
- super.ngOnInit();
21
- // options$ can be passed as an array, promise that resolves array, or observable that resolves array
22
- // this functions accounts for all possibilities and converts to observable that resolves array
23
- this.options$ = observablifyOptions(this.config().options, this.group());
24
- }
25
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: RadioFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
26
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: RadioFieldComponent, isStandalone: true, selector: "crispr-radio-field", usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config()\"\n [group]=\"group()\">\n\n <mat-radio-group\n [attr.data-testid]=\"testId()\"\n [formControl]=\"control()\"\n [color]=\"config().color\">\n @for (option of options$ | async; track option) {\n <mat-radio-button class=\"example-radio-button\" [value]=\"option.value\">\n {{option.label}}\n </mat-radio-button>\n }\n </mat-radio-group>\n</crispr-field-container>\n", styles: ["mat-radio-button{padding:12px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "directive", type: i2.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i2.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "ngmodule", type: FormValidationHandlerModule }, { kind: "directive", type: i6.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true }); }
27
- }
28
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: RadioFieldComponent, decorators: [{
29
- type: Component,
30
- args: [{ selector: 'crispr-radio-field', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
31
- CommonModule,
32
- ReactiveFormsModule,
33
- FieldContainerComponent,
34
- MatRadioModule,
35
- FormValidationHandlerModule,
36
- ], standalone: true, template: "<crispr-field-container\n [config]=\"config()\"\n [group]=\"group()\">\n\n <mat-radio-group\n [attr.data-testid]=\"testId()\"\n [formControl]=\"control()\"\n [color]=\"config().color\">\n @for (option of options$ | async; track option) {\n <mat-radio-button class=\"example-radio-button\" [value]=\"option.value\">\n {{option.label}}\n </mat-radio-button>\n }\n </mat-radio-group>\n</crispr-field-container>\n", styles: ["mat-radio-button{padding:12px}\n"] }]
37
- }] });
38
-
39
- export { RadioFieldComponent };
40
- //# sourceMappingURL=tft-crispr-forms-index-D99OHDPc.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tft-crispr-forms-index-D99OHDPc.mjs","sources":["../../../../libs/crispr-forms/src/lib/ui/radio-field/radio-field.component.ts","../../../../libs/crispr-forms/src/lib/ui/radio-field/radio-field.component.html"],"sourcesContent":["/* eslint-disable @nx/enforce-module-boundaries */\nimport { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';\nimport { Observable } from 'rxjs';\n\nimport { MatRadioModule } from '@angular/material/radio';\nimport { ReactiveFormsModule } from '@angular/forms';\nimport { CommonModule } from '@angular/common';\nimport { FormValidationHandlerModule } from '@tft/form-validation-handler';\nimport { FieldContainerComponent } from '../field-container';\nimport { RadioFieldConfig, SelectOption, observablifyOptions } from '../../utils';\nimport { CrisprControlComponent } from '../../utils/abstracts/crispr-control.abstract';\n\n@Component({\n selector: 'crispr-radio-field',\n templateUrl: './radio-field.component.html',\n styleUrls: ['./radio-field.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n CommonModule,\n ReactiveFormsModule,\n FieldContainerComponent,\n MatRadioModule,\n FormValidationHandlerModule,\n ],\n standalone: true\n})\nexport class RadioFieldComponent extends CrisprControlComponent<RadioFieldConfig> implements OnInit {\n defaultConfig = {};\n options$: Observable<SelectOption[]>;\n ngOnInit() {\n super.ngOnInit();\n // options$ can be passed as an array, promise that resolves array, or observable that resolves array\n // this functions accounts for all possibilities and converts to observable that resolves array\n this.options$ = observablifyOptions(this.config().options, this.group());\n }\n}\n","<crispr-field-container\n [config]=\"config()\"\n [group]=\"group()\">\n\n <mat-radio-group\n [attr.data-testid]=\"testId()\"\n [formControl]=\"control()\"\n [color]=\"config().color\">\n @for (option of options$ | async; track option) {\n <mat-radio-button class=\"example-radio-button\" [value]=\"option.value\">\n {{option.label}}\n </mat-radio-button>\n }\n </mat-radio-group>\n</crispr-field-container>\n"],"names":["i3","i4"],"mappings":"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"}
@@ -1,83 +0,0 @@
1
- import * as i0 from '@angular/core';
2
- import { ViewChild, ChangeDetectionStrategy, Component } from '@angular/core';
3
- import { tap } from 'rxjs/operators';
4
- import * as i3 from '@angular/material/select';
5
- import { MatSelectModule } from '@angular/material/select';
6
- import * as i1$2 from '@angular/common';
7
- import { CommonModule } from '@angular/common';
8
- import * as i1 from '@angular/material/checkbox';
9
- import { MatCheckboxModule } from '@angular/material/checkbox';
10
- import * as i1$1 from '@angular/forms';
11
- import { ReactiveFormsModule } from '@angular/forms';
12
- import * as i2 from '@angular/material/form-field';
13
- import { MatFormFieldModule } from '@angular/material/form-field';
14
- import { O as OptionComponent } from './tft-crispr-forms-index-3aw152gK.mjs';
15
- import * as i6 from '@tft/form-validation-handler';
16
- import { FormValidationHandlerModule } from '@tft/form-validation-handler';
17
- import { a as CrisprControlComponent, o as observablifyOptions, I as InfoComponent, F as FieldContainerComponent } from './tft-crispr-forms-tft-crispr-forms-8liD7eof.mjs';
18
- import * as i2$1 from '@angular/material/autocomplete';
19
-
20
- /* eslint-disable @nx/enforce-module-boundaries */
21
- class SelectFieldComponent extends CrisprControlComponent {
22
- constructor() {
23
- super(...arguments);
24
- this.defaultConfig = {
25
- enableToggleAll: false,
26
- color: 'primary',
27
- };
28
- this.allSelected = false;
29
- }
30
- ngOnInit() {
31
- super.ngOnInit();
32
- // options$ can be passed as an array, promise that resolves array, or observable that resolves array
33
- // this functions accounts for all possibilities and converts to observable that resolves array
34
- this.options$ = observablifyOptions(this.config().options, this.group()).pipe(tap(() => {
35
- // mat-select.writeValue() runs before async options render, so _setSelectionByValue
36
- // finds no matches. Re-apply the value after options are in the DOM.
37
- setTimeout(() => {
38
- const ctrl = this.control();
39
- if (ctrl?.value != null) {
40
- ctrl.setValue(ctrl.value, { emitEvent: false });
41
- }
42
- });
43
- }));
44
- }
45
- ngAfterViewInit() {
46
- if (this.config().multiple &&
47
- this.config().enableToggleAll &&
48
- this.selectField.options?.length === this.value()?.length) {
49
- this.allSelected = true;
50
- }
51
- }
52
- toggleAll(isSelected) {
53
- if (isSelected) {
54
- this.selectField.options.forEach((option) => option.deselect());
55
- }
56
- else {
57
- this.selectField.options.forEach((option) => option.select());
58
- }
59
- this.allSelected = !this.allSelected;
60
- }
61
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: SelectFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
62
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: SelectFieldComponent, isStandalone: true, selector: "crispr-select-field", viewQueries: [{ propertyName: "selectField", first: true, predicate: ["selectField"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config()\"\n [group]=\"group()\">\n\n <mat-form-field\n [attr.data-testid]=\"testId()\"\n [color]=\"config().color\"\n [appearance]=\"config().appearance\"\n [formGroup]=\"group()\">\n @if (config().label) {<mat-label>{{config().label}}</mat-label>}\n <mat-select\n #selectField\n [formControlName]=\"config().controlName\"\n [placeholder]=\"config().placeholder\"\n [multiple]=\"config().multiple\">\n\n @if (config()?.multiple && config().enableToggleAll) {\n <mat-checkbox\n [color]=\"config().color\"\n [checked]=\"allSelected\"\n (click)=\"toggleAll(allSelected)\">\n Select All\n </mat-checkbox>\n }\n @for (option of options$ | async; track option) {\n <mat-option\n [value]=\"option.value\">\n <crispr-option [option]=\"option\">\n </crispr-option>\n </mat-option>\n }\n\n </mat-select>\n\n @if (config().fieldSuffix) {<span matSuffix>{{config().fieldSuffix}}</span>}\n @if (config().info) {<crispr-info matSuffix [info]=\"config().info\"></crispr-info>}\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", styles: ["mat-checkbox{display:block;padding:16px}crispr-info[matSuffix]{margin-right:.75em}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: InfoComponent, selector: "crispr-info", inputs: ["info"] }, { kind: "component", type: OptionComponent, selector: "crispr-option", inputs: ["option"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i2.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: i3.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i2$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: FormValidationHandlerModule }, { kind: "directive", type: i6.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { kind: "directive", type: i6.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { kind: "component", type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "pipe", type: i1$2.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true }); }
63
- }
64
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: SelectFieldComponent, decorators: [{
65
- type: Component,
66
- args: [{ selector: 'crispr-select-field', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
67
- CommonModule,
68
- InfoComponent,
69
- OptionComponent,
70
- MatCheckboxModule,
71
- MatSelectModule,
72
- ReactiveFormsModule,
73
- FormValidationHandlerModule,
74
- FieldContainerComponent,
75
- MatFormFieldModule,
76
- ], standalone: true, template: "<crispr-field-container\n [config]=\"config()\"\n [group]=\"group()\">\n\n <mat-form-field\n [attr.data-testid]=\"testId()\"\n [color]=\"config().color\"\n [appearance]=\"config().appearance\"\n [formGroup]=\"group()\">\n @if (config().label) {<mat-label>{{config().label}}</mat-label>}\n <mat-select\n #selectField\n [formControlName]=\"config().controlName\"\n [placeholder]=\"config().placeholder\"\n [multiple]=\"config().multiple\">\n\n @if (config()?.multiple && config().enableToggleAll) {\n <mat-checkbox\n [color]=\"config().color\"\n [checked]=\"allSelected\"\n (click)=\"toggleAll(allSelected)\">\n Select All\n </mat-checkbox>\n }\n @for (option of options$ | async; track option) {\n <mat-option\n [value]=\"option.value\">\n <crispr-option [option]=\"option\">\n </crispr-option>\n </mat-option>\n }\n\n </mat-select>\n\n @if (config().fieldSuffix) {<span matSuffix>{{config().fieldSuffix}}</span>}\n @if (config().info) {<crispr-info matSuffix [info]=\"config().info\"></crispr-info>}\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", styles: ["mat-checkbox{display:block;padding:16px}crispr-info[matSuffix]{margin-right:.75em}\n"] }]
77
- }], propDecorators: { selectField: [{
78
- type: ViewChild,
79
- args: ['selectField']
80
- }] } });
81
-
82
- export { SelectFieldComponent };
83
- //# sourceMappingURL=tft-crispr-forms-index-DYWkX7D3.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tft-crispr-forms-index-DYWkX7D3.mjs","sources":["../../../../libs/crispr-forms/src/lib/ui/select-field/select-field.component.ts","../../../../libs/crispr-forms/src/lib/ui/select-field/select-field.component.html"],"sourcesContent":["/* eslint-disable @nx/enforce-module-boundaries */\nimport {\n Component,\n OnInit,\n ChangeDetectionStrategy,\n ViewChild,\n AfterViewInit,\n} from '@angular/core';\nimport { Observable } from 'rxjs';\nimport { tap } from 'rxjs/operators';\n\nimport { MatSelect, MatSelectModule } from '@angular/material/select';\nimport { ThemePalette } from '@angular/material/core';\nimport { CommonModule } from '@angular/common';\nimport { MatCheckboxModule } from '@angular/material/checkbox';\nimport { ReactiveFormsModule } from '@angular/forms';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { OptionComponent } from '../option';\nimport { FormValidationHandlerModule } from '@tft/form-validation-handler';\nimport { InfoComponent } from '../info';\nimport { FieldContainerComponent } from '../field-container';\nimport {\n observablifyOptions,\n SelectFieldConfig,\n SelectOption,\n} from '../../utils';\nimport { CrisprControlComponent } from '../../utils/abstracts/crispr-control.abstract';\n\n@Component({\n selector: 'crispr-select-field',\n templateUrl: './select-field.component.html',\n styleUrls: ['./select-field.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n CommonModule,\n InfoComponent,\n OptionComponent,\n MatCheckboxModule,\n MatSelectModule,\n ReactiveFormsModule,\n FormValidationHandlerModule,\n FieldContainerComponent,\n MatFormFieldModule,\n ],\n standalone: true\n})\nexport class SelectFieldComponent\n extends CrisprControlComponent<SelectFieldConfig>\n implements OnInit, AfterViewInit\n{\n defaultConfig = {\n enableToggleAll: false,\n color: 'primary' as ThemePalette,\n };\n options$: Observable<SelectOption[]>;\n allSelected = false;\n\n @ViewChild('selectField') selectField: MatSelect;\n\n ngOnInit() {\n super.ngOnInit();\n // options$ can be passed as an array, promise that resolves array, or observable that resolves array\n // this functions accounts for all possibilities and converts to observable that resolves array\n this.options$ = observablifyOptions(this.config().options, this.group()).pipe(\n tap(() => {\n // mat-select.writeValue() runs before async options render, so _setSelectionByValue\n // finds no matches. Re-apply the value after options are in the DOM.\n setTimeout(() => {\n const ctrl = this.control();\n if (ctrl?.value != null) {\n ctrl.setValue(ctrl.value, { emitEvent: false });\n }\n });\n })\n );\n }\n\n ngAfterViewInit() {\n if (\n this.config().multiple &&\n this.config().enableToggleAll &&\n this.selectField.options?.length === (this.value() as any[])?.length\n ) {\n this.allSelected = true;\n }\n }\n\n toggleAll(isSelected: boolean) {\n if (isSelected) {\n this.selectField.options.forEach((option) => option.deselect());\n } else {\n this.selectField.options.forEach((option) => option.select());\n }\n this.allSelected = !this.allSelected;\n }\n}\n","<crispr-field-container\n [config]=\"config()\"\n [group]=\"group()\">\n\n <mat-form-field\n [attr.data-testid]=\"testId()\"\n [color]=\"config().color\"\n [appearance]=\"config().appearance\"\n [formGroup]=\"group()\">\n @if (config().label) {<mat-label>{{config().label}}</mat-label>}\n <mat-select\n #selectField\n [formControlName]=\"config().controlName\"\n [placeholder]=\"config().placeholder\"\n [multiple]=\"config().multiple\">\n\n @if (config()?.multiple && config().enableToggleAll) {\n <mat-checkbox\n [color]=\"config().color\"\n [checked]=\"allSelected\"\n (click)=\"toggleAll(allSelected)\">\n Select All\n </mat-checkbox>\n }\n @for (option of options$ | async; track option) {\n <mat-option\n [value]=\"option.value\">\n <crispr-option [option]=\"option\">\n </crispr-option>\n </mat-option>\n }\n\n </mat-select>\n\n @if (config().fieldSuffix) {<span matSuffix>{{config().fieldSuffix}}</span>}\n @if (config().info) {<crispr-info matSuffix [info]=\"config().info\"></crispr-info>}\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":["i5","i7"],"mappings":"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"}