@tft/crispr-forms 21.0.4 → 21.0.6

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 (43) hide show
  1. package/fesm2022/{tft-crispr-forms-autocomplete-field.component-CpEWI7bT.mjs → tft-crispr-forms-autocomplete-field.component-BrFPYj9i.mjs} +3 -3
  2. package/fesm2022/{tft-crispr-forms-autocomplete-field.component-CpEWI7bT.mjs.map → tft-crispr-forms-autocomplete-field.component-BrFPYj9i.mjs.map} +1 -1
  3. package/fesm2022/{tft-crispr-forms-index-usD7jUs3.mjs → tft-crispr-forms-index-1oUkFYPd.mjs} +2 -2
  4. package/fesm2022/{tft-crispr-forms-index-usD7jUs3.mjs.map → tft-crispr-forms-index-1oUkFYPd.mjs.map} +1 -1
  5. package/fesm2022/{tft-crispr-forms-index-DuvnSHLl.mjs → tft-crispr-forms-index-B9tVg0fe.mjs} +2 -2
  6. package/fesm2022/{tft-crispr-forms-index-DuvnSHLl.mjs.map → tft-crispr-forms-index-B9tVg0fe.mjs.map} +1 -1
  7. package/fesm2022/{tft-crispr-forms-index-CLJ89Dev.mjs → tft-crispr-forms-index-BNGj_Q31.mjs} +3 -3
  8. package/fesm2022/{tft-crispr-forms-index-CLJ89Dev.mjs.map → tft-crispr-forms-index-BNGj_Q31.mjs.map} +1 -1
  9. package/fesm2022/{tft-crispr-forms-index-DvrD-Lli.mjs → tft-crispr-forms-index-BVUDqeAd.mjs} +10 -18
  10. package/fesm2022/tft-crispr-forms-index-BVUDqeAd.mjs.map +1 -0
  11. package/fesm2022/{tft-crispr-forms-index-DOpDpDdt.mjs → tft-crispr-forms-index-BYfudl7n.mjs} +2 -2
  12. package/fesm2022/{tft-crispr-forms-index-DOpDpDdt.mjs.map → tft-crispr-forms-index-BYfudl7n.mjs.map} +1 -1
  13. package/fesm2022/{tft-crispr-forms-index-D6cKptyg.mjs → tft-crispr-forms-index-By2zsul9.mjs} +2 -2
  14. package/fesm2022/{tft-crispr-forms-index-D6cKptyg.mjs.map → tft-crispr-forms-index-By2zsul9.mjs.map} +1 -1
  15. package/fesm2022/{tft-crispr-forms-index-DAx6Am4i.mjs → tft-crispr-forms-index-CLSsoEGa.mjs} +2 -2
  16. package/fesm2022/{tft-crispr-forms-index-DAx6Am4i.mjs.map → tft-crispr-forms-index-CLSsoEGa.mjs.map} +1 -1
  17. package/fesm2022/{tft-crispr-forms-index-kjMTlZoq.mjs → tft-crispr-forms-index-CMJfbPJv.mjs} +2 -2
  18. package/fesm2022/{tft-crispr-forms-index-kjMTlZoq.mjs.map → tft-crispr-forms-index-CMJfbPJv.mjs.map} +1 -1
  19. package/fesm2022/tft-crispr-forms-index-CXHhQct3.mjs +2 -0
  20. package/fesm2022/tft-crispr-forms-index-CXHhQct3.mjs.map +1 -0
  21. package/fesm2022/tft-crispr-forms-index-Cch_yKzh.mjs +181 -0
  22. package/fesm2022/tft-crispr-forms-index-Cch_yKzh.mjs.map +1 -0
  23. package/fesm2022/{tft-crispr-forms-index-CG3cLos3.mjs → tft-crispr-forms-index-HtH17liK.mjs} +3 -3
  24. package/fesm2022/{tft-crispr-forms-index-CG3cLos3.mjs.map → tft-crispr-forms-index-HtH17liK.mjs.map} +1 -1
  25. package/fesm2022/{tft-crispr-forms-index-UAYeTe3L.mjs → tft-crispr-forms-index-SEXABbga.mjs} +2 -2
  26. package/fesm2022/{tft-crispr-forms-index-UAYeTe3L.mjs.map → tft-crispr-forms-index-SEXABbga.mjs.map} +1 -1
  27. package/fesm2022/{tft-crispr-forms-index-CvTUJeC6.mjs → tft-crispr-forms-index-SXLsJ2dx.mjs} +2 -2
  28. package/fesm2022/{tft-crispr-forms-index-CvTUJeC6.mjs.map → tft-crispr-forms-index-SXLsJ2dx.mjs.map} +1 -1
  29. package/fesm2022/{tft-crispr-forms-index-joNvlmny.mjs → tft-crispr-forms-index-g-9P16CE.mjs} +2 -2
  30. package/fesm2022/{tft-crispr-forms-index-joNvlmny.mjs.map → tft-crispr-forms-index-g-9P16CE.mjs.map} +1 -1
  31. package/fesm2022/{tft-crispr-forms-index-DEu5NqmR.mjs → tft-crispr-forms-index-hpO3y8-r.mjs} +2 -2
  32. package/fesm2022/{tft-crispr-forms-index-DEu5NqmR.mjs.map → tft-crispr-forms-index-hpO3y8-r.mjs.map} +1 -1
  33. package/fesm2022/tft-crispr-forms-tft-crispr-forms-Dhjn_QdV.mjs +982 -0
  34. package/fesm2022/tft-crispr-forms-tft-crispr-forms-Dhjn_QdV.mjs.map +1 -0
  35. package/fesm2022/tft-crispr-forms.mjs +1 -981
  36. package/fesm2022/tft-crispr-forms.mjs.map +1 -1
  37. package/package.json +1 -1
  38. package/types/tft-crispr-forms.d.ts +26 -2
  39. package/fesm2022/tft-crispr-forms-index-BICpK-GR.mjs +0 -2
  40. package/fesm2022/tft-crispr-forms-index-BICpK-GR.mjs.map +0 -1
  41. package/fesm2022/tft-crispr-forms-index-DW1QGkrv.mjs +0 -137
  42. package/fesm2022/tft-crispr-forms-index-DW1QGkrv.mjs.map +0 -1
  43. package/fesm2022/tft-crispr-forms-index-DvrD-Lli.mjs.map +0 -1
