@yuuvis/client-framework 3.22.1 → 3.24.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.
- package/fesm2022/yuuvis-client-framework-forms.mjs +403 -19
- package/fesm2022/yuuvis-client-framework-forms.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-metadata-form.mjs +8 -6
- package/fesm2022/yuuvis-client-framework-metadata-form.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-object-form.mjs +27 -4
- package/fesm2022/yuuvis-client-framework-object-form.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-query-list.mjs +144 -69
- package/fesm2022/yuuvis-client-framework-query-list.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-smart-search.mjs +35 -3
- package/fesm2022/yuuvis-client-framework-smart-search.mjs.map +1 -1
- package/lib/assets/i18n/de.json +2 -0
- package/lib/assets/i18n/en.json +2 -0
- package/package.json +5 -5
- package/types/yuuvis-client-framework-forms.d.ts +135 -4
- package/types/yuuvis-client-framework-query-list.d.ts +20 -12
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, DestroyRef, input, signal, effect, untracked, Component, forwardRef, ChangeDetectionStrategy,
|
|
2
|
+
import { inject, DestroyRef, input, signal, effect, untracked, Component, ChangeDetectorRef, forwardRef, ChangeDetectionStrategy, ElementRef, computed, linkedSignal, viewChild, output, Input, NgModule } from '@angular/core';
|
|
3
3
|
import { takeUntilDestroyed, rxResource } from '@angular/core/rxjs-interop';
|
|
4
4
|
import * as i1$1 from '@angular/forms';
|
|
5
5
|
import { FormControl, Validators, ReactiveFormsModule, FormBuilder, NG_VALUE_ACCESSOR, NG_VALIDATORS, FormGroup, FormsModule } from '@angular/forms';
|
|
6
6
|
import { MatFormFieldControl, MatFormFieldModule } from '@angular/material/form-field';
|
|
7
7
|
import * as i1 from '@angular/material/select';
|
|
8
8
|
import { MatSelectModule } from '@angular/material/select';
|
|
9
|
-
import { SystemService, TranslateService, Classification, TranslatePipe, Situation, Utils, Operator, OperatorLabel, CatalogService, LocaleNumberPipe, FileSizePipe, IdmService, UserService, AppCacheService, FREE_TEXT_OPTION, USER_ID_REGEX, STORAGE_ROLES_KEY, SearchUtils, LocaleDatePipe, SearchService, DmsService, ObjectConfigService, DmsObject, BaseObjectTypeField, ClassificationPrefix } from '@yuuvis/client-core';
|
|
9
|
+
import { SystemService, TranslateService, Classification, TranslatePipe, Situation, ObjectFormControl, Utils, Operator, OperatorLabel, CatalogService, LocaleNumberPipe, FileSizePipe, IdmService, UserService, AppCacheService, FREE_TEXT_OPTION, USER_ID_REGEX, STORAGE_ROLES_KEY, SearchUtils, LocaleDatePipe, SearchService, DmsService, ObjectConfigService, DmsObject, BaseObjectTypeField, ClassificationPrefix } from '@yuuvis/client-core';
|
|
10
10
|
import { AbstractMatFormField, injectNgControl, FormTranslateService, DialogComponent, ScrollButtonsComponent } from '@yuuvis/client-framework/common';
|
|
11
11
|
import * as i1$3 from '@angular/common';
|
|
12
|
-
import {
|
|
12
|
+
import { CommonModule, NgClass } from '@angular/common';
|
|
13
13
|
import { MatButtonModule } from '@angular/material/button';
|
|
14
14
|
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule, MatDialog } from '@angular/material/dialog';
|
|
15
15
|
import * as i2 from '@angular/material/icon';
|
|
@@ -42,6 +42,15 @@ class FormUtils {
|
|
|
42
42
|
static getErrorState(control) {
|
|
43
43
|
return control.invalid && (control.dirty || control.touched);
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Writes the errors of a form element's inner control onto the hosting control without
|
|
47
|
+
* dropping the host's own validation result (e.g. `required` set up by the surrounding form).
|
|
48
|
+
* `host.setErrors(inner.errors)` alone would wipe those whenever the inner control is valid.
|
|
49
|
+
*/
|
|
50
|
+
static mergeInnerErrors(host, inner) {
|
|
51
|
+
const ownErrors = host.validator ? host.validator(host) : null;
|
|
52
|
+
host.setErrors(ownErrors || inner.errors ? { ...ownErrors, ...inner.errors } : null);
|
|
53
|
+
}
|
|
45
54
|
}
|
|
46
55
|
|
|
47
56
|
class CatalogComponent extends AbstractMatFormField {
|
|
@@ -152,30 +161,254 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImpo
|
|
|
152
161
|
args: [{ selector: 'yuv-catalog', imports: [MatSelectModule, ReactiveFormsModule, TranslatePipe], providers: [{ provide: MatFormFieldControl, useExisting: CatalogComponent }], template: "<mat-select [multiple]=\"multiple()\" [disabled]=\"readonly()\" [formControl]=\"formCtrl\">\n @if (!multiple() && !required) {\n <mat-option [value]=\"null\">{{ 'yuv.form.element.catalog.option.none' | translate }}</mat-option>\n }\n @for (o of _options(); track o) {\n <mat-option [value]=\"o.value\">{{ o.label }}</mat-option>\n }\n</mat-select>\n" }]
|
|
153
162
|
}], propDecorators: { readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], classifications: [{ type: i0.Input, args: [{ isSignal: true, alias: "classifications", required: false }] }], situation: [{ type: i0.Input, args: [{ isSignal: true, alias: "situation", required: false }] }] } });
|
|
154
163
|
|
|
164
|
+
const HEX_PATTERN = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
|
|
165
|
+
/**
|
|
166
|
+
* Form input for a color value. Renders a hex text input alongside a native color picker
|
|
167
|
+
* swatch; both stay in sync. The value is a hex color string (e.g. `#2A70AC`).
|
|
168
|
+
*
|
|
169
|
+
* Implements `ControlValueAccessor` so it can be used within Angular forms and Material form
|
|
170
|
+
* fields.
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* <mat-form-field>
|
|
174
|
+
* <mat-label>Primary color</mat-label>
|
|
175
|
+
* <yuv-color formControlName="primaryColor"></yuv-color>
|
|
176
|
+
* </mat-form-field>
|
|
177
|
+
*/
|
|
178
|
+
class ColorComponent extends AbstractMatFormField {
|
|
179
|
+
constructor() {
|
|
180
|
+
super(...arguments);
|
|
181
|
+
this.#dRef = inject(DestroyRef);
|
|
182
|
+
/** the color swatch (native `<input type="color">`, always a full 6-digit hex) */
|
|
183
|
+
this.colorFc = new FormControl('#000000', { nonNullable: true });
|
|
184
|
+
/** the editable hex text input (source of truth for the value) */
|
|
185
|
+
this.textFc = new FormControl(null);
|
|
186
|
+
this.ngControl = injectNgControl(this);
|
|
187
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
188
|
+
this.propagateChange = (_) => { };
|
|
189
|
+
}
|
|
190
|
+
#dRef;
|
|
191
|
+
writeValue(value) {
|
|
192
|
+
this.value = value;
|
|
193
|
+
this.textFc.setValue(value ?? null, { emitEvent: false });
|
|
194
|
+
if (value && HEX_PATTERN.test(value)) {
|
|
195
|
+
this.colorFc.setValue(value, { emitEvent: false });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
registerOnChange(fn) {
|
|
199
|
+
this.propagateChange = fn;
|
|
200
|
+
}
|
|
201
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
202
|
+
registerOnTouched() { }
|
|
203
|
+
setDisabledState(isDisabled) {
|
|
204
|
+
if (isDisabled) {
|
|
205
|
+
this.colorFc.disable();
|
|
206
|
+
this.textFc.disable();
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
this.colorFc.enable();
|
|
210
|
+
this.textFc.enable();
|
|
211
|
+
}
|
|
212
|
+
this.disabled = isDisabled;
|
|
213
|
+
}
|
|
214
|
+
ngOnInit() {
|
|
215
|
+
const validators = [(control) => this.#hexValidator(control.value)];
|
|
216
|
+
if (this.required)
|
|
217
|
+
validators.push(() => (this.value ? null : { required: true }));
|
|
218
|
+
this.textFc.setValidators(validators);
|
|
219
|
+
this.textFc.statusChanges.pipe(takeUntilDestroyed(this.#dRef)).subscribe(() => {
|
|
220
|
+
this.errorState = FormUtils.getErrorState(this.textFc);
|
|
221
|
+
this.ngControl?.control?.setErrors(this.textFc.errors);
|
|
222
|
+
});
|
|
223
|
+
// hex text drives the value; keep the swatch in sync when the text is a valid hex
|
|
224
|
+
this.textFc.valueChanges.pipe(takeUntilDestroyed(this.#dRef)).subscribe((v) => {
|
|
225
|
+
const hex = v?.trim() || null;
|
|
226
|
+
this.value = hex;
|
|
227
|
+
if (hex && HEX_PATTERN.test(hex)) {
|
|
228
|
+
this.colorFc.setValue(hex, { emitEvent: false });
|
|
229
|
+
}
|
|
230
|
+
this.propagateChange(hex);
|
|
231
|
+
});
|
|
232
|
+
// swatch changes update the hex text (which re-propagates)
|
|
233
|
+
this.colorFc.valueChanges.pipe(takeUntilDestroyed(this.#dRef)).subscribe((v) => {
|
|
234
|
+
this.textFc.setValue(v);
|
|
235
|
+
});
|
|
236
|
+
this.textFc.updateValueAndValidity();
|
|
237
|
+
}
|
|
238
|
+
ngOnDestroy() {
|
|
239
|
+
super.onNgOnDestroy();
|
|
240
|
+
}
|
|
241
|
+
#hexValidator(value) {
|
|
242
|
+
if (!value)
|
|
243
|
+
return null;
|
|
244
|
+
return HEX_PATTERN.test(value.trim()) ? null : { color: { valid: false } };
|
|
245
|
+
}
|
|
246
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ColorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
247
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.20", type: ColorComponent, isStandalone: true, selector: "yuv-color", providers: [{ provide: MatFormFieldControl, useExisting: ColorComponent }], usesInheritance: true, ngImport: i0, template: "<span class=\"yuv-color\">\n <label class=\"yuv-color__swatch\" [style.background-color]=\"colorFc.value\">\n <input type=\"color\" [formControl]=\"colorFc\" aria-hidden=\"true\" tabindex=\"-1\" />\n </label>\n <input class=\"yuv-color__hex\" type=\"text\" autocomplete=\"off\" spellcheck=\"false\" [formControl]=\"textFc\" />\n</span>\n", styles: [".yuv-color{display:inline-flex;align-items:center;gap:var(--ymt-spacing-xs);width:100%;margin-block-start:var(--ymt-spacing-xs)}.yuv-color__swatch{position:relative;flex:0 0 auto;inline-size:var(--ymt-sizing-m);block-size:var(--ymt-sizing-m);border-radius:var(--ymt-corner-xs);border:var(--ymt-outline-width) solid var(--ymt-outline-variant);overflow:hidden;cursor:pointer;outline:2px solid currentColor;outline-offset:-1px}.yuv-color__swatch input[type=color]{position:absolute;inset:0;inline-size:100%;block-size:100%;padding:0;border:none;opacity:0;cursor:pointer}.yuv-color__hex{flex:1 1 auto;min-inline-size:0;border:none;outline:none;background:transparent;color:var(--ymt-text-color);font:var(--ymt-font-body)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] }); }
|
|
248
|
+
}
|
|
249
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ColorComponent, decorators: [{
|
|
250
|
+
type: Component,
|
|
251
|
+
args: [{ selector: 'yuv-color', standalone: true, imports: [CommonModule, ReactiveFormsModule], providers: [{ provide: MatFormFieldControl, useExisting: ColorComponent }], template: "<span class=\"yuv-color\">\n <label class=\"yuv-color__swatch\" [style.background-color]=\"colorFc.value\">\n <input type=\"color\" [formControl]=\"colorFc\" aria-hidden=\"true\" tabindex=\"-1\" />\n </label>\n <input class=\"yuv-color__hex\" type=\"text\" autocomplete=\"off\" spellcheck=\"false\" [formControl]=\"textFc\" />\n</span>\n", styles: [".yuv-color{display:inline-flex;align-items:center;gap:var(--ymt-spacing-xs);width:100%;margin-block-start:var(--ymt-spacing-xs)}.yuv-color__swatch{position:relative;flex:0 0 auto;inline-size:var(--ymt-sizing-m);block-size:var(--ymt-sizing-m);border-radius:var(--ymt-corner-xs);border:var(--ymt-outline-width) solid var(--ymt-outline-variant);overflow:hidden;cursor:pointer;outline:2px solid currentColor;outline-offset:-1px}.yuv-color__swatch input[type=color]{position:absolute;inset:0;inline-size:100%;block-size:100%;padding:0;border:none;opacity:0;cursor:pointer}.yuv-color__hex{flex:1 1 auto;min-inline-size:0;border:none;outline:none;background:transparent;color:var(--ymt-text-color);font:var(--ymt-font-body)}\n"] }]
|
|
252
|
+
}] });
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* @ignore
|
|
256
|
+
* Scripting element for one cell of the table row that is being edited. Mirrors the
|
|
257
|
+
* properties form scripts know from the elements of `scope.model`, but applies changes
|
|
258
|
+
* to the controls of the row editing dialog instead of the object form.
|
|
259
|
+
*/
|
|
260
|
+
class TableRowScopeElement {
|
|
261
|
+
constructor(element, onChange) {
|
|
262
|
+
this.element = element;
|
|
263
|
+
this.onChange = onChange;
|
|
264
|
+
if (this.element['value'] === undefined) {
|
|
265
|
+
this.element['value'] = null;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Called when the user changed the cell value. Triggers the elements `onchange` callback
|
|
270
|
+
* with the element itself and the rows model (siblings), like form scripts get it for table rows.
|
|
271
|
+
*/
|
|
272
|
+
update(value, rowModel) {
|
|
273
|
+
const newValue = value === undefined || value === '' ? null : value;
|
|
274
|
+
if (JSON.stringify(this.element['value']) === JSON.stringify(newValue))
|
|
275
|
+
return;
|
|
276
|
+
this.element['value'] = newValue;
|
|
277
|
+
const onchange = this.onchange;
|
|
278
|
+
if (typeof onchange === 'function') {
|
|
279
|
+
try {
|
|
280
|
+
onchange(this, rowModel);
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
console.error(`Error in form script onchange of table column '${this.name}'`, err);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
set value(value) {
|
|
288
|
+
if (JSON.stringify(this.element['value']) === JSON.stringify(value))
|
|
289
|
+
return;
|
|
290
|
+
this.element['value'] = value;
|
|
291
|
+
this.onChange(this.name, { name: 'value', newValue: value });
|
|
292
|
+
}
|
|
293
|
+
get value() {
|
|
294
|
+
return this.element['value'];
|
|
295
|
+
}
|
|
296
|
+
set required(required) {
|
|
297
|
+
this.element['required'] = required;
|
|
298
|
+
this.onChange(this.name, { name: 'required', newValue: required });
|
|
299
|
+
}
|
|
300
|
+
get required() {
|
|
301
|
+
return !!this.element['required'];
|
|
302
|
+
}
|
|
303
|
+
set readonly(readonly) {
|
|
304
|
+
this.element['readonly'] = readonly;
|
|
305
|
+
this.onChange(this.name, { name: 'readonly', newValue: readonly });
|
|
306
|
+
}
|
|
307
|
+
get readonly() {
|
|
308
|
+
return !!this.element['readonly'];
|
|
309
|
+
}
|
|
310
|
+
set error(error) {
|
|
311
|
+
this.element['error'] = error;
|
|
312
|
+
this.onChange(this.name, { name: 'error', newValue: error });
|
|
313
|
+
}
|
|
314
|
+
get error() {
|
|
315
|
+
return this.element['error'] || null;
|
|
316
|
+
}
|
|
317
|
+
set onchange(onchange) {
|
|
318
|
+
this.element['onchange'] = onchange;
|
|
319
|
+
}
|
|
320
|
+
get onchange() {
|
|
321
|
+
return this.element['onchange'] || null;
|
|
322
|
+
}
|
|
323
|
+
get name() {
|
|
324
|
+
return this.element.name;
|
|
325
|
+
}
|
|
326
|
+
get label() {
|
|
327
|
+
return this.element['label'];
|
|
328
|
+
}
|
|
329
|
+
get description() {
|
|
330
|
+
return this.element['description'];
|
|
331
|
+
}
|
|
332
|
+
get type() {
|
|
333
|
+
return this.element['type'];
|
|
334
|
+
}
|
|
335
|
+
get classifications() {
|
|
336
|
+
return this.element['classifications'];
|
|
337
|
+
}
|
|
338
|
+
get scale() {
|
|
339
|
+
return this.element['scale'];
|
|
340
|
+
}
|
|
341
|
+
get precision() {
|
|
342
|
+
return this.element['precision'];
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
155
346
|
class EditTableDataComponent {
|
|
156
347
|
constructor() {
|
|
157
348
|
this.#fb = inject(FormBuilder);
|
|
158
349
|
this.#system = inject(SystemService);
|
|
159
350
|
this.#errorMessage = inject(FormTranslateService);
|
|
351
|
+
this.#destroyRef = inject(DestroyRef);
|
|
352
|
+
this.#cdRef = inject(ChangeDetectorRef);
|
|
160
353
|
this.#dialogData = inject(MAT_DIALOG_DATA);
|
|
161
354
|
this.#dialogRef = inject((MatDialogRef));
|
|
162
355
|
this.errorMessage = signal(null, ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
|
|
163
356
|
this.tableForm = this.#fb.group({});
|
|
164
357
|
this.isInnerTableForm = input(true, ...(ngDevMode ? [{ debugName: "isInnerTableForm" }] : /* istanbul ignore next */ []));
|
|
165
358
|
this.formElement = this.#dialogData.formElement || {};
|
|
166
|
-
this.columns = (this.formElement['elements'] || []).map((c) => ({
|
|
359
|
+
this.columns = signal((this.formElement['elements'] || []).map((c) => ({
|
|
167
360
|
...c,
|
|
168
361
|
propertyType: c.type,
|
|
169
362
|
_internalType: this.#system.getInternalFormElementType(c.type, c.classifications, c.catalog)
|
|
170
|
-
}));
|
|
363
|
+
})), ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
171
364
|
this.#elementData = this.#dialogData.elementData || {};
|
|
172
365
|
this.situation = this.#dialogData.situation || Situation.EDIT;
|
|
173
366
|
this.header = this.#dialogData.label || '';
|
|
174
367
|
this.adding = this.#dialogData.adding;
|
|
368
|
+
// may be disabled by the tables 'onrowedit' form script callback
|
|
369
|
+
this.saveEnabled = signal(true, ...(ngDevMode ? [{ debugName: "saveEnabled" }] : /* istanbul ignore next */ []));
|
|
370
|
+
this.#onRowScriptingChange = (name, change) => {
|
|
371
|
+
const control = this.tableForm.get(name);
|
|
372
|
+
if (!control)
|
|
373
|
+
return;
|
|
374
|
+
switch (change.name) {
|
|
375
|
+
case 'value': {
|
|
376
|
+
control.setValue(change.newValue);
|
|
377
|
+
control.markAsDirty();
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
case 'required': {
|
|
381
|
+
this.#updateColumn(control, { required: !!change.newValue });
|
|
382
|
+
control.setValidators(this.#getValidators(control._eoFormElement));
|
|
383
|
+
control.markAsTouched();
|
|
384
|
+
control.updateValueAndValidity();
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
case 'readonly': {
|
|
388
|
+
this.#updateColumn(control, { readonly: !!change.newValue });
|
|
389
|
+
if (change.newValue) {
|
|
390
|
+
control.disable();
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
control.enable();
|
|
394
|
+
}
|
|
395
|
+
break;
|
|
396
|
+
}
|
|
397
|
+
case 'error': {
|
|
398
|
+
control._eoFormElement.error = change.newValue;
|
|
399
|
+
control.markAsTouched();
|
|
400
|
+
control.updateValueAndValidity();
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
this.#cdRef.markForCheck();
|
|
405
|
+
};
|
|
175
406
|
}
|
|
176
407
|
#fb;
|
|
177
408
|
#system;
|
|
178
409
|
#errorMessage;
|
|
410
|
+
#destroyRef;
|
|
411
|
+
#cdRef;
|
|
179
412
|
#dialogData;
|
|
180
413
|
#dialogRef;
|
|
181
414
|
#elementData;
|
|
@@ -185,16 +418,32 @@ class EditTableDataComponent {
|
|
|
185
418
|
submit() {
|
|
186
419
|
const data = this.tableForm.getRawValue();
|
|
187
420
|
Object.keys(data).forEach((key) => (data[key] === '' || data[key] === undefined) && (data[key] = null));
|
|
188
|
-
if (this.tableForm.valid && this.#dialogRef)
|
|
421
|
+
if (this.tableForm.valid && this.saveEnabled() && this.#dialogRef)
|
|
189
422
|
this.#dialogRef.close(data);
|
|
190
423
|
}
|
|
191
424
|
ngOnInit() {
|
|
192
|
-
|
|
193
|
-
|
|
425
|
+
this.#initFormControls();
|
|
426
|
+
this.#initErrorMessages();
|
|
427
|
+
this.#initRowScripting();
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Adds one control per table column to the row form and fills it with the data of the row being edited.
|
|
431
|
+
*/
|
|
432
|
+
#initFormControls() {
|
|
433
|
+
this.columns().forEach((column) => {
|
|
434
|
+
const control = new ObjectFormControl({ value: '', disabled: column.readonly });
|
|
435
|
+
control._eoFormElement = column;
|
|
436
|
+
control.setValidators(this.#getValidators(column));
|
|
437
|
+
this.tableForm.addControl(column.name, control);
|
|
194
438
|
});
|
|
195
439
|
this.tableForm.setValidators(this.#globalErrorValidator());
|
|
196
440
|
this.#elementData && this.tableForm.patchValue(this.#elementData);
|
|
197
|
-
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Keeps the error messages shown by the dialog in sync with the errors of the row form.
|
|
444
|
+
*/
|
|
445
|
+
#initErrorMessages() {
|
|
446
|
+
this.tableForm.valueChanges.subscribe(() => {
|
|
198
447
|
this.errorMessage.set(this.tableForm.errors
|
|
199
448
|
? Object.keys(this.tableForm.errors).map((key) => this.tableForm.errors && this.tableForm.errors[key]
|
|
200
449
|
? Object.keys(this.tableForm.errors[key]).map((k) => ({
|
|
@@ -204,6 +453,57 @@ class EditTableDataComponent {
|
|
|
204
453
|
: null);
|
|
205
454
|
});
|
|
206
455
|
}
|
|
456
|
+
/**
|
|
457
|
+
* Runs the 'onrowedit' callback the table form element provides (see `TableRowEditSupport`),
|
|
458
|
+
* e.g. registered by a form script. The callback gets the table element and a 'row' object
|
|
459
|
+
* whose model provides access to the cells of the row being edited. Changes applied to the
|
|
460
|
+
* row model are reflected by the dialog immediately and are discarded once it is closed.
|
|
461
|
+
*/
|
|
462
|
+
#initRowScripting() {
|
|
463
|
+
const rowEdit = this.#dialogData.rowEdit;
|
|
464
|
+
if (!rowEdit)
|
|
465
|
+
return;
|
|
466
|
+
const model = {};
|
|
467
|
+
this.columns().forEach((column) => {
|
|
468
|
+
const value = this.tableForm.get(column.name)?.value;
|
|
469
|
+
const element = { ...column, value: value === '' ? null : value };
|
|
470
|
+
model[column.name] = new TableRowScopeElement(element, this.#onRowScriptingChange);
|
|
471
|
+
});
|
|
472
|
+
const row = {
|
|
473
|
+
index: rowEdit.index,
|
|
474
|
+
persisted: rowEdit.persisted,
|
|
475
|
+
saveEnabled: true,
|
|
476
|
+
model
|
|
477
|
+
};
|
|
478
|
+
try {
|
|
479
|
+
rowEdit.callback(rowEdit.table, row);
|
|
480
|
+
}
|
|
481
|
+
catch (err) {
|
|
482
|
+
console.error(`Error in form script onrowedit of table '${this.formElement['name']}'`, err);
|
|
483
|
+
}
|
|
484
|
+
// row properties are only evaluated synchronously
|
|
485
|
+
this.saveEnabled.set(row.saveEnabled !== false);
|
|
486
|
+
// subscribe after running the callback, so values set by onrowedit won't trigger onchange handlers
|
|
487
|
+
Object.keys(model).forEach((name) => this.tableForm
|
|
488
|
+
.get(name)
|
|
489
|
+
?.valueChanges.pipe(takeUntilDestroyed(this.#destroyRef))
|
|
490
|
+
.subscribe((value) => model[name].update(value, model)));
|
|
491
|
+
}
|
|
492
|
+
#onRowScriptingChange;
|
|
493
|
+
// replace the column so the form field picks up the changed properties
|
|
494
|
+
#updateColumn(control, patch) {
|
|
495
|
+
const column = { ...control._eoFormElement, ...patch };
|
|
496
|
+
control._eoFormElement = column;
|
|
497
|
+
this.columns.update((columns) => columns.map((col) => (col.name === column.name ? column : col)));
|
|
498
|
+
}
|
|
499
|
+
#getValidators(column) {
|
|
500
|
+
// errors set by form scripts (rendered by the form field using the 'eoformScript' key)
|
|
501
|
+
const scriptError = (control) => control._eoFormElement?.error ? { eoformScript: { valid: false } } : null;
|
|
502
|
+
const validators = [scriptError];
|
|
503
|
+
if (column.required)
|
|
504
|
+
validators.push(Validators.required);
|
|
505
|
+
return validators;
|
|
506
|
+
}
|
|
207
507
|
#globalErrorValidator() {
|
|
208
508
|
return (control) => {
|
|
209
509
|
const formGroup = control;
|
|
@@ -234,7 +534,7 @@ class EditTableDataComponent {
|
|
|
234
534
|
useExisting: forwardRef(() => EditTableDataComponent),
|
|
235
535
|
multi: true
|
|
236
536
|
}
|
|
237
|
-
], ngImport: i0, template: "<yuv-dialog [headertitle]=\"(adding ? 'yuv.form.element.data.grid.add.headline' : 'yuv.form.element.data.grid.edit.headline') | translate: { headline: header }\">\n <main>\n <div [formGroup]=\"tableForm\">\n <div class=\"fields\">\n @for (element of columns; track
|
|
537
|
+
], ngImport: i0, template: "<yuv-dialog [headertitle]=\"(adding ? 'yuv.form.element.data.grid.add.headline' : 'yuv.form.element.data.grid.edit.headline') | translate: { headline: header }\">\n <main>\n <div [formGroup]=\"tableForm\">\n <div class=\"fields\">\n @for (element of columns(); track element.name) {\n <div [attr.data-name]=\"element.name\" class=\"form-field\">\n <yuv-metadata-form-field [field]=\"element\" [formControlName]=\"element.name\" [situation]=\"situation\"></yuv-metadata-form-field>\n </div>\n }\n </div>\n </div>\n </main>\n\n <footer>\n <button ymtButton=\"secondary\" (click)=\"cancel()\">{{ 'yuv.form.element.data.grid.edit.cancel' | translate }}</button>\n <button ymtButton=\"primary\" (click)=\"submit()\" [disabled]=\"!tableForm.dirty || !tableForm.valid || !saveEnabled()\">\n @if (adding) {\n {{ 'yuv.form.element.data.grid.edit.add' | translate }}\n } @else {\n {{ 'yuv.object-metadata.button.save' | translate }}\n }\n </button>\n </footer>\n</yuv-dialog>\n", styles: [":host .fields{padding:var(--ymt-spacing-m)}:host .fields .form-field:not(:last-child){margin-block-end:var(--ymt-spacing-s)}:host .err-msg{font:var(--ymt-font-body-subtle);color:var(--ymt-danger);padding:var(--ymt-spacing-2xs) 0;border:0}\n"], dependencies: [{ 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: "component", type: DialogComponent, selector: "yuv-dialog", inputs: ["headertitle", "headertitel"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: MetadataFormFieldComponent, selector: "yuv-metadata-form-field", inputs: ["formChangedSubject", "field", "variant", "situation"] }, { kind: "directive", type: YmtButtonDirective, selector: "button[ymtButton], a[ymtButton]", inputs: ["ymtButton", "disabled", "aria-disabled", "disableRipple", "disabledInteractive", "button-size"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
238
538
|
}
|
|
239
539
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: EditTableDataComponent, decorators: [{
|
|
240
540
|
type: Component,
|
|
@@ -253,7 +553,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImpo
|
|
|
253
553
|
useExisting: forwardRef(() => EditTableDataComponent),
|
|
254
554
|
multi: true
|
|
255
555
|
}
|
|
256
|
-
], template: "<yuv-dialog [headertitle]=\"(adding ? 'yuv.form.element.data.grid.add.headline' : 'yuv.form.element.data.grid.edit.headline') | translate: { headline: header }\">\n <main>\n <div [formGroup]=\"tableForm\">\n <div class=\"fields\">\n @for (element of columns; track
|
|
556
|
+
], template: "<yuv-dialog [headertitle]=\"(adding ? 'yuv.form.element.data.grid.add.headline' : 'yuv.form.element.data.grid.edit.headline') | translate: { headline: header }\">\n <main>\n <div [formGroup]=\"tableForm\">\n <div class=\"fields\">\n @for (element of columns(); track element.name) {\n <div [attr.data-name]=\"element.name\" class=\"form-field\">\n <yuv-metadata-form-field [field]=\"element\" [formControlName]=\"element.name\" [situation]=\"situation\"></yuv-metadata-form-field>\n </div>\n }\n </div>\n </div>\n </main>\n\n <footer>\n <button ymtButton=\"secondary\" (click)=\"cancel()\">{{ 'yuv.form.element.data.grid.edit.cancel' | translate }}</button>\n <button ymtButton=\"primary\" (click)=\"submit()\" [disabled]=\"!tableForm.dirty || !tableForm.valid || !saveEnabled()\">\n @if (adding) {\n {{ 'yuv.form.element.data.grid.edit.add' | translate }}\n } @else {\n {{ 'yuv.object-metadata.button.save' | translate }}\n }\n </button>\n </footer>\n</yuv-dialog>\n", styles: [":host .fields{padding:var(--ymt-spacing-m)}:host .fields .form-field:not(:last-child){margin-block-end:var(--ymt-spacing-s)}:host .err-msg{font:var(--ymt-font-body-subtle);color:var(--ymt-danger);padding:var(--ymt-spacing-2xs) 0;border:0}\n"] }]
|
|
257
557
|
}], propDecorators: { isInnerTableForm: [{ type: i0.Input, args: [{ isSignal: true, alias: "isInnerTableForm", required: false }] }] } });
|
|
258
558
|
|
|
259
559
|
var DataGridSizeType;
|
|
@@ -265,6 +565,7 @@ var DataGridSizeType;
|
|
|
265
565
|
DataGridSizeType["AUTO"] = "auto";
|
|
266
566
|
})(DataGridSizeType || (DataGridSizeType = {}));
|
|
267
567
|
|
|
568
|
+
const isRowObject = (row) => typeof row === 'object' && row !== null;
|
|
268
569
|
const MATERIAL = [MatMenuModule, MatMenuTrigger, MatIconModule, MatButtonModule, MatTableModule, MatTooltipModule];
|
|
269
570
|
class DataGridComponent {
|
|
270
571
|
constructor() {
|
|
@@ -290,6 +591,12 @@ class DataGridComponent {
|
|
|
290
591
|
: formElement && formElement['label'];
|
|
291
592
|
}, ...(ngDevMode ? [{ debugName: "tableLabel" }] : /* istanbul ignore next */ []));
|
|
292
593
|
this.selectedRow = signal(null, ...(ngDevMode ? [{ debugName: "selectedRow" }] : /* istanbul ignore next */ []));
|
|
594
|
+
// Rows that are persisted, i.e. not added while the current form is being edited ('row.persisted'
|
|
595
|
+
// of the 'onrowedit' callback). Rows are tracked by identity and carried over by value whenever
|
|
596
|
+
// they get recreated (e.g. by writeValue), so identical rows can't be told apart.
|
|
597
|
+
this.#persistedRows = new WeakSet();
|
|
598
|
+
// serialized rows the current form element has been loaded with
|
|
599
|
+
this.#loadedRows = [];
|
|
293
600
|
this.isRequired = false;
|
|
294
601
|
this.isInvalid = false;
|
|
295
602
|
this.icons = {
|
|
@@ -314,7 +621,12 @@ class DataGridComponent {
|
|
|
314
621
|
const data = this.#toRowObjects(formElement ? formElement['value'] || [] : [], elements);
|
|
315
622
|
// rendering only — the value already lives in the form model, so a (re)bind
|
|
316
623
|
// of the formElement input must never propagate back or dirty the control
|
|
317
|
-
untracked(() =>
|
|
624
|
+
untracked(() => {
|
|
625
|
+
if (!formElement)
|
|
626
|
+
return;
|
|
627
|
+
this.#resetPersistedRows(data);
|
|
628
|
+
this.#updateTable(elements, data);
|
|
629
|
+
});
|
|
318
630
|
}, ...(ngDevMode ? [{ debugName: "#loadData" }] : /* istanbul ignore next */ []));
|
|
319
631
|
this.propagateChange = () => { };
|
|
320
632
|
this.onTouched = () => { };
|
|
@@ -322,6 +634,12 @@ class DataGridComponent {
|
|
|
322
634
|
#dialog;
|
|
323
635
|
#systemService;
|
|
324
636
|
#cdRef;
|
|
637
|
+
// Rows that are persisted, i.e. not added while the current form is being edited ('row.persisted'
|
|
638
|
+
// of the 'onrowedit' callback). Rows are tracked by identity and carried over by value whenever
|
|
639
|
+
// they get recreated (e.g. by writeValue), so identical rows can't be told apart.
|
|
640
|
+
#persistedRows;
|
|
641
|
+
// serialized rows the current form element has been loaded with
|
|
642
|
+
#loadedRows;
|
|
325
643
|
#loadData;
|
|
326
644
|
// if the form element is created from the ObjectTypeField it contains 'columnDefinitions' instead of 'elements'
|
|
327
645
|
// therefore we need to map them here for proper table rendering
|
|
@@ -353,7 +671,7 @@ class DataGridComponent {
|
|
|
353
671
|
return row;
|
|
354
672
|
});
|
|
355
673
|
}
|
|
356
|
-
#openEditOverlay(elementData, adding = false) {
|
|
674
|
+
#openEditOverlay(elementData, adding = false, rowIndex = -1, persisted = false) {
|
|
357
675
|
return this.#dialog
|
|
358
676
|
.open(EditTableDataComponent, {
|
|
359
677
|
minWidth: '25%',
|
|
@@ -364,7 +682,8 @@ class DataGridComponent {
|
|
|
364
682
|
elementData,
|
|
365
683
|
situation: this.situation(),
|
|
366
684
|
adding,
|
|
367
|
-
label: this.tableLabel()
|
|
685
|
+
label: this.tableLabel(),
|
|
686
|
+
rowEdit: this.#rowEditContext(rowIndex, persisted)
|
|
368
687
|
}
|
|
369
688
|
})
|
|
370
689
|
.afterClosed()
|
|
@@ -377,8 +696,13 @@ class DataGridComponent {
|
|
|
377
696
|
if (this.readonly())
|
|
378
697
|
return;
|
|
379
698
|
this.selectedRow.set(element);
|
|
380
|
-
this.#
|
|
699
|
+
const rowIndex = this.#rowIndex(element);
|
|
700
|
+
const persisted = isRowObject(element) && this.#persistedRows.has(element);
|
|
701
|
+
this.#openEditOverlay(element, false, rowIndex, persisted).subscribe((result) => {
|
|
381
702
|
if (result) {
|
|
703
|
+
// an edited row keeps its persisted state
|
|
704
|
+
if (persisted)
|
|
705
|
+
this.#persistedRows.add(result);
|
|
382
706
|
const updatedData = this.dataSource().map((item) => JSON.stringify(item) === JSON.stringify(element) ? result : item);
|
|
383
707
|
const formElement = this.mappedFormElement();
|
|
384
708
|
if (formElement) {
|
|
@@ -403,6 +727,43 @@ class DataGridComponent {
|
|
|
403
727
|
}
|
|
404
728
|
});
|
|
405
729
|
}
|
|
730
|
+
// context for the row editing dialog, only if the table form element provides an 'onrowedit' callback
|
|
731
|
+
#rowEditContext(index, persisted) {
|
|
732
|
+
const formElement = this.mappedFormElement();
|
|
733
|
+
const callback = formElement?.onrowedit;
|
|
734
|
+
if (typeof callback !== 'function')
|
|
735
|
+
return undefined;
|
|
736
|
+
const resolve = formElement?.resolveRowEditTable;
|
|
737
|
+
const table = typeof resolve === 'function' ? resolve() : undefined;
|
|
738
|
+
return { callback, table: table ?? formElement, index, persisted };
|
|
739
|
+
}
|
|
740
|
+
// rows the form element is loaded with are persisted, unless the form is about to create a new object
|
|
741
|
+
#resetPersistedRows(rows) {
|
|
742
|
+
const persisted = this.situation() === Situation.CREATE ? [] : rows.filter(isRowObject);
|
|
743
|
+
this.#persistedRows = new WeakSet(persisted);
|
|
744
|
+
this.#loadedRows = persisted.map((row) => JSON.stringify(row));
|
|
745
|
+
}
|
|
746
|
+
// rows got recreated: carry over the persisted state of the previous (or the loaded) rows by value
|
|
747
|
+
#carryOverPersistedRows(previous, rows) {
|
|
748
|
+
const candidates = [
|
|
749
|
+
...previous.filter((row) => isRowObject(row) && this.#persistedRows.has(row)).map((row) => JSON.stringify(row)),
|
|
750
|
+
...this.#loadedRows
|
|
751
|
+
];
|
|
752
|
+
rows.forEach((row) => {
|
|
753
|
+
if (!isRowObject(row) || this.#persistedRows.has(row))
|
|
754
|
+
return;
|
|
755
|
+
const idx = candidates.indexOf(JSON.stringify(row));
|
|
756
|
+
if (idx > -1) {
|
|
757
|
+
candidates.splice(idx, 1);
|
|
758
|
+
this.#persistedRows.add(row);
|
|
759
|
+
}
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
#rowIndex(element) {
|
|
763
|
+
const rows = this.dataSource();
|
|
764
|
+
const index = rows.indexOf(element);
|
|
765
|
+
return index > -1 ? index : rows.findIndex((item) => JSON.stringify(item) === JSON.stringify(element));
|
|
766
|
+
}
|
|
406
767
|
removeRow(element) {
|
|
407
768
|
const updatedData = this.dataSource().filter((item) => JSON.stringify(item) !== JSON.stringify(element));
|
|
408
769
|
const formElement = this.mappedFormElement();
|
|
@@ -454,7 +815,9 @@ class DataGridComponent {
|
|
|
454
815
|
*/
|
|
455
816
|
writeValue(obj) {
|
|
456
817
|
const elements = this.#resolveElements(this.formElement());
|
|
457
|
-
|
|
818
|
+
const rows = this.#toRowObjects(Array.isArray(obj) ? obj : [], elements);
|
|
819
|
+
this.#carryOverPersistedRows(this.dataSource(), rows);
|
|
820
|
+
this.#updateTable(elements, rows);
|
|
458
821
|
}
|
|
459
822
|
registerOnChange(fn) {
|
|
460
823
|
this.propagateChange = fn;
|
|
@@ -535,6 +898,7 @@ class DatetimeComponent extends AbstractMatFormField {
|
|
|
535
898
|
this.pickerCmp = viewChild.required(DatepickerComponent);
|
|
536
899
|
this.ngControl = injectNgControl(this);
|
|
537
900
|
this.fc = new FormControl(null);
|
|
901
|
+
this.#hostControl = null;
|
|
538
902
|
this._locale = signal(this.translate.getCurrentLang(), ...(ngDevMode ? [{ debugName: "_locale" }] : /* istanbul ignore next */ []));
|
|
539
903
|
this.locale = input(this.translate.getCurrentLang(), ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
|
|
540
904
|
this.#localeEffect = effect(() => {
|
|
@@ -560,6 +924,8 @@ class DatetimeComponent extends AbstractMatFormField {
|
|
|
560
924
|
this.propagateChange = (_) => { };
|
|
561
925
|
}
|
|
562
926
|
#dRef;
|
|
927
|
+
#hostControl;
|
|
928
|
+
#hostControlSub;
|
|
563
929
|
#localeEffect;
|
|
564
930
|
openCalendar() {
|
|
565
931
|
this.pickerCmp().openCalendar();
|
|
@@ -603,11 +969,29 @@ class DatetimeComponent extends AbstractMatFormField {
|
|
|
603
969
|
this.translate.onLangChange.subscribe((evt) => this._locale.set(evt.lang));
|
|
604
970
|
this.fc.valueChanges.pipe(takeUntilDestroyed(this.#dRef)).subscribe((value) => this.onValueChange(value));
|
|
605
971
|
this.fc.statusChanges.pipe(takeUntilDestroyed(this.#dRef)).subscribe(() => {
|
|
606
|
-
this.errorState = FormUtils.getErrorState(this.fc);
|
|
607
972
|
if (this.ngControl?.control) {
|
|
608
|
-
this.ngControl.control
|
|
973
|
+
FormUtils.mergeInnerErrors(this.ngControl.control, this.fc);
|
|
609
974
|
}
|
|
975
|
+
this.#updateErrorState();
|
|
610
976
|
});
|
|
977
|
+
this.#dRef.onDestroy(() => this.#hostControlSub?.unsubscribe());
|
|
978
|
+
}
|
|
979
|
+
ngDoCheck() {
|
|
980
|
+
// With `formControlName` the host control is only resolved after this component's `ngOnInit`,
|
|
981
|
+
// and a `[formControl]` binding may swap it later, so (re)attach whenever it changes.
|
|
982
|
+
const host = this.ngControl?.control ?? null;
|
|
983
|
+
if (host && host !== this.#hostControl) {
|
|
984
|
+
this.#hostControl = host;
|
|
985
|
+
this.#hostControlSub?.unsubscribe();
|
|
986
|
+
// The host carries the validation of the surrounding form (e.g. `required`) and may be
|
|
987
|
+
// touched from outside (form scripts, submit handling), so reflect it in the error state.
|
|
988
|
+
this.#hostControlSub = host.events.subscribe(() => this.#updateErrorState());
|
|
989
|
+
this.#updateErrorState();
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
#updateErrorState() {
|
|
993
|
+
const host = this.ngControl?.control;
|
|
994
|
+
this.errorState = FormUtils.getErrorState(this.fc) || (!!host && FormUtils.getErrorState(host));
|
|
611
995
|
}
|
|
612
996
|
#setLabels() {
|
|
613
997
|
this.labels = {
|
|
@@ -2903,5 +3287,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImpo
|
|
|
2903
3287
|
* Generated bundle index. Do not edit.
|
|
2904
3288
|
*/
|
|
2905
3289
|
|
|
2906
|
-
export { CatalogComponent, DataGridComponent, DatetimeComponent, DatetimeRangeComponent, DynamicCatalogComponent, FormUtils, I18nCatalogComponent, NumberComponent, NumberRangeComponent, OrganizationComponent, OrganizationSetComponent, RangeSelectDateComponent, RangeSelectFilesizeComponent, ReferenceComponent, StringComponent, YuvFormsModule };
|
|
3290
|
+
export { CatalogComponent, ColorComponent, DataGridComponent, DatetimeComponent, DatetimeRangeComponent, DynamicCatalogComponent, FormUtils, I18nCatalogComponent, NumberComponent, NumberRangeComponent, OrganizationComponent, OrganizationSetComponent, RangeSelectDateComponent, RangeSelectFilesizeComponent, ReferenceComponent, StringComponent, YuvFormsModule };
|
|
2907
3291
|
//# sourceMappingURL=yuuvis-client-framework-forms.mjs.map
|