@mosaicoo/form-angular 0.3.0 → 0.4.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/mosaicoo-form-angular-designer.mjs +110 -11
- package/fesm2022/mosaicoo-form-angular-designer.mjs.map +1 -1
- package/fesm2022/mosaicoo-form-angular.mjs +348 -90
- package/fesm2022/mosaicoo-form-angular.mjs.map +1 -1
- package/package.json +2 -2
- package/types/mosaicoo-form-angular-designer.d.ts +8 -1
- package/types/mosaicoo-form-angular.d.ts +132 -66
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NgComponentOutlet, DOCUMENT } from '@angular/common';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { InjectionToken, makeEnvironmentProviders, input, signal, inject, effect, untracked, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, output } from '@angular/core';
|
|
4
|
-
import { importForm, createLegacyImporter, createFormEngine, collectInputs } from '@mosaicoo/form-core';
|
|
3
|
+
import { InjectionToken, makeEnvironmentProviders, input, signal, inject, ChangeDetectorRef, effect, untracked, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, output } from '@angular/core';
|
|
4
|
+
import { maskValue, importForm, createLegacyImporter, createFormEngine, collectInputs } from '@mosaicoo/form-core';
|
|
5
5
|
|
|
6
6
|
/** Multi-provider token: maps merge, later providers win on conflicts. */
|
|
7
7
|
const MFORM_FIELD_COMPONENTS = new InjectionToken('MFORM_FIELD_COMPONENTS');
|
|
@@ -11,6 +11,7 @@ const MFORM_FIELD_COMPONENTS = new InjectionToken('MFORM_FIELD_COMPONENTS');
|
|
|
11
11
|
* base URLs, caching). Without it, a plain `fetch` is used.
|
|
12
12
|
*/
|
|
13
13
|
const MFORM_REMOTE_FETCHER = new InjectionToken('MFORM_REMOTE_FETCHER');
|
|
14
|
+
const MFORM_UPLOAD = new InjectionToken('MFORM_UPLOAD');
|
|
14
15
|
/**
|
|
15
16
|
* Registers renderer extensions at any injector level:
|
|
16
17
|
*
|
|
@@ -33,6 +34,9 @@ function provideMosaicooForm(config) {
|
|
|
33
34
|
if (config.remoteFetcher) {
|
|
34
35
|
providers.push({ provide: MFORM_REMOTE_FETCHER, useValue: config.remoteFetcher });
|
|
35
36
|
}
|
|
37
|
+
if (config.uploadFiles) {
|
|
38
|
+
providers.push({ provide: MFORM_UPLOAD, useValue: config.uploadFiles });
|
|
39
|
+
}
|
|
36
40
|
return makeEnvironmentProviders(providers);
|
|
37
41
|
}
|
|
38
42
|
|
|
@@ -53,11 +57,36 @@ class FormNodeComponent {
|
|
|
53
57
|
bare = input(false, ...(ngDevMode ? [{ debugName: "bare" }] : /* istanbul ignore next */ []));
|
|
54
58
|
/** Host-registered providers for `optionsSource: provider` fields. */
|
|
55
59
|
providers = input({}, ...(ngDevMode ? [{ debugName: "providers" }] : /* istanbul ignore next */ []));
|
|
60
|
+
/** Rendering mode inherited from the renderer. */
|
|
61
|
+
mode = input('edit', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
|
|
62
|
+
/** Renderer-supplied refresh hook for async completions (zoneless-safe). */
|
|
63
|
+
notify = input(() => { }, ...(ngDevMode ? [{ debugName: "notify" }] : /* istanbul ignore next */ []));
|
|
56
64
|
activeTab = signal(0, ...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
|
|
57
65
|
/** DI-registered custom field components (maps merge; later wins). */
|
|
58
66
|
componentMaps = inject(MFORM_FIELD_COMPONENTS, { optional: true });
|
|
59
67
|
/** Host transport for remote options; plain fetch when absent. */
|
|
60
68
|
remoteFetcher = inject(MFORM_REMOTE_FETCHER, { optional: true });
|
|
69
|
+
/** Host-owned upload for `file` fields. */
|
|
70
|
+
uploader = inject(MFORM_UPLOAD, { optional: true });
|
|
71
|
+
/**
|
|
72
|
+
* Async resolutions (debounce timers, provider promises) finish outside
|
|
73
|
+
* any template event — explicitly schedule the refresh for zoneless apps.
|
|
74
|
+
*/
|
|
75
|
+
changeDetector = inject(ChangeDetectorRef);
|
|
76
|
+
uploading = signal(false, ...(ngDevMode ? [{ debugName: "uploading" }] : /* istanbul ignore next */ []));
|
|
77
|
+
/** Effective disabled state: mode, schema flag or calculated field. */
|
|
78
|
+
controlDisabled() {
|
|
79
|
+
return (this.mode() !== 'edit' ||
|
|
80
|
+
this.field().disabled === true ||
|
|
81
|
+
this.field().calculate !== undefined);
|
|
82
|
+
}
|
|
83
|
+
interactive() {
|
|
84
|
+
return this.mode() === 'edit';
|
|
85
|
+
}
|
|
86
|
+
pending() {
|
|
87
|
+
this.tick();
|
|
88
|
+
return this.engine().isPending(this.path());
|
|
89
|
+
}
|
|
61
90
|
/** Custom component registered for this field type, if any. */
|
|
62
91
|
customComponent() {
|
|
63
92
|
const node = this.node();
|
|
@@ -119,7 +148,11 @@ class FormNodeComponent {
|
|
|
119
148
|
if (!provider)
|
|
120
149
|
return; // no provider: static options/fallback stand
|
|
121
150
|
Promise.resolve(provider({ field: node, path, data: engine.getData(), args: source.args }))
|
|
122
|
-
.then(
|
|
151
|
+
.then((options) => {
|
|
152
|
+
apply(options);
|
|
153
|
+
this.changeDetector.markForCheck();
|
|
154
|
+
this.notify()();
|
|
155
|
+
})
|
|
123
156
|
.catch(() => { }); // provider failure keeps the static fallback
|
|
124
157
|
}
|
|
125
158
|
else {
|
|
@@ -133,6 +166,7 @@ class FormNodeComponent {
|
|
|
133
166
|
label: String(item[source.labelKey ?? 'label'] ?? item[source.valueKey ?? 'value'] ?? ''),
|
|
134
167
|
value: (item[source.valueKey ?? 'value'] ?? ''),
|
|
135
168
|
}))))
|
|
169
|
+
.then(() => this.changeDetector.markForCheck())
|
|
136
170
|
.catch(() => { });
|
|
137
171
|
}
|
|
138
172
|
});
|
|
@@ -217,7 +251,12 @@ class FormNodeComponent {
|
|
|
217
251
|
}
|
|
218
252
|
stringValue() {
|
|
219
253
|
const value = this.value();
|
|
220
|
-
|
|
254
|
+
if (value === undefined || value === null)
|
|
255
|
+
return '';
|
|
256
|
+
const mask = this.field().format?.mask;
|
|
257
|
+
if (mask && typeof value === 'string')
|
|
258
|
+
return maskValue(value, mask).masked;
|
|
259
|
+
return String(value);
|
|
221
260
|
}
|
|
222
261
|
mapValue() {
|
|
223
262
|
const value = this.value();
|
|
@@ -275,7 +314,15 @@ class FormNodeComponent {
|
|
|
275
314
|
this.engine().setValue(this.path(), value);
|
|
276
315
|
}
|
|
277
316
|
setString(event) {
|
|
278
|
-
const
|
|
317
|
+
const target = event.target;
|
|
318
|
+
const raw = target.value;
|
|
319
|
+
const mask = this.field().format?.mask;
|
|
320
|
+
if (mask) {
|
|
321
|
+
const { masked, raw: stripped } = maskValue(raw, mask);
|
|
322
|
+
target.value = masked; // the control always shows the masked shape
|
|
323
|
+
this.setValue(this.field().format?.keepMask ? masked : stripped);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
279
326
|
if (this.field().dataType === 'number') {
|
|
280
327
|
const parsed = raw === '' ? undefined : Number(raw);
|
|
281
328
|
this.setValue(parsed !== undefined && Number.isFinite(parsed) ? parsed : undefined);
|
|
@@ -296,7 +343,32 @@ class FormNodeComponent {
|
|
|
296
343
|
}
|
|
297
344
|
setFiles(event) {
|
|
298
345
|
const files = event.target.files;
|
|
299
|
-
|
|
346
|
+
const list = files ? Array.from(files) : [];
|
|
347
|
+
if (!this.uploader || list.length === 0) {
|
|
348
|
+
// no host uploader: only file names are stored
|
|
349
|
+
this.setValue(list.map((f) => f.name));
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const field = this.field();
|
|
353
|
+
const path = this.path();
|
|
354
|
+
this.uploading.set(true);
|
|
355
|
+
Promise.all(list.map((file) => this.uploader(file, { field, path })))
|
|
356
|
+
.then((refs) => this.setValue(refs))
|
|
357
|
+
.catch(() => { }) // host upload failure keeps the previous value
|
|
358
|
+
.finally(() => {
|
|
359
|
+
this.uploading.set(false);
|
|
360
|
+
this.changeDetector.markForCheck();
|
|
361
|
+
this.notify()();
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
/** Names shown under a `file` control (refs or plain names). */
|
|
365
|
+
fileNames() {
|
|
366
|
+
const value = this.value();
|
|
367
|
+
if (!Array.isArray(value))
|
|
368
|
+
return [];
|
|
369
|
+
return value.map((item) => typeof item === 'object' && item !== null
|
|
370
|
+
? String(item.name ?? '')
|
|
371
|
+
: String(item));
|
|
300
372
|
}
|
|
301
373
|
prefix() {
|
|
302
374
|
const value = this.node().props?.['prefix'];
|
|
@@ -326,7 +398,69 @@ class FormNodeComponent {
|
|
|
326
398
|
}
|
|
327
399
|
touch() {
|
|
328
400
|
this.engine().markTouched(this.path());
|
|
329
|
-
|
|
401
|
+
// Async-aware: resolves immediately for sync-only fields; pending events
|
|
402
|
+
// drive the busy indicator otherwise.
|
|
403
|
+
void this.engine().validateFieldAsync(this.path());
|
|
404
|
+
}
|
|
405
|
+
// -- reference (autocomplete) ---------------------------------------------
|
|
406
|
+
refOptions = signal([], ...(ngDevMode ? [{ debugName: "refOptions" }] : /* istanbul ignore next */ []));
|
|
407
|
+
refOpen = signal(false, ...(ngDevMode ? [{ debugName: "refOpen" }] : /* istanbul ignore next */ []));
|
|
408
|
+
refTimer = null;
|
|
409
|
+
/** Label of the chosen option (falls back to the raw value). */
|
|
410
|
+
refLabel = signal(null, ...(ngDevMode ? [{ debugName: "refLabel" }] : /* istanbul ignore next */ []));
|
|
411
|
+
refDisplay() {
|
|
412
|
+
return this.refLabel() ?? this.stringValue();
|
|
413
|
+
}
|
|
414
|
+
refSearch(event) {
|
|
415
|
+
const query = event.target.value;
|
|
416
|
+
this.refLabel.set(null);
|
|
417
|
+
if (this.refTimer)
|
|
418
|
+
clearTimeout(this.refTimer);
|
|
419
|
+
this.refTimer = setTimeout(() => this.refResolve(query), 250);
|
|
420
|
+
}
|
|
421
|
+
refResolve(query) {
|
|
422
|
+
const source = this.field().optionsSource;
|
|
423
|
+
if (!source || source.type !== 'provider') {
|
|
424
|
+
// static options filter locally
|
|
425
|
+
const filter = query.toLowerCase();
|
|
426
|
+
this.refOptions.set((this.field().options ?? []).filter((o) => o.label.toLowerCase().includes(filter)));
|
|
427
|
+
this.refOpen.set(true);
|
|
428
|
+
this.changeDetector.markForCheck();
|
|
429
|
+
this.notify()();
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
const provider = this.providers()[source.name];
|
|
433
|
+
if (!provider)
|
|
434
|
+
return;
|
|
435
|
+
Promise.resolve(provider({
|
|
436
|
+
field: this.field(),
|
|
437
|
+
path: this.path(),
|
|
438
|
+
data: this.engine().getData(),
|
|
439
|
+
args: source.args,
|
|
440
|
+
query,
|
|
441
|
+
}))
|
|
442
|
+
.then((options) => {
|
|
443
|
+
this.refOptions.set(options);
|
|
444
|
+
this.refOpen.set(true);
|
|
445
|
+
this.changeDetector.markForCheck();
|
|
446
|
+
this.notify()();
|
|
447
|
+
})
|
|
448
|
+
.catch(() => { });
|
|
449
|
+
}
|
|
450
|
+
refPick(option) {
|
|
451
|
+
this.setValue(option.value);
|
|
452
|
+
this.refLabel.set(option.label);
|
|
453
|
+
this.refOpen.set(false);
|
|
454
|
+
this.touch();
|
|
455
|
+
}
|
|
456
|
+
refBlur() {
|
|
457
|
+
// let a click on an option land before closing
|
|
458
|
+
setTimeout(() => {
|
|
459
|
+
this.refOpen.set(false);
|
|
460
|
+
this.changeDetector.markForCheck();
|
|
461
|
+
this.notify()();
|
|
462
|
+
}, 150);
|
|
463
|
+
this.touch();
|
|
330
464
|
}
|
|
331
465
|
addRow() {
|
|
332
466
|
this.engine().addRow(this.path());
|
|
@@ -335,18 +469,20 @@ class FormNodeComponent {
|
|
|
335
469
|
this.engine().removeRow(this.path(), index);
|
|
336
470
|
}
|
|
337
471
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FormNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
338
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FormNodeComponent, isStandalone: true, selector: "mform-node", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, engine: { classPropertyName: "engine", publicName: "engine", isSignal: true, isRequired: true, transformFunction: null }, tick: { classPropertyName: "tick", publicName: "tick", isSignal: true, isRequired: true, transformFunction: null }, scope: { classPropertyName: "scope", publicName: "scope", isSignal: true, isRequired: false, transformFunction: null }, bare: { classPropertyName: "bare", publicName: "bare", isSignal: true, isRequired: false, transformFunction: null }, providers: { classPropertyName: "providers", publicName: "providers", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "mform-node" }, ngImport: i0, template: `
|
|
472
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FormNodeComponent, isStandalone: true, selector: "mform-node", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, engine: { classPropertyName: "engine", publicName: "engine", isSignal: true, isRequired: true, transformFunction: null }, tick: { classPropertyName: "tick", publicName: "tick", isSignal: true, isRequired: true, transformFunction: null }, scope: { classPropertyName: "scope", publicName: "scope", isSignal: true, isRequired: false, transformFunction: null }, bare: { classPropertyName: "bare", publicName: "bare", isSignal: true, isRequired: false, transformFunction: null }, providers: { classPropertyName: "providers", publicName: "providers", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, notify: { classPropertyName: "notify", publicName: "notify", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "mform-node" }, ngImport: i0, template: `
|
|
339
473
|
@let n = node();
|
|
340
474
|
@if (visible()) {
|
|
341
475
|
@switch (n.kind) {
|
|
342
476
|
@case ('static') {
|
|
343
477
|
@if (n.type === 'button') {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
478
|
+
@if (interactive()) {
|
|
479
|
+
<button
|
|
480
|
+
class="mform-btn"
|
|
481
|
+
[type]="buttonAction() === 'submit' ? 'submit' : 'button'"
|
|
482
|
+
>
|
|
483
|
+
{{ n.label || 'Submit' }}
|
|
484
|
+
</button>
|
|
485
|
+
}
|
|
350
486
|
} @else if (n.type === 'content') {
|
|
351
487
|
<div class="mform-content" [innerHTML]="content()"></div>
|
|
352
488
|
} @else {
|
|
@@ -362,7 +498,7 @@ class FormNodeComponent {
|
|
|
362
498
|
@for (column of columns(); track $index) {
|
|
363
499
|
<div class="mform-column">
|
|
364
500
|
@for (child of column; track child.key) {
|
|
365
|
-
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [scope]="childScope()" />
|
|
501
|
+
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [mode]="mode()" [notify]="notify()" [scope]="childScope()" />
|
|
366
502
|
}
|
|
367
503
|
</div>
|
|
368
504
|
}
|
|
@@ -387,7 +523,7 @@ class FormNodeComponent {
|
|
|
387
523
|
@for (tab of container().children; track tab.key; let i = $index) {
|
|
388
524
|
@if (activeTab() === i) {
|
|
389
525
|
<div class="mform-tabpanel" role="tabpanel">
|
|
390
|
-
<mform-node [node]="tab" [engine]="engine()" [tick]="tick()" [providers]="providers()" [scope]="childScope()" [bare]="true" />
|
|
526
|
+
<mform-node [node]="tab" [engine]="engine()" [tick]="tick()" [providers]="providers()" [mode]="mode()" [notify]="notify()" [scope]="childScope()" [bare]="true" />
|
|
391
527
|
</div>
|
|
392
528
|
}
|
|
393
529
|
}
|
|
@@ -403,20 +539,24 @@ class FormNodeComponent {
|
|
|
403
539
|
<div class="mform-grid-row" role="group" [attr.aria-label]="(container().label || container().key) + ' ' + (i + 1)">
|
|
404
540
|
<div class="mform-grid-fields">
|
|
405
541
|
@for (child of container().children; track child.key) {
|
|
406
|
-
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [scope]="rowScope(i)" />
|
|
542
|
+
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [mode]="mode()" [notify]="notify()" [scope]="rowScope(i)" />
|
|
407
543
|
}
|
|
408
544
|
</div>
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
545
|
+
@if (interactive()) {
|
|
546
|
+
<button
|
|
547
|
+
type="button"
|
|
548
|
+
class="mform-row-remove"
|
|
549
|
+
(click)="removeRow(i)"
|
|
550
|
+
[attr.aria-label]="'Remove row ' + (i + 1)"
|
|
551
|
+
>
|
|
552
|
+
✕
|
|
553
|
+
</button>
|
|
554
|
+
}
|
|
417
555
|
</div>
|
|
418
556
|
}
|
|
419
|
-
|
|
557
|
+
@if (interactive()) {
|
|
558
|
+
<button type="button" class="mform-row-add" (click)="addRow()">+ Add</button>
|
|
559
|
+
}
|
|
420
560
|
</div>
|
|
421
561
|
</section>
|
|
422
562
|
}
|
|
@@ -426,14 +566,14 @@ class FormNodeComponent {
|
|
|
426
566
|
<header class="mform-panel-head">{{ container().label }}</header>
|
|
427
567
|
<div class="mform-panel-body">
|
|
428
568
|
@for (child of container().children; track child.key) {
|
|
429
|
-
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [scope]="childScope()" />
|
|
569
|
+
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [mode]="mode()" [notify]="notify()" [scope]="childScope()" />
|
|
430
570
|
}
|
|
431
571
|
</div>
|
|
432
572
|
</section>
|
|
433
573
|
} @else {
|
|
434
574
|
<div class="mform-group">
|
|
435
575
|
@for (child of container().children; track child.key) {
|
|
436
|
-
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [scope]="childScope()" />
|
|
576
|
+
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [mode]="mode()" [notify]="notify()" [scope]="childScope()" />
|
|
437
577
|
}
|
|
438
578
|
</div>
|
|
439
579
|
}
|
|
@@ -447,7 +587,7 @@ class FormNodeComponent {
|
|
|
447
587
|
[ngComponentOutletInputs]="customInputs()"
|
|
448
588
|
/>
|
|
449
589
|
} @else if (field().type !== 'hidden') {
|
|
450
|
-
<div class="mform-field" [class.has-error]="errors().length > 0">
|
|
590
|
+
<div class="mform-field" [class.has-error]="errors().length > 0" [class.is-pending]="pending()">
|
|
451
591
|
@if (field().type !== 'checkbox') {
|
|
452
592
|
<label class="mform-label" [attr.for]="controlId()">
|
|
453
593
|
{{ field().label || field().key }}
|
|
@@ -463,7 +603,7 @@ class FormNodeComponent {
|
|
|
463
603
|
[id]="controlId()"
|
|
464
604
|
[value]="stringValue()"
|
|
465
605
|
[placeholder]="field().placeholder || ''"
|
|
466
|
-
[disabled]="
|
|
606
|
+
[disabled]="controlDisabled()"
|
|
467
607
|
[attr.rows]="rowsProp()"
|
|
468
608
|
[attr.aria-required]="required() || null"
|
|
469
609
|
[attr.aria-invalid]="errors().length > 0 || null"
|
|
@@ -476,7 +616,7 @@ class FormNodeComponent {
|
|
|
476
616
|
<select
|
|
477
617
|
class="mform-control"
|
|
478
618
|
[id]="controlId()"
|
|
479
|
-
[disabled]="
|
|
619
|
+
[disabled]="controlDisabled()"
|
|
480
620
|
[attr.aria-required]="required() || null"
|
|
481
621
|
[attr.aria-invalid]="errors().length > 0 || null"
|
|
482
622
|
[attr.aria-describedby]="describedBy()"
|
|
@@ -502,7 +642,7 @@ class FormNodeComponent {
|
|
|
502
642
|
type="radio"
|
|
503
643
|
[name]="controlId()"
|
|
504
644
|
[checked]="stringValue() === '' + option.value"
|
|
505
|
-
[disabled]="
|
|
645
|
+
[disabled]="controlDisabled()"
|
|
506
646
|
(change)="setValue(option.value)"
|
|
507
647
|
(blur)="touch()"
|
|
508
648
|
/>
|
|
@@ -517,7 +657,7 @@ class FormNodeComponent {
|
|
|
517
657
|
type="checkbox"
|
|
518
658
|
[id]="controlId()"
|
|
519
659
|
[checked]="value() === true"
|
|
520
|
-
[disabled]="
|
|
660
|
+
[disabled]="controlDisabled()"
|
|
521
661
|
[attr.aria-invalid]="errors().length > 0 || null"
|
|
522
662
|
[attr.aria-describedby]="describedBy()"
|
|
523
663
|
(change)="setChecked($event)"
|
|
@@ -538,7 +678,7 @@ class FormNodeComponent {
|
|
|
538
678
|
<input
|
|
539
679
|
type="checkbox"
|
|
540
680
|
[checked]="mapValue()['' + option.value] === true"
|
|
541
|
-
[disabled]="
|
|
681
|
+
[disabled]="controlDisabled()"
|
|
542
682
|
(change)="toggleMap('' + option.value, $event)"
|
|
543
683
|
(blur)="touch()"
|
|
544
684
|
/>
|
|
@@ -564,7 +704,7 @@ class FormNodeComponent {
|
|
|
564
704
|
type="text"
|
|
565
705
|
[id]="controlId()"
|
|
566
706
|
[placeholder]="field().placeholder || ''"
|
|
567
|
-
[disabled]="
|
|
707
|
+
[disabled]="controlDisabled()"
|
|
568
708
|
[attr.aria-describedby]="describedBy()"
|
|
569
709
|
(keydown.enter)="addTag($event)"
|
|
570
710
|
(blur)="touch()"
|
|
@@ -577,11 +717,45 @@ class FormNodeComponent {
|
|
|
577
717
|
type="file"
|
|
578
718
|
multiple
|
|
579
719
|
[id]="controlId()"
|
|
580
|
-
[disabled]="
|
|
720
|
+
[disabled]="controlDisabled() || uploading()"
|
|
721
|
+
[attr.aria-busy]="uploading() || null"
|
|
581
722
|
[attr.aria-describedby]="describedBy()"
|
|
582
723
|
(change)="setFiles($event)"
|
|
583
724
|
(blur)="touch()"
|
|
584
725
|
/>
|
|
726
|
+
@if (uploading()) {
|
|
727
|
+
<div class="mform-desc" role="status">Uploading…</div>
|
|
728
|
+
}
|
|
729
|
+
@for (name of fileNames(); track $index) {
|
|
730
|
+
<div class="mform-file-name">📎 {{ name }}</div>
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
@case ('reference') {
|
|
734
|
+
<div class="mform-reference">
|
|
735
|
+
<input
|
|
736
|
+
class="mform-control"
|
|
737
|
+
type="text"
|
|
738
|
+
role="combobox"
|
|
739
|
+
[id]="controlId()"
|
|
740
|
+
[value]="refDisplay()"
|
|
741
|
+
[placeholder]="field().placeholder || ''"
|
|
742
|
+
[disabled]="controlDisabled()"
|
|
743
|
+
[attr.aria-expanded]="refOpen()"
|
|
744
|
+
[attr.aria-invalid]="errors().length > 0 || null"
|
|
745
|
+
[attr.aria-describedby]="describedBy()"
|
|
746
|
+
(input)="refSearch($event)"
|
|
747
|
+
(blur)="refBlur()"
|
|
748
|
+
/>
|
|
749
|
+
@if (refOpen() && refOptions().length > 0) {
|
|
750
|
+
<ul class="mform-ref-list" role="listbox">
|
|
751
|
+
@for (option of refOptions(); track option.value) {
|
|
752
|
+
<li role="option">
|
|
753
|
+
<button type="button" (click)="refPick(option)">{{ option.label }}</button>
|
|
754
|
+
</li>
|
|
755
|
+
}
|
|
756
|
+
</ul>
|
|
757
|
+
}
|
|
758
|
+
</div>
|
|
585
759
|
}
|
|
586
760
|
@case ('unsupported') {
|
|
587
761
|
<input
|
|
@@ -603,7 +777,7 @@ class FormNodeComponent {
|
|
|
603
777
|
[id]="controlId()"
|
|
604
778
|
[value]="stringValue()"
|
|
605
779
|
[placeholder]="field().placeholder || ''"
|
|
606
|
-
[disabled]="
|
|
780
|
+
[disabled]="controlDisabled()"
|
|
607
781
|
[attr.step]="field().type === 'currency' ? '0.01' : null"
|
|
608
782
|
[attr.inputmode]="field().type === 'currency' ? 'decimal' : null"
|
|
609
783
|
[attr.aria-required]="required() || null"
|
|
@@ -629,7 +803,7 @@ class FormNodeComponent {
|
|
|
629
803
|
}
|
|
630
804
|
}
|
|
631
805
|
}
|
|
632
|
-
`, isInline: true, dependencies: [{ kind: "component", type: FormNodeComponent, selector: "mform-node", inputs: ["node", "engine", "tick", "scope", "bare", "providers"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
806
|
+
`, isInline: true, dependencies: [{ kind: "component", type: FormNodeComponent, selector: "mform-node", inputs: ["node", "engine", "tick", "scope", "bare", "providers", "mode", "notify"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
633
807
|
}
|
|
634
808
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FormNodeComponent, decorators: [{
|
|
635
809
|
type: Component,
|
|
@@ -645,12 +819,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
645
819
|
@switch (n.kind) {
|
|
646
820
|
@case ('static') {
|
|
647
821
|
@if (n.type === 'button') {
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
822
|
+
@if (interactive()) {
|
|
823
|
+
<button
|
|
824
|
+
class="mform-btn"
|
|
825
|
+
[type]="buttonAction() === 'submit' ? 'submit' : 'button'"
|
|
826
|
+
>
|
|
827
|
+
{{ n.label || 'Submit' }}
|
|
828
|
+
</button>
|
|
829
|
+
}
|
|
654
830
|
} @else if (n.type === 'content') {
|
|
655
831
|
<div class="mform-content" [innerHTML]="content()"></div>
|
|
656
832
|
} @else {
|
|
@@ -666,7 +842,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
666
842
|
@for (column of columns(); track $index) {
|
|
667
843
|
<div class="mform-column">
|
|
668
844
|
@for (child of column; track child.key) {
|
|
669
|
-
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [scope]="childScope()" />
|
|
845
|
+
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [mode]="mode()" [notify]="notify()" [scope]="childScope()" />
|
|
670
846
|
}
|
|
671
847
|
</div>
|
|
672
848
|
}
|
|
@@ -691,7 +867,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
691
867
|
@for (tab of container().children; track tab.key; let i = $index) {
|
|
692
868
|
@if (activeTab() === i) {
|
|
693
869
|
<div class="mform-tabpanel" role="tabpanel">
|
|
694
|
-
<mform-node [node]="tab" [engine]="engine()" [tick]="tick()" [providers]="providers()" [scope]="childScope()" [bare]="true" />
|
|
870
|
+
<mform-node [node]="tab" [engine]="engine()" [tick]="tick()" [providers]="providers()" [mode]="mode()" [notify]="notify()" [scope]="childScope()" [bare]="true" />
|
|
695
871
|
</div>
|
|
696
872
|
}
|
|
697
873
|
}
|
|
@@ -707,20 +883,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
707
883
|
<div class="mform-grid-row" role="group" [attr.aria-label]="(container().label || container().key) + ' ' + (i + 1)">
|
|
708
884
|
<div class="mform-grid-fields">
|
|
709
885
|
@for (child of container().children; track child.key) {
|
|
710
|
-
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [scope]="rowScope(i)" />
|
|
886
|
+
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [mode]="mode()" [notify]="notify()" [scope]="rowScope(i)" />
|
|
711
887
|
}
|
|
712
888
|
</div>
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
889
|
+
@if (interactive()) {
|
|
890
|
+
<button
|
|
891
|
+
type="button"
|
|
892
|
+
class="mform-row-remove"
|
|
893
|
+
(click)="removeRow(i)"
|
|
894
|
+
[attr.aria-label]="'Remove row ' + (i + 1)"
|
|
895
|
+
>
|
|
896
|
+
✕
|
|
897
|
+
</button>
|
|
898
|
+
}
|
|
721
899
|
</div>
|
|
722
900
|
}
|
|
723
|
-
|
|
901
|
+
@if (interactive()) {
|
|
902
|
+
<button type="button" class="mform-row-add" (click)="addRow()">+ Add</button>
|
|
903
|
+
}
|
|
724
904
|
</div>
|
|
725
905
|
</section>
|
|
726
906
|
}
|
|
@@ -730,14 +910,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
730
910
|
<header class="mform-panel-head">{{ container().label }}</header>
|
|
731
911
|
<div class="mform-panel-body">
|
|
732
912
|
@for (child of container().children; track child.key) {
|
|
733
|
-
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [scope]="childScope()" />
|
|
913
|
+
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [mode]="mode()" [notify]="notify()" [scope]="childScope()" />
|
|
734
914
|
}
|
|
735
915
|
</div>
|
|
736
916
|
</section>
|
|
737
917
|
} @else {
|
|
738
918
|
<div class="mform-group">
|
|
739
919
|
@for (child of container().children; track child.key) {
|
|
740
|
-
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [scope]="childScope()" />
|
|
920
|
+
<mform-node [node]="child" [engine]="engine()" [tick]="tick()" [providers]="providers()" [mode]="mode()" [notify]="notify()" [scope]="childScope()" />
|
|
741
921
|
}
|
|
742
922
|
</div>
|
|
743
923
|
}
|
|
@@ -751,7 +931,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
751
931
|
[ngComponentOutletInputs]="customInputs()"
|
|
752
932
|
/>
|
|
753
933
|
} @else if (field().type !== 'hidden') {
|
|
754
|
-
<div class="mform-field" [class.has-error]="errors().length > 0">
|
|
934
|
+
<div class="mform-field" [class.has-error]="errors().length > 0" [class.is-pending]="pending()">
|
|
755
935
|
@if (field().type !== 'checkbox') {
|
|
756
936
|
<label class="mform-label" [attr.for]="controlId()">
|
|
757
937
|
{{ field().label || field().key }}
|
|
@@ -767,7 +947,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
767
947
|
[id]="controlId()"
|
|
768
948
|
[value]="stringValue()"
|
|
769
949
|
[placeholder]="field().placeholder || ''"
|
|
770
|
-
[disabled]="
|
|
950
|
+
[disabled]="controlDisabled()"
|
|
771
951
|
[attr.rows]="rowsProp()"
|
|
772
952
|
[attr.aria-required]="required() || null"
|
|
773
953
|
[attr.aria-invalid]="errors().length > 0 || null"
|
|
@@ -780,7 +960,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
780
960
|
<select
|
|
781
961
|
class="mform-control"
|
|
782
962
|
[id]="controlId()"
|
|
783
|
-
[disabled]="
|
|
963
|
+
[disabled]="controlDisabled()"
|
|
784
964
|
[attr.aria-required]="required() || null"
|
|
785
965
|
[attr.aria-invalid]="errors().length > 0 || null"
|
|
786
966
|
[attr.aria-describedby]="describedBy()"
|
|
@@ -806,7 +986,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
806
986
|
type="radio"
|
|
807
987
|
[name]="controlId()"
|
|
808
988
|
[checked]="stringValue() === '' + option.value"
|
|
809
|
-
[disabled]="
|
|
989
|
+
[disabled]="controlDisabled()"
|
|
810
990
|
(change)="setValue(option.value)"
|
|
811
991
|
(blur)="touch()"
|
|
812
992
|
/>
|
|
@@ -821,7 +1001,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
821
1001
|
type="checkbox"
|
|
822
1002
|
[id]="controlId()"
|
|
823
1003
|
[checked]="value() === true"
|
|
824
|
-
[disabled]="
|
|
1004
|
+
[disabled]="controlDisabled()"
|
|
825
1005
|
[attr.aria-invalid]="errors().length > 0 || null"
|
|
826
1006
|
[attr.aria-describedby]="describedBy()"
|
|
827
1007
|
(change)="setChecked($event)"
|
|
@@ -842,7 +1022,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
842
1022
|
<input
|
|
843
1023
|
type="checkbox"
|
|
844
1024
|
[checked]="mapValue()['' + option.value] === true"
|
|
845
|
-
[disabled]="
|
|
1025
|
+
[disabled]="controlDisabled()"
|
|
846
1026
|
(change)="toggleMap('' + option.value, $event)"
|
|
847
1027
|
(blur)="touch()"
|
|
848
1028
|
/>
|
|
@@ -868,7 +1048,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
868
1048
|
type="text"
|
|
869
1049
|
[id]="controlId()"
|
|
870
1050
|
[placeholder]="field().placeholder || ''"
|
|
871
|
-
[disabled]="
|
|
1051
|
+
[disabled]="controlDisabled()"
|
|
872
1052
|
[attr.aria-describedby]="describedBy()"
|
|
873
1053
|
(keydown.enter)="addTag($event)"
|
|
874
1054
|
(blur)="touch()"
|
|
@@ -881,11 +1061,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
881
1061
|
type="file"
|
|
882
1062
|
multiple
|
|
883
1063
|
[id]="controlId()"
|
|
884
|
-
[disabled]="
|
|
1064
|
+
[disabled]="controlDisabled() || uploading()"
|
|
1065
|
+
[attr.aria-busy]="uploading() || null"
|
|
885
1066
|
[attr.aria-describedby]="describedBy()"
|
|
886
1067
|
(change)="setFiles($event)"
|
|
887
1068
|
(blur)="touch()"
|
|
888
1069
|
/>
|
|
1070
|
+
@if (uploading()) {
|
|
1071
|
+
<div class="mform-desc" role="status">Uploading…</div>
|
|
1072
|
+
}
|
|
1073
|
+
@for (name of fileNames(); track $index) {
|
|
1074
|
+
<div class="mform-file-name">📎 {{ name }}</div>
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
@case ('reference') {
|
|
1078
|
+
<div class="mform-reference">
|
|
1079
|
+
<input
|
|
1080
|
+
class="mform-control"
|
|
1081
|
+
type="text"
|
|
1082
|
+
role="combobox"
|
|
1083
|
+
[id]="controlId()"
|
|
1084
|
+
[value]="refDisplay()"
|
|
1085
|
+
[placeholder]="field().placeholder || ''"
|
|
1086
|
+
[disabled]="controlDisabled()"
|
|
1087
|
+
[attr.aria-expanded]="refOpen()"
|
|
1088
|
+
[attr.aria-invalid]="errors().length > 0 || null"
|
|
1089
|
+
[attr.aria-describedby]="describedBy()"
|
|
1090
|
+
(input)="refSearch($event)"
|
|
1091
|
+
(blur)="refBlur()"
|
|
1092
|
+
/>
|
|
1093
|
+
@if (refOpen() && refOptions().length > 0) {
|
|
1094
|
+
<ul class="mform-ref-list" role="listbox">
|
|
1095
|
+
@for (option of refOptions(); track option.value) {
|
|
1096
|
+
<li role="option">
|
|
1097
|
+
<button type="button" (click)="refPick(option)">{{ option.label }}</button>
|
|
1098
|
+
</li>
|
|
1099
|
+
}
|
|
1100
|
+
</ul>
|
|
1101
|
+
}
|
|
1102
|
+
</div>
|
|
889
1103
|
}
|
|
890
1104
|
@case ('unsupported') {
|
|
891
1105
|
<input
|
|
@@ -907,7 +1121,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
907
1121
|
[id]="controlId()"
|
|
908
1122
|
[value]="stringValue()"
|
|
909
1123
|
[placeholder]="field().placeholder || ''"
|
|
910
|
-
[disabled]="
|
|
1124
|
+
[disabled]="controlDisabled()"
|
|
911
1125
|
[attr.step]="field().type === 'currency' ? '0.01' : null"
|
|
912
1126
|
[attr.inputmode]="field().type === 'currency' ? 'decimal' : null"
|
|
913
1127
|
[attr.aria-required]="required() || null"
|
|
@@ -935,7 +1149,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
935
1149
|
}
|
|
936
1150
|
`,
|
|
937
1151
|
}]
|
|
938
|
-
}], ctorParameters: () => [], propDecorators: { node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: true }] }], engine: [{ type: i0.Input, args: [{ isSignal: true, alias: "engine", required: true }] }], tick: [{ type: i0.Input, args: [{ isSignal: true, alias: "tick", required: true }] }], scope: [{ type: i0.Input, args: [{ isSignal: true, alias: "scope", required: false }] }], bare: [{ type: i0.Input, args: [{ isSignal: true, alias: "bare", required: false }] }], providers: [{ type: i0.Input, args: [{ isSignal: true, alias: "providers", required: false }] }] } });
|
|
1152
|
+
}], ctorParameters: () => [], propDecorators: { node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: true }] }], engine: [{ type: i0.Input, args: [{ isSignal: true, alias: "engine", required: true }] }], tick: [{ type: i0.Input, args: [{ isSignal: true, alias: "tick", required: true }] }], scope: [{ type: i0.Input, args: [{ isSignal: true, alias: "scope", required: false }] }], bare: [{ type: i0.Input, args: [{ isSignal: true, alias: "bare", required: false }] }], providers: [{ type: i0.Input, args: [{ isSignal: true, alias: "providers", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], notify: [{ type: i0.Input, args: [{ isSignal: true, alias: "notify", required: false }] }] } });
|
|
939
1153
|
|
|
940
1154
|
/**
|
|
941
1155
|
* `<mform-renderer>` — renders a form at runtime from a `FormSchema` (or any
|
|
@@ -958,6 +1172,20 @@ class FormRendererComponent {
|
|
|
958
1172
|
optionsProviders = input({}, ...(ngDevMode ? [{ debugName: "optionsProviders" }] : /* istanbul ignore next */ []));
|
|
959
1173
|
/** Host-supplied message resolver (localization of validation messages). */
|
|
960
1174
|
messages = input(null, ...(ngDevMode ? [{ debugName: "messages" }] : /* istanbul ignore next */ []));
|
|
1175
|
+
/** Named custom validators (sync or async — Promises get pending states). */
|
|
1176
|
+
validators = input(null, ...(ngDevMode ? [{ debugName: "validators" }] : /* istanbul ignore next */ []));
|
|
1177
|
+
/** `edit` (default), `readonly` (no actions) or `disabled`. */
|
|
1178
|
+
mode = input('edit', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
|
|
1179
|
+
/**
|
|
1180
|
+
* Optional host submission: called after a VALID submit with the result;
|
|
1181
|
+
* rejections surface as the submission error state. Persistence transport
|
|
1182
|
+
* stays entirely on the host side.
|
|
1183
|
+
*/
|
|
1184
|
+
submitHandler = input(null, ...(ngDevMode ? [{ debugName: "submitHandler" }] : /* istanbul ignore next */ []));
|
|
1185
|
+
/** True while async validation or the submit handler is running. */
|
|
1186
|
+
submitting = signal(false, ...(ngDevMode ? [{ debugName: "submitting" }] : /* istanbul ignore next */ []));
|
|
1187
|
+
/** Message when the host submission rejected. */
|
|
1188
|
+
submitError = signal(null, ...(ngDevMode ? [{ debugName: "submitError" }] : /* istanbul ignore next */ []));
|
|
961
1189
|
/** Fixed renderer texts (override to localize). `{{count}}` in `summary`. */
|
|
962
1190
|
labels = input({
|
|
963
1191
|
previous: 'Previous',
|
|
@@ -980,6 +1208,8 @@ class FormRendererComponent {
|
|
|
980
1208
|
valueChanged = output();
|
|
981
1209
|
/** Bumped on every engine event; nodes read it to refresh. */
|
|
982
1210
|
tick = signal(0, ...(ngDevMode ? [{ debugName: "tick" }] : /* istanbul ignore next */ []));
|
|
1211
|
+
/** Handed to nodes so async completions re-render (zoneless-safe). */
|
|
1212
|
+
bumpTick = () => this.tick.update((v) => v + 1);
|
|
983
1213
|
/** Active wizard step index. */
|
|
984
1214
|
currentStep = signal(0, ...(ngDevMode ? [{ debugName: "currentStep" }] : /* istanbul ignore next */ []));
|
|
985
1215
|
resolved = computed(() => {
|
|
@@ -1010,6 +1240,7 @@ class FormRendererComponent {
|
|
|
1010
1240
|
? createFormEngine(schema, {
|
|
1011
1241
|
initialData: this.initialData() ?? undefined,
|
|
1012
1242
|
messages: this.messages() ?? undefined,
|
|
1243
|
+
validators: this.validators() ?? undefined,
|
|
1013
1244
|
})
|
|
1014
1245
|
: null;
|
|
1015
1246
|
}, ...(ngDevMode ? [{ debugName: "engine" }] : /* istanbul ignore next */ []));
|
|
@@ -1060,22 +1291,37 @@ class FormRendererComponent {
|
|
|
1060
1291
|
this.currentStep.update((index) => Math.min(this.steps().length - 1, index + 1));
|
|
1061
1292
|
}
|
|
1062
1293
|
// -- submission -----------------------------------------------------------
|
|
1063
|
-
onSubmit(event) {
|
|
1294
|
+
async onSubmit(event) {
|
|
1064
1295
|
event.preventDefault();
|
|
1065
1296
|
const engine = this.engine();
|
|
1066
|
-
if (!engine)
|
|
1297
|
+
if (!engine || this.submitting() || this.mode() !== 'edit')
|
|
1067
1298
|
return;
|
|
1068
|
-
|
|
1069
|
-
this.
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1299
|
+
this.submitting.set(true);
|
|
1300
|
+
this.submitError.set(null);
|
|
1301
|
+
try {
|
|
1302
|
+
const result = await engine.submitAsync();
|
|
1303
|
+
this.errorSummary.set(result.errors);
|
|
1304
|
+
if (!result.ok) {
|
|
1305
|
+
if (this.isWizard()) {
|
|
1306
|
+
const stepIndex = this.stepIndexForPath(result.errors[0]?.path ?? '');
|
|
1307
|
+
if (stepIndex >= 0)
|
|
1308
|
+
this.currentStep.set(stepIndex);
|
|
1309
|
+
}
|
|
1310
|
+
this.focusFirstError(result.errors);
|
|
1075
1311
|
}
|
|
1076
|
-
this.
|
|
1312
|
+
else if (this.submitHandler()) {
|
|
1313
|
+
try {
|
|
1314
|
+
await this.submitHandler()(result);
|
|
1315
|
+
}
|
|
1316
|
+
catch (error) {
|
|
1317
|
+
this.submitError.set(String(error instanceof Error ? error.message : error));
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
this.submitted.emit(result);
|
|
1321
|
+
}
|
|
1322
|
+
finally {
|
|
1323
|
+
this.submitting.set(false);
|
|
1077
1324
|
}
|
|
1078
|
-
this.submitted.emit(result);
|
|
1079
1325
|
}
|
|
1080
1326
|
/** Finds the wizard step that owns a (possibly row-indexed) data path. */
|
|
1081
1327
|
stepIndexForPath(path) {
|
|
@@ -1095,7 +1341,7 @@ class FormRendererComponent {
|
|
|
1095
1341
|
queueMicrotask(() => this.documentRef.getElementById(id)?.focus());
|
|
1096
1342
|
}
|
|
1097
1343
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FormRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1098
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FormRendererComponent, isStandalone: true, selector: "mform-renderer", inputs: { schema: { classPropertyName: "schema", publicName: "schema", isSignal: true, isRequired: false, transformFunction: null }, source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, initialData: { classPropertyName: "initialData", publicName: "initialData", isSignal: true, isRequired: false, transformFunction: null }, optionsProviders: { classPropertyName: "optionsProviders", publicName: "optionsProviders", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { submitted: "submitted", valueChanged: "valueChanged" }, ngImport: i0, template: `
|
|
1344
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FormRendererComponent, isStandalone: true, selector: "mform-renderer", inputs: { schema: { classPropertyName: "schema", publicName: "schema", isSignal: true, isRequired: false, transformFunction: null }, source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, initialData: { classPropertyName: "initialData", publicName: "initialData", isSignal: true, isRequired: false, transformFunction: null }, optionsProviders: { classPropertyName: "optionsProviders", publicName: "optionsProviders", isSignal: true, isRequired: false, transformFunction: null }, messages: { classPropertyName: "messages", publicName: "messages", isSignal: true, isRequired: false, transformFunction: null }, validators: { classPropertyName: "validators", publicName: "validators", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, submitHandler: { classPropertyName: "submitHandler", publicName: "submitHandler", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { submitted: "submitted", valueChanged: "valueChanged" }, ngImport: i0, template: `
|
|
1099
1345
|
@if (engine(); as engine) {
|
|
1100
1346
|
<form class="mform-root" novalidate (submit)="onSubmit($event)">
|
|
1101
1347
|
@if (errorSummary().length > 0) {
|
|
@@ -1128,6 +1374,7 @@ class FormRendererComponent {
|
|
|
1128
1374
|
[engine]="engine"
|
|
1129
1375
|
[tick]="tick()"
|
|
1130
1376
|
[providers]="optionsProviders()"
|
|
1377
|
+
[mode]="mode()" [notify]="bumpTick"
|
|
1131
1378
|
[bare]="true"
|
|
1132
1379
|
/>
|
|
1133
1380
|
}
|
|
@@ -1141,18 +1388,23 @@ class FormRendererComponent {
|
|
|
1141
1388
|
<button type="button" class="mform-btn" (click)="nextStep()">
|
|
1142
1389
|
{{ labels().next }}
|
|
1143
1390
|
</button>
|
|
1144
|
-
} @else {
|
|
1145
|
-
<button type="submit" class="mform-btn"
|
|
1391
|
+
} @else if (mode() === 'edit') {
|
|
1392
|
+
<button type="submit" class="mform-btn" [disabled]="submitting()">
|
|
1393
|
+
{{ submitting() ? '…' : labels().submit }}
|
|
1394
|
+
</button>
|
|
1146
1395
|
}
|
|
1147
1396
|
</div>
|
|
1148
1397
|
} @else {
|
|
1149
1398
|
@for (node of engine.schema.fields; track node.key) {
|
|
1150
|
-
<mform-node [node]="node" [engine]="engine" [tick]="tick()" [providers]="optionsProviders()" />
|
|
1399
|
+
<mform-node [node]="node" [engine]="engine" [tick]="tick()" [providers]="optionsProviders()" [mode]="mode()" [notify]="bumpTick" />
|
|
1151
1400
|
}
|
|
1152
1401
|
}
|
|
1402
|
+
@if (submitError(); as error) {
|
|
1403
|
+
<div class="mform-summary" role="alert">{{ error }}</div>
|
|
1404
|
+
}
|
|
1153
1405
|
</form>
|
|
1154
1406
|
}
|
|
1155
|
-
`, isInline: true, styles: [".mform-root{display:flex;flex-direction:column;gap:var(--mform-gap, 16px);font-family:var(--mform-font, system-ui, \"Segoe UI\", sans-serif);color:var(--mform-text, #1f1b2e)}.mform-node{display:contents}.mform-field{display:flex;flex-direction:column;gap:6px}.mform-label{font-size:var(--mform-label-size, 13px);font-weight:var(--mform-label-weight, 600)}.mform-req{color:var(--mform-danger, #c62842);margin-left:2px}.mform-control{font:inherit;width:100%;padding:var(--mform-control-padding, 9px 12px);border:1px solid var(--mform-border, #d9d5e6);border-radius:var(--mform-control-radius, 8px);background:var(--mform-control-bg, #fff);color:inherit;box-sizing:border-box}textarea.mform-control{min-height:72px;resize:vertical}.mform-control:focus-visible{outline:2px solid var(--mform-focus, #8e6ff0);outline-offset:1px;border-color:var(--mform-focus, #8e6ff0)}.mform-field.has-error .mform-control{border-color:var(--mform-danger, #c62842)}.mform-desc{font-size:12px;color:var(--mform-muted, #6b6580)}.mform-error{font-size:12px;color:var(--mform-danger, #c62842)}.mform-choices{display:flex;flex-direction:column;gap:6px}.mform-check{display:flex;align-items:center;gap:8px;font-size:14px;cursor:pointer}.mform-check input{width:16px;height:16px;accent-color:var(--mform-primary, #6d4bd0)}.mform-panel{border:1px solid var(--mform-border, #d9d5e6);border-radius:var(--mform-radius, 10px);overflow:hidden}.mform-panel-head{background:var(--mform-panel-head-bg, linear-gradient(90deg, #efeaff, #f8f6ff));color:var(--mform-panel-head-text, inherit);padding:10px 16px;font-weight:600;font-size:14px;border-bottom:1px solid var(--mform-border, #d9d5e6)}.mform-panel-body,.mform-group,.mform-column,.mform-tabpanel{display:flex;flex-direction:column;gap:var(--mform-gap, 16px)}.mform-panel-body{padding:var(--mform-panel-padding, 16px)}.mform-columns{display:grid;gap:var(--mform-gap, 16px)}@media(max-width:640px){.mform-columns{grid-template-columns:1fr!important}}.mform-affix{display:flex;align-items:center}.mform-affix.has-affix{border:1px solid var(--mform-border, #d9d5e6);border-radius:var(--mform-control-radius, 8px);background:var(--mform-control-bg, #fff)}.mform-affix.has-affix .mform-control{border:none;background:none;flex:1}.mform-affix.has-affix:focus-within{outline:2px solid var(--mform-focus, #8e6ff0);outline-offset:1px}.mform-prefix,.mform-suffix{padding:0 10px;color:var(--mform-muted, #6b6580);font-size:13px;white-space:nowrap}.mform-tags{display:flex;flex-wrap:wrap;gap:6px;align-items:center}.mform-tag{background:var(--mform-primary, #6d4bd0);color:var(--mform-primary-contrast, #fff);border-radius:999px;padding:3px 10px;font-size:12px;display:inline-flex;align-items:center;gap:6px}.mform-tag button{border:none;background:none;color:inherit;cursor:pointer;font-size:12px;padding:0;line-height:1}.mform-tag-input{flex:1;min-width:140px;width:auto}.mform-tabbar{display:flex;gap:4px;border-bottom:2px solid var(--mform-border, #d9d5e6);margin-bottom:14px}.mform-tab{padding:8px 18px;font:inherit;font-size:14px;border:none;background:none;color:var(--mform-muted, #6b6580);cursor:pointer}.mform-tab.is-active{color:var(--mform-primary, #6d4bd0);font-weight:600;border-bottom:2px solid var(--mform-primary, #6d4bd0);margin-bottom:-2px}.mform-grid-row{display:flex;align-items:flex-start;gap:8px;padding:10px 0;border-bottom:1px dashed var(--mform-border, #d9d5e6)}.mform-grid-fields{flex:1;display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:var(--mform-gap, 16px)}.mform-row-remove{border:none;background:none;color:var(--mform-muted, #6b6580);font:inherit;cursor:pointer;padding:6px 8px}.mform-row-remove:hover{color:var(--mform-danger, #c62842)}.mform-row-add{align-self:flex-start;background:none;border:1px dashed var(--mform-primary, #6d4bd0);color:var(--mform-primary, #6d4bd0);padding:7px 14px;border-radius:var(--mform-control-radius, 8px);font:inherit;font-size:13px;cursor:pointer}.mform-btn{align-self:flex-start;background:var(--mform-primary, #6d4bd0);color:var(--mform-primary-contrast, #fff);border:none;border-radius:var(--mform-control-radius, 8px);padding:11px 26px;font:inherit;font-weight:600;cursor:pointer}.mform-btn:hover{filter:brightness(1.08)}.mform-btn:focus-visible{outline:2px solid var(--mform-focus, #8e6ff0);outline-offset:2px}.mform-content{font-size:14px}.mform-unsupported{font-size:13px;color:var(--mform-muted, #6b6580);border:1px dashed var(--mform-border, #d9d5e6);border-radius:var(--mform-radius, 10px);padding:10px 14px}.mform-steps{display:flex;gap:18px;list-style:none;margin:0 0 4px;padding:0 0 12px;border-bottom:1px solid var(--mform-border, #d9d5e6);flex-wrap:wrap}.mform-step{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--mform-muted, #6b6580)}.mform-step-index{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;border:1.5px solid var(--mform-border, #d9d5e6);font-size:11px;font-weight:600}.mform-step.is-active{color:var(--mform-primary, #6d4bd0);font-weight:600}.mform-step.is-active .mform-step-index{border-color:var(--mform-primary, #6d4bd0);background:var(--mform-primary, #6d4bd0);color:var(--mform-primary-contrast, #fff)}.mform-step.is-done .mform-step-index{border-color:var(--mform-primary, #6d4bd0);color:var(--mform-primary, #6d4bd0)}.mform-wizard-nav{display:flex;gap:10px;padding-top:4px}.mform-btn-secondary{background:none;border:1px solid var(--mform-primary, #6d4bd0);color:var(--mform-primary, #6d4bd0)}.mform-summary{border:1px solid var(--mform-danger, #c62842);background:var(--mform-danger-bg, #fdf0f2);color:var(--mform-danger, #c62842);border-radius:var(--mform-radius, 10px);padding:12px 16px;font-size:13px}.mform-summary ul{margin:6px 0 0;padding-left:18px}\n"], dependencies: [{ kind: "component", type: FormNodeComponent, selector: "mform-node", inputs: ["node", "engine", "tick", "scope", "bare", "providers"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
1407
|
+
`, isInline: true, styles: [".mform-root{display:flex;flex-direction:column;gap:var(--mform-gap, 16px);font-family:var(--mform-font, system-ui, \"Segoe UI\", sans-serif);color:var(--mform-text, #1f1b2e)}.mform-node{display:contents}.mform-field{display:flex;flex-direction:column;gap:6px}.mform-label{font-size:var(--mform-label-size, 13px);font-weight:var(--mform-label-weight, 600)}.mform-req{color:var(--mform-danger, #c62842);margin-left:2px}.mform-control{font:inherit;width:100%;padding:var(--mform-control-padding, 9px 12px);border:1px solid var(--mform-border, #d9d5e6);border-radius:var(--mform-control-radius, 8px);background:var(--mform-control-bg, #fff);color:inherit;box-sizing:border-box}textarea.mform-control{min-height:72px;resize:vertical}.mform-control:focus-visible{outline:2px solid var(--mform-focus, #8e6ff0);outline-offset:1px;border-color:var(--mform-focus, #8e6ff0)}.mform-field.has-error .mform-control{border-color:var(--mform-danger, #c62842)}.mform-desc{font-size:12px;color:var(--mform-muted, #6b6580)}.mform-error{font-size:12px;color:var(--mform-danger, #c62842)}.mform-choices{display:flex;flex-direction:column;gap:6px}.mform-check{display:flex;align-items:center;gap:8px;font-size:14px;cursor:pointer}.mform-check input{width:16px;height:16px;accent-color:var(--mform-primary, #6d4bd0)}.mform-panel{border:1px solid var(--mform-border, #d9d5e6);border-radius:var(--mform-radius, 10px);overflow:hidden}.mform-panel-head{background:var(--mform-panel-head-bg, linear-gradient(90deg, #efeaff, #f8f6ff));color:var(--mform-panel-head-text, inherit);padding:10px 16px;font-weight:600;font-size:14px;border-bottom:1px solid var(--mform-border, #d9d5e6)}.mform-panel-body,.mform-group,.mform-column,.mform-tabpanel{display:flex;flex-direction:column;gap:var(--mform-gap, 16px)}.mform-panel-body{padding:var(--mform-panel-padding, 16px)}.mform-columns{display:grid;gap:var(--mform-gap, 16px)}@media(max-width:640px){.mform-columns{grid-template-columns:1fr!important}}.mform-affix{display:flex;align-items:center}.mform-affix.has-affix{border:1px solid var(--mform-border, #d9d5e6);border-radius:var(--mform-control-radius, 8px);background:var(--mform-control-bg, #fff)}.mform-affix.has-affix .mform-control{border:none;background:none;flex:1}.mform-affix.has-affix:focus-within{outline:2px solid var(--mform-focus, #8e6ff0);outline-offset:1px}.mform-prefix,.mform-suffix{padding:0 10px;color:var(--mform-muted, #6b6580);font-size:13px;white-space:nowrap}.mform-tags{display:flex;flex-wrap:wrap;gap:6px;align-items:center}.mform-tag{background:var(--mform-primary, #6d4bd0);color:var(--mform-primary-contrast, #fff);border-radius:999px;padding:3px 10px;font-size:12px;display:inline-flex;align-items:center;gap:6px}.mform-tag button{border:none;background:none;color:inherit;cursor:pointer;font-size:12px;padding:0;line-height:1}.mform-tag-input{flex:1;min-width:140px;width:auto}.mform-field.is-pending .mform-control{background-image:linear-gradient(90deg,transparent 0%,rgb(109 75 208 / 12%) 50%,transparent 100%);background-size:200% 100%;animation:mform-pending 1.2s linear infinite}@keyframes mform-pending{0%{background-position:200% 0}to{background-position:-200% 0}}.mform-file-name{font-size:12px;color:var(--mform-muted, #6b6580);padding:2px 0}.mform-reference{position:relative}.mform-ref-list{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:10;margin:0;padding:4px;list-style:none;background:var(--mform-control-bg, #fff);border:1px solid var(--mform-border, #d9d5e6);border-radius:var(--mform-control-radius, 8px);box-shadow:0 8px 24px #1f1b2e1f;max-height:220px;overflow-y:auto}.mform-ref-list button{display:block;width:100%;text-align:left;font:inherit;font-size:13px;padding:7px 10px;border:none;border-radius:6px;background:none;color:inherit;cursor:pointer}.mform-ref-list button:hover{background:var(--mform-bg, #f6f5fa)}.mform-tabbar{display:flex;gap:4px;border-bottom:2px solid var(--mform-border, #d9d5e6);margin-bottom:14px}.mform-tab{padding:8px 18px;font:inherit;font-size:14px;border:none;background:none;color:var(--mform-muted, #6b6580);cursor:pointer}.mform-tab.is-active{color:var(--mform-primary, #6d4bd0);font-weight:600;border-bottom:2px solid var(--mform-primary, #6d4bd0);margin-bottom:-2px}.mform-grid-row{display:flex;align-items:flex-start;gap:8px;padding:10px 0;border-bottom:1px dashed var(--mform-border, #d9d5e6)}.mform-grid-fields{flex:1;display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:var(--mform-gap, 16px)}.mform-row-remove{border:none;background:none;color:var(--mform-muted, #6b6580);font:inherit;cursor:pointer;padding:6px 8px}.mform-row-remove:hover{color:var(--mform-danger, #c62842)}.mform-row-add{align-self:flex-start;background:none;border:1px dashed var(--mform-primary, #6d4bd0);color:var(--mform-primary, #6d4bd0);padding:7px 14px;border-radius:var(--mform-control-radius, 8px);font:inherit;font-size:13px;cursor:pointer}.mform-btn{align-self:flex-start;background:var(--mform-primary, #6d4bd0);color:var(--mform-primary-contrast, #fff);border:none;border-radius:var(--mform-control-radius, 8px);padding:11px 26px;font:inherit;font-weight:600;cursor:pointer}.mform-btn:hover{filter:brightness(1.08)}.mform-btn:focus-visible{outline:2px solid var(--mform-focus, #8e6ff0);outline-offset:2px}.mform-content{font-size:14px}.mform-unsupported{font-size:13px;color:var(--mform-muted, #6b6580);border:1px dashed var(--mform-border, #d9d5e6);border-radius:var(--mform-radius, 10px);padding:10px 14px}.mform-steps{display:flex;gap:18px;list-style:none;margin:0 0 4px;padding:0 0 12px;border-bottom:1px solid var(--mform-border, #d9d5e6);flex-wrap:wrap}.mform-step{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--mform-muted, #6b6580)}.mform-step-index{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;border:1.5px solid var(--mform-border, #d9d5e6);font-size:11px;font-weight:600}.mform-step.is-active{color:var(--mform-primary, #6d4bd0);font-weight:600}.mform-step.is-active .mform-step-index{border-color:var(--mform-primary, #6d4bd0);background:var(--mform-primary, #6d4bd0);color:var(--mform-primary-contrast, #fff)}.mform-step.is-done .mform-step-index{border-color:var(--mform-primary, #6d4bd0);color:var(--mform-primary, #6d4bd0)}.mform-wizard-nav{display:flex;gap:10px;padding-top:4px}.mform-btn-secondary{background:none;border:1px solid var(--mform-primary, #6d4bd0);color:var(--mform-primary, #6d4bd0)}.mform-summary{border:1px solid var(--mform-danger, #c62842);background:var(--mform-danger-bg, #fdf0f2);color:var(--mform-danger, #c62842);border-radius:var(--mform-radius, 10px);padding:12px 16px;font-size:13px}.mform-summary ul{margin:6px 0 0;padding-left:18px}\n"], dependencies: [{ kind: "component", type: FormNodeComponent, selector: "mform-node", inputs: ["node", "engine", "tick", "scope", "bare", "providers", "mode", "notify"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
1156
1408
|
}
|
|
1157
1409
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FormRendererComponent, decorators: [{
|
|
1158
1410
|
type: Component,
|
|
@@ -1189,6 +1441,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
1189
1441
|
[engine]="engine"
|
|
1190
1442
|
[tick]="tick()"
|
|
1191
1443
|
[providers]="optionsProviders()"
|
|
1444
|
+
[mode]="mode()" [notify]="bumpTick"
|
|
1192
1445
|
[bare]="true"
|
|
1193
1446
|
/>
|
|
1194
1447
|
}
|
|
@@ -1202,19 +1455,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
1202
1455
|
<button type="button" class="mform-btn" (click)="nextStep()">
|
|
1203
1456
|
{{ labels().next }}
|
|
1204
1457
|
</button>
|
|
1205
|
-
} @else {
|
|
1206
|
-
<button type="submit" class="mform-btn"
|
|
1458
|
+
} @else if (mode() === 'edit') {
|
|
1459
|
+
<button type="submit" class="mform-btn" [disabled]="submitting()">
|
|
1460
|
+
{{ submitting() ? '…' : labels().submit }}
|
|
1461
|
+
</button>
|
|
1207
1462
|
}
|
|
1208
1463
|
</div>
|
|
1209
1464
|
} @else {
|
|
1210
1465
|
@for (node of engine.schema.fields; track node.key) {
|
|
1211
|
-
<mform-node [node]="node" [engine]="engine" [tick]="tick()" [providers]="optionsProviders()" />
|
|
1466
|
+
<mform-node [node]="node" [engine]="engine" [tick]="tick()" [providers]="optionsProviders()" [mode]="mode()" [notify]="bumpTick" />
|
|
1212
1467
|
}
|
|
1213
1468
|
}
|
|
1469
|
+
@if (submitError(); as error) {
|
|
1470
|
+
<div class="mform-summary" role="alert">{{ error }}</div>
|
|
1471
|
+
}
|
|
1214
1472
|
</form>
|
|
1215
1473
|
}
|
|
1216
|
-
`, styles: [".mform-root{display:flex;flex-direction:column;gap:var(--mform-gap, 16px);font-family:var(--mform-font, system-ui, \"Segoe UI\", sans-serif);color:var(--mform-text, #1f1b2e)}.mform-node{display:contents}.mform-field{display:flex;flex-direction:column;gap:6px}.mform-label{font-size:var(--mform-label-size, 13px);font-weight:var(--mform-label-weight, 600)}.mform-req{color:var(--mform-danger, #c62842);margin-left:2px}.mform-control{font:inherit;width:100%;padding:var(--mform-control-padding, 9px 12px);border:1px solid var(--mform-border, #d9d5e6);border-radius:var(--mform-control-radius, 8px);background:var(--mform-control-bg, #fff);color:inherit;box-sizing:border-box}textarea.mform-control{min-height:72px;resize:vertical}.mform-control:focus-visible{outline:2px solid var(--mform-focus, #8e6ff0);outline-offset:1px;border-color:var(--mform-focus, #8e6ff0)}.mform-field.has-error .mform-control{border-color:var(--mform-danger, #c62842)}.mform-desc{font-size:12px;color:var(--mform-muted, #6b6580)}.mform-error{font-size:12px;color:var(--mform-danger, #c62842)}.mform-choices{display:flex;flex-direction:column;gap:6px}.mform-check{display:flex;align-items:center;gap:8px;font-size:14px;cursor:pointer}.mform-check input{width:16px;height:16px;accent-color:var(--mform-primary, #6d4bd0)}.mform-panel{border:1px solid var(--mform-border, #d9d5e6);border-radius:var(--mform-radius, 10px);overflow:hidden}.mform-panel-head{background:var(--mform-panel-head-bg, linear-gradient(90deg, #efeaff, #f8f6ff));color:var(--mform-panel-head-text, inherit);padding:10px 16px;font-weight:600;font-size:14px;border-bottom:1px solid var(--mform-border, #d9d5e6)}.mform-panel-body,.mform-group,.mform-column,.mform-tabpanel{display:flex;flex-direction:column;gap:var(--mform-gap, 16px)}.mform-panel-body{padding:var(--mform-panel-padding, 16px)}.mform-columns{display:grid;gap:var(--mform-gap, 16px)}@media(max-width:640px){.mform-columns{grid-template-columns:1fr!important}}.mform-affix{display:flex;align-items:center}.mform-affix.has-affix{border:1px solid var(--mform-border, #d9d5e6);border-radius:var(--mform-control-radius, 8px);background:var(--mform-control-bg, #fff)}.mform-affix.has-affix .mform-control{border:none;background:none;flex:1}.mform-affix.has-affix:focus-within{outline:2px solid var(--mform-focus, #8e6ff0);outline-offset:1px}.mform-prefix,.mform-suffix{padding:0 10px;color:var(--mform-muted, #6b6580);font-size:13px;white-space:nowrap}.mform-tags{display:flex;flex-wrap:wrap;gap:6px;align-items:center}.mform-tag{background:var(--mform-primary, #6d4bd0);color:var(--mform-primary-contrast, #fff);border-radius:999px;padding:3px 10px;font-size:12px;display:inline-flex;align-items:center;gap:6px}.mform-tag button{border:none;background:none;color:inherit;cursor:pointer;font-size:12px;padding:0;line-height:1}.mform-tag-input{flex:1;min-width:140px;width:auto}.mform-tabbar{display:flex;gap:4px;border-bottom:2px solid var(--mform-border, #d9d5e6);margin-bottom:14px}.mform-tab{padding:8px 18px;font:inherit;font-size:14px;border:none;background:none;color:var(--mform-muted, #6b6580);cursor:pointer}.mform-tab.is-active{color:var(--mform-primary, #6d4bd0);font-weight:600;border-bottom:2px solid var(--mform-primary, #6d4bd0);margin-bottom:-2px}.mform-grid-row{display:flex;align-items:flex-start;gap:8px;padding:10px 0;border-bottom:1px dashed var(--mform-border, #d9d5e6)}.mform-grid-fields{flex:1;display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:var(--mform-gap, 16px)}.mform-row-remove{border:none;background:none;color:var(--mform-muted, #6b6580);font:inherit;cursor:pointer;padding:6px 8px}.mform-row-remove:hover{color:var(--mform-danger, #c62842)}.mform-row-add{align-self:flex-start;background:none;border:1px dashed var(--mform-primary, #6d4bd0);color:var(--mform-primary, #6d4bd0);padding:7px 14px;border-radius:var(--mform-control-radius, 8px);font:inherit;font-size:13px;cursor:pointer}.mform-btn{align-self:flex-start;background:var(--mform-primary, #6d4bd0);color:var(--mform-primary-contrast, #fff);border:none;border-radius:var(--mform-control-radius, 8px);padding:11px 26px;font:inherit;font-weight:600;cursor:pointer}.mform-btn:hover{filter:brightness(1.08)}.mform-btn:focus-visible{outline:2px solid var(--mform-focus, #8e6ff0);outline-offset:2px}.mform-content{font-size:14px}.mform-unsupported{font-size:13px;color:var(--mform-muted, #6b6580);border:1px dashed var(--mform-border, #d9d5e6);border-radius:var(--mform-radius, 10px);padding:10px 14px}.mform-steps{display:flex;gap:18px;list-style:none;margin:0 0 4px;padding:0 0 12px;border-bottom:1px solid var(--mform-border, #d9d5e6);flex-wrap:wrap}.mform-step{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--mform-muted, #6b6580)}.mform-step-index{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;border:1.5px solid var(--mform-border, #d9d5e6);font-size:11px;font-weight:600}.mform-step.is-active{color:var(--mform-primary, #6d4bd0);font-weight:600}.mform-step.is-active .mform-step-index{border-color:var(--mform-primary, #6d4bd0);background:var(--mform-primary, #6d4bd0);color:var(--mform-primary-contrast, #fff)}.mform-step.is-done .mform-step-index{border-color:var(--mform-primary, #6d4bd0);color:var(--mform-primary, #6d4bd0)}.mform-wizard-nav{display:flex;gap:10px;padding-top:4px}.mform-btn-secondary{background:none;border:1px solid var(--mform-primary, #6d4bd0);color:var(--mform-primary, #6d4bd0)}.mform-summary{border:1px solid var(--mform-danger, #c62842);background:var(--mform-danger-bg, #fdf0f2);color:var(--mform-danger, #c62842);border-radius:var(--mform-radius, 10px);padding:12px 16px;font-size:13px}.mform-summary ul{margin:6px 0 0;padding-left:18px}\n"] }]
|
|
1217
|
-
}], ctorParameters: () => [], propDecorators: { schema: [{ type: i0.Input, args: [{ isSignal: true, alias: "schema", required: false }] }], source: [{ type: i0.Input, args: [{ isSignal: true, alias: "source", required: false }] }], initialData: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialData", required: false }] }], optionsProviders: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionsProviders", required: false }] }], messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], submitted: [{ type: i0.Output, args: ["submitted"] }], valueChanged: [{ type: i0.Output, args: ["valueChanged"] }] } });
|
|
1474
|
+
`, styles: [".mform-root{display:flex;flex-direction:column;gap:var(--mform-gap, 16px);font-family:var(--mform-font, system-ui, \"Segoe UI\", sans-serif);color:var(--mform-text, #1f1b2e)}.mform-node{display:contents}.mform-field{display:flex;flex-direction:column;gap:6px}.mform-label{font-size:var(--mform-label-size, 13px);font-weight:var(--mform-label-weight, 600)}.mform-req{color:var(--mform-danger, #c62842);margin-left:2px}.mform-control{font:inherit;width:100%;padding:var(--mform-control-padding, 9px 12px);border:1px solid var(--mform-border, #d9d5e6);border-radius:var(--mform-control-radius, 8px);background:var(--mform-control-bg, #fff);color:inherit;box-sizing:border-box}textarea.mform-control{min-height:72px;resize:vertical}.mform-control:focus-visible{outline:2px solid var(--mform-focus, #8e6ff0);outline-offset:1px;border-color:var(--mform-focus, #8e6ff0)}.mform-field.has-error .mform-control{border-color:var(--mform-danger, #c62842)}.mform-desc{font-size:12px;color:var(--mform-muted, #6b6580)}.mform-error{font-size:12px;color:var(--mform-danger, #c62842)}.mform-choices{display:flex;flex-direction:column;gap:6px}.mform-check{display:flex;align-items:center;gap:8px;font-size:14px;cursor:pointer}.mform-check input{width:16px;height:16px;accent-color:var(--mform-primary, #6d4bd0)}.mform-panel{border:1px solid var(--mform-border, #d9d5e6);border-radius:var(--mform-radius, 10px);overflow:hidden}.mform-panel-head{background:var(--mform-panel-head-bg, linear-gradient(90deg, #efeaff, #f8f6ff));color:var(--mform-panel-head-text, inherit);padding:10px 16px;font-weight:600;font-size:14px;border-bottom:1px solid var(--mform-border, #d9d5e6)}.mform-panel-body,.mform-group,.mform-column,.mform-tabpanel{display:flex;flex-direction:column;gap:var(--mform-gap, 16px)}.mform-panel-body{padding:var(--mform-panel-padding, 16px)}.mform-columns{display:grid;gap:var(--mform-gap, 16px)}@media(max-width:640px){.mform-columns{grid-template-columns:1fr!important}}.mform-affix{display:flex;align-items:center}.mform-affix.has-affix{border:1px solid var(--mform-border, #d9d5e6);border-radius:var(--mform-control-radius, 8px);background:var(--mform-control-bg, #fff)}.mform-affix.has-affix .mform-control{border:none;background:none;flex:1}.mform-affix.has-affix:focus-within{outline:2px solid var(--mform-focus, #8e6ff0);outline-offset:1px}.mform-prefix,.mform-suffix{padding:0 10px;color:var(--mform-muted, #6b6580);font-size:13px;white-space:nowrap}.mform-tags{display:flex;flex-wrap:wrap;gap:6px;align-items:center}.mform-tag{background:var(--mform-primary, #6d4bd0);color:var(--mform-primary-contrast, #fff);border-radius:999px;padding:3px 10px;font-size:12px;display:inline-flex;align-items:center;gap:6px}.mform-tag button{border:none;background:none;color:inherit;cursor:pointer;font-size:12px;padding:0;line-height:1}.mform-tag-input{flex:1;min-width:140px;width:auto}.mform-field.is-pending .mform-control{background-image:linear-gradient(90deg,transparent 0%,rgb(109 75 208 / 12%) 50%,transparent 100%);background-size:200% 100%;animation:mform-pending 1.2s linear infinite}@keyframes mform-pending{0%{background-position:200% 0}to{background-position:-200% 0}}.mform-file-name{font-size:12px;color:var(--mform-muted, #6b6580);padding:2px 0}.mform-reference{position:relative}.mform-ref-list{position:absolute;top:calc(100% + 4px);left:0;right:0;z-index:10;margin:0;padding:4px;list-style:none;background:var(--mform-control-bg, #fff);border:1px solid var(--mform-border, #d9d5e6);border-radius:var(--mform-control-radius, 8px);box-shadow:0 8px 24px #1f1b2e1f;max-height:220px;overflow-y:auto}.mform-ref-list button{display:block;width:100%;text-align:left;font:inherit;font-size:13px;padding:7px 10px;border:none;border-radius:6px;background:none;color:inherit;cursor:pointer}.mform-ref-list button:hover{background:var(--mform-bg, #f6f5fa)}.mform-tabbar{display:flex;gap:4px;border-bottom:2px solid var(--mform-border, #d9d5e6);margin-bottom:14px}.mform-tab{padding:8px 18px;font:inherit;font-size:14px;border:none;background:none;color:var(--mform-muted, #6b6580);cursor:pointer}.mform-tab.is-active{color:var(--mform-primary, #6d4bd0);font-weight:600;border-bottom:2px solid var(--mform-primary, #6d4bd0);margin-bottom:-2px}.mform-grid-row{display:flex;align-items:flex-start;gap:8px;padding:10px 0;border-bottom:1px dashed var(--mform-border, #d9d5e6)}.mform-grid-fields{flex:1;display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:var(--mform-gap, 16px)}.mform-row-remove{border:none;background:none;color:var(--mform-muted, #6b6580);font:inherit;cursor:pointer;padding:6px 8px}.mform-row-remove:hover{color:var(--mform-danger, #c62842)}.mform-row-add{align-self:flex-start;background:none;border:1px dashed var(--mform-primary, #6d4bd0);color:var(--mform-primary, #6d4bd0);padding:7px 14px;border-radius:var(--mform-control-radius, 8px);font:inherit;font-size:13px;cursor:pointer}.mform-btn{align-self:flex-start;background:var(--mform-primary, #6d4bd0);color:var(--mform-primary-contrast, #fff);border:none;border-radius:var(--mform-control-radius, 8px);padding:11px 26px;font:inherit;font-weight:600;cursor:pointer}.mform-btn:hover{filter:brightness(1.08)}.mform-btn:focus-visible{outline:2px solid var(--mform-focus, #8e6ff0);outline-offset:2px}.mform-content{font-size:14px}.mform-unsupported{font-size:13px;color:var(--mform-muted, #6b6580);border:1px dashed var(--mform-border, #d9d5e6);border-radius:var(--mform-radius, 10px);padding:10px 14px}.mform-steps{display:flex;gap:18px;list-style:none;margin:0 0 4px;padding:0 0 12px;border-bottom:1px solid var(--mform-border, #d9d5e6);flex-wrap:wrap}.mform-step{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--mform-muted, #6b6580)}.mform-step-index{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;border:1.5px solid var(--mform-border, #d9d5e6);font-size:11px;font-weight:600}.mform-step.is-active{color:var(--mform-primary, #6d4bd0);font-weight:600}.mform-step.is-active .mform-step-index{border-color:var(--mform-primary, #6d4bd0);background:var(--mform-primary, #6d4bd0);color:var(--mform-primary-contrast, #fff)}.mform-step.is-done .mform-step-index{border-color:var(--mform-primary, #6d4bd0);color:var(--mform-primary, #6d4bd0)}.mform-wizard-nav{display:flex;gap:10px;padding-top:4px}.mform-btn-secondary{background:none;border:1px solid var(--mform-primary, #6d4bd0);color:var(--mform-primary, #6d4bd0)}.mform-summary{border:1px solid var(--mform-danger, #c62842);background:var(--mform-danger-bg, #fdf0f2);color:var(--mform-danger, #c62842);border-radius:var(--mform-radius, 10px);padding:12px 16px;font-size:13px}.mform-summary ul{margin:6px 0 0;padding-left:18px}\n"] }]
|
|
1475
|
+
}], ctorParameters: () => [], propDecorators: { schema: [{ type: i0.Input, args: [{ isSignal: true, alias: "schema", required: false }] }], source: [{ type: i0.Input, args: [{ isSignal: true, alias: "source", required: false }] }], initialData: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialData", required: false }] }], optionsProviders: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionsProviders", required: false }] }], messages: [{ type: i0.Input, args: [{ isSignal: true, alias: "messages", required: false }] }], validators: [{ type: i0.Input, args: [{ isSignal: true, alias: "validators", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], submitHandler: [{ type: i0.Input, args: [{ isSignal: true, alias: "submitHandler", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], submitted: [{ type: i0.Output, args: ["submitted"] }], valueChanged: [{ type: i0.Output, args: ["valueChanged"] }] } });
|
|
1218
1476
|
|
|
1219
1477
|
/*
|
|
1220
1478
|
* Runtime entry point of @mosaicoo/form-angular.
|
|
@@ -1229,5 +1487,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
1229
1487
|
* Generated bundle index. Do not edit.
|
|
1230
1488
|
*/
|
|
1231
1489
|
|
|
1232
|
-
export { FormNodeComponent, FormRendererComponent, MFORM_FIELD_COMPONENTS, MFORM_REMOTE_FETCHER, provideMosaicooForm };
|
|
1490
|
+
export { FormNodeComponent, FormRendererComponent, MFORM_FIELD_COMPONENTS, MFORM_REMOTE_FETCHER, MFORM_UPLOAD, provideMosaicooForm };
|
|
1233
1491
|
//# sourceMappingURL=mosaicoo-form-angular.mjs.map
|