ng-form-foundry 0.5.4 → 0.6.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 +5 -3
- package/fesm2022/ng-form-foundry.mjs +212 -57
- package/fesm2022/ng-form-foundry.mjs.map +1 -1
- package/index.d.ts +85 -5
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -152,6 +152,14 @@ type LeafList<TKind extends Leaf['type'] = Leaf['type']> = {
|
|
|
152
152
|
maxItems?: number;
|
|
153
153
|
/** Present every item in this base — see {@link LeafNumber.radix}. */
|
|
154
154
|
radix?: 2 | 8 | 16;
|
|
155
|
+
/**
|
|
156
|
+
* Optional scalar list whose *presence itself* is data — an absent key,
|
|
157
|
+
* distinct from a present-but-empty list. Off means no control and no key in
|
|
158
|
+
* the value; on means the (possibly empty) list is materialized. Mirrors
|
|
159
|
+
* {@link NodeGroup.presence}; lets a round-trip distinguish `x = ( )` (present,
|
|
160
|
+
* empty) from an absent `x`.
|
|
161
|
+
*/
|
|
162
|
+
presence?: boolean;
|
|
155
163
|
};
|
|
156
164
|
type NodeGroupList = {
|
|
157
165
|
kind: 'nodeGroupList';
|
|
@@ -161,6 +169,8 @@ type NodeGroupList = {
|
|
|
161
169
|
type: NodeGroup;
|
|
162
170
|
minItems?: number;
|
|
163
171
|
maxItems?: number;
|
|
172
|
+
/** Optional list whose presence is itself data — see {@link LeafList.presence}. */
|
|
173
|
+
presence?: boolean;
|
|
164
174
|
};
|
|
165
175
|
type NodeGroup = {
|
|
166
176
|
kind: 'nodeGroup';
|
|
@@ -327,6 +337,24 @@ declare function addMapEntry(group: FormGroup, map: NodeMap, key?: string): stri
|
|
|
327
337
|
declare function renameMapEntry(group: FormGroup, map: NodeMap, oldKey: string, newKey: string): boolean;
|
|
328
338
|
/** Remove entry `key` unless the map is at `minEntries`. Returns whether it was removed. */
|
|
329
339
|
declare function removeMapEntry(group: FormGroup, map: NodeMap, key: string): boolean;
|
|
340
|
+
/**
|
|
341
|
+
* Materialize or de-materialize an optional (presence) child of `group`,
|
|
342
|
+
* mirroring the presence toggle the form UI offers — but callable by any host
|
|
343
|
+
* holding the {@link FormGroup}, for a key at any depth. `present: true` builds
|
|
344
|
+
* the child fresh from `schema` (seeded with `initial` if given; nested
|
|
345
|
+
* presence descendants start absent, as {@link buildControl}); `present: false`
|
|
346
|
+
* removes it, dropping the key from the form value.
|
|
347
|
+
*
|
|
348
|
+
* The materialize direction is why the coupling exists: a materialized
|
|
349
|
+
* non-nullable presence leaf carries `Validators.required`, because an
|
|
350
|
+
* enabled-but-empty key would serialize as `null` and fail a typed schema. A
|
|
351
|
+
* host that materializes fields for editing therefore drops the ones left
|
|
352
|
+
* empty on cancel by de-materializing them — this API is that primitive.
|
|
353
|
+
*
|
|
354
|
+
* `schema` must be the presence node for `key`; a non-presence `schema` is a
|
|
355
|
+
* no-op. Returns whether the form changed.
|
|
356
|
+
*/
|
|
357
|
+
declare function setNodePresence(group: FormGroup, schema: NodeType, key: string, present: boolean, initial?: unknown): boolean;
|
|
330
358
|
/**
|
|
331
359
|
* Build the `AbstractControl` for a single schema node.
|
|
332
360
|
*
|
|
@@ -525,7 +553,8 @@ declare class DynamicRecursiveFormComponent implements OnInit {
|
|
|
525
553
|
* Add or remove a presence node's control on this form — any presence kind:
|
|
526
554
|
* group, leaf, map, or choice. Removing it drops the key from `form.value`;
|
|
527
555
|
* adding it builds the control fresh from its schema (nested presence
|
|
528
|
-
* children start absent).
|
|
556
|
+
* children start absent). Delegates to {@link setNodePresence}, the
|
|
557
|
+
* host-callable primitive.
|
|
529
558
|
*/
|
|
530
559
|
toggleNodePresence(key: string, schema: NodeType, present: boolean): void;
|
|
531
560
|
/**
|
|
@@ -549,6 +578,14 @@ declare class DynamicRecursiveFormComponent implements OnInit {
|
|
|
549
578
|
* rendered field when the toggle just created it.
|
|
550
579
|
*/
|
|
551
580
|
toggleLeafPresence(key: string, schema: Leaf, present: boolean): void;
|
|
581
|
+
/**
|
|
582
|
+
* Materialize an absent presence (optional / `advisoryRequired`) list *with
|
|
583
|
+
* its first entry* — clicking "Add <list>" makes the first entry appear at
|
|
584
|
+
* once. An optional list has no present-empty state: removing the last entry
|
|
585
|
+
* de-materializes it (→ absent). A required list is always present instead and
|
|
586
|
+
* uses the renderer's own "Add item" affordance, so it never routes here.
|
|
587
|
+
*/
|
|
588
|
+
addPresenceList(key: string, schema: NodeType): void;
|
|
552
589
|
protected objectKeys(obj: Record<string, unknown>): string[];
|
|
553
590
|
/** The active case name of a choice control, or null if none is selected. */
|
|
554
591
|
protected activeCase(key: string): string | null;
|
|
@@ -638,6 +675,7 @@ interface TreeNode {
|
|
|
638
675
|
/** Present on a present optional child node: drives the row's remove control. */
|
|
639
676
|
presenceRemovable?: {
|
|
640
677
|
key: string;
|
|
678
|
+
schema: NodeType;
|
|
641
679
|
};
|
|
642
680
|
/** Field-layout appearance inherited from ancestor groups, for the node's detail-section form. */
|
|
643
681
|
inherited?: Appearance | null;
|
|
@@ -724,6 +762,7 @@ declare class ConfigEditorComponent implements OnDestroy {
|
|
|
724
762
|
private shape;
|
|
725
763
|
private changes?;
|
|
726
764
|
private readonly host;
|
|
765
|
+
private readonly cdr;
|
|
727
766
|
/** Stable per-instance ids for the shape signature, so replacing a control (setControl) reads as a structural change. */
|
|
728
767
|
private readonly controlIds;
|
|
729
768
|
private controlIdSeq;
|
|
@@ -731,6 +770,21 @@ declare class ConfigEditorComponent implements OnDestroy {
|
|
|
731
770
|
ngOnDestroy(): void;
|
|
732
771
|
/** Bind the editor to a schema/form pair: fresh tree, root selection, and shape-sync subscription. */
|
|
733
772
|
private attach;
|
|
773
|
+
/**
|
|
774
|
+
* Force the editor to re-read the bound form. A leaf field normally reflects
|
|
775
|
+
* an external `setValue` on its own — the reactive value accessor writes the
|
|
776
|
+
* value synchronously, no change detection needed — so this is only for the
|
|
777
|
+
* corners that bypass that: a structural change made with
|
|
778
|
+
* `{ emitEvent: false }` (the tree wouldn't otherwise rebuild), a non-reactive
|
|
779
|
+
* display (the case selector, a map key) that needs re-reading, or a host
|
|
780
|
+
* whose change detector was detached during the mutation.
|
|
781
|
+
*
|
|
782
|
+
* It re-syncs the tree structure and **tears down and recreates** the detail
|
|
783
|
+
* sections, so every rendered control rebinds to the live form and re-pulls
|
|
784
|
+
* its current value — even a field whose bound input somehow missed the
|
|
785
|
+
* external write.
|
|
786
|
+
*/
|
|
787
|
+
refresh(): void;
|
|
734
788
|
select(node: TreeNode, reveal?: boolean): void;
|
|
735
789
|
/**
|
|
736
790
|
* Root-to-`target` path for the detail-pane breadcrumb (inclusive of both ends),
|
|
@@ -940,6 +994,7 @@ declare class LeafListRendererComponent implements OnInit {
|
|
|
940
994
|
formArray: any;
|
|
941
995
|
editable: boolean;
|
|
942
996
|
minItems: number;
|
|
997
|
+
maxItems: number;
|
|
943
998
|
/**
|
|
944
999
|
* The parent group's grid layout (its `fieldsLayout` styles). A stacked list
|
|
945
1000
|
* spans the parent's full row, so its entries repeat the same tracks and
|
|
@@ -948,6 +1003,12 @@ declare class LeafListRendererComponent implements OnInit {
|
|
|
948
1003
|
*/
|
|
949
1004
|
layout: LayoutStyles | null;
|
|
950
1005
|
message: EventEmitter<any>;
|
|
1006
|
+
/**
|
|
1007
|
+
* Emitted from the empty-list remove button when the list is a presence list —
|
|
1008
|
+
* the host removes the whole list (de-materializes it, → absent). Only wired
|
|
1009
|
+
* for a `presence` `leafList`; the parent maps it to `setNodePresence`.
|
|
1010
|
+
*/
|
|
1011
|
+
removeList: EventEmitter<void>;
|
|
951
1012
|
matDialog: MatDialog;
|
|
952
1013
|
/**
|
|
953
1014
|
* Take a full-width row of its own once the array holds more than one entry.
|
|
@@ -961,10 +1022,14 @@ declare class LeafListRendererComponent implements OnInit {
|
|
|
961
1022
|
/** Applies {@link layout} to the host (the entries' container) while stacked. */
|
|
962
1023
|
get hostLayout(): LayoutStyles | null;
|
|
963
1024
|
ngOnInit(): void;
|
|
1025
|
+
get effectiveMin(): number;
|
|
1026
|
+
get effectiveMax(): number;
|
|
1027
|
+
/** Whether another item may be appended (below the effective maximum). */
|
|
1028
|
+
get canAdd(): boolean;
|
|
964
1029
|
removeItem($index: number): void;
|
|
965
1030
|
addItem(): void;
|
|
966
1031
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LeafListRendererComponent, never>;
|
|
967
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LeafListRendererComponent, "nff-leaf-list-renderer", never, { "leaf_": { "alias": "leaf_"; "required": false; }; "initialValue": { "alias": "initialValue"; "required": false; }; "formArray": { "alias": "formArray"; "required": false; }; "editable": { "alias": "editable"; "required": false; }; "minItems": { "alias": "minItems"; "required": false; }; "layout": { "alias": "layout"; "required": false; }; }, { "message": "message"; }, never, never, true, never>;
|
|
1032
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LeafListRendererComponent, "nff-leaf-list-renderer", never, { "leaf_": { "alias": "leaf_"; "required": false; }; "initialValue": { "alias": "initialValue"; "required": false; }; "formArray": { "alias": "formArray"; "required": false; }; "editable": { "alias": "editable"; "required": false; }; "minItems": { "alias": "minItems"; "required": false; }; "maxItems": { "alias": "maxItems"; "required": false; }; "layout": { "alias": "layout"; "required": false; }; }, { "message": "message"; "removeList": "removeList"; }, never, never, true, never>;
|
|
968
1033
|
}
|
|
969
1034
|
|
|
970
1035
|
declare class LeafEnumRendererComponent {
|
|
@@ -1053,17 +1118,27 @@ declare class NodeGroupListRendererComponent implements OnInit, AfterViewInit {
|
|
|
1053
1118
|
/** Field-layout appearance from the enclosing group, forwarded to every item form. */
|
|
1054
1119
|
inheritedAppearance: Appearance | null;
|
|
1055
1120
|
message: EventEmitter<any>;
|
|
1121
|
+
/**
|
|
1122
|
+
* Emitted when the last entry of a presence (optional / advisoryRequired) list
|
|
1123
|
+
* is removed — the host de-materializes the whole list (→ absent). An optional
|
|
1124
|
+
* list has no present-empty state; a required list never routes here.
|
|
1125
|
+
*/
|
|
1126
|
+
removeList: EventEmitter<void>;
|
|
1056
1127
|
items: QueryList<DynamicRecursiveFormComponent>;
|
|
1057
1128
|
cdr: ChangeDetectorRef;
|
|
1058
1129
|
ngOnInit(): void;
|
|
1130
|
+
get effectiveMin(): number;
|
|
1131
|
+
get effectiveMax(): number;
|
|
1132
|
+
/** Whether another item may be appended (below the effective maximum). */
|
|
1133
|
+
get canAdd(): boolean;
|
|
1059
1134
|
ngAfterViewInit(): void;
|
|
1060
1135
|
removeItem($index: number): void;
|
|
1061
|
-
addItem: (index
|
|
1136
|
+
addItem: (index?: number) => void;
|
|
1062
1137
|
setLastEditable(): void;
|
|
1063
1138
|
asFormGroup(group: any): FormGroup;
|
|
1064
1139
|
getTitle($index: number): string;
|
|
1065
1140
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NodeGroupListRendererComponent, never>;
|
|
1066
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NodeGroupListRendererComponent, "nff-node-group-list-renderer", never, { "nodeGroupList": { "alias": "nodeGroupList"; "required": false; }; "initialValue": { "alias": "initialValue"; "required": false; }; "formArray": { "alias": "formArray"; "required": false; }; "editable": { "alias": "editable"; "required": false; }; "showAbsentOptionals": { "alias": "showAbsentOptionals"; "required": false; }; "minItems": { "alias": "minItems"; "required": false; }; "maxItems": { "alias": "maxItems"; "required": false; }; "inheritedAppearance": { "alias": "inheritedAppearance"; "required": false; }; }, { "message": "message"; }, never, never, true, never>;
|
|
1141
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NodeGroupListRendererComponent, "nff-node-group-list-renderer", never, { "nodeGroupList": { "alias": "nodeGroupList"; "required": false; }; "initialValue": { "alias": "initialValue"; "required": false; }; "formArray": { "alias": "formArray"; "required": false; }; "editable": { "alias": "editable"; "required": false; }; "showAbsentOptionals": { "alias": "showAbsentOptionals"; "required": false; }; "minItems": { "alias": "minItems"; "required": false; }; "maxItems": { "alias": "maxItems"; "required": false; }; "inheritedAppearance": { "alias": "inheritedAppearance"; "required": false; }; }, { "message": "message"; "removeList": "removeList"; }, never, never, true, never>;
|
|
1067
1142
|
}
|
|
1068
1143
|
|
|
1069
1144
|
/**
|
|
@@ -1094,6 +1169,10 @@ declare class NodeMapRendererComponent implements OnChanges {
|
|
|
1094
1169
|
get valueLeaf(): Leaf;
|
|
1095
1170
|
/** The value schema as a group (used when `value.kind === 'nodeGroup'`). */
|
|
1096
1171
|
get valueGroup(): NodeGroup;
|
|
1172
|
+
/** Narrowing casts for the complex value kinds the template renders. */
|
|
1173
|
+
protected asLeafList(v: unknown): LeafList;
|
|
1174
|
+
protected asNodeGroupList(v: unknown): NodeGroupList;
|
|
1175
|
+
protected asNodeMap(v: unknown): NodeMap;
|
|
1097
1176
|
get atMax(): boolean;
|
|
1098
1177
|
get atMin(): boolean;
|
|
1099
1178
|
/** Append a new entry under a unique placeholder key. Delegates to {@link addMapEntry}. */
|
|
@@ -1108,9 +1187,10 @@ declare class NodeMapRendererComponent implements OnChanges {
|
|
|
1108
1187
|
renameEntry(oldKey: string, rawKey: string): void;
|
|
1109
1188
|
protected readonly asFormControl: typeof asFormControl;
|
|
1110
1189
|
protected readonly asFormGroup: typeof asFormGroup;
|
|
1190
|
+
protected readonly asFormArray: typeof asFormArray;
|
|
1111
1191
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NodeMapRendererComponent, never>;
|
|
1112
1192
|
static ɵcmp: _angular_core.ɵɵComponentDeclaration<NodeMapRendererComponent, "nff-node-map-renderer", never, { "nodeMap": { "alias": "nodeMap"; "required": false; }; "formGroup": { "alias": "formGroup"; "required": false; }; "editable": { "alias": "editable"; "required": false; }; "showAbsentOptionals": { "alias": "showAbsentOptionals"; "required": false; }; "inheritedAppearance": { "alias": "inheritedAppearance"; "required": false; }; }, {}, never, never, true, never>;
|
|
1113
1193
|
}
|
|
1114
1194
|
|
|
1115
|
-
export { CASE_KEY, ConfigEditorComponent, DynamicRecursiveFormComponent, LeafEnumRendererComponent, LeafListRendererComponent, LeafRendererComponent, NodeGroupListRendererComponent, NodeMapRendererComponent, RadixInputDirective, addMapEntry, buildControl, buildFormFromSchema, caseDisplayLabels, caseFields, defineSchema, formatRadix, removeMapEntry, renameMapEntry, resolveChoiceCase, serializeForm, switchChoiceCase, toWireValue };
|
|
1195
|
+
export { CASE_KEY, ConfigEditorComponent, DynamicRecursiveFormComponent, LeafEnumRendererComponent, LeafListRendererComponent, LeafRendererComponent, NodeGroupListRendererComponent, NodeMapRendererComponent, RadixInputDirective, addMapEntry, buildControl, buildFormFromSchema, caseDisplayLabels, caseFields, defineSchema, formatRadix, removeMapEntry, renameMapEntry, resolveChoiceCase, serializeForm, setNodePresence, switchChoiceCase, toWireValue };
|
|
1116
1196
|
export type { AnonLeaf, Appearance, ChoiceCase, DFormControl, DFormGroup, FormGroupType, Leaf, LeafBase, LeafBoolean, LeafEnum, LeafList, LeafNumber, LeafRuntimeType, LeafString, NodeChoice, NodeGroup, NodeGroupList, NodeMap, NodeType, Radix };
|
package/package.json
CHANGED