ng-form-foundry 0.0.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +72 -38
  3. package/fesm2022/ng-form-foundry.mjs +822 -0
  4. package/fesm2022/ng-form-foundry.mjs.map +1 -0
  5. package/index.d.ts +307 -0
  6. package/package.json +42 -5
  7. package/ng-package.json +0 -7
  8. package/src/lib/core/dynamic-recursive-forms-builder.ts +0 -129
  9. package/src/lib/core/utils.ts +0 -33
  10. package/src/lib/dynamic-recursive-form/anon-leaf-renderer/anon-leaf-renderer.component.html +0 -31
  11. package/src/lib/dynamic-recursive-form/anon-leaf-renderer/anon-leaf-renderer.component.scss +0 -11
  12. package/src/lib/dynamic-recursive-form/anon-leaf-renderer/anon-leaf-renderer.component.spec.ts +0 -22
  13. package/src/lib/dynamic-recursive-form/anon-leaf-renderer/anon-leaf-renderer.component.ts +0 -39
  14. package/src/lib/dynamic-recursive-form/dynamic-recursive-form.component.html +0 -168
  15. package/src/lib/dynamic-recursive-form/dynamic-recursive-form.component.scss +0 -128
  16. package/src/lib/dynamic-recursive-form/dynamic-recursive-form.component.spec.ts +0 -23
  17. package/src/lib/dynamic-recursive-form/dynamic-recursive-form.component.ts +0 -71
  18. package/src/lib/dynamic-recursive-form/dynamic-recursive-form.stories.ts +0 -36
  19. package/src/lib/dynamic-recursive-form/leaf-enum-renderer/leaf-enum-renderer.component.html +0 -8
  20. package/src/lib/dynamic-recursive-form/leaf-enum-renderer/leaf-enum-renderer.component.scss +0 -9
  21. package/src/lib/dynamic-recursive-form/leaf-enum-renderer/leaf-enum-renderer.component.spec.ts +0 -22
  22. package/src/lib/dynamic-recursive-form/leaf-enum-renderer/leaf-enum-renderer.component.ts +0 -21
  23. package/src/lib/dynamic-recursive-form/leaf-list-renderer/leaf-list-renderer.component.html +0 -31
  24. package/src/lib/dynamic-recursive-form/leaf-list-renderer/leaf-list-renderer.component.scss +0 -57
  25. package/src/lib/dynamic-recursive-form/leaf-list-renderer/leaf-list-renderer.component.spec.ts +0 -23
  26. package/src/lib/dynamic-recursive-form/leaf-list-renderer/leaf-list-renderer.component.ts +0 -52
  27. package/src/lib/dynamic-recursive-form/leaf-renderer/leaf-renderer.component.html +0 -17
  28. package/src/lib/dynamic-recursive-form/leaf-renderer/leaf-renderer.component.scss +0 -11
  29. package/src/lib/dynamic-recursive-form/leaf-renderer/leaf-renderer.component.spec.ts +0 -22
  30. package/src/lib/dynamic-recursive-form/leaf-renderer/leaf-renderer.component.ts +0 -41
  31. package/src/lib/dynamic-recursive-form/node-group-list-renderer/node-group-list-renderer.component.html +0 -24
  32. package/src/lib/dynamic-recursive-form/node-group-list-renderer/node-group-list-renderer.component.scss +0 -48
  33. package/src/lib/dynamic-recursive-form/node-group-list-renderer/node-group-list-renderer.component.spec.ts +0 -22
  34. package/src/lib/dynamic-recursive-form/node-group-list-renderer/node-group-list-renderer.component.ts +0 -101
  35. package/src/lib/types/dynamic-recursive.types.ts +0 -97
  36. package/src/lib/types/examples/complex-oai.ts +0 -938
  37. package/src/public-api.ts +0 -12
  38. package/tsconfig.lib.json +0 -18
  39. package/tsconfig.lib.prod.json +0 -11
  40. package/tsconfig.spec.json +0 -14
