@mosaicoo/form-angular 0.1.0 → 0.2.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/README.md
CHANGED
|
@@ -39,6 +39,25 @@ export class MyPage {}
|
|
|
39
39
|
the form adopts your design system; override `[labels]` and `[messages]`
|
|
40
40
|
to localize.
|
|
41
41
|
|
|
42
|
+
## Extending
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
// Register custom field components and your HTTP transport once:
|
|
46
|
+
bootstrapApplication(App, {
|
|
47
|
+
providers: [
|
|
48
|
+
provideMosaicooForm({
|
|
49
|
+
components: { signature: SignatureFieldComponent }, // new or overridden types
|
|
50
|
+
remoteFetcher: (url) => api.get(url), // auth/caching stay yours
|
|
51
|
+
}),
|
|
52
|
+
],
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
A registered component receives `field`, `engine`, `path` and `tick` as signal
|
|
57
|
+
inputs and talks to the form exclusively through the engine
|
|
58
|
+
(`engine.getValue/setValue/markTouched`) — validation, conditional visibility
|
|
59
|
+
and events keep working with no extra wiring.
|
|
60
|
+
|
|
42
61
|
## Theming example
|
|
43
62
|
|
|
44
63
|
```css
|
|
@@ -1,7 +1,41 @@
|
|
|
1
|
+
import { NgComponentOutlet, DOCUMENT } from '@angular/common';
|
|
1
2
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, signal, effect, untracked, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, output } from '@angular/core';
|
|
3
|
+
import { InjectionToken, makeEnvironmentProviders, input, signal, inject, effect, untracked, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, output } from '@angular/core';
|
|
3
4
|
import { importForm, createLegacyImporter, createFormEngine, collectInputs } from '@mosaicoo/form-core';
|
|
4
5
|
|
|
6
|
+
/** Multi-provider token: maps merge, later providers win on conflicts. */
|
|
7
|
+
const MFORM_FIELD_COMPONENTS = new InjectionToken('MFORM_FIELD_COMPONENTS');
|
|
8
|
+
/**
|
|
9
|
+
* Transport used for `optionsSource: { type: 'remote' }` fields. Register it
|
|
10
|
+
* to route those requests through the host's HTTP stack (authentication,
|
|
11
|
+
* base URLs, caching). Without it, a plain `fetch` is used.
|
|
12
|
+
*/
|
|
13
|
+
const MFORM_REMOTE_FETCHER = new InjectionToken('MFORM_REMOTE_FETCHER');
|
|
14
|
+
/**
|
|
15
|
+
* Registers renderer extensions at any injector level:
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* bootstrapApplication(App, {
|
|
19
|
+
* providers: [
|
|
20
|
+
* provideMosaicooForm({
|
|
21
|
+
* components: { signature: SignatureFieldComponent },
|
|
22
|
+
* remoteFetcher: (url) => authenticatedGet(url),
|
|
23
|
+
* }),
|
|
24
|
+
* ],
|
|
25
|
+
* });
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
function provideMosaicooForm(config) {
|
|
29
|
+
const providers = [];
|
|
30
|
+
if (config.components) {
|
|
31
|
+
providers.push({ provide: MFORM_FIELD_COMPONENTS, useValue: config.components, multi: true });
|
|
32
|
+
}
|
|
33
|
+
if (config.remoteFetcher) {
|
|
34
|
+
providers.push({ provide: MFORM_REMOTE_FETCHER, useValue: config.remoteFetcher });
|
|
35
|
+
}
|
|
36
|
+
return makeEnvironmentProviders(providers);
|
|
37
|
+
}
|
|
38
|
+
|
|
5
39
|
/**
|
|
6
40
|
* Renders one schema node (input, container or static) and recurses into
|
|
7
41
|
* children. State lives in the headless engine — this component only projects
|
|
@@ -20,10 +54,37 @@ class FormNodeComponent {
|
|
|
20
54
|
/** Host-registered providers for `optionsSource: provider` fields. */
|
|
21
55
|
providers = input({}, ...(ngDevMode ? [{ debugName: "providers" }] : /* istanbul ignore next */ []));
|
|
22
56
|
activeTab = signal(0, ...(ngDevMode ? [{ debugName: "activeTab" }] : /* istanbul ignore next */ []));
|
|
57
|
+
/** DI-registered custom field components (maps merge; later wins). */
|
|
58
|
+
componentMaps = inject(MFORM_FIELD_COMPONENTS, { optional: true });
|
|
59
|
+
/** Host transport for remote options; plain fetch when absent. */
|
|
60
|
+
remoteFetcher = inject(MFORM_REMOTE_FETCHER, { optional: true });
|
|
61
|
+
/** Custom component registered for this field type, if any. */
|
|
62
|
+
customComponent() {
|
|
63
|
+
const node = this.node();
|
|
64
|
+
if (node.kind !== 'input' || !this.componentMaps)
|
|
65
|
+
return null;
|
|
66
|
+
for (let i = this.componentMaps.length - 1; i >= 0; i--) {
|
|
67
|
+
const match = this.componentMaps[i]?.[node.type];
|
|
68
|
+
if (match)
|
|
69
|
+
return match;
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
/** Inputs handed to a custom component (MformFieldComponent contract). */
|
|
74
|
+
customInputs() {
|
|
75
|
+
return {
|
|
76
|
+
field: this.field(),
|
|
77
|
+
engine: this.engine(),
|
|
78
|
+
path: this.path(),
|
|
79
|
+
tick: this.tick(),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
23
82
|
/** Options resolved from a dynamic source (provider or remote URL). */
|
|
24
83
|
resolvedOptions = signal(null, ...(ngDevMode ? [{ debugName: "resolvedOptions" }] : /* istanbul ignore next */ []));
|
|
25
84
|
/** Snapshot of the observed refresh source at the last resolution. */
|
|
26
85
|
lastRefreshKey = null;
|
|
86
|
+
/** Discards resolutions that arrive after a newer request started. */
|
|
87
|
+
optionsRequestSeq = 0;
|
|
27
88
|
constructor() {
|
|
28
89
|
effect(() => {
|
|
29
90
|
const node = this.node();
|
|
@@ -47,18 +108,28 @@ class FormNodeComponent {
|
|
|
47
108
|
if (refreshKey === this.lastRefreshKey)
|
|
48
109
|
return;
|
|
49
110
|
this.lastRefreshKey = refreshKey;
|
|
111
|
+
// Stale-response guard: only the latest request may write options.
|
|
112
|
+
const requestId = ++this.optionsRequestSeq;
|
|
113
|
+
const apply = (options) => {
|
|
114
|
+
if (requestId === this.optionsRequestSeq)
|
|
115
|
+
this.resolvedOptions.set(options);
|
|
116
|
+
};
|
|
50
117
|
if (source.type === 'provider') {
|
|
51
118
|
const provider = registry[source.name];
|
|
52
119
|
if (!provider)
|
|
53
120
|
return; // no provider: static options/fallback stand
|
|
54
121
|
Promise.resolve(provider({ field: node, path, data: engine.getData(), args: source.args }))
|
|
55
|
-
.then(
|
|
122
|
+
.then(apply)
|
|
56
123
|
.catch(() => { }); // provider failure keeps the static fallback
|
|
57
124
|
}
|
|
58
125
|
else {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
126
|
+
// The host's transport (auth, base URL, caching) when registered via
|
|
127
|
+
// provideMosaicooForm; plain fetch as the zero-config default.
|
|
128
|
+
const request = this.remoteFetcher
|
|
129
|
+
? this.remoteFetcher(source.url)
|
|
130
|
+
: fetch(source.url).then((response) => (response.ok ? response.json() : []));
|
|
131
|
+
request
|
|
132
|
+
.then((list) => apply((Array.isArray(list) ? list : []).map((item) => ({
|
|
62
133
|
label: String(item[source.labelKey ?? 'label'] ?? item[source.valueKey ?? 'value'] ?? ''),
|
|
63
134
|
value: (item[source.valueKey ?? 'value'] ?? ''),
|
|
64
135
|
}))))
|
|
@@ -344,7 +415,12 @@ class FormNodeComponent {
|
|
|
344
415
|
}
|
|
345
416
|
}
|
|
346
417
|
@case ('input') {
|
|
347
|
-
@if (
|
|
418
|
+
@if (customComponent(); as custom) {
|
|
419
|
+
<ng-container
|
|
420
|
+
[ngComponentOutlet]="custom"
|
|
421
|
+
[ngComponentOutletInputs]="customInputs()"
|
|
422
|
+
/>
|
|
423
|
+
} @else if (field().type !== 'hidden') {
|
|
348
424
|
<div class="mform-field" [class.has-error]="errors().length > 0">
|
|
349
425
|
@if (field().type !== 'checkbox') {
|
|
350
426
|
<label class="mform-label" [attr.for]="controlId()">
|
|
@@ -493,7 +569,7 @@ class FormNodeComponent {
|
|
|
493
569
|
}
|
|
494
570
|
}
|
|
495
571
|
}
|
|
496
|
-
`, isInline: true, dependencies: [{ kind: "component", type: FormNodeComponent, selector: "mform-node", inputs: ["node", "engine", "tick", "scope", "bare", "providers"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
572
|
+
`, 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 });
|
|
497
573
|
}
|
|
498
574
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FormNodeComponent, decorators: [{
|
|
499
575
|
type: Component,
|
|
@@ -502,6 +578,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
502
578
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
503
579
|
encapsulation: ViewEncapsulation.None,
|
|
504
580
|
host: { class: 'mform-node' },
|
|
581
|
+
imports: [NgComponentOutlet],
|
|
505
582
|
template: `
|
|
506
583
|
@let n = node();
|
|
507
584
|
@if (visible()) {
|
|
@@ -608,7 +685,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
608
685
|
}
|
|
609
686
|
}
|
|
610
687
|
@case ('input') {
|
|
611
|
-
@if (
|
|
688
|
+
@if (customComponent(); as custom) {
|
|
689
|
+
<ng-container
|
|
690
|
+
[ngComponentOutlet]="custom"
|
|
691
|
+
[ngComponentOutletInputs]="customInputs()"
|
|
692
|
+
/>
|
|
693
|
+
} @else if (field().type !== 'hidden') {
|
|
612
694
|
<div class="mform-field" [class.has-error]="errors().length > 0">
|
|
613
695
|
@if (field().type !== 'checkbox') {
|
|
614
696
|
<label class="mform-label" [attr.for]="controlId()">
|
|
@@ -909,13 +991,14 @@ class FormRendererComponent {
|
|
|
909
991
|
.join('.');
|
|
910
992
|
return this.steps().findIndex((step) => collectInputs({ version: 1, fields: step.children }).some((entry) => entry.path === pattern));
|
|
911
993
|
}
|
|
994
|
+
documentRef = inject(DOCUMENT);
|
|
912
995
|
focusFirstError(errors) {
|
|
913
996
|
const first = errors[0];
|
|
914
997
|
if (!first)
|
|
915
998
|
return;
|
|
916
999
|
const id = `mform-${first.path.replace(/\./g, '-')}`;
|
|
917
1000
|
// Focus after the view updated with the error states.
|
|
918
|
-
queueMicrotask(() =>
|
|
1001
|
+
queueMicrotask(() => this.documentRef.getElementById(id)?.focus());
|
|
919
1002
|
}
|
|
920
1003
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FormRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
921
1004
|
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: `
|
|
@@ -1039,9 +1122,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
|
|
|
1039
1122
|
`, 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)}.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"] }]
|
|
1040
1123
|
}], 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"] }] } });
|
|
1041
1124
|
|
|
1125
|
+
/*
|
|
1126
|
+
* Runtime entry point of @mosaicoo/form-angular.
|
|
1127
|
+
*
|
|
1128
|
+
* Architectural note: this primary entry stays runtime-only. Authoring
|
|
1129
|
+
* tooling (the visual designer) will ship as a SECONDARY entry point
|
|
1130
|
+
* (`@mosaicoo/form-angular/designer`) so applications that only render
|
|
1131
|
+
* forms never load authoring code — a requirement for federated hosts.
|
|
1132
|
+
*/
|
|
1133
|
+
|
|
1042
1134
|
/**
|
|
1043
1135
|
* Generated bundle index. Do not edit.
|
|
1044
1136
|
*/
|
|
1045
1137
|
|
|
1046
|
-
export { FormNodeComponent, FormRendererComponent };
|
|
1138
|
+
export { FormNodeComponent, FormRendererComponent, MFORM_FIELD_COMPONENTS, MFORM_REMOTE_FETCHER, provideMosaicooForm };
|
|
1047
1139
|
//# sourceMappingURL=mosaicoo-form-angular.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mosaicoo-form-angular.mjs","sources":["../../../packages/angular/src/lib/form-node.component.ts","../../../packages/angular/src/lib/form-renderer.component.ts","../../../packages/angular/src/mosaicoo-form-angular.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n effect,\n input,\n signal,\n untracked,\n} from '@angular/core';\nimport type {\n ContainerField,\n FieldNode,\n FieldOption,\n FormEngine,\n InputField,\n OptionsProviderRegistry,\n StaticField,\n} from '@mosaicoo/form-core';\n\n/**\n * Renders one schema node (input, container or static) and recurses into\n * children. State lives in the headless engine — this component only projects\n * it and forwards user interaction. `tick` changes whenever the engine emits,\n * invalidating the OnPush view.\n */\n@Component({\n selector: 'mform-node',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: { class: 'mform-node' },\n template: `\n @let n = node();\n @if (visible()) {\n @switch (n.kind) {\n @case ('static') {\n @if (n.type === 'button') {\n <button\n class=\"mform-btn\"\n [type]=\"buttonAction() === 'submit' ? 'submit' : 'button'\"\n >\n {{ n.label || 'Submit' }}\n </button>\n } @else if (n.type === 'content') {\n <div class=\"mform-content\" [innerHTML]=\"content()\"></div>\n } @else {\n <div class=\"mform-unsupported\" role=\"note\">\n {{ n.label || n.key }} — unsupported content\n </div>\n }\n }\n @case ('container') {\n @switch (containerLayout()) {\n @case ('columns') {\n <div class=\"mform-columns\" [style.grid-template-columns]=\"columnsTemplate()\">\n @for (column of columns(); track $index) {\n <div class=\"mform-column\">\n @for (child of column; track child.key) {\n <mform-node [node]=\"child\" [engine]=\"engine()\" [tick]=\"tick()\" [providers]=\"providers()\" [scope]=\"childScope()\" />\n }\n </div>\n }\n </div>\n }\n @case ('tabs') {\n <div class=\"mform-tabs\">\n <div class=\"mform-tabbar\" role=\"tablist\">\n @for (tab of container().children; track tab.key; let i = $index) {\n <button\n type=\"button\"\n class=\"mform-tab\"\n role=\"tab\"\n [class.is-active]=\"activeTab() === i\"\n [attr.aria-selected]=\"activeTab() === i\"\n (click)=\"activeTab.set(i)\"\n >\n {{ tab.label || 'Tab ' + (i + 1) }}\n </button>\n }\n </div>\n @for (tab of container().children; track tab.key; let i = $index) {\n @if (activeTab() === i) {\n <div class=\"mform-tabpanel\" role=\"tabpanel\">\n <mform-node [node]=\"tab\" [engine]=\"engine()\" [tick]=\"tick()\" [providers]=\"providers()\" [scope]=\"childScope()\" [bare]=\"true\" />\n </div>\n }\n }\n </div>\n }\n @case ('array') {\n <section class=\"mform-panel mform-grid\">\n @if (container().label) {\n <header class=\"mform-panel-head\">{{ container().label }}</header>\n }\n <div class=\"mform-panel-body\">\n @for (row of rows(); track $index; let i = $index) {\n <div class=\"mform-grid-row\" role=\"group\" [attr.aria-label]=\"(container().label || container().key) + ' ' + (i + 1)\">\n <div class=\"mform-grid-fields\">\n @for (child of container().children; track child.key) {\n <mform-node [node]=\"child\" [engine]=\"engine()\" [tick]=\"tick()\" [providers]=\"providers()\" [scope]=\"rowScope(i)\" />\n }\n </div>\n <button\n type=\"button\"\n class=\"mform-row-remove\"\n (click)=\"removeRow(i)\"\n [attr.aria-label]=\"'Remove row ' + (i + 1)\"\n >\n ✕\n </button>\n </div>\n }\n <button type=\"button\" class=\"mform-row-add\" (click)=\"addRow()\">+ Add</button>\n </div>\n </section>\n }\n @default {\n @if (container().label && !bare()) {\n <section class=\"mform-panel\">\n <header class=\"mform-panel-head\">{{ container().label }}</header>\n <div class=\"mform-panel-body\">\n @for (child of container().children; track child.key) {\n <mform-node [node]=\"child\" [engine]=\"engine()\" [tick]=\"tick()\" [providers]=\"providers()\" [scope]=\"childScope()\" />\n }\n </div>\n </section>\n } @else {\n <div class=\"mform-group\">\n @for (child of container().children; track child.key) {\n <mform-node [node]=\"child\" [engine]=\"engine()\" [tick]=\"tick()\" [providers]=\"providers()\" [scope]=\"childScope()\" />\n }\n </div>\n }\n }\n }\n }\n @case ('input') {\n @if (field().type !== 'hidden') {\n <div class=\"mform-field\" [class.has-error]=\"errors().length > 0\">\n @if (field().type !== 'checkbox') {\n <label class=\"mform-label\" [attr.for]=\"controlId()\">\n {{ field().label || field().key }}\n @if (required()) {\n <span class=\"mform-req\" aria-hidden=\"true\">*</span>\n }\n </label>\n }\n @switch (field().type) {\n @case ('textarea') {\n <textarea\n class=\"mform-control\"\n [id]=\"controlId()\"\n [value]=\"stringValue()\"\n [placeholder]=\"field().placeholder || ''\"\n [disabled]=\"field().disabled === true\"\n [attr.rows]=\"rowsProp()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"errors().length > 0 || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (input)=\"setString($event)\"\n (blur)=\"touch()\"\n ></textarea>\n }\n @case ('select') {\n <select\n class=\"mform-control\"\n [id]=\"controlId()\"\n [disabled]=\"field().disabled === true\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"errors().length > 0 || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (change)=\"setSelect($event)\"\n (blur)=\"touch()\"\n >\n <option value=\"\" [selected]=\"stringValue() === ''\"></option>\n @for (option of options(); track option.value) {\n <option\n [value]=\"option.value\"\n [selected]=\"stringValue() === '' + option.value\"\n >\n {{ option.label }}\n </option>\n }\n </select>\n }\n @case ('radio') {\n <div class=\"mform-choices\" role=\"radiogroup\" [attr.aria-label]=\"field().label || field().key\">\n @for (option of options(); track option.value) {\n <label class=\"mform-check\">\n <input\n type=\"radio\"\n [name]=\"controlId()\"\n [checked]=\"stringValue() === '' + option.value\"\n [disabled]=\"field().disabled === true\"\n (change)=\"setValue(option.value)\"\n (blur)=\"touch()\"\n />\n <span>{{ option.label }}</span>\n </label>\n }\n </div>\n }\n @case ('checkbox') {\n <label class=\"mform-check\">\n <input\n type=\"checkbox\"\n [id]=\"controlId()\"\n [checked]=\"value() === true\"\n [disabled]=\"field().disabled === true\"\n [attr.aria-invalid]=\"errors().length > 0 || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (change)=\"setChecked($event)\"\n (blur)=\"touch()\"\n />\n <span>\n {{ field().label || field().key }}\n @if (required()) {\n <span class=\"mform-req\" aria-hidden=\"true\">*</span>\n }\n </span>\n </label>\n }\n @case ('checkbox-group') {\n <div class=\"mform-choices\" role=\"group\" [attr.aria-label]=\"field().label || field().key\">\n @for (option of options(); track option.value) {\n <label class=\"mform-check\">\n <input\n type=\"checkbox\"\n [checked]=\"mapValue()['' + option.value] === true\"\n [disabled]=\"field().disabled === true\"\n (change)=\"toggleMap('' + option.value, $event)\"\n (blur)=\"touch()\"\n />\n <span>{{ option.label }}</span>\n </label>\n }\n </div>\n }\n @case ('file') {\n <input\n class=\"mform-control\"\n type=\"file\"\n multiple\n [id]=\"controlId()\"\n [disabled]=\"field().disabled === true\"\n [attr.aria-describedby]=\"describedBy()\"\n (change)=\"setFiles($event)\"\n (blur)=\"touch()\"\n />\n }\n @case ('unsupported') {\n <input\n class=\"mform-control\"\n type=\"text\"\n disabled\n [id]=\"controlId()\"\n [value]=\"'Unsupported field (' + (sourceType() || 'unknown') + ')'\"\n />\n }\n @default {\n <input\n class=\"mform-control\"\n [type]=\"inputType()\"\n [id]=\"controlId()\"\n [value]=\"stringValue()\"\n [placeholder]=\"field().placeholder || ''\"\n [disabled]=\"field().disabled === true\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"errors().length > 0 || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (input)=\"setString($event)\"\n (blur)=\"touch()\"\n />\n }\n }\n @if (field().description) {\n <div class=\"mform-desc\" [id]=\"controlId() + '-desc'\">{{ field().description }}</div>\n }\n @for (error of errors(); track error.rule) {\n <div class=\"mform-error\" [id]=\"controlId() + '-err'\" role=\"alert\">{{ error.message }}</div>\n }\n </div>\n }\n }\n }\n }\n `,\n})\nexport class FormNodeComponent {\n readonly node = input.required<FieldNode>();\n readonly engine = input.required<FormEngine>();\n /** Monotonic counter bumped on every engine event — invalidates the view. */\n readonly tick = input.required<number>();\n /** Data-path prefix (set by array rows and nested groups above this node). */\n readonly scope = input<string>('');\n /** Suppresses the panel chrome (used when a tab already framed the child). */\n readonly bare = input<boolean>(false);\n /** Host-registered providers for `optionsSource: provider` fields. */\n readonly providers = input<OptionsProviderRegistry>({});\n\n readonly activeTab = signal(0);\n\n /** Options resolved from a dynamic source (provider or remote URL). */\n private readonly resolvedOptions = signal<FieldOption[] | null>(null);\n /** Snapshot of the observed refresh source at the last resolution. */\n private lastRefreshKey: string | null = null;\n\n constructor() {\n effect(() => {\n const node = this.node();\n const registry = this.providers();\n if (node.kind !== 'input' || !node.optionsSource) {\n this.resolvedOptions.set(null);\n return;\n }\n const source = node.optionsSource;\n // With refreshOn, engine events re-run this effect; the refresh key\n // then decides whether the observed data actually changed.\n if (source.refreshOn) this.tick();\n const engine = untracked(() => this.engine());\n const path = untracked(() => this.path());\n const refreshKey = !source.refreshOn\n ? 'static'\n : source.refreshOn === 'data'\n ? JSON.stringify(engine.getData())\n : JSON.stringify(engine.getValue(source.refreshOn) ?? null);\n if (refreshKey === this.lastRefreshKey) return;\n this.lastRefreshKey = refreshKey;\n if (source.type === 'provider') {\n const provider = registry[source.name];\n if (!provider) return; // no provider: static options/fallback stand\n Promise.resolve(\n provider({ field: node, path, data: engine.getData(), args: source.args }),\n )\n .then((options) => this.resolvedOptions.set(options))\n .catch(() => {}); // provider failure keeps the static fallback\n } else {\n fetch(source.url)\n .then((response) => (response.ok ? response.json() : []))\n .then((list: Array<Record<string, unknown>>) =>\n this.resolvedOptions.set(\n (Array.isArray(list) ? list : []).map((item) => ({\n label: String(item[source.labelKey ?? 'label'] ?? item[source.valueKey ?? 'value'] ?? ''),\n value: (item[source.valueKey ?? 'value'] ?? '') as FieldOption['value'],\n })),\n ),\n )\n .catch(() => {});\n }\n });\n }\n\n /** Effective options: dynamically resolved first, static as fallback. */\n options(): FieldOption[] {\n return this.resolvedOptions() ?? this.field().options ?? [];\n }\n\n // -- typed views of the node ---------------------------------------------\n\n field(): InputField {\n return this.node() as InputField;\n }\n\n container(): ContainerField {\n return this.node() as ContainerField;\n }\n\n content(): string {\n return (this.node() as StaticField).content ?? '';\n }\n\n buttonAction(): string {\n return String(this.node().props?.['action'] ?? 'submit');\n }\n\n sourceType(): string {\n return String(this.node().props?.['sourceType'] ?? '');\n }\n\n rowsProp(): number | null {\n const rows = this.node().props?.['rows'];\n return typeof rows === 'number' ? rows : null;\n }\n\n // -- paths and visibility -------------------------------------------------\n\n /** Data path of this node (inputs) or of its scope (containers). */\n readonly path = computed(() => {\n const scope = this.scope();\n const node = this.node();\n if (node.kind === 'input') return scope ? `${scope}.${node.key}` : node.key;\n if (node.kind === 'container' && node.dataScope !== 'inherit') {\n return scope ? `${scope}.${node.key}` : node.key;\n }\n return scope;\n });\n\n /** Scope handed to children (nested/array containers extend it). */\n readonly childScope = computed(() => {\n const node = this.node();\n if (node.kind === 'container' && node.dataScope === 'nested') return this.path();\n return this.scope();\n });\n\n rowScope(index: number): string {\n return `${this.path()}.${index}`;\n }\n\n visible(): boolean {\n this.tick();\n const node = this.node();\n const key = node.kind === 'input' ? this.path() : node.key;\n return this.engine().isVisible(key);\n }\n\n containerLayout(): 'columns' | 'tabs' | 'array' | 'block' {\n const node = this.container();\n if (node.dataScope === 'array') return 'array';\n if (node.type === 'tabs') return 'tabs';\n if (node.type === 'columns' && node.columns?.length) return 'columns';\n return 'block';\n }\n\n columns(): FieldNode[][] {\n const node = this.container();\n return (node.columns ?? []).map((column) =>\n column.children\n .map((index) => node.children[index])\n .filter((child): child is FieldNode => child !== undefined),\n );\n }\n\n columnsTemplate(): string {\n const cols = this.container().columns ?? [];\n const total = cols.reduce((sum, c) => sum + c.width, 0) || 12;\n return cols.map((c) => `${((c.width / total) * 100).toFixed(3)}fr`).join(' ');\n }\n\n // -- values ---------------------------------------------------------------\n\n value(): unknown {\n this.tick();\n return this.engine().getValue(this.path());\n }\n\n stringValue(): string {\n const value = this.value();\n return value === undefined || value === null ? '' : String(value);\n }\n\n mapValue(): Record<string, unknown> {\n const value = this.value();\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n }\n\n rows(): unknown[] {\n const value = this.value();\n return Array.isArray(value) ? value : [];\n }\n\n required(): boolean {\n return this.field().validators?.some((v) => v.type === 'required') ?? false;\n }\n\n errors() {\n this.tick();\n return this.engine().getFieldErrors(this.path());\n }\n\n controlId(): string {\n return `mform-${this.path().replace(/\\./g, '-')}`;\n }\n\n describedBy(): string | null {\n const parts: string[] = [];\n if (this.field().description) parts.push(`${this.controlId()}-desc`);\n if (this.errors().length > 0) parts.push(`${this.controlId()}-err`);\n return parts.length ? parts.join(' ') : null;\n }\n\n inputType(): string {\n switch (this.field().type) {\n case 'number':\n case 'currency':\n return 'number';\n case 'email':\n return 'email';\n case 'password':\n return 'password';\n case 'phone':\n return 'tel';\n case 'url':\n return 'url';\n case 'time':\n return 'time';\n case 'datetime':\n return 'datetime-local';\n case 'day':\n return 'date';\n default:\n return 'text';\n }\n }\n\n // -- interaction ----------------------------------------------------------\n\n setValue(value: unknown): void {\n this.engine().setValue(this.path(), value);\n }\n\n setString(event: Event): void {\n const raw = (event.target as HTMLInputElement | HTMLTextAreaElement).value;\n if (this.field().dataType === 'number') {\n const parsed = raw === '' ? undefined : Number(raw);\n this.setValue(parsed !== undefined && Number.isFinite(parsed) ? parsed : undefined);\n } else {\n this.setValue(raw);\n }\n }\n\n setSelect(event: Event): void {\n this.setValue((event.target as HTMLSelectElement).value);\n }\n\n setChecked(event: Event): void {\n this.setValue((event.target as HTMLInputElement).checked);\n }\n\n toggleMap(option: string, event: Event): void {\n const checked = (event.target as HTMLInputElement).checked;\n this.setValue({ ...this.mapValue(), [option]: checked });\n }\n\n setFiles(event: Event): void {\n const files = (event.target as HTMLInputElement).files;\n this.setValue(files ? Array.from(files).map((f) => f.name) : []);\n }\n\n touch(): void {\n this.engine().markTouched(this.path());\n this.engine().validateField(this.path());\n }\n\n addRow(): void {\n this.engine().addRow(this.path());\n }\n\n removeRow(index: number): void {\n this.engine().removeRow(this.path(), index);\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n effect,\n input,\n output,\n signal,\n} from '@angular/core';\nimport {\n collectInputs,\n createFormEngine,\n createLegacyImporter,\n importForm,\n type ContainerField,\n type FieldError,\n type FormEngine,\n type FormSchema,\n type ImportWarning,\n type MessageResolver,\n type OptionsProviderRegistry,\n type SubmitResult,\n} from '@mosaicoo/form-core';\nimport { FormNodeComponent } from './form-node.component.js';\n\n/**\n * `<mform-renderer>` — renders a form at runtime from a `FormSchema` (or any\n * definition a registered importer understands) and manages its lifecycle:\n * values, validation, conditional visibility and submission. Wizard schemas\n * (`settings.display: 'wizard'`) render as steps with per-step validation.\n *\n * Theming: every visual primitive reads a `--mform-*` CSS custom property\n * with a self-contained fallback, so the component looks finished on its own\n * and adopts the host design system when the host overrides the tokens.\n */\n@Component({\n selector: 'mform-renderer',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [FormNodeComponent],\n styleUrls: ['./form-theme.css'],\n template: `\n @if (engine(); as engine) {\n <form class=\"mform-root\" novalidate (submit)=\"onSubmit($event)\">\n @if (errorSummary().length > 0) {\n <div class=\"mform-summary\" role=\"alert\" tabindex=\"-1\">\n <strong>{{ summaryTitle() }}</strong>\n <ul>\n @for (error of errorSummary(); track error.path + error.rule) {\n <li>{{ error.message }}</li>\n }\n </ul>\n </div>\n }\n @if (isWizard()) {\n <ol class=\"mform-steps\">\n @for (step of steps(); track step.key; let i = $index) {\n <li\n class=\"mform-step\"\n [class.is-active]=\"currentStep() === i\"\n [class.is-done]=\"i < currentStep()\"\n [attr.aria-current]=\"currentStep() === i ? 'step' : null\"\n >\n <span class=\"mform-step-index\">{{ i + 1 }}</span>\n <span class=\"mform-step-label\">{{ step.label || 'Step ' + (i + 1) }}</span>\n </li>\n }\n </ol>\n @if (steps()[currentStep()]; as step) {\n <mform-node\n [node]=\"step\"\n [engine]=\"engine\"\n [tick]=\"tick()\"\n [providers]=\"optionsProviders()\"\n [bare]=\"true\"\n />\n }\n <div class=\"mform-wizard-nav\">\n @if (currentStep() > 0) {\n <button type=\"button\" class=\"mform-btn mform-btn-secondary\" (click)=\"previousStep()\">\n {{ labels().previous }}\n </button>\n }\n @if (currentStep() < steps().length - 1) {\n <button type=\"button\" class=\"mform-btn\" (click)=\"nextStep()\">\n {{ labels().next }}\n </button>\n } @else {\n <button type=\"submit\" class=\"mform-btn\">{{ labels().submit }}</button>\n }\n </div>\n } @else {\n @for (node of engine.schema.fields; track node.key) {\n <mform-node [node]=\"node\" [engine]=\"engine\" [tick]=\"tick()\" [providers]=\"optionsProviders()\" />\n }\n }\n </form>\n }\n `,\n})\nexport class FormRendererComponent {\n /** Native schema input. Takes precedence over `source`. */\n readonly schema = input<FormSchema | null>(null);\n /** Foreign definition (object or JSON string) resolved via importers. */\n readonly source = input<unknown>(null);\n /** Initial data merged over schema defaults. */\n readonly initialData = input<Record<string, unknown> | null>(null);\n /** Named providers resolving `optionsSource: provider` fields. */\n readonly optionsProviders = input<OptionsProviderRegistry>({});\n /** Host-supplied message resolver (localization of validation messages). */\n readonly messages = input<MessageResolver | null>(null);\n /** Fixed renderer texts (override to localize). `{{count}}` in `summary`. */\n readonly labels = input(\n {\n previous: 'Previous',\n next: 'Next',\n submit: 'Submit',\n summary: '{{count}} field(s) need attention:',\n },\n {\n transform: (value: Partial<{ previous: string; next: string; submit: string; summary: string }>) => ({\n previous: 'Previous',\n next: 'Next',\n submit: 'Submit',\n summary: '{{count}} field(s) need attention:',\n ...value,\n }),\n },\n );\n\n summaryTitle(): string {\n return this.labels().summary.replace(/\\{\\{\\s*count\\s*\\}\\}/g, String(this.errorSummary().length));\n }\n\n /** Fired on submit; `ok` is false when validation failed. */\n readonly submitted = output<SubmitResult>();\n /** Fired on every value change with the full data snapshot. */\n readonly valueChanged = output<Record<string, unknown>>();\n\n /** Bumped on every engine event; nodes read it to refresh. */\n readonly tick = signal(0);\n /** Active wizard step index. */\n readonly currentStep = signal(0);\n\n private readonly resolved = computed<{\n schema: FormSchema | null;\n warnings: ImportWarning[];\n }>(() => {\n const native = this.schema();\n if (native) return { schema: native, warnings: [] };\n const source = this.source();\n if (source === null || source === undefined) return { schema: null, warnings: [] };\n try {\n const result = importForm(source, [createLegacyImporter()]);\n return { schema: result.schema, warnings: result.warnings };\n } catch {\n return {\n schema: null,\n warnings: [\n { code: 'unreadable-source', message: 'The form definition could not be read.' },\n ],\n };\n }\n });\n\n /** Import degradations for the current `source`, if any. */\n readonly importWarnings = computed(() => this.resolved().warnings);\n\n readonly engine = computed<FormEngine | null>(() => {\n const schema = this.resolved().schema;\n return schema\n ? createFormEngine(schema, {\n initialData: this.initialData() ?? undefined,\n messages: this.messages() ?? undefined,\n })\n : null;\n });\n\n readonly isWizard = computed(\n () => this.resolved().schema?.settings?.display === 'wizard' && this.steps().length > 0,\n );\n\n /** Wizard pages: the top-level containers of the schema. */\n readonly steps = computed<ContainerField[]>(() =>\n (this.resolved().schema?.fields ?? []).filter(\n (node): node is ContainerField => node.kind === 'container',\n ),\n );\n\n readonly errorSummary = signal<FieldError[]>([]);\n\n constructor() {\n effect((onCleanup) => {\n const engine = this.engine();\n this.errorSummary.set([]);\n this.tick.set(0);\n this.currentStep.set(0);\n if (!engine) return;\n const unsubscribe = engine.subscribe((event) => {\n this.tick.update((v) => v + 1);\n if (event.type === 'value-change') {\n this.valueChanged.emit(engine.getData());\n }\n if (event.type === 'validation') {\n // Keep the banner in sync as the user fixes fields after a submit.\n if (this.errorSummary().length > 0) {\n this.errorSummary.set(event.errors);\n }\n }\n });\n onCleanup(unsubscribe);\n });\n }\n\n // -- wizard navigation ----------------------------------------------------\n\n previousStep(): void {\n this.errorSummary.set([]);\n this.currentStep.update((step) => Math.max(0, step - 1));\n }\n\n nextStep(): void {\n const engine = this.engine();\n const step = this.steps()[this.currentStep()];\n if (!engine || !step) return;\n const errors = engine.validateContainer(step.key);\n if (errors.length > 0) {\n this.errorSummary.set(errors);\n this.focusFirstError(errors);\n return;\n }\n this.errorSummary.set([]);\n this.currentStep.update((index) => Math.min(this.steps().length - 1, index + 1));\n }\n\n // -- submission -----------------------------------------------------------\n\n onSubmit(event: Event): void {\n event.preventDefault();\n const engine = this.engine();\n if (!engine) return;\n const result = engine.submit();\n this.errorSummary.set(result.errors);\n if (!result.ok) {\n if (this.isWizard()) {\n const stepIndex = this.stepIndexForPath(result.errors[0]?.path ?? '');\n if (stepIndex >= 0) this.currentStep.set(stepIndex);\n }\n this.focusFirstError(result.errors);\n }\n this.submitted.emit(result);\n }\n\n /** Finds the wizard step that owns a (possibly row-indexed) data path. */\n private stepIndexForPath(path: string): number {\n const pattern = path\n .split('.')\n .map((part) => (/^\\d+$/.test(part) ? '*' : part))\n .join('.');\n return this.steps().findIndex((step) =>\n collectInputs({ version: 1, fields: step.children }).some(\n (entry) => entry.path === pattern,\n ),\n );\n }\n\n private focusFirstError(errors: FieldError[]): void {\n const first = errors[0];\n if (!first) return;\n const id = `mform-${first.path.replace(/\\./g, '-')}`;\n // Focus after the view updated with the error states.\n queueMicrotask(() => document.getElementById(id)?.focus());\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mosaicoo-form-angular.mjs","sources":["../../../packages/angular/src/lib/providers.ts","../../../packages/angular/src/lib/form-node.component.ts","../../../packages/angular/src/lib/form-renderer.component.ts","../../../packages/angular/src/public-api.ts","../../../packages/angular/src/mosaicoo-form-angular.ts"],"sourcesContent":["import {\n InjectionToken,\n makeEnvironmentProviders,\n type EnvironmentProviders,\n type Provider,\n type Type,\n} from '@angular/core';\nimport type { FormEngine, InputField, RemoteOptionsFetcher } from '@mosaicoo/form-core';\n\n/**\n * Extension surface of the renderer.\n *\n * Hosts extend or replace field rendering by registering components per field\n * `type` — new types (signature, rating, references…) plug in, and built-in\n * types can be overridden (e.g. a design-system adapter swapping the native\n * select for its own). The registry is DI-scoped: different areas of an app\n * can provide different catalogs.\n */\n\n/**\n * Contract of a registered field component. Implementations receive these\n * values as signal inputs with the SAME names (`field`, `engine`, `path`,\n * `tick`) and interact with the form exclusively through the engine —\n * `engine.getValue(path)` / `engine.setValue(path, value)` /\n * `engine.markTouched(path)` — so validation, conditionals and events keep\n * working with no extra wiring.\n */\nexport interface MformFieldComponent {\n field: () => InputField;\n engine: () => FormEngine;\n path: () => string;\n /** Bumped on every engine event; read it to stay in sync. */\n tick: () => number;\n}\n\n/** Map of field `type` → component implementing {@link MformFieldComponent}. */\nexport type FieldComponentMap = Record<string, Type<unknown>>;\n\n/** Multi-provider token: maps merge, later providers win on conflicts. */\nexport const MFORM_FIELD_COMPONENTS = new InjectionToken<FieldComponentMap[]>(\n 'MFORM_FIELD_COMPONENTS',\n);\n\n/**\n * Transport used for `optionsSource: { type: 'remote' }` fields. Register it\n * to route those requests through the host's HTTP stack (authentication,\n * base URLs, caching). Without it, a plain `fetch` is used.\n */\nexport const MFORM_REMOTE_FETCHER = new InjectionToken<RemoteOptionsFetcher>(\n 'MFORM_REMOTE_FETCHER',\n);\n\nexport interface MosaicooFormConfig {\n /** Custom/override field components, keyed by field `type`. */\n components?: FieldComponentMap;\n /** Host transport for remote options sources. */\n remoteFetcher?: RemoteOptionsFetcher;\n}\n\n/**\n * Registers renderer extensions at any injector level:\n *\n * ```ts\n * bootstrapApplication(App, {\n * providers: [\n * provideMosaicooForm({\n * components: { signature: SignatureFieldComponent },\n * remoteFetcher: (url) => authenticatedGet(url),\n * }),\n * ],\n * });\n * ```\n */\nexport function provideMosaicooForm(config: MosaicooFormConfig): EnvironmentProviders {\n const providers: Provider[] = [];\n if (config.components) {\n providers.push({ provide: MFORM_FIELD_COMPONENTS, useValue: config.components, multi: true });\n }\n if (config.remoteFetcher) {\n providers.push({ provide: MFORM_REMOTE_FETCHER, useValue: config.remoteFetcher });\n }\n return makeEnvironmentProviders(providers);\n}\n","import { NgComponentOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n signal,\n untracked,\n type Type,\n} from '@angular/core';\nimport type {\n ContainerField,\n FieldNode,\n FieldOption,\n FormEngine,\n InputField,\n OptionsProviderRegistry,\n StaticField,\n} from '@mosaicoo/form-core';\nimport { MFORM_FIELD_COMPONENTS, MFORM_REMOTE_FETCHER } from './providers.js';\n\n/**\n * Renders one schema node (input, container or static) and recurses into\n * children. State lives in the headless engine — this component only projects\n * it and forwards user interaction. `tick` changes whenever the engine emits,\n * invalidating the OnPush view.\n */\n@Component({\n selector: 'mform-node',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: { class: 'mform-node' },\n imports: [NgComponentOutlet],\n template: `\n @let n = node();\n @if (visible()) {\n @switch (n.kind) {\n @case ('static') {\n @if (n.type === 'button') {\n <button\n class=\"mform-btn\"\n [type]=\"buttonAction() === 'submit' ? 'submit' : 'button'\"\n >\n {{ n.label || 'Submit' }}\n </button>\n } @else if (n.type === 'content') {\n <div class=\"mform-content\" [innerHTML]=\"content()\"></div>\n } @else {\n <div class=\"mform-unsupported\" role=\"note\">\n {{ n.label || n.key }} — unsupported content\n </div>\n }\n }\n @case ('container') {\n @switch (containerLayout()) {\n @case ('columns') {\n <div class=\"mform-columns\" [style.grid-template-columns]=\"columnsTemplate()\">\n @for (column of columns(); track $index) {\n <div class=\"mform-column\">\n @for (child of column; track child.key) {\n <mform-node [node]=\"child\" [engine]=\"engine()\" [tick]=\"tick()\" [providers]=\"providers()\" [scope]=\"childScope()\" />\n }\n </div>\n }\n </div>\n }\n @case ('tabs') {\n <div class=\"mform-tabs\">\n <div class=\"mform-tabbar\" role=\"tablist\">\n @for (tab of container().children; track tab.key; let i = $index) {\n <button\n type=\"button\"\n class=\"mform-tab\"\n role=\"tab\"\n [class.is-active]=\"activeTab() === i\"\n [attr.aria-selected]=\"activeTab() === i\"\n (click)=\"activeTab.set(i)\"\n >\n {{ tab.label || 'Tab ' + (i + 1) }}\n </button>\n }\n </div>\n @for (tab of container().children; track tab.key; let i = $index) {\n @if (activeTab() === i) {\n <div class=\"mform-tabpanel\" role=\"tabpanel\">\n <mform-node [node]=\"tab\" [engine]=\"engine()\" [tick]=\"tick()\" [providers]=\"providers()\" [scope]=\"childScope()\" [bare]=\"true\" />\n </div>\n }\n }\n </div>\n }\n @case ('array') {\n <section class=\"mform-panel mform-grid\">\n @if (container().label) {\n <header class=\"mform-panel-head\">{{ container().label }}</header>\n }\n <div class=\"mform-panel-body\">\n @for (row of rows(); track $index; let i = $index) {\n <div class=\"mform-grid-row\" role=\"group\" [attr.aria-label]=\"(container().label || container().key) + ' ' + (i + 1)\">\n <div class=\"mform-grid-fields\">\n @for (child of container().children; track child.key) {\n <mform-node [node]=\"child\" [engine]=\"engine()\" [tick]=\"tick()\" [providers]=\"providers()\" [scope]=\"rowScope(i)\" />\n }\n </div>\n <button\n type=\"button\"\n class=\"mform-row-remove\"\n (click)=\"removeRow(i)\"\n [attr.aria-label]=\"'Remove row ' + (i + 1)\"\n >\n ✕\n </button>\n </div>\n }\n <button type=\"button\" class=\"mform-row-add\" (click)=\"addRow()\">+ Add</button>\n </div>\n </section>\n }\n @default {\n @if (container().label && !bare()) {\n <section class=\"mform-panel\">\n <header class=\"mform-panel-head\">{{ container().label }}</header>\n <div class=\"mform-panel-body\">\n @for (child of container().children; track child.key) {\n <mform-node [node]=\"child\" [engine]=\"engine()\" [tick]=\"tick()\" [providers]=\"providers()\" [scope]=\"childScope()\" />\n }\n </div>\n </section>\n } @else {\n <div class=\"mform-group\">\n @for (child of container().children; track child.key) {\n <mform-node [node]=\"child\" [engine]=\"engine()\" [tick]=\"tick()\" [providers]=\"providers()\" [scope]=\"childScope()\" />\n }\n </div>\n }\n }\n }\n }\n @case ('input') {\n @if (customComponent(); as custom) {\n <ng-container\n [ngComponentOutlet]=\"custom\"\n [ngComponentOutletInputs]=\"customInputs()\"\n />\n } @else if (field().type !== 'hidden') {\n <div class=\"mform-field\" [class.has-error]=\"errors().length > 0\">\n @if (field().type !== 'checkbox') {\n <label class=\"mform-label\" [attr.for]=\"controlId()\">\n {{ field().label || field().key }}\n @if (required()) {\n <span class=\"mform-req\" aria-hidden=\"true\">*</span>\n }\n </label>\n }\n @switch (field().type) {\n @case ('textarea') {\n <textarea\n class=\"mform-control\"\n [id]=\"controlId()\"\n [value]=\"stringValue()\"\n [placeholder]=\"field().placeholder || ''\"\n [disabled]=\"field().disabled === true\"\n [attr.rows]=\"rowsProp()\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"errors().length > 0 || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (input)=\"setString($event)\"\n (blur)=\"touch()\"\n ></textarea>\n }\n @case ('select') {\n <select\n class=\"mform-control\"\n [id]=\"controlId()\"\n [disabled]=\"field().disabled === true\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"errors().length > 0 || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (change)=\"setSelect($event)\"\n (blur)=\"touch()\"\n >\n <option value=\"\" [selected]=\"stringValue() === ''\"></option>\n @for (option of options(); track option.value) {\n <option\n [value]=\"option.value\"\n [selected]=\"stringValue() === '' + option.value\"\n >\n {{ option.label }}\n </option>\n }\n </select>\n }\n @case ('radio') {\n <div class=\"mform-choices\" role=\"radiogroup\" [attr.aria-label]=\"field().label || field().key\">\n @for (option of options(); track option.value) {\n <label class=\"mform-check\">\n <input\n type=\"radio\"\n [name]=\"controlId()\"\n [checked]=\"stringValue() === '' + option.value\"\n [disabled]=\"field().disabled === true\"\n (change)=\"setValue(option.value)\"\n (blur)=\"touch()\"\n />\n <span>{{ option.label }}</span>\n </label>\n }\n </div>\n }\n @case ('checkbox') {\n <label class=\"mform-check\">\n <input\n type=\"checkbox\"\n [id]=\"controlId()\"\n [checked]=\"value() === true\"\n [disabled]=\"field().disabled === true\"\n [attr.aria-invalid]=\"errors().length > 0 || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (change)=\"setChecked($event)\"\n (blur)=\"touch()\"\n />\n <span>\n {{ field().label || field().key }}\n @if (required()) {\n <span class=\"mform-req\" aria-hidden=\"true\">*</span>\n }\n </span>\n </label>\n }\n @case ('checkbox-group') {\n <div class=\"mform-choices\" role=\"group\" [attr.aria-label]=\"field().label || field().key\">\n @for (option of options(); track option.value) {\n <label class=\"mform-check\">\n <input\n type=\"checkbox\"\n [checked]=\"mapValue()['' + option.value] === true\"\n [disabled]=\"field().disabled === true\"\n (change)=\"toggleMap('' + option.value, $event)\"\n (blur)=\"touch()\"\n />\n <span>{{ option.label }}</span>\n </label>\n }\n </div>\n }\n @case ('file') {\n <input\n class=\"mform-control\"\n type=\"file\"\n multiple\n [id]=\"controlId()\"\n [disabled]=\"field().disabled === true\"\n [attr.aria-describedby]=\"describedBy()\"\n (change)=\"setFiles($event)\"\n (blur)=\"touch()\"\n />\n }\n @case ('unsupported') {\n <input\n class=\"mform-control\"\n type=\"text\"\n disabled\n [id]=\"controlId()\"\n [value]=\"'Unsupported field (' + (sourceType() || 'unknown') + ')'\"\n />\n }\n @default {\n <input\n class=\"mform-control\"\n [type]=\"inputType()\"\n [id]=\"controlId()\"\n [value]=\"stringValue()\"\n [placeholder]=\"field().placeholder || ''\"\n [disabled]=\"field().disabled === true\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"errors().length > 0 || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (input)=\"setString($event)\"\n (blur)=\"touch()\"\n />\n }\n }\n @if (field().description) {\n <div class=\"mform-desc\" [id]=\"controlId() + '-desc'\">{{ field().description }}</div>\n }\n @for (error of errors(); track error.rule) {\n <div class=\"mform-error\" [id]=\"controlId() + '-err'\" role=\"alert\">{{ error.message }}</div>\n }\n </div>\n }\n }\n }\n }\n `,\n})\nexport class FormNodeComponent {\n readonly node = input.required<FieldNode>();\n readonly engine = input.required<FormEngine>();\n /** Monotonic counter bumped on every engine event — invalidates the view. */\n readonly tick = input.required<number>();\n /** Data-path prefix (set by array rows and nested groups above this node). */\n readonly scope = input<string>('');\n /** Suppresses the panel chrome (used when a tab already framed the child). */\n readonly bare = input<boolean>(false);\n /** Host-registered providers for `optionsSource: provider` fields. */\n readonly providers = input<OptionsProviderRegistry>({});\n\n readonly activeTab = signal(0);\n\n /** DI-registered custom field components (maps merge; later wins). */\n private readonly componentMaps = inject(MFORM_FIELD_COMPONENTS, { optional: true });\n /** Host transport for remote options; plain fetch when absent. */\n private readonly remoteFetcher = inject(MFORM_REMOTE_FETCHER, { optional: true });\n\n /** Custom component registered for this field type, if any. */\n customComponent(): Type<unknown> | null {\n const node = this.node();\n if (node.kind !== 'input' || !this.componentMaps) return null;\n for (let i = this.componentMaps.length - 1; i >= 0; i--) {\n const match = this.componentMaps[i]?.[node.type];\n if (match) return match;\n }\n return null;\n }\n\n /** Inputs handed to a custom component (MformFieldComponent contract). */\n customInputs(): Record<string, unknown> {\n return {\n field: this.field(),\n engine: this.engine(),\n path: this.path(),\n tick: this.tick(),\n };\n }\n\n /** Options resolved from a dynamic source (provider or remote URL). */\n private readonly resolvedOptions = signal<FieldOption[] | null>(null);\n /** Snapshot of the observed refresh source at the last resolution. */\n private lastRefreshKey: string | null = null;\n /** Discards resolutions that arrive after a newer request started. */\n private optionsRequestSeq = 0;\n\n constructor() {\n effect(() => {\n const node = this.node();\n const registry = this.providers();\n if (node.kind !== 'input' || !node.optionsSource) {\n this.resolvedOptions.set(null);\n return;\n }\n const source = node.optionsSource;\n // With refreshOn, engine events re-run this effect; the refresh key\n // then decides whether the observed data actually changed.\n if (source.refreshOn) this.tick();\n const engine = untracked(() => this.engine());\n const path = untracked(() => this.path());\n const refreshKey = !source.refreshOn\n ? 'static'\n : source.refreshOn === 'data'\n ? JSON.stringify(engine.getData())\n : JSON.stringify(engine.getValue(source.refreshOn) ?? null);\n if (refreshKey === this.lastRefreshKey) return;\n this.lastRefreshKey = refreshKey;\n // Stale-response guard: only the latest request may write options.\n const requestId = ++this.optionsRequestSeq;\n const apply = (options: FieldOption[]) => {\n if (requestId === this.optionsRequestSeq) this.resolvedOptions.set(options);\n };\n if (source.type === 'provider') {\n const provider = registry[source.name];\n if (!provider) return; // no provider: static options/fallback stand\n Promise.resolve(\n provider({ field: node, path, data: engine.getData(), args: source.args }),\n )\n .then(apply)\n .catch(() => {}); // provider failure keeps the static fallback\n } else {\n // The host's transport (auth, base URL, caching) when registered via\n // provideMosaicooForm; plain fetch as the zero-config default.\n const request = this.remoteFetcher\n ? this.remoteFetcher(source.url)\n : fetch(source.url).then((response) => (response.ok ? response.json() : []));\n request\n .then((list) =>\n apply(\n (Array.isArray(list) ? (list as Array<Record<string, unknown>>) : []).map((item) => ({\n label: String(item[source.labelKey ?? 'label'] ?? item[source.valueKey ?? 'value'] ?? ''),\n value: (item[source.valueKey ?? 'value'] ?? '') as FieldOption['value'],\n })),\n ),\n )\n .catch(() => {});\n }\n });\n }\n\n /** Effective options: dynamically resolved first, static as fallback. */\n options(): FieldOption[] {\n return this.resolvedOptions() ?? this.field().options ?? [];\n }\n\n // -- typed views of the node ---------------------------------------------\n\n field(): InputField {\n return this.node() as InputField;\n }\n\n container(): ContainerField {\n return this.node() as ContainerField;\n }\n\n content(): string {\n return (this.node() as StaticField).content ?? '';\n }\n\n buttonAction(): string {\n return String(this.node().props?.['action'] ?? 'submit');\n }\n\n sourceType(): string {\n return String(this.node().props?.['sourceType'] ?? '');\n }\n\n rowsProp(): number | null {\n const rows = this.node().props?.['rows'];\n return typeof rows === 'number' ? rows : null;\n }\n\n // -- paths and visibility -------------------------------------------------\n\n /** Data path of this node (inputs) or of its scope (containers). */\n readonly path = computed(() => {\n const scope = this.scope();\n const node = this.node();\n if (node.kind === 'input') return scope ? `${scope}.${node.key}` : node.key;\n if (node.kind === 'container' && node.dataScope !== 'inherit') {\n return scope ? `${scope}.${node.key}` : node.key;\n }\n return scope;\n });\n\n /** Scope handed to children (nested/array containers extend it). */\n readonly childScope = computed(() => {\n const node = this.node();\n if (node.kind === 'container' && node.dataScope === 'nested') return this.path();\n return this.scope();\n });\n\n rowScope(index: number): string {\n return `${this.path()}.${index}`;\n }\n\n visible(): boolean {\n this.tick();\n const node = this.node();\n const key = node.kind === 'input' ? this.path() : node.key;\n return this.engine().isVisible(key);\n }\n\n containerLayout(): 'columns' | 'tabs' | 'array' | 'block' {\n const node = this.container();\n if (node.dataScope === 'array') return 'array';\n if (node.type === 'tabs') return 'tabs';\n if (node.type === 'columns' && node.columns?.length) return 'columns';\n return 'block';\n }\n\n columns(): FieldNode[][] {\n const node = this.container();\n return (node.columns ?? []).map((column) =>\n column.children\n .map((index) => node.children[index])\n .filter((child): child is FieldNode => child !== undefined),\n );\n }\n\n columnsTemplate(): string {\n const cols = this.container().columns ?? [];\n const total = cols.reduce((sum, c) => sum + c.width, 0) || 12;\n return cols.map((c) => `${((c.width / total) * 100).toFixed(3)}fr`).join(' ');\n }\n\n // -- values ---------------------------------------------------------------\n\n value(): unknown {\n this.tick();\n return this.engine().getValue(this.path());\n }\n\n stringValue(): string {\n const value = this.value();\n return value === undefined || value === null ? '' : String(value);\n }\n\n mapValue(): Record<string, unknown> {\n const value = this.value();\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n }\n\n rows(): unknown[] {\n const value = this.value();\n return Array.isArray(value) ? value : [];\n }\n\n required(): boolean {\n return this.field().validators?.some((v) => v.type === 'required') ?? false;\n }\n\n errors() {\n this.tick();\n return this.engine().getFieldErrors(this.path());\n }\n\n controlId(): string {\n return `mform-${this.path().replace(/\\./g, '-')}`;\n }\n\n describedBy(): string | null {\n const parts: string[] = [];\n if (this.field().description) parts.push(`${this.controlId()}-desc`);\n if (this.errors().length > 0) parts.push(`${this.controlId()}-err`);\n return parts.length ? parts.join(' ') : null;\n }\n\n inputType(): string {\n switch (this.field().type) {\n case 'number':\n case 'currency':\n return 'number';\n case 'email':\n return 'email';\n case 'password':\n return 'password';\n case 'phone':\n return 'tel';\n case 'url':\n return 'url';\n case 'time':\n return 'time';\n case 'datetime':\n return 'datetime-local';\n case 'day':\n return 'date';\n default:\n return 'text';\n }\n }\n\n // -- interaction ----------------------------------------------------------\n\n setValue(value: unknown): void {\n this.engine().setValue(this.path(), value);\n }\n\n setString(event: Event): void {\n const raw = (event.target as HTMLInputElement | HTMLTextAreaElement).value;\n if (this.field().dataType === 'number') {\n const parsed = raw === '' ? undefined : Number(raw);\n this.setValue(parsed !== undefined && Number.isFinite(parsed) ? parsed : undefined);\n } else {\n this.setValue(raw);\n }\n }\n\n setSelect(event: Event): void {\n this.setValue((event.target as HTMLSelectElement).value);\n }\n\n setChecked(event: Event): void {\n this.setValue((event.target as HTMLInputElement).checked);\n }\n\n toggleMap(option: string, event: Event): void {\n const checked = (event.target as HTMLInputElement).checked;\n this.setValue({ ...this.mapValue(), [option]: checked });\n }\n\n setFiles(event: Event): void {\n const files = (event.target as HTMLInputElement).files;\n this.setValue(files ? Array.from(files).map((f) => f.name) : []);\n }\n\n touch(): void {\n this.engine().markTouched(this.path());\n this.engine().validateField(this.path());\n }\n\n addRow(): void {\n this.engine().addRow(this.path());\n }\n\n removeRow(index: number): void {\n this.engine().removeRow(this.path(), index);\n }\n}\n","import { DOCUMENT } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n output,\n signal,\n} from '@angular/core';\nimport {\n collectInputs,\n createFormEngine,\n createLegacyImporter,\n importForm,\n type ContainerField,\n type FieldError,\n type FormEngine,\n type FormSchema,\n type ImportWarning,\n type MessageResolver,\n type OptionsProviderRegistry,\n type SubmitResult,\n} from '@mosaicoo/form-core';\nimport { FormNodeComponent } from './form-node.component.js';\n\n/**\n * `<mform-renderer>` — renders a form at runtime from a `FormSchema` (or any\n * definition a registered importer understands) and manages its lifecycle:\n * values, validation, conditional visibility and submission. Wizard schemas\n * (`settings.display: 'wizard'`) render as steps with per-step validation.\n *\n * Theming: every visual primitive reads a `--mform-*` CSS custom property\n * with a self-contained fallback, so the component looks finished on its own\n * and adopts the host design system when the host overrides the tokens.\n */\n@Component({\n selector: 'mform-renderer',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [FormNodeComponent],\n styleUrls: ['./form-theme.css'],\n template: `\n @if (engine(); as engine) {\n <form class=\"mform-root\" novalidate (submit)=\"onSubmit($event)\">\n @if (errorSummary().length > 0) {\n <div class=\"mform-summary\" role=\"alert\" tabindex=\"-1\">\n <strong>{{ summaryTitle() }}</strong>\n <ul>\n @for (error of errorSummary(); track error.path + error.rule) {\n <li>{{ error.message }}</li>\n }\n </ul>\n </div>\n }\n @if (isWizard()) {\n <ol class=\"mform-steps\">\n @for (step of steps(); track step.key; let i = $index) {\n <li\n class=\"mform-step\"\n [class.is-active]=\"currentStep() === i\"\n [class.is-done]=\"i < currentStep()\"\n [attr.aria-current]=\"currentStep() === i ? 'step' : null\"\n >\n <span class=\"mform-step-index\">{{ i + 1 }}</span>\n <span class=\"mform-step-label\">{{ step.label || 'Step ' + (i + 1) }}</span>\n </li>\n }\n </ol>\n @if (steps()[currentStep()]; as step) {\n <mform-node\n [node]=\"step\"\n [engine]=\"engine\"\n [tick]=\"tick()\"\n [providers]=\"optionsProviders()\"\n [bare]=\"true\"\n />\n }\n <div class=\"mform-wizard-nav\">\n @if (currentStep() > 0) {\n <button type=\"button\" class=\"mform-btn mform-btn-secondary\" (click)=\"previousStep()\">\n {{ labels().previous }}\n </button>\n }\n @if (currentStep() < steps().length - 1) {\n <button type=\"button\" class=\"mform-btn\" (click)=\"nextStep()\">\n {{ labels().next }}\n </button>\n } @else {\n <button type=\"submit\" class=\"mform-btn\">{{ labels().submit }}</button>\n }\n </div>\n } @else {\n @for (node of engine.schema.fields; track node.key) {\n <mform-node [node]=\"node\" [engine]=\"engine\" [tick]=\"tick()\" [providers]=\"optionsProviders()\" />\n }\n }\n </form>\n }\n `,\n})\nexport class FormRendererComponent {\n /** Native schema input. Takes precedence over `source`. */\n readonly schema = input<FormSchema | null>(null);\n /** Foreign definition (object or JSON string) resolved via importers. */\n readonly source = input<unknown>(null);\n /** Initial data merged over schema defaults. */\n readonly initialData = input<Record<string, unknown> | null>(null);\n /** Named providers resolving `optionsSource: provider` fields. */\n readonly optionsProviders = input<OptionsProviderRegistry>({});\n /** Host-supplied message resolver (localization of validation messages). */\n readonly messages = input<MessageResolver | null>(null);\n /** Fixed renderer texts (override to localize). `{{count}}` in `summary`. */\n readonly labels = input(\n {\n previous: 'Previous',\n next: 'Next',\n submit: 'Submit',\n summary: '{{count}} field(s) need attention:',\n },\n {\n transform: (value: Partial<{ previous: string; next: string; submit: string; summary: string }>) => ({\n previous: 'Previous',\n next: 'Next',\n submit: 'Submit',\n summary: '{{count}} field(s) need attention:',\n ...value,\n }),\n },\n );\n\n summaryTitle(): string {\n return this.labels().summary.replace(/\\{\\{\\s*count\\s*\\}\\}/g, String(this.errorSummary().length));\n }\n\n /** Fired on submit; `ok` is false when validation failed. */\n readonly submitted = output<SubmitResult>();\n /** Fired on every value change with the full data snapshot. */\n readonly valueChanged = output<Record<string, unknown>>();\n\n /** Bumped on every engine event; nodes read it to refresh. */\n readonly tick = signal(0);\n /** Active wizard step index. */\n readonly currentStep = signal(0);\n\n private readonly resolved = computed<{\n schema: FormSchema | null;\n warnings: ImportWarning[];\n }>(() => {\n const native = this.schema();\n if (native) return { schema: native, warnings: [] };\n const source = this.source();\n if (source === null || source === undefined) return { schema: null, warnings: [] };\n try {\n const result = importForm(source, [createLegacyImporter()]);\n return { schema: result.schema, warnings: result.warnings };\n } catch {\n return {\n schema: null,\n warnings: [\n { code: 'unreadable-source', message: 'The form definition could not be read.' },\n ],\n };\n }\n });\n\n /** Import degradations for the current `source`, if any. */\n readonly importWarnings = computed(() => this.resolved().warnings);\n\n readonly engine = computed<FormEngine | null>(() => {\n const schema = this.resolved().schema;\n return schema\n ? createFormEngine(schema, {\n initialData: this.initialData() ?? undefined,\n messages: this.messages() ?? undefined,\n })\n : null;\n });\n\n readonly isWizard = computed(\n () => this.resolved().schema?.settings?.display === 'wizard' && this.steps().length > 0,\n );\n\n /** Wizard pages: the top-level containers of the schema. */\n readonly steps = computed<ContainerField[]>(() =>\n (this.resolved().schema?.fields ?? []).filter(\n (node): node is ContainerField => node.kind === 'container',\n ),\n );\n\n readonly errorSummary = signal<FieldError[]>([]);\n\n constructor() {\n effect((onCleanup) => {\n const engine = this.engine();\n this.errorSummary.set([]);\n this.tick.set(0);\n this.currentStep.set(0);\n if (!engine) return;\n const unsubscribe = engine.subscribe((event) => {\n this.tick.update((v) => v + 1);\n if (event.type === 'value-change') {\n this.valueChanged.emit(engine.getData());\n }\n if (event.type === 'validation') {\n // Keep the banner in sync as the user fixes fields after a submit.\n if (this.errorSummary().length > 0) {\n this.errorSummary.set(event.errors);\n }\n }\n });\n onCleanup(unsubscribe);\n });\n }\n\n // -- wizard navigation ----------------------------------------------------\n\n previousStep(): void {\n this.errorSummary.set([]);\n this.currentStep.update((step) => Math.max(0, step - 1));\n }\n\n nextStep(): void {\n const engine = this.engine();\n const step = this.steps()[this.currentStep()];\n if (!engine || !step) return;\n const errors = engine.validateContainer(step.key);\n if (errors.length > 0) {\n this.errorSummary.set(errors);\n this.focusFirstError(errors);\n return;\n }\n this.errorSummary.set([]);\n this.currentStep.update((index) => Math.min(this.steps().length - 1, index + 1));\n }\n\n // -- submission -----------------------------------------------------------\n\n onSubmit(event: Event): void {\n event.preventDefault();\n const engine = this.engine();\n if (!engine) return;\n const result = engine.submit();\n this.errorSummary.set(result.errors);\n if (!result.ok) {\n if (this.isWizard()) {\n const stepIndex = this.stepIndexForPath(result.errors[0]?.path ?? '');\n if (stepIndex >= 0) this.currentStep.set(stepIndex);\n }\n this.focusFirstError(result.errors);\n }\n this.submitted.emit(result);\n }\n\n /** Finds the wizard step that owns a (possibly row-indexed) data path. */\n private stepIndexForPath(path: string): number {\n const pattern = path\n .split('.')\n .map((part) => (/^\\d+$/.test(part) ? '*' : part))\n .join('.');\n return this.steps().findIndex((step) =>\n collectInputs({ version: 1, fields: step.children }).some(\n (entry) => entry.path === pattern,\n ),\n );\n }\n\n private readonly documentRef = inject(DOCUMENT);\n\n private focusFirstError(errors: FieldError[]): void {\n const first = errors[0];\n if (!first) return;\n const id = `mform-${first.path.replace(/\\./g, '-')}`;\n // Focus after the view updated with the error states.\n queueMicrotask(() => this.documentRef.getElementById(id)?.focus());\n }\n}\n","/*\n * Runtime entry point of @mosaicoo/form-angular.\n *\n * Architectural note: this primary entry stays runtime-only. Authoring\n * tooling (the visual designer) will ship as a SECONDARY entry point\n * (`@mosaicoo/form-angular/designer`) so applications that only render\n * forms never load authoring code — a requirement for federated hosts.\n */\nexport { FormRendererComponent } from './lib/form-renderer.component.js';\nexport { FormNodeComponent } from './lib/form-node.component.js';\nexport {\n MFORM_FIELD_COMPONENTS,\n MFORM_REMOTE_FETCHER,\n provideMosaicooForm,\n type FieldComponentMap,\n type MformFieldComponent,\n type MosaicooFormConfig,\n} from './lib/providers.js';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mosaicoo/form-angular",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Angular renderer for Mosaicoo Form: accessible, token-themable dynamic forms with wizard mode and host-provided dynamic options",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Mosaicoo",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@angular/core": "^21.0.0"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@mosaicoo/form-core": "^0.
|
|
32
|
+
"@mosaicoo/form-core": "^0.2.0",
|
|
33
33
|
"tslib": "^2.3.0"
|
|
34
34
|
},
|
|
35
35
|
"sideEffects": false,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
|
+
import { Type, InjectionToken, EnvironmentProviders } from '@angular/core';
|
|
2
3
|
import * as _mosaicoo_form_core from '@mosaicoo/form-core';
|
|
3
|
-
import { FormSchema, OptionsProviderRegistry, MessageResolver, SubmitResult, ImportWarning, FormEngine, ContainerField, FieldError, FieldNode, FieldOption, InputField } from '@mosaicoo/form-core';
|
|
4
|
+
import { FormSchema, OptionsProviderRegistry, MessageResolver, SubmitResult, ImportWarning, FormEngine, ContainerField, FieldError, FieldNode, FieldOption, InputField, RemoteOptionsFetcher } from '@mosaicoo/form-core';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* `<mform-renderer>` — renders a form at runtime from a `FormSchema` (or any
|
|
@@ -58,6 +59,7 @@ declare class FormRendererComponent {
|
|
|
58
59
|
onSubmit(event: Event): void;
|
|
59
60
|
/** Finds the wizard step that owns a (possibly row-indexed) data path. */
|
|
60
61
|
private stepIndexForPath;
|
|
62
|
+
private readonly documentRef;
|
|
61
63
|
private focusFirstError;
|
|
62
64
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<FormRendererComponent, never>;
|
|
63
65
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FormRendererComponent, "mform-renderer", never, { "schema": { "alias": "schema"; "required": false; "isSignal": true; }; "source": { "alias": "source"; "required": false; "isSignal": true; }; "initialData": { "alias": "initialData"; "required": false; "isSignal": true; }; "optionsProviders": { "alias": "optionsProviders"; "required": false; "isSignal": true; }; "messages": { "alias": "messages"; "required": false; "isSignal": true; }; "labels": { "alias": "labels"; "required": false; "isSignal": true; }; }, { "submitted": "submitted"; "valueChanged": "valueChanged"; }, never, never, true, never>;
|
|
@@ -81,10 +83,20 @@ declare class FormNodeComponent {
|
|
|
81
83
|
/** Host-registered providers for `optionsSource: provider` fields. */
|
|
82
84
|
readonly providers: _angular_core.InputSignal<OptionsProviderRegistry>;
|
|
83
85
|
readonly activeTab: _angular_core.WritableSignal<number>;
|
|
86
|
+
/** DI-registered custom field components (maps merge; later wins). */
|
|
87
|
+
private readonly componentMaps;
|
|
88
|
+
/** Host transport for remote options; plain fetch when absent. */
|
|
89
|
+
private readonly remoteFetcher;
|
|
90
|
+
/** Custom component registered for this field type, if any. */
|
|
91
|
+
customComponent(): Type<unknown> | null;
|
|
92
|
+
/** Inputs handed to a custom component (MformFieldComponent contract). */
|
|
93
|
+
customInputs(): Record<string, unknown>;
|
|
84
94
|
/** Options resolved from a dynamic source (provider or remote URL). */
|
|
85
95
|
private readonly resolvedOptions;
|
|
86
96
|
/** Snapshot of the observed refresh source at the last resolution. */
|
|
87
97
|
private lastRefreshKey;
|
|
98
|
+
/** Discards resolutions that arrive after a newer request started. */
|
|
99
|
+
private optionsRequestSeq;
|
|
88
100
|
constructor();
|
|
89
101
|
/** Effective options: dynamically resolved first, static as fallback. */
|
|
90
102
|
options(): FieldOption[];
|
|
@@ -125,4 +137,61 @@ declare class FormNodeComponent {
|
|
|
125
137
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<FormNodeComponent, "mform-node", never, { "node": { "alias": "node"; "required": true; "isSignal": true; }; "engine": { "alias": "engine"; "required": true; "isSignal": true; }; "tick": { "alias": "tick"; "required": true; "isSignal": true; }; "scope": { "alias": "scope"; "required": false; "isSignal": true; }; "bare": { "alias": "bare"; "required": false; "isSignal": true; }; "providers": { "alias": "providers"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
126
138
|
}
|
|
127
139
|
|
|
128
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Extension surface of the renderer.
|
|
142
|
+
*
|
|
143
|
+
* Hosts extend or replace field rendering by registering components per field
|
|
144
|
+
* `type` — new types (signature, rating, references…) plug in, and built-in
|
|
145
|
+
* types can be overridden (e.g. a design-system adapter swapping the native
|
|
146
|
+
* select for its own). The registry is DI-scoped: different areas of an app
|
|
147
|
+
* can provide different catalogs.
|
|
148
|
+
*/
|
|
149
|
+
/**
|
|
150
|
+
* Contract of a registered field component. Implementations receive these
|
|
151
|
+
* values as signal inputs with the SAME names (`field`, `engine`, `path`,
|
|
152
|
+
* `tick`) and interact with the form exclusively through the engine —
|
|
153
|
+
* `engine.getValue(path)` / `engine.setValue(path, value)` /
|
|
154
|
+
* `engine.markTouched(path)` — so validation, conditionals and events keep
|
|
155
|
+
* working with no extra wiring.
|
|
156
|
+
*/
|
|
157
|
+
interface MformFieldComponent {
|
|
158
|
+
field: () => InputField;
|
|
159
|
+
engine: () => FormEngine;
|
|
160
|
+
path: () => string;
|
|
161
|
+
/** Bumped on every engine event; read it to stay in sync. */
|
|
162
|
+
tick: () => number;
|
|
163
|
+
}
|
|
164
|
+
/** Map of field `type` → component implementing {@link MformFieldComponent}. */
|
|
165
|
+
type FieldComponentMap = Record<string, Type<unknown>>;
|
|
166
|
+
/** Multi-provider token: maps merge, later providers win on conflicts. */
|
|
167
|
+
declare const MFORM_FIELD_COMPONENTS: InjectionToken<FieldComponentMap[]>;
|
|
168
|
+
/**
|
|
169
|
+
* Transport used for `optionsSource: { type: 'remote' }` fields. Register it
|
|
170
|
+
* to route those requests through the host's HTTP stack (authentication,
|
|
171
|
+
* base URLs, caching). Without it, a plain `fetch` is used.
|
|
172
|
+
*/
|
|
173
|
+
declare const MFORM_REMOTE_FETCHER: InjectionToken<RemoteOptionsFetcher>;
|
|
174
|
+
interface MosaicooFormConfig {
|
|
175
|
+
/** Custom/override field components, keyed by field `type`. */
|
|
176
|
+
components?: FieldComponentMap;
|
|
177
|
+
/** Host transport for remote options sources. */
|
|
178
|
+
remoteFetcher?: RemoteOptionsFetcher;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Registers renderer extensions at any injector level:
|
|
182
|
+
*
|
|
183
|
+
* ```ts
|
|
184
|
+
* bootstrapApplication(App, {
|
|
185
|
+
* providers: [
|
|
186
|
+
* provideMosaicooForm({
|
|
187
|
+
* components: { signature: SignatureFieldComponent },
|
|
188
|
+
* remoteFetcher: (url) => authenticatedGet(url),
|
|
189
|
+
* }),
|
|
190
|
+
* ],
|
|
191
|
+
* });
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
declare function provideMosaicooForm(config: MosaicooFormConfig): EnvironmentProviders;
|
|
195
|
+
|
|
196
|
+
export { FormNodeComponent, FormRendererComponent, MFORM_FIELD_COMPONENTS, MFORM_REMOTE_FETCHER, provideMosaicooForm };
|
|
197
|
+
export type { FieldComponentMap, MformFieldComponent, MosaicooFormConfig };
|