ng-form-foundry 0.2.1 → 0.3.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.
- package/README.md +9 -6
- package/fesm2022/ng-form-foundry.mjs +1090 -291
- package/fesm2022/ng-form-foundry.mjs.map +1 -1
- package/index.d.ts +501 -89
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FormControl, FormArray, FormGroup } from '@angular/forms';
|
|
2
|
-
import * as
|
|
3
|
-
import { OnInit,
|
|
2
|
+
import * as _angular_core from '@angular/core';
|
|
3
|
+
import { OnInit, OnDestroy, AfterViewInit, ElementRef, EventEmitter, QueryList, ChangeDetectorRef, OnChanges, SimpleChanges } from '@angular/core';
|
|
4
4
|
import { MatDialog } from '@angular/material/dialog';
|
|
5
5
|
|
|
6
6
|
type LeafRuntimeType<T> = T extends 'string' ? string : T extends 'number' ? number : T extends 'boolean' ? boolean : T extends 'enum' ? string | number : never;
|
|
@@ -10,6 +10,26 @@ type LeafBase = {
|
|
|
10
10
|
required?: true | undefined;
|
|
11
11
|
label?: string;
|
|
12
12
|
description?: string;
|
|
13
|
+
/**
|
|
14
|
+
* The value may be `null` (JSON Schema `type: [T, 'null']`). Builds a nullable
|
|
15
|
+
* control (drops `nonNullable`), so `null` is a first-class value the
|
|
16
|
+
* constraint validators accept and that survives the round-trip. Distinct from
|
|
17
|
+
* {@link presence}: `nullable` is an explicit `null`, `presence` is an absent key.
|
|
18
|
+
*/
|
|
19
|
+
nullable?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Optional scalar whose *presence itself* is data (mirrors {@link NodeGroup.presence}).
|
|
22
|
+
* Rendered with an on/off toggle; the control is removed from the parent group
|
|
23
|
+
* when absent (so it drops from `form.value`) and re-added when toggled on. The
|
|
24
|
+
* builder omits it unless an initial value is supplied.
|
|
25
|
+
*/
|
|
26
|
+
presence?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Render the field read-only even when the surrounding form is editable.
|
|
29
|
+
* Combine with `default` to express a JSON Schema `const` (a fixed,
|
|
30
|
+
* display-only value); single-element `enum` is the alternative for a constant.
|
|
31
|
+
*/
|
|
32
|
+
readOnly?: boolean;
|
|
13
33
|
};
|
|
14
34
|
type AnonLeaf = {
|
|
15
35
|
[K in Leaf['type']]: {
|
|
@@ -19,10 +39,30 @@ type AnonLeaf = {
|
|
|
19
39
|
type LeafString = LeafBase & {
|
|
20
40
|
type: 'string';
|
|
21
41
|
default?: LeafRuntimeType<'string'>;
|
|
42
|
+
/**
|
|
43
|
+
* Reject values that don't match this regular expression. Follows JSON Schema
|
|
44
|
+
* `pattern` semantics — an *unanchored* `RegExp.test`, so it matches anywhere
|
|
45
|
+
* in the value unless the pattern itself anchors with `^`/`$`.
|
|
46
|
+
*/
|
|
47
|
+
pattern?: string;
|
|
48
|
+
/** Minimum string length (JSON Schema `minLength`). */
|
|
49
|
+
minLength?: number;
|
|
50
|
+
/** Maximum string length (JSON Schema `maxLength`). */
|
|
51
|
+
maxLength?: number;
|
|
52
|
+
/** Semantic string format (JSON Schema `format`); adds a matching validator. */
|
|
53
|
+
format?: 'email' | 'uri' | 'url';
|
|
22
54
|
};
|
|
23
55
|
type LeafNumber = LeafBase & {
|
|
24
56
|
type: 'number';
|
|
25
57
|
default?: LeafRuntimeType<'number'>;
|
|
58
|
+
/** Require a whole-number value (JSON Schema `type: 'integer'`). */
|
|
59
|
+
integer?: boolean;
|
|
60
|
+
/** Inclusive lower bound (JSON Schema `minimum`). */
|
|
61
|
+
min?: number;
|
|
62
|
+
/** Inclusive upper bound (JSON Schema `maximum`). */
|
|
63
|
+
max?: number;
|
|
64
|
+
/** Require the value to be an integer multiple of this number (JSON Schema `multipleOf`). */
|
|
65
|
+
multipleOf?: number;
|
|
26
66
|
};
|
|
27
67
|
type LeafBoolean = LeafBase & {
|
|
28
68
|
type: 'boolean';
|
|
@@ -37,6 +77,8 @@ type LeafEnum = LeafBase & {
|
|
|
37
77
|
type Appearance = {
|
|
38
78
|
flatten?: boolean;
|
|
39
79
|
noBorder?: boolean;
|
|
80
|
+
/** Start this node's section panel collapsed. Ignored when `flatten` is set. */
|
|
81
|
+
collapsed?: boolean;
|
|
40
82
|
};
|
|
41
83
|
type Leaf = LeafString | LeafNumber | LeafBoolean | LeafEnum;
|
|
42
84
|
type LeafList<TKind extends Leaf['type'] = Leaf['type']> = {
|
|
@@ -75,30 +117,163 @@ type NodeGroup = {
|
|
|
75
117
|
children: Record<string, NodeType>;
|
|
76
118
|
appearance?: Appearance;
|
|
77
119
|
};
|
|
120
|
+
/**
|
|
121
|
+
* One case of a {@link NodeChoice}: either a record of named fields (an object
|
|
122
|
+
* branch), or a single node (a *leaf-bodied* case — e.g. an `anyOf` branch that
|
|
123
|
+
* is a bare scalar). A single node is normalized to a one-field record keyed by
|
|
124
|
+
* its `name` when the form is built.
|
|
125
|
+
*/
|
|
126
|
+
type ChoiceCase = Record<string, NodeType> | NodeType;
|
|
78
127
|
/**
|
|
79
128
|
* A discriminated selection: the user picks one `case`, and only that case's
|
|
80
129
|
* fields are present. In the form it is a FormGroup holding a `__case` control
|
|
81
130
|
* (the active case name) plus that case's field controls; switching the case
|
|
82
131
|
* swaps the field controls.
|
|
132
|
+
*
|
|
133
|
+
* Cases may be **anonymous / auto-named** (any string key) — for JSON Schema
|
|
134
|
+
* `anyOf`/`oneOf` branches with no name. When a built form is seeded from inline
|
|
135
|
+
* data that carries no `__case`, the builder **infers** the active case from the
|
|
136
|
+
* data shape (the case whose fields best match), so a choice round-trips from
|
|
137
|
+
* real instance data. See the schema reference for the required-set / `const`
|
|
138
|
+
* discriminator recipe.
|
|
83
139
|
*/
|
|
84
140
|
type NodeChoice = {
|
|
85
141
|
kind: 'choice';
|
|
86
142
|
name: string;
|
|
87
143
|
label?: string;
|
|
88
|
-
cases: Record<string,
|
|
144
|
+
cases: Record<string, ChoiceCase>;
|
|
145
|
+
/**
|
|
146
|
+
* Display labels for cases, keyed by case name — for anonymous/auto-named
|
|
147
|
+
* branches whose keys are not human-friendly. Falls back to the case name.
|
|
148
|
+
*/
|
|
149
|
+
caseLabels?: Record<string, string>;
|
|
89
150
|
default?: string;
|
|
90
151
|
mandatory?: boolean;
|
|
152
|
+
/** Optional choice: rendered with an on/off toggle, omitted from the value when absent. */
|
|
153
|
+
presence?: boolean;
|
|
154
|
+
appearance?: Appearance;
|
|
91
155
|
};
|
|
92
|
-
/**
|
|
156
|
+
/**
|
|
157
|
+
* The control name that records which case of a {@link NodeChoice} is active.
|
|
158
|
+
* The name is reserved: it cannot be used as a case field name (the builder
|
|
159
|
+
* throws) or as a map entry key (the entry helpers reject it).
|
|
160
|
+
*/
|
|
93
161
|
declare const CASE_KEY = "__case";
|
|
94
|
-
|
|
95
|
-
|
|
162
|
+
/**
|
|
163
|
+
* An open, arbitrary-keyed record: unlike {@link NodeGroup} (a fixed, declared
|
|
164
|
+
* key set), a map's keys are runtime data and every value conforms to one shared
|
|
165
|
+
* `value` schema. Maps JSON Schema `additionalProperties: <schema>` /
|
|
166
|
+
* `patternProperties`. In the form it is a `FormGroup` whose control *names* are
|
|
167
|
+
* the entry keys, so `getRawValue()` is the map object directly; the renderer
|
|
168
|
+
* lets the user add, remove, and rename entries.
|
|
169
|
+
*/
|
|
170
|
+
type NodeMap = {
|
|
171
|
+
kind: 'map';
|
|
172
|
+
name: string;
|
|
173
|
+
label?: string;
|
|
174
|
+
description?: string;
|
|
175
|
+
/** The schema every entry's value conforms to. */
|
|
176
|
+
value: NodeType;
|
|
177
|
+
/** Label for the key column in the editor. Defaults to "Key". */
|
|
178
|
+
keyLabel?: string;
|
|
179
|
+
/** `patternProperties`: entry keys must match this regular expression. */
|
|
180
|
+
keyPattern?: string;
|
|
181
|
+
/** Minimum number of entries (JSON Schema `minProperties`). */
|
|
182
|
+
minEntries?: number;
|
|
183
|
+
/** Maximum number of entries (JSON Schema `maxProperties`). */
|
|
184
|
+
maxEntries?: number;
|
|
185
|
+
/** Optional map: rendered with an on/off toggle, omitted from the value when absent. */
|
|
186
|
+
presence?: boolean;
|
|
187
|
+
appearance?: Appearance;
|
|
188
|
+
};
|
|
189
|
+
type NodeType = Leaf | LeafList | NodeGroup | NodeGroupList | NodeChoice | NodeMap;
|
|
190
|
+
type DFormControl<T extends NodeType> = T extends Leaf ? FormControl<LeafRuntimeType<T['type']>> : T extends LeafList ? FormArray<FormControl<LeafRuntimeType<T['type']>>> : T extends NodeGroup ? DFormGroup<T> : T extends NodeGroupList ? FormArray<DFormGroup<T['type']>> : T extends NodeChoice ? FormGroup<any> : T extends NodeMap ? FormGroup<any> : never;
|
|
96
191
|
type FormGroupType<T extends NodeGroup> = {
|
|
97
192
|
[TChild in keyof T['children']]: DFormControl<T['children'][TChild]>;
|
|
98
193
|
};
|
|
99
194
|
type DFormGroup<T extends NodeGroup> = FormGroup<FormGroupType<T>>;
|
|
100
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Normalize a {@link ChoiceCase} to a field record. A field record is returned
|
|
198
|
+
* as-is; a single node (a leaf-bodied case, e.g. a scalar `anyOf` branch) becomes
|
|
199
|
+
* a one-field record keyed by the node's `name`. The discriminant is a top-level
|
|
200
|
+
* `kind` string, which a field record never has (its keys are field names).
|
|
201
|
+
*
|
|
202
|
+
* Throws when a case field is keyed `__case`: that name is reserved for the
|
|
203
|
+
* choice discriminator ({@link CASE_KEY}) and a field under it would silently
|
|
204
|
+
* clobber the active-case control.
|
|
205
|
+
*/
|
|
206
|
+
declare function caseFields(body: ChoiceCase): Record<string, NodeType>;
|
|
207
|
+
/**
|
|
208
|
+
* The active case of a choice: an explicit `__case` in the initial value, else
|
|
209
|
+
* the case whose fields best match the initial data (inline wire data carries no
|
|
210
|
+
* `__case`), else the schema `default`. This lets a choice seed from real
|
|
211
|
+
* instance data whose branch is discriminated by which fields are present.
|
|
212
|
+
*/
|
|
213
|
+
declare function resolveChoiceCase(choice: NodeChoice, initial?: Record<string, unknown> | null): string | undefined;
|
|
214
|
+
/**
|
|
215
|
+
* Switch a choice's FormGroup to `caseName`: sets `__case`, removes every other
|
|
216
|
+
* control, and builds `caseName`'s fields (normalized via {@link caseFields})
|
|
217
|
+
* with their defaults. Presence fields of the new case start absent — the
|
|
218
|
+
* switch carries no data that could make them present. An unknown case name
|
|
219
|
+
* leaves only `__case`. The swap is atomic: one value change fires, and every
|
|
220
|
+
* observable snapshot has fields matching its discriminator.
|
|
221
|
+
*/
|
|
222
|
+
declare function switchChoiceCase(group: FormGroup, choice: NodeChoice, caseName: string): void;
|
|
223
|
+
/**
|
|
224
|
+
* Append a map entry built from `map.value` and return its committed key, or
|
|
225
|
+
* `null` when nothing was added. With no `key`, the first free `keyN`
|
|
226
|
+
* placeholder is generated (not checked against `keyPattern` — placeholders are
|
|
227
|
+
* meant to be renamed). An explicit `key` is rejected when it duplicates an
|
|
228
|
+
* existing entry or violates `keyPattern`. Rejects when `maxEntries` is reached.
|
|
229
|
+
*/
|
|
230
|
+
declare function addMapEntry(group: FormGroup, map: NodeMap, key?: string): string | null;
|
|
231
|
+
/**
|
|
232
|
+
* Rename entry `oldKey` to `newKey.trim()`, preserving the control instance
|
|
233
|
+
* (so the value survives) and the entry's position in the group's key order —
|
|
234
|
+
* the order `getRawValue()` serializes and the tree editor renders. Returns
|
|
235
|
+
* whether the rename was committed: an empty, reserved (`__case`), unchanged,
|
|
236
|
+
* duplicate, or `keyPattern`-violating key is a no-op, leaving the entry under
|
|
237
|
+
* its current name. Entry keys are looked up verbatim — never via
|
|
238
|
+
* `AbstractControl.get`, which would split keys like `10.0.0.1` into
|
|
239
|
+
* dot-delimited paths. Emits a single value change.
|
|
240
|
+
*/
|
|
241
|
+
declare function renameMapEntry(group: FormGroup, map: NodeMap, oldKey: string, newKey: string): boolean;
|
|
242
|
+
/** Remove entry `key` unless the map is at `minEntries`. Returns whether it was removed. */
|
|
243
|
+
declare function removeMapEntry(group: FormGroup, map: NodeMap, key: string): boolean;
|
|
244
|
+
/**
|
|
245
|
+
* Build the `AbstractControl` for a single schema node.
|
|
246
|
+
*
|
|
247
|
+
* Dispatches on `node.kind`: a `leaf` becomes a `FormControl`, a `leafList` a
|
|
248
|
+
* `FormArray` of controls, a `nodeGroup` a nested `FormGroup`, and a
|
|
249
|
+
* `nodeGroupList` a `FormArray` of groups. `initial` is the runtime value for
|
|
250
|
+
* this node — a scalar for a leaf, an array for a list, an object for a group —
|
|
251
|
+
* and seeds the control's value (falling back to the node's `default`).
|
|
252
|
+
*
|
|
253
|
+
* Most callers use {@link buildFormFromSchema}; this is exposed for building a
|
|
254
|
+
* control from a single non-root node.
|
|
255
|
+
*/
|
|
101
256
|
declare function buildControl<T extends NodeType>(node: T, initial?: unknown | null): DFormControl<T> | FormControl<LeafRuntimeType<any>> | FormArray<any>;
|
|
257
|
+
/**
|
|
258
|
+
* Build a typed `FormGroup` from a root `NodeGroup` schema.
|
|
259
|
+
*
|
|
260
|
+
* The returned group's control structure, keys, and value types are inferred
|
|
261
|
+
* from the schema literal — a `leaf` of `type: 'number'` yields a
|
|
262
|
+
* `FormControl<number>`, a `nodeGroup` a nested `FormGroup`, and so on. `initial`
|
|
263
|
+
* is an optional value object keyed by the schema's `children` keys; each child
|
|
264
|
+
* control is seeded from its matching slice (falling back to the node `default`).
|
|
265
|
+
*
|
|
266
|
+
* Presence nodes whose key is absent from `initial` get no control, at any depth
|
|
267
|
+
* — plain children, list items, map values, and choice case fields alike — so
|
|
268
|
+
* they are absent from the form value until enabled. A key present with an
|
|
269
|
+
* explicit `null` keeps its control: `null` is a value, absence is the missing
|
|
270
|
+
* key.
|
|
271
|
+
*
|
|
272
|
+
* Inference only holds when `schema`'s literal type is preserved. Author schemas
|
|
273
|
+
* with {@link defineSchema} or a `satisfies NodeGroup` annotation — never
|
|
274
|
+
* `const schema: NodeGroup = ...`, which widens `children` and erases the field
|
|
275
|
+
* names and value types.
|
|
276
|
+
*/
|
|
102
277
|
declare function buildFormFromSchema<S extends NodeGroup>(schema: S, initial?: Record<string, unknown> | null): DFormGroup<S>;
|
|
103
278
|
/**
|
|
104
279
|
* Capture a schema literal with its exact type while checking it against
|
|
@@ -120,40 +295,72 @@ declare function asFormArray(control: any): FormArray;
|
|
|
120
295
|
declare function asFormGroup(control: any): FormGroup;
|
|
121
296
|
|
|
122
297
|
declare class DynamicRecursiveFormComponent implements OnInit {
|
|
123
|
-
schema
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
298
|
+
/** The form-description schema to render (a root or nested `NodeGroup`). */
|
|
299
|
+
readonly schema: _angular_core.InputSignal<NodeGroup>;
|
|
300
|
+
/** Optional value object to seed the form; keyed by the schema's `children` keys. */
|
|
301
|
+
readonly initialValue: _angular_core.InputSignal<Record<string, unknown> | null>;
|
|
302
|
+
/** The reactive group this form binds to. Defaults to an empty group. */
|
|
303
|
+
readonly formGroup: _angular_core.InputSignal<FormGroup<any>>;
|
|
304
|
+
/** Index of this form within a parent list, used by `addButtonCallback`. */
|
|
305
|
+
readonly index: _angular_core.InputSignal<number | null>;
|
|
306
|
+
/** Whether this form may be removed from a parent list (shows a remove control). */
|
|
307
|
+
readonly removable: _angular_core.InputSignal<boolean>;
|
|
308
|
+
/** Emitted when the user removes this form from a parent list. */
|
|
309
|
+
readonly remove: _angular_core.OutputEmitterRef<void>;
|
|
310
|
+
/** Card/section title; falls back to the schema label or name. */
|
|
311
|
+
readonly title: _angular_core.InputSignal<string | undefined>;
|
|
312
|
+
/** Whether fields accept input. Two-way: also toggled by the built-in edit control. */
|
|
313
|
+
readonly editable: _angular_core.ModelSignal<boolean>;
|
|
314
|
+
/** Invoked with {@link index} to append a new sibling form to a parent list. */
|
|
315
|
+
readonly addButtonCallback: _angular_core.InputSignal<((index: number) => void) | null>;
|
|
316
|
+
/**
|
|
317
|
+
* Key of a presence leaf whose field should grab focus when it renders — lets
|
|
318
|
+
* a host that added the control itself (e.g. the tree editor's optionals
|
|
319
|
+
* menu) hand focus to the new field, like the form's own add button does.
|
|
320
|
+
*/
|
|
321
|
+
readonly focusLeaf: _angular_core.InputSignal<string | null>;
|
|
322
|
+
/** True when the schema is a root group (rendered flat, without a wrapping card). */
|
|
323
|
+
readonly root: _angular_core.Signal<boolean>;
|
|
133
324
|
ngOnInit(): void;
|
|
134
|
-
get nodeGroupChildrenList(): Array<{
|
|
325
|
+
protected get nodeGroupChildrenList(): Array<{
|
|
135
326
|
key: string;
|
|
136
327
|
value: NodeType;
|
|
137
328
|
}>;
|
|
138
|
-
emitRemoveEvent(): void;
|
|
329
|
+
protected emitRemoveEvent(): void;
|
|
330
|
+
/** The key of the presence leaf the user just enabled; its field grabs focus when rendered. */
|
|
331
|
+
protected presenceFocusKey: string | null;
|
|
332
|
+
/**
|
|
333
|
+
* Add or remove a presence node's control on this form — any presence kind:
|
|
334
|
+
* group, leaf, map, or choice. Removing it drops the key from `form.value`;
|
|
335
|
+
* adding it builds the control fresh from its schema (nested presence
|
|
336
|
+
* children start absent).
|
|
337
|
+
*/
|
|
338
|
+
toggleNodePresence(key: string, schema: NodeType, present: boolean): void;
|
|
139
339
|
/**
|
|
140
|
-
*
|
|
141
|
-
*
|
|
340
|
+
* {@link toggleNodePresence} for a presence leaf, additionally focusing the
|
|
341
|
+
* rendered field when the toggle just created it.
|
|
142
342
|
*/
|
|
143
|
-
|
|
144
|
-
protected
|
|
145
|
-
objectKeys(obj: Record<string, unknown>): string[];
|
|
343
|
+
toggleLeafPresence(key: string, schema: Leaf, present: boolean): void;
|
|
344
|
+
protected objectKeys(obj: Record<string, unknown>): string[];
|
|
146
345
|
/** The active case name of a choice control, or null if none is selected. */
|
|
147
|
-
activeCase(key: string): string | null;
|
|
346
|
+
protected activeCase(key: string): string | null;
|
|
148
347
|
/** A synthetic flattened NodeGroup used to render the active case's fields against the choice's FormGroup. */
|
|
149
|
-
caseAsGroup(choice: NodeChoice, caseName: string): NodeGroup;
|
|
150
|
-
/**
|
|
348
|
+
protected caseAsGroup(choice: NodeChoice, caseName: string): NodeGroup;
|
|
349
|
+
/** The display label for a case: the schema's `caseLabels` entry, else the case name. */
|
|
350
|
+
caseLabel(choice: NodeChoice, caseName: string): string;
|
|
351
|
+
/**
|
|
352
|
+
* A copy of a group flagged to render its fields inline (no inner panel). Used
|
|
353
|
+
* for a presence group's body, whose container is the presence panel itself, so
|
|
354
|
+
* the group's own section panel would be a redundant second box.
|
|
355
|
+
*/
|
|
356
|
+
protected flatGroup(group: NodeGroup): NodeGroup;
|
|
357
|
+
/** Swap a choice's field controls when the selected case changes. Delegates to {@link switchChoiceCase}. */
|
|
151
358
|
switchCase(key: string, choice: NodeChoice, caseName: string): void;
|
|
152
359
|
protected readonly asFormGroup: typeof asFormGroup;
|
|
153
360
|
protected readonly asFormArray: typeof asFormArray;
|
|
154
361
|
protected readonly asFormControl: typeof asFormControl;
|
|
155
|
-
static ɵfac:
|
|
156
|
-
static ɵcmp:
|
|
362
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<DynamicRecursiveFormComponent, never>;
|
|
363
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<DynamicRecursiveFormComponent, "nff-dynamic-recursive-form", never, { "schema": { "alias": "schema"; "required": true; "isSignal": true; }; "initialValue": { "alias": "initialValue"; "required": false; "isSignal": true; }; "formGroup": { "alias": "formGroup"; "required": false; "isSignal": true; }; "index": { "alias": "index"; "required": false; "isSignal": true; }; "removable": { "alias": "removable"; "required": false; "isSignal": true; }; "title": { "alias": "title"; "required": false; "isSignal": true; }; "editable": { "alias": "editable"; "required": false; "isSignal": true; }; "addButtonCallback": { "alias": "addButtonCallback"; "required": false; "isSignal": true; }; "focusLeaf": { "alias": "focusLeaf"; "required": false; "isSignal": true; }; }, { "remove": "remove"; "editable": "editableChange"; }, never, never, true, never>;
|
|
157
364
|
}
|
|
158
365
|
|
|
159
366
|
/** Metadata on a list-container node that lets the tree add items to its FormArray. */
|
|
@@ -162,91 +369,260 @@ interface ListRef {
|
|
|
162
369
|
itemSchema: NodeGroup;
|
|
163
370
|
itemLabel: string;
|
|
164
371
|
minItems: number;
|
|
372
|
+
maxItems?: number;
|
|
165
373
|
}
|
|
166
|
-
/**
|
|
374
|
+
/** An absent optional (presence) child, offered by its parent node's "+ Optional field" menu. */
|
|
375
|
+
interface OptionalEntry {
|
|
376
|
+
key: string;
|
|
377
|
+
schema: NodeType;
|
|
378
|
+
label: string;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* One flat section of the detail pane. The selected node's subtree renders as a
|
|
382
|
+
* pre-order list of these — no nesting chrome: each section after the first is
|
|
383
|
+
* separated by a breadcrumb heading (`trail`), and holds only the node's *own*
|
|
384
|
+
* fields (`schema` is a leaf-only slice; complex children are sections of their
|
|
385
|
+
* own, deeper in the list).
|
|
386
|
+
*/
|
|
387
|
+
interface DetailSection {
|
|
388
|
+
node: TreeNode;
|
|
389
|
+
/** Selected-node-to-here trail, rendered as the section's breadcrumb heading (omitted on the first section). */
|
|
390
|
+
trail: TreeNode[];
|
|
391
|
+
/** Leaf-only slice of the node's own schema, or null when it has no own fields. */
|
|
392
|
+
schema: NodeGroup | null;
|
|
393
|
+
/** The group `schema` binds to (the node's group; for a choice, the choice group). */
|
|
394
|
+
group: FormGroup | null;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* A navigable node in the config tree. Its `id` is the node's stable path from
|
|
398
|
+
* the root (`system/ntp`, `ifaces/0`, `servers/web1`), so expansion and
|
|
399
|
+
* selection survive tree rebuilds. Segments are `%`/`/`-escaped, since map
|
|
400
|
+
* entry keys are arbitrary runtime data; list-item identity is positional.
|
|
401
|
+
*/
|
|
167
402
|
interface TreeNode {
|
|
168
403
|
id: string;
|
|
169
404
|
label: string;
|
|
170
405
|
children: TreeNode[];
|
|
171
|
-
/**
|
|
172
|
-
leaves: {
|
|
173
|
-
key: string;
|
|
174
|
-
node: Leaf;
|
|
175
|
-
}[];
|
|
176
|
-
leafLists: {
|
|
177
|
-
key: string;
|
|
178
|
-
node: LeafList;
|
|
179
|
-
}[];
|
|
180
|
-
/** The FormGroup holding this node's leaves, or null for a list-container node. */
|
|
406
|
+
/** The node's own FormGroup, or null for a list-container or map node. */
|
|
181
407
|
group: FormGroup | null;
|
|
408
|
+
/** The node's own schema, set on group-backed nodes (groups, list items, group-valued map entries). */
|
|
409
|
+
schema?: NodeGroup;
|
|
182
410
|
/** Present on a nodeGroupList node: lets a `+` add an item. */
|
|
183
411
|
list?: ListRef;
|
|
184
|
-
/** Present on a list-item node: the
|
|
412
|
+
/** Present on a list-item node: its current index in the parent list (removal goes through the parent list array). */
|
|
185
413
|
removable?: {
|
|
186
|
-
array: FormArray;
|
|
187
414
|
index: number;
|
|
188
415
|
};
|
|
189
|
-
/**
|
|
190
|
-
|
|
191
|
-
|
|
416
|
+
/** Absent optional children of this node, offered by its "+ Optional field" menu (schema order). */
|
|
417
|
+
optionals?: OptionalEntry[];
|
|
418
|
+
/** Present on a present optional child node: drives the row's remove control. */
|
|
419
|
+
presenceRemovable?: {
|
|
420
|
+
key: string;
|
|
421
|
+
};
|
|
422
|
+
/** Present on a choice node: the choice schema and its FormGroup (holding `__case` + the active case's fields). */
|
|
423
|
+
choice?: {
|
|
424
|
+
schema: NodeChoice;
|
|
425
|
+
group: FormGroup;
|
|
426
|
+
};
|
|
427
|
+
/** Present on a map node. `complex` maps expand entries as child nodes. */
|
|
428
|
+
map?: {
|
|
429
|
+
schema: NodeMap;
|
|
430
|
+
group: FormGroup;
|
|
431
|
+
complex: boolean;
|
|
432
|
+
};
|
|
433
|
+
/** Present on a complex-map entry node: addresses the entry in its map for remove/rename. */
|
|
434
|
+
mapEntry?: {
|
|
435
|
+
mapGroup: FormGroup;
|
|
436
|
+
mapSchema: NodeMap;
|
|
192
437
|
key: string;
|
|
193
|
-
schema: NodeGroup;
|
|
194
438
|
};
|
|
195
|
-
/** For a presence node: whether the group is currently present. */
|
|
196
|
-
present?: boolean;
|
|
197
439
|
}
|
|
198
440
|
/**
|
|
199
|
-
* A tree/detail editor for a schema-built form: the structure (
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
441
|
+
* A tree/detail editor for a schema-built form: the structure (groups, lists,
|
|
442
|
+
* maps, choices) is a tree on the left, and selecting a node renders that
|
|
443
|
+
* node's **entire subtree** on the right as a **flat list of sections** — the
|
|
444
|
+
* node's own fields first, then every descendant's fields, each separated by a
|
|
445
|
+
* breadcrumb heading (`Service / Deploy scope / …`) instead of nested panels.
|
|
446
|
+
* Leaf fields render through {@link DynamicRecursiveFormComponent} with a
|
|
447
|
+
* leaf-only schema slice; choice selectors, map rows, and add controls render
|
|
448
|
+
* inline in their section. The tree adds row conveniences of its own: `+` on
|
|
449
|
+
* list and map rows, a delete control on removable rows, and a
|
|
450
|
+
* "+ Optional field" menu for absent presence children.
|
|
451
|
+
*
|
|
452
|
+
* The tree is **derived state**: any structural change to the form — made
|
|
453
|
+
* through the tree rows or through the detail sections — triggers a rebuild (a
|
|
454
|
+
* cheap shape signature over `valueChanges` detects it). Node ids are stable
|
|
455
|
+
* paths, so expansion and selection survive rebuilds. Swapping the `schema` or
|
|
456
|
+
* `formGroup` input rebinds the editor to the new pair, resetting expansion
|
|
457
|
+
* and selection.
|
|
458
|
+
*
|
|
459
|
+
* The component draws no outer container — only a divider between the tree and
|
|
460
|
+
* detail panes — so the embedding client owns the surrounding chrome.
|
|
204
461
|
*/
|
|
205
|
-
declare class ConfigEditorComponent implements
|
|
206
|
-
schema
|
|
207
|
-
|
|
208
|
-
|
|
462
|
+
declare class ConfigEditorComponent implements OnDestroy {
|
|
463
|
+
/** The form-description schema whose structure the tree renders. */
|
|
464
|
+
readonly schema: _angular_core.InputSignal<NodeGroup>;
|
|
465
|
+
/** The schema-built reactive group the editor binds to and mutates. */
|
|
466
|
+
readonly formGroup: _angular_core.InputSignal<FormGroup<any>>;
|
|
467
|
+
/** Whether fields accept input and structural controls (add/remove/menus) show. */
|
|
468
|
+
readonly editable: _angular_core.InputSignal<boolean>;
|
|
209
469
|
root: TreeNode;
|
|
210
470
|
selected: TreeNode | null;
|
|
471
|
+
/** The selected subtree as a flat, breadcrumb-separated section list. */
|
|
472
|
+
sections: DetailSection[];
|
|
473
|
+
/** Root-to-selection trail for the detail-pane breadcrumb, computed once per selection. */
|
|
474
|
+
breadcrumb: TreeNode[];
|
|
211
475
|
readonly expanded: Set<string>;
|
|
212
|
-
private
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
|
|
476
|
+
private shape;
|
|
477
|
+
private changes?;
|
|
478
|
+
private readonly host;
|
|
479
|
+
/** Stable per-instance ids for the shape signature, so replacing a control (setControl) reads as a structural change. */
|
|
480
|
+
private readonly controlIds;
|
|
481
|
+
private controlIdSeq;
|
|
482
|
+
constructor();
|
|
483
|
+
ngOnDestroy(): void;
|
|
484
|
+
/** Bind the editor to a schema/form pair: fresh tree, root selection, and shape-sync subscription. */
|
|
485
|
+
private attach;
|
|
486
|
+
select(node: TreeNode, reveal?: boolean): void;
|
|
217
487
|
/**
|
|
218
488
|
* Root-to-`target` path for the detail-pane breadcrumb (inclusive of both ends),
|
|
219
|
-
* or an empty array if `target` is not in the current tree.
|
|
220
|
-
* call so it stays correct after add/remove/presence mutations rebuild subtrees.
|
|
489
|
+
* or an empty array if `target` is not in the current tree.
|
|
221
490
|
*/
|
|
222
491
|
pathTo(target: TreeNode): TreeNode[];
|
|
223
|
-
toggle(node: TreeNode): void;
|
|
224
|
-
/**
|
|
492
|
+
protected toggle(node: TreeNode): void;
|
|
493
|
+
/** Keyboard access for tree rows: Enter/Space selects, ArrowRight expands, ArrowLeft collapses. */
|
|
494
|
+
protected onRowKeydown(event: KeyboardEvent, node: TreeNode): void;
|
|
495
|
+
/** Whether the row shows an expand twisty: it has child rows to reveal (children or an optionals menu row). */
|
|
496
|
+
protected hasExpandableContent(node: TreeNode): boolean;
|
|
497
|
+
/**
|
|
498
|
+
* Whether the node's form subtree holds a validation error. Group/choice, list,
|
|
499
|
+
* and map nodes each check their backing control; `invalid` aggregates over
|
|
500
|
+
* descendants, so an error anywhere below lights every ancestor row.
|
|
501
|
+
*/
|
|
502
|
+
protected hasError(node: TreeNode): boolean;
|
|
503
|
+
/** Append a new item to a list node's FormArray (up to `maxItems`), then select it. */
|
|
225
504
|
addItem(listNode: TreeNode): void;
|
|
226
|
-
/**
|
|
505
|
+
/**
|
|
506
|
+
* Remove a list item from its FormArray (down to `minItems`). List-item
|
|
507
|
+
* identity is positional, so expansion state under the list is cleared —
|
|
508
|
+
* otherwise it would silently migrate to the items that shift into the
|
|
509
|
+
* removed indexes.
|
|
510
|
+
*/
|
|
227
511
|
removeItem(listNode: TreeNode, item: TreeNode): void;
|
|
228
|
-
/**
|
|
229
|
-
|
|
230
|
-
protected
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
|
|
512
|
+
/** The just-added optional leaf (section path + key) whose field grabs focus when rendered. */
|
|
513
|
+
protected focusSectionId: string | null;
|
|
514
|
+
protected focusLeafKey: string | null;
|
|
515
|
+
/** Add an absent optional child from the menu: build its control and select the node it lands on. */
|
|
516
|
+
addOptional(node: TreeNode, entry: OptionalEntry): void;
|
|
517
|
+
/** Remove a present optional child node, returning its entry to the parent's menu. */
|
|
518
|
+
removeOptional(parent: TreeNode, node: TreeNode): void;
|
|
519
|
+
/** The active case name of a choice node, or null when none is selected. */
|
|
520
|
+
activeCase(node: TreeNode): string | null;
|
|
521
|
+
/** The display label of a choice node's active case, or null when no case is selected. */
|
|
522
|
+
activeCaseLabel(node: TreeNode): string | null;
|
|
523
|
+
/** The display label for a case: the schema's `caseLabels` entry, else the case name. */
|
|
524
|
+
protected caseLabel(choice: NodeChoice, caseName: string): string;
|
|
525
|
+
/** Switch a choice node's active case; the structural sync rebuilds the tree and sections. */
|
|
526
|
+
switchTreeCase(node: TreeNode, caseName: string): void;
|
|
527
|
+
protected objectKeys(obj: Record<string, unknown>): string[];
|
|
528
|
+
/** Append a new entry to a complex map node under a generated unique key, then select it. */
|
|
529
|
+
addTreeMapEntry(mapNode: TreeNode): void;
|
|
530
|
+
/** Remove a complex map entry (down to `minEntries`). */
|
|
531
|
+
removeTreeMapEntry(mapNode: TreeNode, entryNode: TreeNode): void;
|
|
532
|
+
/**
|
|
533
|
+
* Commit a rename-on-blur of a map entry's key; on success the entry is
|
|
534
|
+
* selected under its new path and its fresh key field regains focus (the
|
|
535
|
+
* rename re-renders the section under a new id, destroying the input that
|
|
536
|
+
* held focus).
|
|
537
|
+
*/
|
|
538
|
+
renameTreeMapEntry(entryNode: TreeNode, rawKey: string): void;
|
|
539
|
+
/** Move keyboard focus to the selected tree row once the action's re-render settles. */
|
|
540
|
+
private focusSelectedRow;
|
|
541
|
+
/** A muted hint for a section whose node currently renders no content of its own. */
|
|
542
|
+
protected emptySectionHint(s: DetailSection): string | null;
|
|
543
|
+
/** Whether a list node is at `maxItems` (the add control is hidden). */
|
|
544
|
+
protected listAtMax(node: TreeNode | undefined): boolean;
|
|
545
|
+
/** Whether a list node is at `minItems` (item remove controls are hidden). */
|
|
546
|
+
protected listAtMin(node: TreeNode | undefined): boolean;
|
|
547
|
+
/** Whether a map node is at `maxEntries` (the add control is hidden). */
|
|
548
|
+
protected mapAtMax(node: TreeNode | undefined): boolean;
|
|
549
|
+
/** Whether a map node is at `minEntries` (entry remove controls are hidden). */
|
|
550
|
+
protected mapAtMin(node: TreeNode | undefined): boolean;
|
|
551
|
+
/** Rebuild the tree from the current form structure if its shape changed. */
|
|
552
|
+
private syncShape;
|
|
553
|
+
/**
|
|
554
|
+
* A cheap structural signature of a control tree: group keys (plus the active
|
|
555
|
+
* `__case`), array lengths, leaf placeholders. Value edits don't change it;
|
|
556
|
+
* added/removed/renamed controls and case switches do. Reading `__case` from
|
|
557
|
+
* any group is safe because the name is reserved (the builder rejects it as a
|
|
558
|
+
* case field name or map entry key), so only choice groups carry it.
|
|
559
|
+
*/
|
|
560
|
+
private shapeOf;
|
|
561
|
+
/** The instance id a container contributes to the shape signature. */
|
|
562
|
+
private uidOf;
|
|
563
|
+
/** Rebuild the whole tree from schema + form and refresh the shape signature. */
|
|
564
|
+
private rebuild;
|
|
565
|
+
/** Re-point `selected` at the rebuilt tree: same path, else the closest surviving ancestor. */
|
|
566
|
+
private reconcileSelection;
|
|
567
|
+
/** The node at `path` in the current tree, or null. Walks by id-prefix segments. */
|
|
568
|
+
private byPath;
|
|
569
|
+
/** Select the node at `path`, falling back through its ancestors to the root. */
|
|
570
|
+
private selectByPath;
|
|
571
|
+
/**
|
|
572
|
+
* Flatten a subtree into detail sections, pre-order: the node's own fields
|
|
573
|
+
* first, then each child as its own breadcrumb-headed section. No nesting
|
|
574
|
+
* chrome — the headings are the boundaries between children.
|
|
575
|
+
*/
|
|
576
|
+
private buildSections;
|
|
577
|
+
/** A section's own renderable fields: a leaf-only schema slice and the group it binds to. */
|
|
578
|
+
private sectionContent;
|
|
579
|
+
/**
|
|
580
|
+
* The node's own fields as a flattened schema: leaf and leafList children
|
|
581
|
+
* only. Complex children are rendered as sections of their own, so the
|
|
582
|
+
* embedded form never draws nested section chrome. Null when there are none.
|
|
583
|
+
*/
|
|
584
|
+
private leafOnly;
|
|
235
585
|
private buildTree;
|
|
236
|
-
|
|
237
|
-
|
|
586
|
+
/** Build the tree node for a single non-leaf child, dispatching on its kind. Null when its control is missing. */
|
|
587
|
+
private buildChildNode;
|
|
588
|
+
/** Synthetic group over a case's normalized fields, so a case body builds like any group. */
|
|
589
|
+
private caseAsGroup;
|
|
590
|
+
/** A node's display label: its schema `label`, else its record key. */
|
|
591
|
+
private labelOf;
|
|
592
|
+
/** Join a parent path and a segment; the root's path is the empty string. */
|
|
593
|
+
private join;
|
|
594
|
+
/**
|
|
595
|
+
* Escape a path segment: `/` is the id separator, and map entry keys are
|
|
596
|
+
* arbitrary runtime data that may contain it. Labels stay unescaped — only
|
|
597
|
+
* node identities encode.
|
|
598
|
+
*/
|
|
599
|
+
private escapeSeg;
|
|
600
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ConfigEditorComponent, never>;
|
|
601
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<ConfigEditorComponent, "nff-config-editor", never, { "schema": { "alias": "schema"; "required": true; "isSignal": true; }; "formGroup": { "alias": "formGroup"; "required": true; "isSignal": true; }; "editable": { "alias": "editable"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
238
602
|
}
|
|
239
603
|
|
|
240
|
-
declare class LeafRendererComponent implements
|
|
604
|
+
declare class LeafRendererComponent implements AfterViewInit {
|
|
605
|
+
private readonly elementRef;
|
|
241
606
|
leaf_: Leaf | AnonLeaf;
|
|
242
607
|
control: FormControl;
|
|
243
|
-
initialValue?: any;
|
|
244
608
|
removable: boolean;
|
|
245
609
|
editable: boolean;
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
610
|
+
/** Focus the field once rendered — for fields the user just added (e.g. an enabled presence leaf). */
|
|
611
|
+
autofocus: boolean;
|
|
612
|
+
/** Emitted when the user removes this field (e.g. an optional presence leaf). */
|
|
613
|
+
readonly remove: _angular_core.OutputEmitterRef<void>;
|
|
614
|
+
constructor(elementRef: ElementRef<HTMLElement>);
|
|
615
|
+
ngAfterViewInit(): void;
|
|
616
|
+
/** Whether this field accepts input: the form is editable and the leaf is not `readOnly`. */
|
|
617
|
+
get fieldEditable(): boolean;
|
|
618
|
+
/**
|
|
619
|
+
* A human-readable message for the control's active validation error, or `''`
|
|
620
|
+
* when valid. `mat-form-field` only shows it once the field is in an error
|
|
621
|
+
* state (invalid and touched), so it can be bound unconditionally.
|
|
622
|
+
*/
|
|
623
|
+
get errorText(): string;
|
|
624
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LeafRendererComponent, never>;
|
|
625
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LeafRendererComponent, "nff-leaf-renderer", never, { "leaf_": { "alias": "leaf_"; "required": false; }; "control": { "alias": "control"; "required": false; }; "removable": { "alias": "removable"; "required": false; }; "editable": { "alias": "editable"; "required": false; }; "autofocus": { "alias": "autofocus"; "required": false; }; }, { "remove": "remove"; }, never, never, true, never>;
|
|
250
626
|
}
|
|
251
627
|
|
|
252
628
|
declare class LeafListRendererComponent implements OnInit {
|
|
@@ -267,8 +643,8 @@ declare class LeafListRendererComponent implements OnInit {
|
|
|
267
643
|
ngOnInit(): void;
|
|
268
644
|
removeItem($index: number): void;
|
|
269
645
|
addItem(): void;
|
|
270
|
-
static ɵfac:
|
|
271
|
-
static ɵcmp:
|
|
646
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LeafListRendererComponent, never>;
|
|
647
|
+
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; }; }, { "message": "message"; }, never, never, true, never>;
|
|
272
648
|
}
|
|
273
649
|
|
|
274
650
|
declare class LeafEnumRendererComponent {
|
|
@@ -278,8 +654,8 @@ declare class LeafEnumRendererComponent {
|
|
|
278
654
|
removable: boolean;
|
|
279
655
|
remove: any;
|
|
280
656
|
editable: boolean;
|
|
281
|
-
static ɵfac:
|
|
282
|
-
static ɵcmp:
|
|
657
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LeafEnumRendererComponent, never>;
|
|
658
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<LeafEnumRendererComponent, "nff-leaf-enum-renderer", never, { "leafEnum": { "alias": "leafEnum"; "required": false; }; "initialValue": { "alias": "initialValue"; "required": false; }; "control": { "alias": "control"; "required": false; }; "removable": { "alias": "removable"; "required": false; }; "remove": { "alias": "remove"; "required": false; }; "editable": { "alias": "editable"; "required": false; }; }, {}, never, never, true, never>;
|
|
283
659
|
}
|
|
284
660
|
|
|
285
661
|
declare class NodeGroupListRendererComponent implements OnInit, AfterViewInit {
|
|
@@ -299,9 +675,45 @@ declare class NodeGroupListRendererComponent implements OnInit, AfterViewInit {
|
|
|
299
675
|
setLastEditable(): void;
|
|
300
676
|
asFormGroup(group: any): FormGroup;
|
|
301
677
|
getTitle($index: number): string;
|
|
302
|
-
static ɵfac:
|
|
303
|
-
static ɵcmp:
|
|
678
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NodeGroupListRendererComponent, never>;
|
|
679
|
+
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; }; "minItems": { "alias": "minItems"; "required": false; }; "maxItems": { "alias": "maxItems"; "required": false; }; }, { "message": "message"; }, never, never, true, never>;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* Renders a {@link NodeMap}: an open, arbitrary-keyed record. Each entry is a row
|
|
684
|
+
* with an editable key and the shared value schema's control; the user can add,
|
|
685
|
+
* remove, and rename entries. The map's control is a `FormGroup` whose control
|
|
686
|
+
* names are the entry keys, so the key is edited as a *rename* (remove + re-add
|
|
687
|
+
* the same control) committed on blur — see {@link renameEntry}.
|
|
688
|
+
*/
|
|
689
|
+
declare class NodeMapRendererComponent implements OnChanges {
|
|
690
|
+
nodeMap: NodeMap;
|
|
691
|
+
formGroup: FormGroup<any>;
|
|
692
|
+
editable: boolean;
|
|
693
|
+
/** Ordered view of entry keys, kept stable across renames (`addControl` appends). */
|
|
694
|
+
entryKeys: string[];
|
|
695
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
696
|
+
/** The value schema as a leaf (used when `value.kind === 'leaf'`). */
|
|
697
|
+
get valueLeaf(): Leaf;
|
|
698
|
+
/** The value schema as a group (used when `value.kind === 'nodeGroup'`). */
|
|
699
|
+
get valueGroup(): NodeGroup;
|
|
700
|
+
get atMax(): boolean;
|
|
701
|
+
get atMin(): boolean;
|
|
702
|
+
/** Append a new entry under a unique placeholder key. Delegates to {@link addMapEntry}. */
|
|
703
|
+
addEntry(): void;
|
|
704
|
+
/** Drop an entry (its control leaves the group, so it drops from the value). Delegates to {@link removeMapEntry}. */
|
|
705
|
+
removeEntry(key: string): void;
|
|
706
|
+
/**
|
|
707
|
+
* Commit an edited key by renaming its control once (the value is preserved).
|
|
708
|
+
* An empty, unchanged, duplicate, or `keyPattern`-violating key is a no-op,
|
|
709
|
+
* leaving the entry under its current name. Delegates to {@link renameMapEntry}.
|
|
710
|
+
*/
|
|
711
|
+
renameEntry(oldKey: string, rawKey: string): void;
|
|
712
|
+
protected readonly asFormControl: typeof asFormControl;
|
|
713
|
+
protected readonly asFormGroup: typeof asFormGroup;
|
|
714
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<NodeMapRendererComponent, never>;
|
|
715
|
+
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; }; }, {}, never, never, true, never>;
|
|
304
716
|
}
|
|
305
717
|
|
|
306
|
-
export { CASE_KEY, ConfigEditorComponent, DynamicRecursiveFormComponent, LeafEnumRendererComponent, LeafListRendererComponent, LeafRendererComponent, NodeGroupListRendererComponent, buildControl, buildFormFromSchema, defineSchema };
|
|
307
|
-
export type { AnonLeaf, Appearance, DFormControl, DFormGroup, FormGroupType, Leaf, LeafBase, LeafBoolean, LeafEnum, LeafList, LeafNumber, LeafRuntimeType, LeafString, NodeChoice, NodeGroup, NodeGroupList, NodeType };
|
|
718
|
+
export { CASE_KEY, ConfigEditorComponent, DynamicRecursiveFormComponent, LeafEnumRendererComponent, LeafListRendererComponent, LeafRendererComponent, NodeGroupListRendererComponent, NodeMapRendererComponent, addMapEntry, buildControl, buildFormFromSchema, caseFields, defineSchema, removeMapEntry, renameMapEntry, resolveChoiceCase, switchChoiceCase };
|
|
719
|
+
export type { AnonLeaf, Appearance, ChoiceCase, DFormControl, DFormGroup, FormGroupType, Leaf, LeafBase, LeafBoolean, LeafEnum, LeafList, LeafNumber, LeafRuntimeType, LeafString, NodeChoice, NodeGroup, NodeGroupList, NodeMap, NodeType };
|