@@ -1,8 +0,0 @@
1
- <mat-form-field [appearance]="editable ? 'fill' : 'outline'">
2
- <mat-label>{{ leafEnum.label ?? leafEnum.name }}</mat-label>
3
- <mat-select [formControl]="control" value="{{ control.value }}">
4
- @for (option of leafEnum.enum; track $index) {
5
- <mat-option [value]="option">{{ leafEnum.enumLabel?.[$index] ?? option }}</mat-option>
6
- }
7
- </mat-select>
8
- </mat-form-field>
@@ -1,9 +0,0 @@
1
- :host {
2
- flex: 1;
3
- min-width: 0;
4
- width: 100%;
5
- }
6
-
7
- mat-form-field {
8
- width: 100%;
9
- }
@@ -1,22 +0,0 @@
1
- import { ComponentFixture, TestBed } from '@angular/core/testing';
2
-
3
- import { LeafEnumRendererComponent } from './leaf-enum-renderer.component';
4
-
5
- describe('DrfLeafEnumRendererComponent', () => {
6
- let component: LeafEnumRendererComponent;
7
- let fixture: ComponentFixture<LeafEnumRendererComponent>;
8
-
9
- beforeEach(async () => {
10
- await TestBed.configureTestingModule({
11
- imports: [LeafEnumRendererComponent],
12
- }).compileComponents();
13
-
14
- fixture = TestBed.createComponent(LeafEnumRendererComponent);
15
- component = fixture.componentInstance;
16
- fixture.detectChanges();
17
- });
18
-
19
- it('should create', () => {
20
- expect(component).toBeTruthy();
21
- });
22
- });
@@ -1,21 +0,0 @@
1
- import { Component, Input } from '@angular/core';
2
- import { LeafEnum } from '../../types/dynamic-recursive.types';
3
- import { FormControl, ReactiveFormsModule } from '@angular/forms';
4
- import { MatFormFieldModule } from '@angular/material/form-field';
5
- import { MatSelectModule } from '@angular/material/select';
6
-
7
- @Component({
8
- selector: 'nff-leaf-enum-renderer',
9
- standalone: true,
10
- imports: [ReactiveFormsModule, MatFormFieldModule, MatSelectModule],
11
- templateUrl: './leaf-enum-renderer.component.html',
12
- styleUrl: './leaf-enum-renderer.component.scss',
13
- })
14
- export class LeafEnumRendererComponent {
15
- @Input() leafEnum!: LeafEnum;
16
- @Input() initialValue!: string;
17
- @Input() control = new FormControl();
18
- @Input() removable: boolean = false;
19
- @Input() remove: any;
20
- @Input() editable: boolean = true;
21
- }
@@ -1,31 +0,0 @@
1
- @if (formArray && leaf_) {
2
- <div class="fields">
3
- @for (control of formArray.controls; track $index) {
4
- <div class="field-item">
5
- <nff-anon-leaf-renderer
6
- [AnonLeaf]="leaf_" [control]="control"
7
- [removable]="minItems == null || formArray.length > minItems"
8
- [index]="$index"
9
- [editable]="editable"
10
- [label]="leaf_.label ?? leaf_.name"
11
- (remove)="removeItem($index)"
12
- />
13
- <div class="actions">
14
- @if (formArray.length > minItems && editable) {
15
- <button class="remove-button small-icon-button" matIconButton (click)="removeItem($index)">
16
- <mat-icon matPrefix>delete</mat-icon>
17
- </button>
18
- }
19
- @if ($last) {
20
- @if (editable) {
21
- <button class="add-button small-icon-button" matIconButton (click)="addItem()">
22
- <mat-icon matPrefix>add</mat-icon>
23
- </button>
24
- }
25
- }
26
- <div class="actions-spacer"></div>
27
- </div>
28
- </div>
29
- }
30
- </div>
31
- }
@@ -1,57 +0,0 @@
1
- @use '@angular/material' as mat;
2
-
3
- :host {
4
- display: flex;
5
- flex-direction: column;
6
- flex-wrap: wrap;
7
- }
8
-
9
- .fields-container {
10
- position: relative;
11
- display: flex;
12
- flex-wrap: wrap;
13
- gap: 8px;
14
- align-items: baseline;
15
- }
16
-
17
- .field-item {
18
- display: flex;
19
- flex-direction: row;
20
- gap: 8px;
21
- align-items: center;
22
- }
23
-
24
- .actions {
25
- z-index: 100;
26
- display: flex;
27
- flex-direction: column; /* stack buttons vertically */
28
- align-items: flex-end;
29
- gap: 4px;
30
- height: 100%;
31
- }
32
-
33
- .actions-spacer {
34
- height: 20px;
35
- }
36
-
37
- nff-anon-leaf-renderer {
38
- width: 100%;
39
- }
40
-
41
- .add-button {
42
- background-color: var(--mat-sys-primary-container);
43
- @include mat.elevation(1);
44
- }
45
-
46
- .remove-button {
47
- background-color: var(--mat-sys-error-container);
48
- @include mat.elevation(1);
49
- }
50
-
51
- .title {
52
- display: flex;
53
- flex-direction: row;
54
- gap: 8px;
55
- align-items: center;
56
- }
57
-
@@ -1,23 +0,0 @@
1
- import { ComponentFixture, TestBed } from '@angular/core/testing';
2
-
3
- import { LeafListRendererComponent } from './leaf-list-renderer.component';
4
-
5
- describe('DrfLeafListRendererComponent', () => {
6
- let component: LeafListRendererComponent;
7
- let fixture: ComponentFixture<LeafListRendererComponent>;
8
-
9
- beforeEach(async () => {
10
- await TestBed.configureTestingModule({
11
- imports: [LeafListRendererComponent]
12
- })
13
- .compileComponents();
14
-
15
- fixture = TestBed.createComponent(LeafListRendererComponent);
16
- component = fixture.componentInstance;
17
- fixture.detectChanges();
18
- });
19
-
20
- it('should create', () => {
21
- expect(component).toBeTruthy();
22
- });
23
- });
@@ -1,52 +0,0 @@
1
- import { Component, EventEmitter, inject, Input, OnInit, Output } from '@angular/core';
2
- import { LeafList } from '../../types/dynamic-recursive.types';
3
- import { FormControl } from '@angular/forms';
4
- import { MatIconModule } from '@angular/material/icon';
5
- import { AnonLeafRendererComponent } from '../anon-leaf-renderer/anon-leaf-renderer.component';
6
- import { MatButtonModule } from '@angular/material/button';
7
- import { MatDialog } from '@angular/material/dialog';
8
- import { MatPrefix } from '@angular/material/input';
9
-
10
- @Component({
11
- selector: 'nff-leaf-list-renderer',
12
- standalone: true,
13
- imports: [
14
- MatIconModule,
15
- AnonLeafRendererComponent,
16
- MatButtonModule,
17
- MatPrefix,
18
- ],
19
- templateUrl: './leaf-list-renderer.component.html',
20
- styleUrl: './leaf-list-renderer.component.scss',
21
- })
22
- export class LeafListRendererComponent implements OnInit {
23
- @Input() leaf_!: LeafList;
24
- @Input() initialValue!: number[] | string[] | boolean[];
25
- @Input() formArray!: any;
26
- @Input() editable: boolean = true;
27
- @Input() minItems: number = 1;
28
- @Output() message = new EventEmitter();
29
-
30
- matDialog = inject(MatDialog);
31
-
32
- ngOnInit() {
33
- if (this.initialValue) {
34
- this.formArray.patchValue(this.initialValue);
35
- }
36
- }
37
-
38
- removeItem($index: number) {
39
- if (this.formArray.length <= this.minItems) {
40
- this.message.emit({
41
- message: 'You cannot remove the last item!',
42
- type: 'error',
43
- })
44
- return;
45
- }
46
- this.formArray.removeAt($index);
47
- }
48
-
49
- addItem() {
50
- this.formArray.push(new FormControl());
51
- }
52
- }
@@ -1,17 +0,0 @@
1
- @if ('name' in leaf_) {
2
- @if (leaf_.type === 'string') {
3
- <mat-form-field [appearance]="editable ? 'fill' : 'outline'">
4
- <mat-label>{{ leaf_.label ?? leaf_.name }}</mat-label>
5
- <input [readonly]="!editable" matInput type="text" [formControl]="control">
6
- </mat-form-field>
7
- } @else if (leaf_.type === 'number') {
8
- <mat-form-field [appearance]="editable ? 'fill' : 'outline'">
9
- <mat-label>{{ leaf_.label ?? leaf_.name }}</mat-label>
10
- <input [readonly]="!editable" matInput type="number" [formControl]="control">
11
- </mat-form-field>
12
- } @else if (leaf_.type === 'boolean') {
13
- <mat-checkbox [formControl]="control">{{ leaf_.label ?? leaf_.name }}</mat-checkbox>
14
- } @else if (leaf_.type === 'enum') {
15
- <nff-leaf-enum-renderer [editable]="editable" [leafEnum]="leaf_" [control]="control"></nff-leaf-enum-renderer>
16
- }
17
- }
@@ -1,11 +0,0 @@
1
- :host {
2
- display: flex;
3
- flex: 1 1 0;
4
- min-width: 20%;
5
- }
6
-
7
- mat-form-field {
8
- flex: 1;
9
- min-width: 0;
10
- }
11
-
@@ -1,22 +0,0 @@
1
- import { ComponentFixture, TestBed } from '@angular/core/testing';
2
-
3
- import { LeafRendererComponent } from './leaf-renderer.component';
4
-
5
- describe('DrfLeafRendererComponent', () => {
6
- let component: LeafRendererComponent;
7
- let fixture: ComponentFixture<LeafRendererComponent>;
8
-
9
- beforeEach(async () => {
10
- await TestBed.configureTestingModule({
11
- imports: [LeafRendererComponent],
12
- }).compileComponents();
13
-
14
- fixture = TestBed.createComponent(LeafRendererComponent);
15
- component = fixture.componentInstance;
16
- fixture.detectChanges();
17
- });
18
-
19
- it('should create', () => {
20
- expect(component).toBeTruthy();
21
- });
22
- });
@@ -1,41 +0,0 @@
1
- import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
2
- import { AnonLeaf, Leaf } from '../../types/dynamic-recursive.types';
3
- import { FormControl, ReactiveFormsModule } from '@angular/forms';
4
- import { MatFormFieldModule } from '@angular/material/form-field';
5
- import { MatInputModule } from '@angular/material/input';
6
- import { MatCheckboxModule } from '@angular/material/checkbox';
7
- import { MatSelectModule } from '@angular/material/select';
8
- import { MatIconModule } from '@angular/material/icon';
9
- import { MatButtonModule } from '@angular/material/button';
10
- import { LeafEnumRendererComponent } from '../leaf-enum-renderer/leaf-enum-renderer.component';
11
-
12
- @Component({
13
- selector: 'nff-leaf-renderer',
14
- standalone: true,
15
- imports: [
16
- MatFormFieldModule,
17
- ReactiveFormsModule,
18
- MatInputModule,
19
- MatCheckboxModule,
20
- MatSelectModule,
21
- MatIconModule,
22
- MatButtonModule,
23
- LeafEnumRendererComponent,
24
- ],
25
- templateUrl: './leaf-renderer.component.html',
26
- styleUrl: './leaf-renderer.component.scss',
27
- })
28
- export class LeafRendererComponent implements OnInit {
29
- @Input() leaf_!: Leaf | AnonLeaf;
30
- @Input() control: FormControl = new FormControl();
31
- @Input() initialValue?: any;
32
- @Input() removable: boolean = false;
33
- @Input() editable = true;
34
- @Output() remove: EventEmitter<number> = new EventEmitter();
35
-
36
- ngOnInit(): void {
37
- if (this.initialValue) {
38
- this.control.patchValue(this.initialValue);
39
- }
40
- }
41
- }
@@ -1,24 +0,0 @@
1
- @if (formArray && nodeGroupList) {
2
- <div class="fields-container">
3
- @for (group of formArray.controls; track $index) {
4
- <div class="field-item">
5
- <nff-dynamic-recursive-form
6
- [schema]="nodeGroupList.type"
7
- [formGroup]="asFormGroup(group)"
8
- [title]="getTitle($index)"
9
- [index]="$index"
10
- [removable]="formArray.length > minItems"
11
- (remove)="removeItem($index)"
12
- [editable]="editable"
13
- />
14
- <div class="actions">
15
- <button matIconButton class="small-icon-button"
16
- matTooltip=" + Add new {{ nodeGroupList.type.label ?? nodeGroupList.type.name }}"
17
- (click)="addItem()">
18
- <mat-icon>add</mat-icon>
19
- </button>
20
- </div>
21
- </div>
22
- }
23
- </div>
24
- }
@@ -1,48 +0,0 @@
1
- :host {
2
- position: relative;
3
- width: 100%;
4
- flex: 1 1 0;
5
- }
6
-
7
- .fields {
8
- display: flex;
9
- flex-direction: column;
10
- flex-wrap: wrap;
11
- width: 100%;
12
- }
13
-
14
- .fields-container {
15
- display: flex;
16
- flex-direction: column;
17
- }
18
-
19
- .field-item {
20
- display: flex;
21
- flex-direction: row;
22
- gap: 8px;
23
- }
24
-
25
- .actions {
26
- display: flex;
27
- flex-direction: row;
28
- gap: 8px;
29
- align-items: center;
30
- margin-top: 0;
31
- padding: 0;
32
- min-width: 24px;
33
- }
34
-
35
- .title {
36
- display: flex;
37
- flex-direction: column;
38
- gap: 8px;
39
- align-items: center;
40
- }
41
-
42
- nff-dynamic-recursive-form {
43
- flex: 1;
44
- }
45
-
46
- .add-button {
47
- background-color: var(--mat-sys-primary-container);
48
- }
@@ -1,22 +0,0 @@
1
- import { ComponentFixture, TestBed } from '@angular/core/testing';
2
-
3
- import { NodeGroupListRendererComponent } from './node-group-list-renderer.component';
4
-
5
- describe('DrfNodeListRendererComponent', () => {
6
- let component: NodeGroupListRendererComponent;
7
- let fixture: ComponentFixture<NodeGroupListRendererComponent>;
8
-
9
- beforeEach(async () => {
10
- await TestBed.configureTestingModule({
11
- imports: [NodeGroupListRendererComponent],
12
- }).compileComponents();
13
-
14
- fixture = TestBed.createComponent(NodeGroupListRendererComponent);
15
- component = fixture.componentInstance;
16
- fixture.detectChanges();
17
- });
18
-
19
- it('should create', () => {
20
- expect(component).toBeTruthy();
21
- });
22
- });
@@ -1,101 +0,0 @@
1
- import {
2
- AfterViewInit,
3
- ChangeDetectorRef,
4
- Component,
5
- EventEmitter,
6
- forwardRef,
7
- inject,
8
- Input,
9
- OnInit,
10
- Output,
11
- QueryList,
12
- ViewChildren
13
- } from '@angular/core';
14
- import { NodeGroupList } from '../../types/dynamic-recursive.types';
15
- import { FormArray, FormGroup } from '@angular/forms';
16
- import { MatButtonModule } from '@angular/material/button';
17
- import { MatIconModule } from '@angular/material/icon';
18
- import { DynamicRecursiveFormComponent } from '../dynamic-recursive-form.component';
19
- import { buildFormFromSchema } from '../../core/dynamic-recursive-forms-builder';
20
- import { MatTooltipModule } from '@angular/material/tooltip';
21
-
22
- @Component({
23
- selector: 'nff-node-group-list-renderer',
24
- standalone: true,
25
- imports: [
26
- forwardRef(() => DynamicRecursiveFormComponent),
27
- MatButtonModule,
28
- MatIconModule,
29
- MatTooltipModule,
30
- ],
31
- templateUrl: './node-group-list-renderer.component.html',
32
- styleUrl: './node-group-list-renderer.component.scss',
33
- })
34
- export class NodeGroupListRendererComponent implements OnInit, AfterViewInit {
35
- @Input() nodeGroupList!: NodeGroupList;
36
- @Input() initialValue!: number[] | string[] | boolean[];
37
- @Input() formArray = new FormArray<any>([]);
38
- @Input() editable: boolean = true;
39
- @Input() minItems: number = 1;
40
- @Input() maxItems: number = 1;
41
- @Output() message = new EventEmitter();
42
- @ViewChildren(DynamicRecursiveFormComponent) items!: QueryList<DynamicRecursiveFormComponent>;
43
-
44
- cdr = inject(ChangeDetectorRef);
45
-
46
- ngOnInit() {
47
- if (this.initialValue) {
48
- this.formArray.patchValue(this.initialValue);
49
- }
50
- if (this.nodeGroupList.maxItems) {
51
- this.maxItems = this.nodeGroupList.maxItems;
52
- }
53
- if (this.nodeGroupList.minItems) {
54
- this.minItems = this.nodeGroupList.minItems;
55
- }
56
- }
57
-
58
- ngAfterViewInit() {
59
- this.items.changes.subscribe(() => {
60
- this.setLastEditable();
61
- });
62
- }
63
-
64
- removeItem($index: number) {
65
- if (this.formArray.length <= this.minItems) {
66
- this.message.emit({
67
- message: `You cannot remove the last ${this.nodeGroupList.type.name} configuration!`,
68
- type: 'error',
69
- })
70
- return;
71
- }
72
- this.formArray.removeAt($index);
73
- }
74
-
75
- addItem() {
76
- this.formArray.push(buildFormFromSchema(this.nodeGroupList.type, null));
77
- }
78
-
79
- setLastEditable() {
80
- const lastItem = this.items.last;
81
- if (lastItem) {
82
- lastItem.editable = this.editable;
83
- }
84
- this.cdr.detectChanges();
85
- }
86
-
87
- asFormGroup(group: any) {
88
- return group as FormGroup;
89
- }
90
-
91
- getTitle($index: number) {
92
- let title = `${this.nodeGroupList.type.label ?? this.nodeGroupList.type.name}`;
93
- if (this.formArray.length > 1) {
94
- return `${title} #${$index + 1}`;
95
- }
96
- else {
97
- return title;
98
- }
99
-
100
- }
101
- }
@@ -1,97 +0,0 @@
1
- import { FormArray, FormControl, FormGroup } from '@angular/forms';
2
-
3
- export type LeafRuntimeType<T> = T extends 'string'
4
- ? string
5
- : T extends 'number'
6
- ? number
7
- : T extends 'boolean'
8
- ? boolean
9
- : T extends 'enum'
10
- ? string | number
11
- : never;
12
-
13
- export type LeafBase = {
14
- kind: 'leaf';
15
- name: string;
16
- required?: true | undefined;
17
- label?: string;
18
- description?: string;
19
- };
20
-
21
- export type AnonLeaf = {
22
- [K in Leaf['type']]: { type: K };
23
- }[Leaf['type']];
24
-
25
- export type LeafString = LeafBase & {
26
- type: 'string';
27
- default?: LeafRuntimeType<'string'>;
28
- };
29
- export type LeafNumber = LeafBase & {
30
- type: 'number';
31
- default?: LeafRuntimeType<'number'>;
32
- };
33
- export type LeafBoolean = LeafBase & {
34
- type: 'boolean';
35
- default?: LeafRuntimeType<'boolean'>;
36
- };
37
- export type LeafEnum = LeafBase & {
38
- type: 'enum';
39
- default?: LeafRuntimeType<'enum'>;
40
- enumLabel?: string[];
41
- enum: LeafRuntimeType<'enum'>[];
42
- };
43
-
44
- export type Appearance = {
45
- flatten?: boolean;
46
- noBorder?: boolean;
47
- }
48
-
49
- export type Leaf = LeafString | LeafNumber | LeafBoolean | LeafEnum;
50
-
51
- export type LeafList<TKind extends Leaf['type'] = Leaf['type']> = {
52
- kind: 'leafList';
53
- label?: string;
54
- name: string;
55
- description?: string;
56
- default?: Exclude<Leaf['default'], undefined>[];
57
- type: TKind;
58
- minItems?: number;
59
- maxItems?: number;
60
- };
61
-
62
- export type NodeGroupList = {
63
- kind: 'nodeGroupList';
64
- name: string;
65
- label?: string;
66
- description?: string;
67
- type: NodeGroup;
68
- minItems?: number;
69
- maxItems?: number;
70
- };
71
-
72
- export type NodeGroup = {
73
- kind: 'nodeGroup';
74
- name: string;
75
- subType?: string;
76
- label?: string;
77
- root?: boolean;
78
- description?: string;
79
- children: Record<string, NodeType>;
80
- appearance?: Appearance;
81
- };
82
-
83
- export type NodeType = Leaf | LeafList | NodeGroup | NodeGroupList;
84
- export type DFormControl<T extends NodeType> = T extends Leaf
85
- ? FormControl<LeafRuntimeType<T['type']>>
86
- : T extends LeafList
87
- ? FormArray<FormControl<LeafRuntimeType<T['type']>>>
88
- : T extends NodeGroup
89
- ? DFormGroup<T>
90
- : T extends NodeGroupList
91
- ? FormArray<DFormGroup<T['type']>>
92
- : never;
93
-
94
- export type FormGroupType<T extends NodeGroup> = {
95
- [TChild in keyof T['children']]: DFormControl<T['children'][TChild]>;
96
- };
97
- export type DFormGroup<T extends NodeGroup> = FormGroup<FormGroupType<T>>;