ng-form-foundry 0.5.5 → 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/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';
@@ -568,6 +578,14 @@ declare class DynamicRecursiveFormComponent implements OnInit {
568
578
  * rendered field when the toggle just created it.
569
579
  */
570
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;
571
589
  protected objectKeys(obj: Record<string, unknown>): string[];
572
590
  /** The active case name of a choice control, or null if none is selected. */
573
591
  protected activeCase(key: string): string | null;
@@ -753,12 +771,18 @@ declare class ConfigEditorComponent implements OnDestroy {
753
771
  /** Bind the editor to a schema/form pair: fresh tree, root selection, and shape-sync subscription. */
754
772
  private attach;
755
773
  /**
756
- * Force the editor to re-read the bound form. Call this when the form was
757
- * mutated in a way the editor's own `valueChanges` subscription could not
758
- * observe a structural change made with `{ emitEvent: false }`, or a
759
- * mutation while a detached change detector left the view unchecked. It
760
- * re-syncs the tree structure, rebuilds the current selection's sections
761
- * from the live controls, and renders them.
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.
762
786
  */
763
787
  refresh(): void;
764
788
  select(node: TreeNode, reveal?: boolean): void;
@@ -979,6 +1003,12 @@ declare class LeafListRendererComponent implements OnInit {
979
1003
  */
980
1004
  layout: LayoutStyles | null;
981
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>;
982
1012
  matDialog: MatDialog;
983
1013
  /**
984
1014
  * Take a full-width row of its own once the array holds more than one entry.
@@ -999,7 +1029,7 @@ declare class LeafListRendererComponent implements OnInit {
999
1029
  removeItem($index: number): void;
1000
1030
  addItem(): void;
1001
1031
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<LeafListRendererComponent, never>;
1002
- 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"; }, 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>;
1003
1033
  }
1004
1034
 
1005
1035
  declare class LeafEnumRendererComponent {
@@ -1088,6 +1118,12 @@ declare class NodeGroupListRendererComponent implements OnInit, AfterViewInit {
1088
1118
  /** Field-layout appearance from the enclosing group, forwarded to every item form. */
1089
1119
  inheritedAppearance: Appearance | null;
1090
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>;
1091
1127
  items: QueryList<DynamicRecursiveFormComponent>;
1092
1128
  cdr: ChangeDetectorRef;
1093
1129
  ngOnInit(): void;
@@ -1102,7 +1138,7 @@ declare class NodeGroupListRendererComponent implements OnInit, AfterViewInit {
1102
1138
  asFormGroup(group: any): FormGroup;
1103
1139
  getTitle($index: number): string;
1104
1140
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<NodeGroupListRendererComponent, never>;
1105
- 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>;
1106
1142
  }
1107
1143
 
1108
1144
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ng-form-foundry",
3
- "version": "0.5.5",
3
+ "version": "0.6.0",
4
4
  "description": "Build fully-typed Angular Reactive Forms and Angular Material UI from a declarative, recursive form-description schema.",
5
5
  "keywords": [
6
6
  "angular",