@@ -1,982 +1,2 @@
1
- import * as i0 from '@angular/core';
2
- import { signal, input, computed, Input, Directive, inject, DestroyRef, EventEmitter, effect, Output, ViewContainerRef, Renderer2, ChangeDetectorRef, Pipe, NgModule, ViewChild, Component, HostListener, ChangeDetectionStrategy } from '@angular/core';
3
- import * as i1 from '@angular/common';
4
- import { CommonModule } from '@angular/common';
5
- import * as i1$1 from '@angular/forms';
6
- import { FormArray, FormControl, FormGroup, ReactiveFormsModule, NgControl } from '@angular/forms';
7
- import * as i6 from '@tft/form-validation-handler';
8
- import { FormValidationHandlerModule } from '@tft/form-validation-handler';
9
- import { from, of, isObservable } from 'rxjs';
10
- import { map, startWith, debounceTime, distinctUntilChanged, switchMap, shareReplay, tap } from 'rxjs/operators';
11
- import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
12
- import * as i1$3 from '@angular/material/button';
13
- import { MatButtonModule } from '@angular/material/button';
14
- import * as i2 from '@angular/material/icon';
15
- import { MatIconModule } from '@angular/material/icon';
16
- import * as i2$2 from '@angular/material/form-field';
17
- import { MatFormFieldModule } from '@angular/material/form-field';
18
- import * as i3 from '@angular/material/input';
19
- import { MatInputModule } from '@angular/material/input';
20
- import * as i2$1 from '@angular/material/tooltip';
21
- import { MatTooltipModule } from '@angular/material/tooltip';
22
- import * as i1$2 from '@angular/material/progress-bar';
23
- import { MatProgressBarModule } from '@angular/material/progress-bar';
24
-
25
- function valueIn(values) {
26
- return map((value) => {
27
- if (value) {
28
- return values.some(v => {
29
- if (isRegex(v)) {
30
- const trimmedStringForRegex = v.substr(1, v.length - 2);
31
- const regex = new RegExp(trimmedStringForRegex);
32
- return regex.test(value);
33
- }
34
- else {
35
- return v === value;
36
- }
37
- });
38
- }
39
- else {
40
- return false;
41
- }
42
- });
43
- }
44
- function isRegex(string) {
45
- return string.startsWith('/') && string.endsWith('/');
46
- }
47
-
48
- const DEFAULT_EMPTY_OPTIONS_MESSAGE = 'No Items';
49
-
50
- // export type ControlType = keyof typeof FIELD_COMPONENTS;
51
- var ControlType;
52
- (function (ControlType) {
53
- ControlType["AUTOCOMPLETE"] = "autocomplete";
54
- ControlType["AUTOCOMPLETE_CHIPLIST"] = "autocompleteChiplist";
55
- ControlType["BUTTON"] = "button";
56
- ControlType["CHECKBOX"] = "checkbox";
57
- ControlType["CUSTOM"] = "custom";
58
- ControlType["DATEPICKER"] = "datepicker";
59
- ControlType["DIVIDER"] = "divider";
60
- ControlType["FILE_UPLOAD"] = "fileUpload";
61
- ControlType["GROUP_LIST"] = "groupList";
62
- ControlType["HEADING"] = "heading";
63
- ControlType["IMAGE_UPLOAD"] = "imageUpload";
64
- ControlType["INPUT"] = "input";
65
- ControlType["MAP"] = "map";
66
- ControlType["RADIO"] = "radio";
67
- ControlType["SELECT"] = "select";
68
- ControlType["SLIDER"] = "slider";
69
- ControlType["SUB_GROUP"] = "subGroup";
70
- ControlType["TEXTAREA"] = "textarea";
71
- ControlType["UNIT_CONVERSION"] = "unitConversion";
72
- })(ControlType || (ControlType = {}));
73
-
74
- /**
75
- * Analyze the config and build a form control to spec. Notice we don't use FormBuilder here
76
- * as we want to keep this function pure.
77
- * @param controlConfig the configuration object for the control to build
78
- * @param value an initial value to use if passed in
79
- */
80
- function createControlForType(controlConfig, value = null) {
81
- // build form control out based on the control type
82
- const control = controlConfig.controlType === ControlType.SUB_GROUP
83
- ? buildFormGroupFromConfig(controlConfig, value)
84
- : controlConfig.controlType === ControlType.GROUP_LIST
85
- ? new FormArray([], controlConfig.validators)
86
- : new FormControl(value || null, controlConfig.validators);
87
- return control;
88
- }
89
-
90
- /**
91
- * Determines if the field config is for a form control (not a divider, heading or other non-control field)
92
- */
93
- function isControlConfig(fieldConfig) {
94
- return 'controlName' in fieldConfig;
95
- }
96
-
97
- /**
98
- * builds out form group based on config
99
- * @param config a configuration for a form group
100
- * @param value an object of initial values to pass in
101
- * @param group the form group to modify and build out
102
- */
103
- function buildFormGroupFromConfig(config, value = null, group = new FormGroup({})) {
104
- config.fields.forEach((controlConfig) => {
105
- if (isControlConfig(controlConfig)) {
106
- // then add a control to the group using the controlName from configuration
107
- const { controlName } = controlConfig;
108
- if (group.get(controlName)) {
109
- group.removeControl(controlName);
110
- }
111
- // if there's a value object and it has a non-null/undefined value for this field use it.
112
- // Otherwise, default to null
113
- const controlValue = (value && value[controlName]) ?? null;
114
- const control = createControlForType(controlConfig, controlValue);
115
- group.addControl(controlName, control);
116
- }
117
- });
118
- group.setValidators(config.validators);
119
- return group;
120
- }
121
-
122
- function callOptionsIfFunction(options, parentGroup, searchString) {
123
- return options instanceof Function ? options(parentGroup, searchString) : options;
124
- }
125
-
126
- /**
127
- * A basic filter function that filters the search string against the label of the options object
128
- * @param options the array of options to filter
129
- * @param searchString the string from the input
130
- */
131
- function filterOptionsByLabel(options, searchString) {
132
- return options.filter(option => {
133
- return option.label && option.label.toLowerCase().includes(searchString.toLowerCase());
134
- });
135
- }
136
-
137
- /**
138
- * The user can give us select options as an array, a function that resolves to a promise,
139
- * or an observable. This functions consumes any of those and returns an observable that
140
- * resolves an array of options
141
- *
142
- * @param options the options passed in from the config
143
- * @param emptyMessageOption the message to display when the array is empty
144
- */
145
- function observablifyOptions(options, parentGroup, searchString) {
146
- const calledOptions = callOptionsIfFunction(options, parentGroup, searchString);
147
- // if options are a promise
148
- const observableOptions = calledOptions instanceof Promise
149
- // convert to observable
150
- ? from(calledOptions)
151
- // if array that isn't empty
152
- : Array.isArray(calledOptions) && calledOptions.length
153
- // convert to observable
154
- ? of(calledOptions)
155
- // if observable
156
- : isObservable(calledOptions)
157
- // return it
158
- ? calledOptions
159
- // else an empty array
160
- : of([]);
161
- return observableOptions;
162
- }
163
-
164
- function convertBytesToMb(bytes) {
165
- return bytes / 1048576;
166
- }
167
- function maxFileSizeValidator(maxFileSize) {
168
- return (control) => {
169
- const controlValue = control.value;
170
- if (!(controlValue instanceof File)) {
171
- return null;
172
- }
173
- const actualFileSize = +convertBytesToMb(controlValue.size).toPrecision(3);
174
- if (maxFileSize > actualFileSize)
175
- return null;
176
- return { maxFileSize: { maxFileSize, actualFileSize } };
177
- };
178
- }
179
- function allowedFileExtValidator(allowedFileExtensions, onlyAllowFiles = true) {
180
- return (control) => {
181
- const controlValue = control.value;
182
- const isFile = controlValue instanceof File;
183
- if (!onlyAllowFiles && !isFile)
184
- return null;
185
- const actualExtension = isFile ? controlValue.name.split('.').pop().toLocaleLowerCase() : 'Not a file';
186
- const isAllowedExtension = allowedFileExtensions.includes(actualExtension);
187
- if (isAllowedExtension) {
188
- return null;
189
- }
190
- return { allowedExtension: { allowedFileExtensions, actualExtension } };
191
- };
192
- }
193
- function allowedFileType(matchExp) {
194
- return (formControl) => {
195
- const value = formControl.value;
196
- if (!(value instanceof File))
197
- return null;
198
- const type = value.type;
199
- const matches = type.match(matchExp);
200
- if (!type || !matches?.length) {
201
- return {
202
- allowedFileType: {
203
- actualType: type,
204
- allowedTypeExp: matchExp
205
- }
206
- };
207
- }
208
- else {
209
- return null;
210
- }
211
- };
212
- }
213
-
214
- class CrisprFieldComponent {
215
- constructor() {
216
- this.config = signal(null, ...(ngDevMode ? [{ debugName: "config" }] : []));
217
- this.testIdPrefix = input(undefined, ...(ngDevMode ? [{ debugName: "testIdPrefix" }] : []));
218
- this.testId = computed(() => {
219
- const controlName = this.config()?.controlName;
220
- if (!controlName)
221
- return undefined;
222
- const prefix = this.testIdPrefix();
223
- return prefix ? `${prefix}.${controlName}` : controlName;
224
- }, ...(ngDevMode ? [{ debugName: "testId" }] : []));
225
- }
226
- // eslint-disable-next-line @angular-eslint/no-input-rename
227
- set inputConfig(config) {
228
- this.updateConfig(config);
229
- }
230
- updateConfig(inputConfig) {
231
- const mergedConfig = this.defaultConfig ? { ...this.defaultConfig, ...inputConfig } : inputConfig;
232
- this.config.set(mergedConfig);
233
- }
234
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
235
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.6", type: CrisprFieldComponent, isStandalone: true, inputs: { inputConfig: { classPropertyName: "inputConfig", publicName: "config", isSignal: false, isRequired: false, transformFunction: null }, testIdPrefix: { classPropertyName: "testIdPrefix", publicName: "testIdPrefix", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
236
- }
237
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprFieldComponent, decorators: [{
238
- type: Directive,
239
- args: [{
240
- standalone: true
241
- }]
242
- }], propDecorators: { inputConfig: [{
243
- type: Input,
244
- args: [{ alias: 'config' }]
245
- }], testIdPrefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "testIdPrefix", required: false }] }] } });
246
-
247
- class CrisprControlComponent extends CrisprFieldComponent {
248
- // eslint-disable-next-line @angular-eslint/no-input-rename
249
- set inputGroup(group) {
250
- this.group.set(group);
251
- }
252
- /*
253
- * Having the input alias allows us to consume these components in the traditional Angular way as well as progammatically in the form builder
254
- */
255
- // eslint-disable-next-line @angular-eslint/no-input-rename
256
- set inputValue(value) {
257
- this.value.set(value);
258
- }
259
- constructor() {
260
- super();
261
- this.destroyRef = inject(DestroyRef);
262
- this.group = signal(null, ...(ngDevMode ? [{ debugName: "group" }] : []));
263
- this.control = computed(() => this.group()?.get(this.config().controlName), ...(ngDevMode ? [{ debugName: "control" }] : []));
264
- this.valueChanges = new EventEmitter();
265
- this.value = signal(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
266
- effect(() => {
267
- this.setControlValue(this.value());
268
- });
269
- }
270
- ngOnInit() {
271
- this.control().valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((value) => {
272
- this.valueChanges.emit(value);
273
- });
274
- // setTimeouts are ugly but this seems to be the only way to get the computed field to compute initial values
275
- setTimeout(() => {
276
- this.control().updateValueAndValidity();
277
- });
278
- }
279
- setControlValue(value) {
280
- if (value && this.control() && this.config().controlType !== ControlType.SUB_GROUP) {
281
- this.control().setValue(value);
282
- }
283
- }
284
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
285
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.6", type: CrisprControlComponent, isStandalone: true, inputs: { inputGroup: ["group", "inputGroup"], inputValue: ["value", "inputValue"] }, outputs: { valueChanges: "valueChanges" }, usesInheritance: true, ngImport: i0 }); }
286
- }
287
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprControlComponent, decorators: [{
288
- type: Directive,
289
- args: [{
290
- standalone: true
291
- }]
292
- }], ctorParameters: () => [], propDecorators: { inputGroup: [{
293
- type: Input,
294
- args: [{ alias: 'group' }]
295
- }], valueChanges: [{
296
- type: Output
297
- }], inputValue: [{
298
- type: Input,
299
- args: [{ alias: 'value' }]
300
- }] } });
301
-
302
- // eslint-disable-next-line @angular-eslint/directive-class-suffix
303
- class AbstractAutocompleteComponent extends CrisprControlComponent {
304
- constructor() {
305
- super(...arguments);
306
- // we need a separate control for the UI because of the way the material autocomplete chiplist works
307
- this.autocompleteInputControl = new FormControl('');
308
- this.config = signal(null, ...(ngDevMode ? [{ debugName: "config" }] : []));
309
- }
310
- ngOnInit() {
311
- super.ngOnInit();
312
- this.group().addControl(this.config().controlName, new FormControl());
313
- // filter options by the search string using either the default filter function or one passed in through config()
314
- this.options$ = this.autocompleteInputControl.valueChanges.pipe(
315
- // this is needed to have the options panel to open on focus
316
- startWith(''), debounceTime(this.config().typeDebounceTime), map((searchText) => typeof searchText === 'string' ? searchText?.trim() : ''), distinctUntilChanged(), switchMap((searchText) => observablifyOptions(this.config().options, this.group(), searchText)), shareReplay(1));
317
- }
318
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: AbstractAutocompleteComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
319
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.6", type: AbstractAutocompleteComponent, isStandalone: true, usesInheritance: true, ngImport: i0 }); }
320
- }
321
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: AbstractAutocompleteComponent, decorators: [{
322
- type: Directive
323
- }] });
324
-
325
- // eslint-disable-next-line @angular-eslint/directive-class-suffix
326
- class CrisprDisplayFieldComponent extends CrisprControlComponent {
327
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprDisplayFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
328
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.6", type: CrisprDisplayFieldComponent, isStandalone: true, usesInheritance: true, ngImport: i0 }); }
329
- }
330
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprDisplayFieldComponent, decorators: [{
331
- type: Directive
332
- }] });
333
-
334
- const FIELD_COMPONENTS = {
335
- groupList: () => Promise.resolve().then(function () { return index$1; }).then(({ FormGroupListComponent }) => FormGroupListComponent),
336
- subGroup: () => Promise.resolve().then(function () { return index; }).then(({ SubGroupComponent }) => SubGroupComponent),
337
- button: () => import('./tft-crispr-forms-index-joNvlmny.mjs').then(({ ButtonComponent }) => ButtonComponent),
338
- input: () => import('./tft-crispr-forms-index-DAx6Am4i.mjs').then(({ InputFieldComponent }) => InputFieldComponent),
339
- select: () => import('./tft-crispr-forms-index-CLJ89Dev.mjs').then(({ SelectFieldComponent }) => SelectFieldComponent),
340
- radio: () => import('./tft-crispr-forms-index-DEu5NqmR.mjs').then(({ RadioFieldComponent }) => RadioFieldComponent),
341
- autocomplete: () => import('./tft-crispr-forms-index-BICpK-GR.mjs').then(({ AutocompleteFieldComponent }) => AutocompleteFieldComponent),
342
- autocompleteChiplist: () => import('./tft-crispr-forms-index-DW1QGkrv.mjs').then(({ AutocompleteChiplistFieldComponent }) => AutocompleteChiplistFieldComponent),
343
- map: () => import('./tft-crispr-forms-index-DvrD-Lli.mjs').then(({ MapFieldComponent }) => MapFieldComponent),
344
- textarea: () => import('./tft-crispr-forms-index-DuvnSHLl.mjs').then(({ TextareaFieldComponent }) => TextareaFieldComponent),
345
- checkbox: () => import('./tft-crispr-forms-index-CvTUJeC6.mjs').then(({ CheckboxFieldComponent }) => CheckboxFieldComponent),
346
- slider: () => import('./tft-crispr-forms-index-D6cKptyg.mjs').then(({ SliderFieldComponent }) => SliderFieldComponent),
347
- datepicker: () => import('./tft-crispr-forms-index-usD7jUs3.mjs').then(({ DatepickerFieldComponent }) => DatepickerFieldComponent),
348
- fileUpload: () => Promise.resolve().then(function () { return index$3; }).then(({ FileUploadFieldComponent }) => FileUploadFieldComponent),
349
- imageUpload: () => import('./tft-crispr-forms-index-DOpDpDdt.mjs').then(({ ImageUploadFieldComponent }) => ImageUploadFieldComponent),
350
- heading: () => Promise.resolve().then(function () { return index$2; }).then(({ HeadingComponent }) => HeadingComponent),
351
- divider: () => import('./tft-crispr-forms-index-kjMTlZoq.mjs').then(({ DividerComponent }) => DividerComponent),
352
- unitConversion: () => import('./tft-crispr-forms-index-CG3cLos3.mjs').then(({ UnitConversionFieldComponent }) => UnitConversionFieldComponent),
353
- };
354
- function isControlComponent(component) {
355
- return component && isControlConfig(component.config()) && 'value' in component;
356
- }
357
- function isControlOrButtonComponent(component) {
358
- return (isControlComponent(component) ||
359
- component.config().controlType === ControlType.BUTTON);
360
- }
361
-
362
- class CrisprFieldDirective {
363
- constructor() {
364
- this.container = inject(ViewContainerRef);
365
- this.renderer = inject(Renderer2);
366
- this.cdr = inject(ChangeDetectorRef);
367
- }
368
- set value(value) {
369
- this._value = value;
370
- // This is needed to keep the group list from resetting control values to the initial input value
371
- this.updateComponentValue(value);
372
- }
373
- get value() {
374
- return this._value;
375
- }
376
- async ngOnInit() {
377
- /**
378
- * create component and set values from config on its instance
379
- */
380
- const component = this.config.component ||
381
- (await FIELD_COMPONENTS[this.config.controlType]());
382
- const componentRef = this.container.createComponent(component);
383
- this.component = componentRef.instance;
384
- componentRef.setInput('config', this.config);
385
- if (isControlOrButtonComponent(this.component)) {
386
- componentRef.setInput('group', this.group);
387
- }
388
- componentRef.setInput('testIdPrefix', this.testIdPrefix);
389
- this.updateComponentValue(this.value);
390
- // adds any config classes to the dynamically generated component
391
- // doing this here keeps us from having to extend a base component into each field component individually
392
- if (!this.config.classes)
393
- return;
394
- this.config.classes.forEach((klass) => {
395
- // check for passing multiple classes in one array element
396
- if (klass.includes(' ')) {
397
- throw Error(`Improperly formatted class. '${klass}' cannot contain spaces.`);
398
- }
399
- else {
400
- this.renderer.addClass(componentRef.location.nativeElement, klass);
401
- }
402
- });
403
- }
404
- updateComponentValue(value) {
405
- if (isControlComponent(this.component)) {
406
- this.component.value.set(value);
407
- // SubGroups won't populate without this detectChanges
408
- this.cdr.detectChanges();
409
- }
410
- }
411
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprFieldDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
412
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.6", type: CrisprFieldDirective, isStandalone: true, selector: "[crisprField]", inputs: { config: "config", group: "group", testIdPrefix: "testIdPrefix", value: "value" }, ngImport: i0 }); }
413
- }
414
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprFieldDirective, decorators: [{
415
- type: Directive,
416
- args: [{
417
- selector: '[crisprField]',
418
- standalone: true,
419
- }]
420
- }], propDecorators: { config: [{
421
- type: Input
422
- }], group: [{
423
- type: Input
424
- }], testIdPrefix: [{
425
- type: Input
426
- }], value: [{
427
- type: Input
428
- }] } });
429
-
430
- class InitialControlValuePipe {
431
- // TODO: does changing any to unknown break anything?
432
- transform(initialFormValue, fieldConfig) {
433
- return initialFormValue && isControlConfig(fieldConfig)
434
- ? initialFormValue[fieldConfig.controlName] || null
435
- : null;
436
- }
437
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: InitialControlValuePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
438
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.6", ngImport: i0, type: InitialControlValuePipe, isStandalone: false, name: "initialControlValue" }); }
439
- }
440
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: InitialControlValuePipe, decorators: [{
441
- type: Pipe,
442
- args: [{
443
- name: 'initialControlValue',
444
- standalone: false
445
- }]
446
- }] });
447
-
448
- class CrisprPipesModule {
449
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprPipesModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
450
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.6", ngImport: i0, type: CrisprPipesModule, declarations: [InitialControlValuePipe], imports: [CommonModule], exports: [InitialControlValuePipe] }); }
451
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprPipesModule, imports: [CommonModule] }); }
452
- }
453
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprPipesModule, decorators: [{
454
- type: NgModule,
455
- args: [{
456
- imports: [
457
- CommonModule
458
- ],
459
- exports: [
460
- InitialControlValuePipe
461
- ],
462
- declarations: [
463
- InitialControlValuePipe
464
- ]
465
- }]
466
- }] });
467
-
468
- class CrisprFormComponent {
469
- constructor() {
470
- this.form = new FormGroup({});
471
- this.value = null;
472
- this.submitted = new EventEmitter();
473
- // proxy value and status change events through to consuming component
474
- this.valueChanges = this.form.valueChanges;
475
- this.statusChanges = this.form.statusChanges;
476
- }
477
- ngOnInit() {
478
- // build out the form, note that we pass in the form as the third argument and the function modifies it
479
- buildFormGroupFromConfig(this.config, this.value, this.form);
480
- }
481
- handleSubmit() {
482
- this.form.markAllAsTouched();
483
- this.submitted.emit(this.form);
484
- }
485
- triggerSubmit() {
486
- this.submitTrigger.nativeElement.click();
487
- }
488
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
489
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: CrisprFormComponent, isStandalone: true, selector: "crispr-form", inputs: { config: "config", form: "form", value: "value" }, outputs: { submitted: "submitted", valueChanges: "valueChanges", statusChanges: "statusChanges" }, viewQueries: [{ propertyName: "submitTrigger", first: true, predicate: ["submitTrigger"], descendants: true }], ngImport: i0, template: "<form\n class=\"crispr-form\"\n [ngClass]=\"config.classes\"\n [formGroup]=\"form\"\n (ngSubmit)=\"handleSubmit()\"\n [autocomplete]=\"config.autocomplete || 'off'\"\n [errorDictionary]=\"config.errorDictionary\"\n #ngFormElement=\"ngForm\">\n\n @for (field of config.fields; track field) {\n <ng-container\n crisprField\n [value]=\"value | initialControlValue : field\"\n [config]=\"field\"\n [group]=\"form\">\n </ng-container>\n }\n <!-- Hidden button, programmatically clicked when crispr form triggerSubmit function called.\n Uses a hidden button with type=\"submit\" because it will trigger both native form submit event\n (which the error handler has to listen for) and ngSubmit event -->\n <button #submitTrigger class=\"submit-trigger\" data-testid=\"submit-trigger\" type=\"submit\">\n </button>\n</form>\n", styles: [".submit-trigger{display:none}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: CrisprFieldDirective, selector: "[crisprField]", inputs: ["config", "group", "testIdPrefix", "value"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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: "ngmodule", type: FormValidationHandlerModule }, { kind: "directive", type: i6.ControlErrorsFormDirective, selector: "form", inputs: ["errorDictionary"] }, { kind: "directive", type: i6.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { kind: "ngmodule", type: CrisprPipesModule }, { kind: "pipe", type: InitialControlValuePipe, name: "initialControlValue" }], preserveWhitespaces: true }); }
490
- }
491
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprFormComponent, decorators: [{
492
- type: Component,
493
- args: [{ selector: 'crispr-form', imports: [
494
- CommonModule,
495
- CrisprFieldDirective,
496
- ReactiveFormsModule,
497
- FormValidationHandlerModule,
498
- CrisprPipesModule,
499
- ], template: "<form\n class=\"crispr-form\"\n [ngClass]=\"config.classes\"\n [formGroup]=\"form\"\n (ngSubmit)=\"handleSubmit()\"\n [autocomplete]=\"config.autocomplete || 'off'\"\n [errorDictionary]=\"config.errorDictionary\"\n #ngFormElement=\"ngForm\">\n\n @for (field of config.fields; track field) {\n <ng-container\n crisprField\n [value]=\"value | initialControlValue : field\"\n [config]=\"field\"\n [group]=\"form\">\n </ng-container>\n }\n <!-- Hidden button, programmatically clicked when crispr form triggerSubmit function called.\n Uses a hidden button with type=\"submit\" because it will trigger both native form submit event\n (which the error handler has to listen for) and ngSubmit event -->\n <button #submitTrigger class=\"submit-trigger\" data-testid=\"submit-trigger\" type=\"submit\">\n </button>\n</form>\n", styles: [".submit-trigger{display:none}\n"] }]
500
- }], propDecorators: { config: [{
501
- type: Input
502
- }], form: [{
503
- type: Input
504
- }], value: [{
505
- type: Input
506
- }], submitted: [{
507
- type: Output
508
- }], valueChanges: [{
509
- type: Output
510
- }], statusChanges: [{
511
- type: Output
512
- }], submitTrigger: [{
513
- type: ViewChild,
514
- args: ['submitTrigger']
515
- }] } });
516
-
517
- class FileDropzoneDirective {
518
- constructor() {
519
- this.fileDrop = new EventEmitter();
520
- this.crisprFileDropzone = true;
521
- }
522
- onDrop($event) {
523
- if (this.crisprFileDropzone) {
524
- $event.preventDefault();
525
- this.fileDrop.emit($event.dataTransfer.files);
526
- }
527
- }
528
- // Prevents DOM from trying to open file in browser
529
- onDragOver($event) {
530
- if (this.crisprFileDropzone) {
531
- $event.preventDefault();
532
- }
533
- }
534
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: FileDropzoneDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
535
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.6", type: FileDropzoneDirective, isStandalone: true, selector: "[crisprFileDropzone]", inputs: { crisprFileDropzone: "crisprFileDropzone" }, outputs: { fileDrop: "fileDrop" }, host: { listeners: { "drop": "onDrop($event)", "dragover": "onDragOver($event)" } }, ngImport: i0 }); }
536
- }
537
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: FileDropzoneDirective, decorators: [{
538
- type: Directive,
539
- args: [{
540
- selector: '[crisprFileDropzone]',
541
- standalone: true,
542
- }]
543
- }], propDecorators: { fileDrop: [{
544
- type: Output
545
- }], crisprFileDropzone: [{
546
- type: Input
547
- }], onDrop: [{
548
- type: HostListener,
549
- args: ['drop', ['$event']]
550
- }], onDragOver: [{
551
- type: HostListener,
552
- args: ['dragover', ['$event']]
553
- }] } });
554
-
555
- class InfoComponent {
556
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: InfoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
557
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: InfoComponent, isStandalone: true, selector: "crispr-info", inputs: { info: "info" }, ngImport: i0, template: "@if (info) {\n <mat-icon\n [matTooltip]=\"info.content\"\n [matTooltipPosition]=\"info.tooltipPosition || 'below'\">\n {{info.iconName || 'info'}}\n </mat-icon>\n}\n", styles: [":host{margin-left:4px}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true }); }
558
- }
559
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: InfoComponent, decorators: [{
560
- type: Component,
561
- args: [{ selector: 'crispr-info', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
562
- MatIconModule,
563
- MatTooltipModule
564
- ], template: "@if (info) {\n <mat-icon\n [matTooltip]=\"info.content\"\n [matTooltipPosition]=\"info.tooltipPosition || 'below'\">\n {{info.iconName || 'info'}}\n </mat-icon>\n}\n", styles: [":host{margin-left:4px}\n"] }]
565
- }], propDecorators: { info: [{
566
- type: Input
567
- }] } });
568
-
569
- const defaultConfig$1 = {
570
- typographyClass: 'mat-h3',
571
- };
572
- class HeadingComponent extends CrisprFieldComponent {
573
- constructor() {
574
- super(...arguments);
575
- this.defaultConfig = defaultConfig$1;
576
- }
577
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: HeadingComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
578
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: HeadingComponent, isStandalone: true, selector: "crispr-heading", usesInheritance: true, ngImport: i0, template: "@if (!!config()?.label) {\n <label\n [ngClass]=\"config().typographyClass\">\n {{ config().label }}\n @if (config().info) {\n <crispr-info\n matSuffix\n [info]=\"config().info\">\n </crispr-info>\n }\n </label>\n}\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "directive", type: i2$2.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "component", type: InfoComponent, selector: "crispr-info", inputs: ["info"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true }); }
579
- }
580
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: HeadingComponent, decorators: [{
581
- type: Component,
582
- args: [{ selector: 'crispr-heading', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, MatFormFieldModule, InfoComponent], standalone: true, template: "@if (!!config()?.label) {\n <label\n [ngClass]=\"config().typographyClass\">\n {{ config().label }}\n @if (config().info) {\n <crispr-info\n matSuffix\n [info]=\"config().info\">\n </crispr-info>\n }\n </label>\n}\n", styles: [":host{display:block}\n"] }]
583
- }] });
584
-
585
- class FieldContainerComponent {
586
- constructor() {
587
- // boolean whether field-container is inline
588
- this.inlineField = false;
589
- this.subs = [];
590
- }
591
- ngOnInit() {
592
- this.disabled$ = this.connectDisabledCallback(this.group, this.config);
593
- // we tried moving this into afterViewChecked and afterContentChecked lifecycle hooks without any luck
594
- if (this.config.computeValue) {
595
- this.subs.push(this.config
596
- .computeValue(this.group)
597
- .pipe(distinctUntilChanged(), tap((computedValue) => this.group.get(this.config.controlName).setValue(computedValue)))
598
- .subscribe());
599
- }
600
- }
601
- ngOnDestroy() {
602
- this.subs.forEach((sub) => sub.unsubscribe);
603
- }
604
- /**
605
- * Connects user defined disabledCallback function to the the view, so that the control is enabled/disabled
606
- * appropriately. It also will hide disabled fields in the UI unless `hideDisabled` is set to
607
- * false in the controls config
608
- * @param group used to get valueChanges from control
609
- * @param config configuration object used to
610
- */
611
- connectDisabledCallback(group, config = null) {
612
- const control = group.get(config.controlName);
613
- // If the disabled$ function exists on the field config then call it with the disabledCallbackConfig
614
- // as a parameter otherwise return an observable of true.
615
- return config?.disabledCallback &&
616
- config.disabledCallback instanceof Function
617
- ? config.disabledCallback(group).pipe(
618
- // This enables/disables when callback conditions are met
619
- tap((shouldDisable) => shouldDisable ? control.disable() : control.enable()))
620
- : of(false);
621
- }
622
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: FieldContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
623
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: FieldContainerComponent, isStandalone: true, selector: "crispr-field-container", inputs: { config: "config", group: "group", inlineField: "inlineField" }, ngImport: i0, template: "@if ((disabled$ | async) ? !config.hideDisabled : true) {\n <div\n [ngClass]=\"config.classes\"\n [class.inline-field]=\"inlineField\"\n class=\"field-container\">\n @if (config.heading) {\n <crispr-heading\n [config]=\"config.heading\">\n </crispr-heading>\n }\n <ng-content>\n </ng-content>\n </div>\n}\n", styles: ["::ng-deep mat-form-field.mat-mdc-form-field{display:block;padding:.25em 0}.inline-field{display:inline-block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: HeadingComponent, selector: "crispr-heading" }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true }); }
624
- }
625
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: FieldContainerComponent, decorators: [{
626
- type: Component,
627
- args: [{ selector: 'crispr-field-container', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, HeadingComponent], template: "@if ((disabled$ | async) ? !config.hideDisabled : true) {\n <div\n [ngClass]=\"config.classes\"\n [class.inline-field]=\"inlineField\"\n class=\"field-container\">\n @if (config.heading) {\n <crispr-heading\n [config]=\"config.heading\">\n </crispr-heading>\n }\n <ng-content>\n </ng-content>\n </div>\n}\n", styles: ["::ng-deep mat-form-field.mat-mdc-form-field{display:block;padding:.25em 0}.inline-field{display:inline-block}\n"] }]
628
- }], propDecorators: { config: [{
629
- type: Input
630
- }], group: [{
631
- type: Input
632
- }], inlineField: [{
633
- type: Input
634
- }] } });
635
-
636
- class SelectedFileComponent {
637
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: SelectedFileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
638
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: SelectedFileComponent, isStandalone: true, selector: "crispr-selected-file", inputs: { fileName: "fileName", progress: "progress", showProgress: "showProgress", color: "color" }, ngImport: i0, template: "<h3 class=\"mat-h3\">{{ fileName }}</h3>\n@if (showProgress) {\n <mat-progress-bar\n mode=\"determinate\"\n [color]=\"color\"\n [value]=\"progress\">\n </mat-progress-bar>\n}\n", styles: ["mat-progress-bar{margin-bottom:8px}\n"], dependencies: [{ kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i1$2.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }], preserveWhitespaces: true }); }
639
- }
640
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: SelectedFileComponent, decorators: [{
641
- type: Component,
642
- args: [{ selector: 'crispr-selected-file', imports: [
643
- MatProgressBarModule
644
- ], template: "<h3 class=\"mat-h3\">{{ fileName }}</h3>\n@if (showProgress) {\n <mat-progress-bar\n mode=\"determinate\"\n [color]=\"color\"\n [value]=\"progress\">\n </mat-progress-bar>\n}\n", styles: ["mat-progress-bar{margin-bottom:8px}\n"] }]
645
- }], propDecorators: { fileName: [{
646
- type: Input
647
- }], progress: [{
648
- type: Input
649
- }], showProgress: [{
650
- type: Input
651
- }], color: [{
652
- type: Input
653
- }] } });
654
-
655
- /* eslint-disable @nx/enforce-module-boundaries */
656
- class FileUploadFieldComponent extends CrisprControlComponent {
657
- // ngControl: NgControl = null;
658
- constructor() {
659
- super();
660
- this.ngControl = inject(NgControl, { optional: true, self: true });
661
- this.defaultConfig = {
662
- allowMultipleFiles: false,
663
- acceptedTypes: '*.*',
664
- dropZoneText: 'DROP FILE HERE',
665
- selectFilesButtonType: 'button',
666
- selectButtonText: 'SELECT',
667
- showClearFilesButton: true,
668
- clearFilesButtonText: 'CLEAR',
669
- uploadButtonText: 'UPLOAD',
670
- uploadButtonType: 'button',
671
- showUploadProgress: false,
672
- disableOnUpload: true,
673
- };
674
- this.selectedFiles = signal(null, ...(ngDevMode ? [{ debugName: "selectedFiles" }] : []));
675
- this.selectedFilesArray = computed(() => this.selectedFiles() ? Array.from(this.selectedFiles()) : [], ...(ngDevMode ? [{ debugName: "selectedFilesArray" }] : []));
676
- this.isUploaded = false;
677
- this.fileProgress = [];
678
- const ngControl = this.ngControl;
679
- if (this.ngControl != null) {
680
- // Setting the value accessor directly (instead of using
681
- // the providers) to avoid running into a circular import.
682
- ngControl.valueAccessor = this;
683
- }
684
- }
685
- ngOnInit() {
686
- super.ngOnInit();
687
- this.disabled$ = this.config().disabledCallback
688
- ? this.config().disabledCallback(this.group())
689
- : of(false);
690
- }
691
- filesChanged(files) {
692
- if (files && files.length > 0) {
693
- this.selectedFiles.set(files);
694
- this.control().patchValue(files);
695
- }
696
- }
697
- uploadFiles() {
698
- if (this.selectedFiles() && this.config().uploadFiles) {
699
- this.isUploaded = true;
700
- this.config().uploadFiles(this.group(), this.selectedFiles(), this);
701
- }
702
- }
703
- resetFileInput() {
704
- this.fileInputRef.nativeElement.value = '';
705
- this.control().patchValue(null);
706
- this.isUploaded = false;
707
- }
708
- writeValue(value) {
709
- // clear file input
710
- // this.host.nativeElement.value = '';
711
- // this.file = null;
712
- }
713
- registerOnChange(fn) {
714
- this.onChange = fn;
715
- }
716
- registerOnTouched(fn) { }
717
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: FileUploadFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
718
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: FileUploadFieldComponent, isStandalone: true, selector: "crispr-file-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 <mat-form-field floatLabel=\"always\"\n [attr.data-testid]=\"testId()\"\n [color]=\"config().color\"\n appearance=\"outline\"\n [crisprFileDropzone]=\"!(disabled$ | async) && !(config().disableOnUpload && isUploaded)\"\n [formGroup]=\"group()\"\n (fileDrop)=\"filesChanged($event)\">\n\n <input [formControlName]=\"config().controlName\" matInput type=\"text\"/>\n <input\n #fileInput\n type=\"file\"\n style=\"display: none\"\n [accept]=\"config().acceptedTypes\"\n [multiple]=\"config().allowMultipleFiles\"\n (change)=\"filesChanged($event.target.files)\"/>\n <mat-label>{{config().label}}</mat-label>\n\n @if (!selectedFiles() || selectedFiles().length === 0) {\n <div class=\"drop-info\">\n <mat-icon class=\"drop-icon\" inline=\"true\">cloud_upload</mat-icon>\n <h2 class=\"mat-h2\">{{config().dropZoneText}}</h2>\n or\n <button\n mat-raised-button\n type=\"button\"\n color=\"primary\"\n [disabled]=\"(disabled$ | async) || config().disableOnUpload && isUploaded\"\n (click)=\"fileInput.click()\"\n [attr.aria-label]=\"config().controlName\">\n {{config().selectButtonText}}\n </button>\n </div>\n } @else {\n <div class=\"selected-files-container\">\n <div class=\"selected-files-list\">\n @for (file of selectedFilesArray(); track file; let i = $index) {\n <crispr-selected-file\n [color]=\"config().color === 'primary' ? 'accent' : 'primary'\"\n [fileName]=\"file.name\"\n [showProgress]=\"config().showUploadProgress\"\n [progress]=\"fileProgress && (fileProgress[i] | async)\">\n </crispr-selected-file>\n }\n </div>\n </div>\n }\n @if (config().hint && (control().valid || !control().touched)) {<mat-hint>{{config().hint}}</mat-hint>}\n </mat-form-field>\n @if ((selectedFiles())?.length > 0) {\n <div class=\"button-container\">\n <button\n mat-button\n (click)=\"resetFileInput()\"\n type=\"button\"\n [disabled]=\"(disabled$ | async) || (config().disableOnUpload && isUploaded)\"\n aria-label=\"Remove Selected File(s)\">\n {{config().clearFilesButtonText}}\n <mat-icon>delete</mat-icon>\n </button>\n @if (!!config().uploadFiles) {\n <button\n mat-raised-button\n type=\"button\"\n color=\"accent\"\n class=\"file-input-button\"\n [disabled]=\"(disabled$ | async) || (config().disableOnUpload && isUploaded)\"\n (click)=\"uploadFiles()\"\n [attr.aria-label]=\"config().uploadButtonText\">\n {{ config().uploadButtonText }}\n </button>\n }\n </div>\n }\n</crispr-field-container>\n", styles: [":host ::ng-deep .mat-mdc-form-field .mat-mdc-form-field-infix{padding-top:0;display:flex;justify-content:center}:host .drop-info{display:flex;flex-direction:column;align-items:center}:host .drop-info .drop-icon{font-size:36px}:host .drop-info .mat-h2{margin:0}:host .button-container{display:flex;justify-content:flex-end;margin-top:-16px}:host .button-container button{margin-left:8px}:host .selected-files-container{width:100%}:host [matInput]{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$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]" }, { 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: 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$3.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$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.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: "ngmodule", type: FormValidationHandlerModule }, { kind: "directive", type: i6.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { kind: "directive", type: i6.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { kind: "directive", type: FileDropzoneDirective, selector: "[crisprFileDropzone]", inputs: ["crisprFileDropzone"], outputs: ["fileDrop"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true }); }
719
- }
720
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: FileUploadFieldComponent, decorators: [{
721
- type: Component,
722
- args: [{ selector: 'crispr-file-upload-field', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
723
- CommonModule,
724
- FieldContainerComponent,
725
- ReactiveFormsModule,
726
- MatIconModule,
727
- MatButtonModule,
728
- MatFormFieldModule,
729
- MatInputModule,
730
- SelectedFileComponent,
731
- FormValidationHandlerModule,
732
- FileDropzoneDirective,
733
- ], standalone: true, template: "<crispr-field-container\n [config]=\"config()\"\n [group]=\"group()\">\n <mat-form-field floatLabel=\"always\"\n [attr.data-testid]=\"testId()\"\n [color]=\"config().color\"\n appearance=\"outline\"\n [crisprFileDropzone]=\"!(disabled$ | async) && !(config().disableOnUpload && isUploaded)\"\n [formGroup]=\"group()\"\n (fileDrop)=\"filesChanged($event)\">\n\n <input [formControlName]=\"config().controlName\" matInput type=\"text\"/>\n <input\n #fileInput\n type=\"file\"\n style=\"display: none\"\n [accept]=\"config().acceptedTypes\"\n [multiple]=\"config().allowMultipleFiles\"\n (change)=\"filesChanged($event.target.files)\"/>\n <mat-label>{{config().label}}</mat-label>\n\n @if (!selectedFiles() || selectedFiles().length === 0) {\n <div class=\"drop-info\">\n <mat-icon class=\"drop-icon\" inline=\"true\">cloud_upload</mat-icon>\n <h2 class=\"mat-h2\">{{config().dropZoneText}}</h2>\n or\n <button\n mat-raised-button\n type=\"button\"\n color=\"primary\"\n [disabled]=\"(disabled$ | async) || config().disableOnUpload && isUploaded\"\n (click)=\"fileInput.click()\"\n [attr.aria-label]=\"config().controlName\">\n {{config().selectButtonText}}\n </button>\n </div>\n } @else {\n <div class=\"selected-files-container\">\n <div class=\"selected-files-list\">\n @for (file of selectedFilesArray(); track file; let i = $index) {\n <crispr-selected-file\n [color]=\"config().color === 'primary' ? 'accent' : 'primary'\"\n [fileName]=\"file.name\"\n [showProgress]=\"config().showUploadProgress\"\n [progress]=\"fileProgress && (fileProgress[i] | async)\">\n </crispr-selected-file>\n }\n </div>\n </div>\n }\n @if (config().hint && (control().valid || !control().touched)) {<mat-hint>{{config().hint}}</mat-hint>}\n </mat-form-field>\n @if ((selectedFiles())?.length > 0) {\n <div class=\"button-container\">\n <button\n mat-button\n (click)=\"resetFileInput()\"\n type=\"button\"\n [disabled]=\"(disabled$ | async) || (config().disableOnUpload && isUploaded)\"\n aria-label=\"Remove Selected File(s)\">\n {{config().clearFilesButtonText}}\n <mat-icon>delete</mat-icon>\n </button>\n @if (!!config().uploadFiles) {\n <button\n mat-raised-button\n type=\"button\"\n color=\"accent\"\n class=\"file-input-button\"\n [disabled]=\"(disabled$ | async) || (config().disableOnUpload && isUploaded)\"\n (click)=\"uploadFiles()\"\n [attr.aria-label]=\"config().uploadButtonText\">\n {{ config().uploadButtonText }}\n </button>\n }\n </div>\n }\n</crispr-field-container>\n", styles: [":host ::ng-deep .mat-mdc-form-field .mat-mdc-form-field-infix{padding-top:0;display:flex;justify-content:center}:host .drop-info{display:flex;flex-direction:column;align-items:center}:host .drop-info .drop-icon{font-size:36px}:host .drop-info .mat-h2{margin:0}:host .button-container{display:flex;justify-content:flex-end;margin-top:-16px}:host .button-container button{margin-left:8px}:host .selected-files-container{width:100%}:host [matInput]{position:absolute;max-height:0;visibility:hidden}\n"] }]
734
- }], ctorParameters: () => [], propDecorators: { fileInputRef: [{
735
- type: ViewChild,
736
- args: ['fileInput']
737
- }] } });
738
-
739
- var index$3 = /*#__PURE__*/Object.freeze({
740
- __proto__: null,
741
- FileUploadFieldComponent: FileUploadFieldComponent
742
- });
743
-
744
- var index$2 = /*#__PURE__*/Object.freeze({
745
- __proto__: null,
746
- FieldContainerComponent: FieldContainerComponent,
747
- FileDropzoneDirective: FileDropzoneDirective,
748
- FileUploadFieldComponent: FileUploadFieldComponent,
749
- HeadingComponent: HeadingComponent,
750
- InfoComponent: InfoComponent,
751
- SelectedFileComponent: SelectedFileComponent
752
- });
753
-
754
- class CrisprDisplayFieldDirective {
755
- constructor() {
756
- this.container = inject(ViewContainerRef);
757
- this.cdr = inject(ChangeDetectorRef);
758
- }
759
- set value(value) {
760
- this._value = value;
761
- // This is needed to keep the group list from resetting control values to the initial input value
762
- this.updateComponentValue(value);
763
- }
764
- get value() {
765
- return this._value;
766
- }
767
- async ngOnInit() {
768
- if (this.component) {
769
- /**
770
- * create component and set values from config on its instance
771
- */
772
- const componentRef = this.container.createComponent(this.component);
773
- this.componentInstance = componentRef.instance;
774
- this.componentInstance.index = this.index;
775
- this.updateComponentValue(this.value);
776
- }
777
- }
778
- updateComponentValue(value) {
779
- if (!this.componentInstance)
780
- return;
781
- this.componentInstance.value = value;
782
- this.cdr.detectChanges();
783
- }
784
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprDisplayFieldDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
785
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.6", type: CrisprDisplayFieldDirective, isStandalone: true, selector: "[crisprDisplayField]", inputs: { group: "group", value: "value", component: "component", index: "index" }, ngImport: i0 }); }
786
- }
787
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprDisplayFieldDirective, decorators: [{
788
- type: Directive,
789
- args: [{
790
- selector: '[crisprDisplayField]',
791
- standalone: true,
792
- }]
793
- }], propDecorators: { group: [{
794
- type: Input
795
- }], value: [{
796
- type: Input
797
- }], component: [{
798
- type: Input
799
- }], index: [{
800
- type: Input
801
- }] } });
802
-
803
- const defaultConfig = {
804
- addButtonLabel: 'ADD ITEM',
805
- minListLength: 1,
806
- };
807
- class FormGroupListComponent extends CrisprControlComponent {
808
- constructor() {
809
- super(...arguments);
810
- this.cdr = inject(ChangeDetectorRef);
811
- this.defaultConfig = defaultConfig;
812
- /**
813
- * By setting this to true when adding/removing items from array,
814
- * we can block original values from overwriting form values
815
- * */
816
- this.blockValue = false;
817
- this.selectedIndex = null;
818
- }
819
- ngOnInit() {
820
- super.ngOnInit();
821
- // TODO: this is required to ngFor of controls in template, must be a better way
822
- }
823
- setControlValue(values) {
824
- if (this.control()) {
825
- if (values?.length > 0) {
826
- // clear any existing values so that new values don't concatenate onto the old
827
- const currentValues = this.control().value;
828
- if (currentValues.length) {
829
- this.control().clear();
830
- }
831
- values.forEach((value) => this.addGroup(value));
832
- }
833
- else if (this.config().displayInitialItem) {
834
- this.addGroup();
835
- }
836
- // needed to ensure new array items render
837
- setTimeout(() => {
838
- this.cdr.detectChanges();
839
- });
840
- }
841
- }
842
- clickDelete(index) {
843
- this.blockValue = true;
844
- this.deleteGroup(index);
845
- }
846
- clickAdd() {
847
- this.blockValue = true;
848
- this.addGroup();
849
- }
850
- addGroup(value = null) {
851
- this.control().push(createControlForType(this.config().itemConfig, value));
852
- // needed to ensure new array items render
853
- setTimeout(() => {
854
- this.cdr.detectChanges();
855
- });
856
- }
857
- deleteGroup(index) {
858
- this.control().removeAt(index);
859
- }
860
- clickEditItem(index) {
861
- this.selectedIndex = index;
862
- }
863
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: FormGroupListComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
864
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: FormGroupListComponent, isStandalone: true, selector: "crispr-form-group-list", usesInheritance: true, ngImport: i0, template: "<crispr-field-container [config]=\"config()\" [group]=\"group()\" [formGroup]=\"group()\">\n\n <div [formArrayName]=\"config().controlName\">\n\n <!-- Don't add trackBy function, it confuses the state of the array -->\n @for (itemControl of control()?.controls; track itemControl; let i = $index; let last = $last) {\n @if (!config().displayItemComponent || i === selectedIndex || (last && selectedIndex ?? true)) {\n <!-- TODO: use content projection to allow custom item label component -->\n <div class=\"item-header\">\n <span class=\"mat-h2\"> {{ config().itemLabelBuilder ? config().itemLabelBuilder(i) : 'Item ' + (i + 1) }} </span>\n @if (i + 1 > config().minListLength) {\n <button mat-icon-button type=\"button\">\n <mat-icon (click)=\"clickDelete(i)\">delete</mat-icon>\n </button>\n }\n </div>\n <div [formGroup]=\"itemControl\">\n <!-- TODO: if chiplists didn't need to have labels mixed in with their values we could use [value]=\"control.value\" below -->\n @for (field of config().itemConfig.fields; track field) {\n <ng-container crisprField [value]=\"blockValue ? null : value && value[i] | initialControlValue : field\"\n [config]=\"field\" [group]=\"itemControl\" [testIdPrefix]=\"testId() + '[' + i + ']'\">\n </ng-container>\n }\n </div>\n } @else {\n <div class=\"display-field-container\" crisprDisplayField [component]=\"config().displayItemComponent\"\n [value]=\"itemControl.value\" [index]=\"i\">\n <button mat-icon-button (click)=\"clickEditItem(i)\">\n <mat-icon>edit</mat-icon>\n </button>\n </div>\n }\n <ng-template #display>\n <div class=\"display-field-container\" crisprDisplayField [component]=\"config().displayItemComponent\"\n [value]=\"itemControl.value\" [index]=\"i\">\n <button mat-icon-button (click)=\"clickEditItem(i)\">\n <mat-icon>edit</mat-icon>\n </button>\n </div>\n </ng-template>\n }\n </div>\n <div class=\"group-footer\">\n <button type=\"button\" class=\"add\" mat-raised-button [color]=\"config().addButtonColor\" (click)=\"clickAdd()\">\n {{config().addItemLabel || config().addButtonLabel}}\n </button>\n </div>\n\n</crispr-field-container>", styles: [".item-header{display:flex;justify-content:space-between}.group-footer{display:flex;justify-content:flex-end}.group-footer button.add{margin-bottom:16px}.display-field-container{position:relative}.display-field-container button{position:absolute;top:0;right:0}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$3.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: "component", type: i1$3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { 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.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: CrisprFieldDirective, selector: "[crisprField]", inputs: ["config", "group", "testIdPrefix", "value"] }, { kind: "directive", type: CrisprDisplayFieldDirective, selector: "[crisprDisplayField]", inputs: ["group", "value", "component", "index"] }, { kind: "ngmodule", type: CrisprPipesModule }, { kind: "ngmodule", type: FormValidationHandlerModule }, { kind: "directive", type: i6.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { kind: "pipe", type: InitialControlValuePipe, name: "initialControlValue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true }); }
865
- }
866
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: FormGroupListComponent, decorators: [{
867
- type: Component,
868
- args: [{ selector: 'crispr-form-group-list', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
869
- MatButtonModule,
870
- MatIconModule,
871
- FieldContainerComponent,
872
- ReactiveFormsModule,
873
- CrisprFieldDirective,
874
- CrisprDisplayFieldDirective,
875
- CrisprPipesModule,
876
- FormValidationHandlerModule
877
- ], standalone: true, template: "<crispr-field-container [config]=\"config()\" [group]=\"group()\" [formGroup]=\"group()\">\n\n <div [formArrayName]=\"config().controlName\">\n\n <!-- Don't add trackBy function, it confuses the state of the array -->\n @for (itemControl of control()?.controls; track itemControl; let i = $index; let last = $last) {\n @if (!config().displayItemComponent || i === selectedIndex || (last && selectedIndex ?? true)) {\n <!-- TODO: use content projection to allow custom item label component -->\n <div class=\"item-header\">\n <span class=\"mat-h2\"> {{ config().itemLabelBuilder ? config().itemLabelBuilder(i) : 'Item ' + (i + 1) }} </span>\n @if (i + 1 > config().minListLength) {\n <button mat-icon-button type=\"button\">\n <mat-icon (click)=\"clickDelete(i)\">delete</mat-icon>\n </button>\n }\n </div>\n <div [formGroup]=\"itemControl\">\n <!-- TODO: if chiplists didn't need to have labels mixed in with their values we could use [value]=\"control.value\" below -->\n @for (field of config().itemConfig.fields; track field) {\n <ng-container crisprField [value]=\"blockValue ? null : value && value[i] | initialControlValue : field\"\n [config]=\"field\" [group]=\"itemControl\" [testIdPrefix]=\"testId() + '[' + i + ']'\">\n </ng-container>\n }\n </div>\n } @else {\n <div class=\"display-field-container\" crisprDisplayField [component]=\"config().displayItemComponent\"\n [value]=\"itemControl.value\" [index]=\"i\">\n <button mat-icon-button (click)=\"clickEditItem(i)\">\n <mat-icon>edit</mat-icon>\n </button>\n </div>\n }\n <ng-template #display>\n <div class=\"display-field-container\" crisprDisplayField [component]=\"config().displayItemComponent\"\n [value]=\"itemControl.value\" [index]=\"i\">\n <button mat-icon-button (click)=\"clickEditItem(i)\">\n <mat-icon>edit</mat-icon>\n </button>\n </div>\n </ng-template>\n }\n </div>\n <div class=\"group-footer\">\n <button type=\"button\" class=\"add\" mat-raised-button [color]=\"config().addButtonColor\" (click)=\"clickAdd()\">\n {{config().addItemLabel || config().addButtonLabel}}\n </button>\n </div>\n\n</crispr-field-container>", styles: [".item-header{display:flex;justify-content:space-between}.group-footer{display:flex;justify-content:flex-end}.group-footer button.add{margin-bottom:16px}.display-field-container{position:relative}.display-field-container button{position:absolute;top:0;right:0}\n"] }]
878
- }] });
879
-
880
- var index$1 = /*#__PURE__*/Object.freeze({
881
- __proto__: null,
882
- FormGroupListComponent: FormGroupListComponent
883
- });
884
-
885
- class SubGroupComponent extends CrisprControlComponent {
886
- ngOnInit() {
887
- super.ngOnInit();
888
- }
889
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: SubGroupComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
890
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.6", type: SubGroupComponent, isStandalone: false, selector: "crispr-sub-group", usesInheritance: true, ngImport: i0, template: "<crispr-field-container [config]=\"config()\" [group]=\"group()\">\n @for (fieldConfig of config().fields; track fieldConfig) {\n <ng-container crisprField [value]=\"value | initialControlValue : fieldConfig\" [config]=\"fieldConfig\"\n [group]=\"control()\" [testIdPrefix]=\"testId()\">\n </ng-container>\n }\n</crispr-field-container>", styles: [""], dependencies: [{ kind: "directive", type: CrisprFieldDirective, selector: "[crisprField]", inputs: ["config", "group", "testIdPrefix", "value"] }, { kind: "component", type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { kind: "pipe", type: InitialControlValuePipe, name: "initialControlValue" }], preserveWhitespaces: true }); }
891
- }
892
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: SubGroupComponent, decorators: [{
893
- type: Component,
894
- args: [{ selector: 'crispr-sub-group', standalone: false, template: "<crispr-field-container [config]=\"config()\" [group]=\"group()\">\n @for (fieldConfig of config().fields; track fieldConfig) {\n <ng-container crisprField [value]=\"value | initialControlValue : fieldConfig\" [config]=\"fieldConfig\"\n [group]=\"control()\" [testIdPrefix]=\"testId()\">\n </ng-container>\n }\n</crispr-field-container>" }]
895
- }] });
896
-
897
- class SubGroupModule {
898
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: SubGroupModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
899
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.6", ngImport: i0, type: SubGroupModule, declarations: [SubGroupComponent], imports: [CommonModule,
900
- CrisprFieldDirective,
901
- FieldContainerComponent,
902
- CrisprPipesModule,
903
- // TODO: Does this need to be here?
904
- FormValidationHandlerModule], exports: [SubGroupComponent] }); }
905
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: SubGroupModule, imports: [CommonModule,
906
- FieldContainerComponent,
907
- CrisprPipesModule,
908
- // TODO: Does this need to be here?
909
- FormValidationHandlerModule] }); }
910
- }
911
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: SubGroupModule, decorators: [{
912
- type: NgModule,
913
- args: [{
914
- imports: [
915
- CommonModule,
916
- CrisprFieldDirective,
917
- FieldContainerComponent,
918
- CrisprPipesModule,
919
- // TODO: Does this need to be here?
920
- FormValidationHandlerModule
921
- ],
922
- exports: [
923
- SubGroupComponent
924
- ],
925
- declarations: [
926
- SubGroupComponent
927
- ]
928
- }]
929
- }] });
930
-
931
- var index = /*#__PURE__*/Object.freeze({
932
- __proto__: null,
933
- SubGroupComponent: SubGroupComponent,
934
- SubGroupModule: SubGroupModule
935
- });
936
-
937
- class CrisprFormsModule {
938
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprFormsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
939
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.6", ngImport: i0, type: CrisprFormsModule, imports: [CommonModule,
940
- ReactiveFormsModule,
941
- FormValidationHandlerModule,
942
- FormGroupListComponent,
943
- FieldContainerComponent,
944
- CrisprFieldDirective,
945
- CrisprDisplayFieldDirective,
946
- SubGroupModule,
947
- CrisprPipesModule,
948
- CrisprFormComponent], exports: [CrisprFormComponent, FieldContainerComponent] }); }
949
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprFormsModule, imports: [CommonModule,
950
- ReactiveFormsModule,
951
- FormValidationHandlerModule,
952
- FormGroupListComponent,
953
- FieldContainerComponent,
954
- SubGroupModule,
955
- CrisprPipesModule,
956
- CrisprFormComponent] }); }
957
- }
958
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CrisprFormsModule, decorators: [{
959
- type: NgModule,
960
- args: [{
961
- imports: [
962
- CommonModule,
963
- ReactiveFormsModule,
964
- FormValidationHandlerModule,
965
- FormGroupListComponent,
966
- FieldContainerComponent,
967
- CrisprFieldDirective,
968
- CrisprDisplayFieldDirective,
969
- SubGroupModule,
970
- CrisprPipesModule,
971
- CrisprFormComponent,
972
- ],
973
- exports: [CrisprFormComponent, FieldContainerComponent],
974
- }]
975
- }] });
976
-
977
- /**
978
- * Generated bundle index. Do not edit.
979
- */
980
-
981
- export { AbstractAutocompleteComponent, ControlType, CrisprControlComponent, CrisprDisplayFieldComponent, CrisprFieldComponent, CrisprFormComponent, CrisprFormsModule, DEFAULT_EMPTY_OPTIONS_MESSAGE, FieldContainerComponent, FileDropzoneDirective, FileUploadFieldComponent, HeadingComponent, InfoComponent, SelectedFileComponent, allowedFileExtValidator, allowedFileType, buildFormGroupFromConfig, callOptionsIfFunction, convertBytesToMb, createControlForType, filterOptionsByLabel, isControlConfig, maxFileSizeValidator, observablifyOptions, valueIn };
1
+ export { A as AbstractAutocompleteComponent, d as ControlType, a as CrisprControlComponent, g as CrisprDisplayFieldComponent, C as CrisprFieldComponent, h as CrisprFormComponent, i as CrisprFormsModule, D as DEFAULT_EMPTY_OPTIONS_MESSAGE, F as FieldContainerComponent, f as FileDropzoneDirective, j as FileUploadFieldComponent, H as HeadingComponent, I as InfoComponent, S as SelectedFileComponent, k as allowedFileExtValidator, l as allowedFileType, b as buildFormGroupFromConfig, m as callOptionsIfFunction, e as convertBytesToMb, n as createControlForType, p as filterOptionsByLabel, q as isControlConfig, r as maxFileSizeValidator, o as observablifyOptions, v as valueIn } from './tft-crispr-forms-tft-crispr-forms-Dhjn_QdV.mjs';
982
2
  //# sourceMappingURL=tft-crispr-forms.mjs.map