@ng-forge/dynamic-forms 1.0.0-rc.1 → 1.0.0-rc.3
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 +16 -0
- package/fesm2022/{ng-forge-dynamic-forms-array-field.component-By12r5Cj.mjs → ng-forge-dynamic-forms-array-field.component-D5qCzJsL.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-array-field.component-By12r5Cj.mjs.map → ng-forge-dynamic-forms-array-field.component-D5qCzJsL.mjs.map} +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-QJzwEYSj.mjs → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-D6ntLtW9.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-QJzwEYSj.mjs.map → ng-forge-dynamic-forms-bootstrap-derivation-orchestrator-D6ntLtW9.mjs.map} +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-container-field.component-BGFguOa9.mjs → ng-forge-dynamic-forms-container-field.component-nB6KFqVs.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-container-field.component-BGFguOa9.mjs.map → ng-forge-dynamic-forms-container-field.component-nB6KFqVs.mjs.map} +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-group-field.component-Bz4GD8Hy.mjs → ng-forge-dynamic-forms-group-field.component-Bq6Sgd6Z.mjs} +2 -2
- package/fesm2022/ng-forge-dynamic-forms-group-field.component-Bq6Sgd6Z.mjs.map +1 -0
- package/fesm2022/ng-forge-dynamic-forms-integration.mjs +6 -6
- package/fesm2022/ng-forge-dynamic-forms-integration.mjs.map +1 -1
- package/fesm2022/ng-forge-dynamic-forms-internal.mjs +281 -42
- package/fesm2022/ng-forge-dynamic-forms-internal.mjs.map +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-DTkMZcnb.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-C59pvc26.mjs} +86 -407
- package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-C59pvc26.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-page-field.component-CjCd5Byo.mjs → ng-forge-dynamic-forms-page-field.component-DRaxbiqA.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-page-field.component-CjCd5Byo.mjs.map → ng-forge-dynamic-forms-page-field.component-DRaxbiqA.mjs.map} +1 -1
- package/fesm2022/ng-forge-dynamic-forms.mjs +2 -2
- package/package.json +3 -3
- package/types/ng-forge-dynamic-forms-integration.d.ts +6 -10
- package/types/ng-forge-dynamic-forms-internal.d.ts +1951 -1750
- package/types/ng-forge-dynamic-forms.d.ts +61 -270
- package/fesm2022/ng-forge-dynamic-forms-group-field.component-Bz4GD8Hy.mjs.map +0 -1
- package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-DTkMZcnb.mjs.map +0 -1
|
@@ -1,10 +1,190 @@
|
|
|
1
|
+
import * as _ng_forge_dynamic_forms_internal from '@ng-forge/dynamic-forms/internal';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { Signal, Type, ResourceRef, ViewContainerRef, InjectionToken, WritableSignal, Injector, TemplateRef, PipeTransform, Resource } from '@angular/core';
|
|
1
4
|
import { Observable, OperatorFunction } from 'rxjs';
|
|
2
5
|
import { FieldContext, TreeValidationResult, ValidationError as ValidationError$1, FieldTree, ReadonlyFieldState, LogicFn, SchemaPath, SchemaPathTree } from '@angular/forms/signals';
|
|
3
|
-
import * as i0 from '@angular/core';
|
|
4
|
-
import { Signal, ResourceRef, Injector, WritableSignal, InjectionToken, Type, ViewContainerRef, TemplateRef, PipeTransform, Resource } from '@angular/core';
|
|
5
|
-
import * as _ng_forge_dynamic_forms_internal from '@ng-forge/dynamic-forms/internal';
|
|
6
6
|
import { FormSchema } from '@ng-forge/dynamic-forms/schema';
|
|
7
7
|
|
|
8
|
+
type DynamicText = string | Observable<string> | Signal<string>;
|
|
9
|
+
|
|
10
|
+
/** Generic reactive value — a static value, an Angular Signal, or an RxJS Observable. */
|
|
11
|
+
type DynamicValue<T> = T | Signal<T> | Observable<T>;
|
|
12
|
+
|
|
13
|
+
/** Universal addon slot names supported by every adapter. */
|
|
14
|
+
type CommonAddonSlot = 'prefix' | 'suffix';
|
|
15
|
+
/** Module-augmentable registry of adapter-specific addon slot names. */
|
|
16
|
+
interface DynamicFormAddonSlotRegistry {
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Union of every valid addon slot — universal slots plus any registered via
|
|
20
|
+
* {@link DynamicFormAddonSlotRegistry} module augmentation.
|
|
21
|
+
*/
|
|
22
|
+
type AddonSlot = CommonAddonSlot | keyof DynamicFormAddonSlotRegistry;
|
|
23
|
+
|
|
24
|
+
/** Base shape every addon type extends. */
|
|
25
|
+
interface BaseAddon<TSlot extends AddonSlot = AddonSlot> {
|
|
26
|
+
/** Slot to render this addon in. */
|
|
27
|
+
readonly slot: TSlot;
|
|
28
|
+
/** CSS class applied to the addon host element. */
|
|
29
|
+
readonly className?: string;
|
|
30
|
+
/** Reactive visibility — when `true`, the addon is removed from layout. */
|
|
31
|
+
readonly hidden?: DynamicValue<boolean>;
|
|
32
|
+
/** Reactive disabled state — primarily relevant for interactive types. */
|
|
33
|
+
readonly disabled?: DynamicValue<boolean>;
|
|
34
|
+
}
|
|
35
|
+
/** Module-augmentable registry of addon types. */
|
|
36
|
+
interface DynamicFormAddonRegistry {
|
|
37
|
+
text: TextAddon;
|
|
38
|
+
template: TemplateAddon;
|
|
39
|
+
component: ComponentAddon;
|
|
40
|
+
}
|
|
41
|
+
/** Union of every registered addon shape. */
|
|
42
|
+
type AnyAddon = DynamicFormAddonRegistry[keyof DynamicFormAddonRegistry];
|
|
43
|
+
/** Renders text content inline. */
|
|
44
|
+
interface TextAddon extends BaseAddon {
|
|
45
|
+
readonly type: 'text';
|
|
46
|
+
readonly text: DynamicText;
|
|
47
|
+
}
|
|
48
|
+
/** Renders a named `<ng-template>` projected into the host `<df-dynamic-form>`. */
|
|
49
|
+
interface TemplateAddon extends BaseAddon {
|
|
50
|
+
readonly type: 'template';
|
|
51
|
+
readonly templateKey: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Renders an arbitrary Angular component as the addon body.
|
|
55
|
+
*
|
|
56
|
+
* @codeOnly The `component` loader is a function and cannot survive
|
|
57
|
+
* `JSON.stringify`/`parse`. The lenient validator drops this type when the
|
|
58
|
+
* config originated from JSON (set via `sanitizeFormConfig({ source: 'json' })`).
|
|
59
|
+
*/
|
|
60
|
+
interface ComponentAddon extends BaseAddon {
|
|
61
|
+
readonly type: 'component';
|
|
62
|
+
readonly component: () => Promise<Type<unknown> | {
|
|
63
|
+
default: Type<unknown>;
|
|
64
|
+
}>;
|
|
65
|
+
readonly inputs?: Record<string, unknown>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
type WithInputSignals<T> = {
|
|
69
|
+
readonly [K in keyof T]-?: Signal<T[K]>;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
type Prettify<T> = {
|
|
73
|
+
[K in keyof T]: T[K];
|
|
74
|
+
} & {};
|
|
75
|
+
|
|
76
|
+
/** Base interface for native HTML attributes that can be passed to form field elements. */
|
|
77
|
+
interface FieldMeta {
|
|
78
|
+
/** Allows any data-* attribute */
|
|
79
|
+
[key: `data-${string}`]: string | undefined;
|
|
80
|
+
/** Allows any aria-* attribute */
|
|
81
|
+
[key: `aria-${string}`]: string | boolean | undefined;
|
|
82
|
+
/** Allows additional custom attributes as escape hatch */
|
|
83
|
+
[key: string]: string | number | boolean | undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Base interface for all dynamic form field definitions.
|
|
88
|
+
*
|
|
89
|
+
* @typeParam TProps - Field-specific properties interface
|
|
90
|
+
* @typeParam TMeta - Native HTML attributes interface (extends FieldMeta)
|
|
91
|
+
*/
|
|
92
|
+
interface FieldDef<TProps, TMeta extends FieldMeta = FieldMeta> {
|
|
93
|
+
/** Unique field identifier used for form binding and value tracking. */
|
|
94
|
+
key: string;
|
|
95
|
+
/** Field type identifier for component selection. */
|
|
96
|
+
type: RegisteredFieldTypes['type'] | (string & {});
|
|
97
|
+
/** Human-readable field label displayed to users. */
|
|
98
|
+
label?: DynamicText;
|
|
99
|
+
/** Field-specific properties and configuration options. */
|
|
100
|
+
props?: TProps;
|
|
101
|
+
/** Native HTML attributes to pass through to the underlying element. */
|
|
102
|
+
meta?: TMeta;
|
|
103
|
+
/** Additional CSS classes for custom styling. */
|
|
104
|
+
className?: string;
|
|
105
|
+
/**
|
|
106
|
+
* Whether the field is disabled and cannot be interacted with.
|
|
107
|
+
*
|
|
108
|
+
* @value false
|
|
109
|
+
*/
|
|
110
|
+
disabled?: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* Whether the field is read-only.
|
|
113
|
+
*
|
|
114
|
+
* @value false
|
|
115
|
+
*/
|
|
116
|
+
readonly?: boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Whether the field is hidden from view.
|
|
119
|
+
*
|
|
120
|
+
* @value false
|
|
121
|
+
*/
|
|
122
|
+
hidden?: boolean;
|
|
123
|
+
/** Tab index for keyboard navigation. */
|
|
124
|
+
tabIndex?: number | undefined;
|
|
125
|
+
/**
|
|
126
|
+
* Whether to exclude this field's value from submission output when hidden.
|
|
127
|
+
*
|
|
128
|
+
* @default undefined (uses form-level or global setting)
|
|
129
|
+
*/
|
|
130
|
+
excludeValueIfHidden?: boolean;
|
|
131
|
+
/**
|
|
132
|
+
* Whether to exclude this field's value from submission output when disabled.
|
|
133
|
+
*
|
|
134
|
+
* @default undefined (uses form-level or global setting)
|
|
135
|
+
*/
|
|
136
|
+
excludeValueIfDisabled?: boolean;
|
|
137
|
+
/**
|
|
138
|
+
* Whether to exclude this field's value from submission output when readonly.
|
|
139
|
+
*
|
|
140
|
+
* @default undefined (uses form-level or global setting)
|
|
141
|
+
*/
|
|
142
|
+
excludeValueIfReadonly?: boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Whether to run validation when this field is hidden — statically (`hidden: true`),
|
|
145
|
+
* via a `hidden` logic rule, or via any hidden ancestor.
|
|
146
|
+
*
|
|
147
|
+
* @default undefined — inherits from parent / form / global default (which is `false`)
|
|
148
|
+
*/
|
|
149
|
+
validateWhenHidden?: boolean;
|
|
150
|
+
/**
|
|
151
|
+
* Column sizing configuration for responsive grid layout.
|
|
152
|
+
*
|
|
153
|
+
* @value 12
|
|
154
|
+
*/
|
|
155
|
+
col?: number;
|
|
156
|
+
/** Wrapper components to chain around this field. */
|
|
157
|
+
wrappers?: readonly WrapperConfig[] | null;
|
|
158
|
+
/**
|
|
159
|
+
* Skip the auto-association layer (`WrapperTypeDefinition.types`) while
|
|
160
|
+
* keeping form-level defaults and any field-level `wrappers`. Use when a
|
|
161
|
+
* global wrapper auto-applies to this field type but isn't wanted here.
|
|
162
|
+
*/
|
|
163
|
+
skipAutoWrappers?: boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Skip the form-level `defaultWrappers` layer while keeping auto-associations
|
|
166
|
+
* and any field-level `wrappers`.
|
|
167
|
+
*/
|
|
168
|
+
skipDefaultWrappers?: boolean;
|
|
169
|
+
/** Addons rendered inside this field's slots (typically `prefix` / `suffix`). */
|
|
170
|
+
addons?: ReadonlyArray<AnyAddon>;
|
|
171
|
+
}
|
|
172
|
+
type IncludedKeys = 'label' | 'className' | 'hidden' | 'tabIndex';
|
|
173
|
+
/**
|
|
174
|
+
* Type utility for extracting component input properties from field definitions.
|
|
175
|
+
*
|
|
176
|
+
* @Component({...})
|
|
177
|
+
* export class MyFieldComponent implements FieldComponent<MyFieldDef> {
|
|
178
|
+
* label = input<string>();
|
|
179
|
+
* className = input<string>();
|
|
180
|
+
* hidden = input<boolean>();
|
|
181
|
+
* tabIndex = input<number>();
|
|
182
|
+
* }
|
|
183
|
+
* ```
|
|
184
|
+
* @typeParam T - Field definition type to extract properties from
|
|
185
|
+
*/
|
|
186
|
+
type FieldComponent<T extends FieldDef<unknown, FieldMeta>> = Prettify<WithInputSignals<Pick<T, IncludedKeys>>>;
|
|
187
|
+
|
|
8
188
|
/**
|
|
9
189
|
* Interface for dynamic forms logger implementations.
|
|
10
190
|
* Allows custom logging integrations (Sentry, DataDog, etc.)
|
|
@@ -257,360 +437,451 @@ interface OrCondition {
|
|
|
257
437
|
/** Discriminated union of all conditional expression types. */
|
|
258
438
|
type ConditionalExpression = FieldValueCondition | CustomCondition | JavascriptCondition | HttpCondition | AsyncCondition | AndCondition | OrCondition;
|
|
259
439
|
|
|
260
|
-
/** Special form-state conditions for button disabled logic. */
|
|
261
|
-
type FormStateCondition =
|
|
262
|
-
/** True when form.valid() === false */
|
|
263
|
-
'formInvalid'
|
|
264
|
-
/** True when form.submitting() === true */
|
|
265
|
-
| 'formSubmitting'
|
|
266
|
-
/** True when fields on the current page are invalid (for paged forms) */
|
|
267
|
-
| 'pageInvalid';
|
|
268
|
-
/** Logic type for controlling field state (hidden, readonly, disabled, required). */
|
|
269
|
-
type StateLogicType = 'hidden' | 'readonly' | 'disabled' | 'required';
|
|
270
440
|
/**
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
441
|
+
* Logic configuration for container fields (page, group, row, array).
|
|
442
|
+
* Containers only support the 'hidden' logic type since they are layout containers,
|
|
443
|
+
* not form controls (they can't be readonly, disabled, or required).
|
|
274
444
|
*/
|
|
275
|
-
interface
|
|
276
|
-
/**
|
|
277
|
-
type:
|
|
278
|
-
/**
|
|
279
|
-
|
|
445
|
+
interface ContainerLogicConfig {
|
|
446
|
+
/** Only 'hidden' is supported for container fields */
|
|
447
|
+
type: 'hidden';
|
|
448
|
+
/**
|
|
449
|
+
* Condition that determines when this container is hidden.
|
|
450
|
+
* Can be a boolean or a conditional expression evaluated against form values.
|
|
451
|
+
*/
|
|
452
|
+
condition: ConditionalExpression | boolean;
|
|
280
453
|
}
|
|
454
|
+
|
|
281
455
|
/**
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
456
|
+
* Row field interface for creating horizontal layouts.
|
|
457
|
+
* A row is a synthetic field type that resolves to a Container at runtime,
|
|
458
|
+
* with a synthesized `{ type: 'row' }` wrapper applied for layout. The row
|
|
459
|
+
* itself does not hold a value — its children flatten into the parent form.
|
|
285
460
|
*/
|
|
286
|
-
interface
|
|
461
|
+
interface RowField<TFields extends readonly RowAllowedChildren[] = readonly RowAllowedChildren[]> extends FieldDef<never> {
|
|
462
|
+
type: 'row';
|
|
463
|
+
/** Child definitions to render within this row */
|
|
464
|
+
readonly fields: TFields;
|
|
465
|
+
/** Row fields do not have a label property * */
|
|
466
|
+
readonly label?: never;
|
|
467
|
+
/** Rows do not support meta - they have no native form element * */
|
|
468
|
+
readonly meta?: never;
|
|
287
469
|
/**
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
* @default 'onChange'
|
|
470
|
+
* Logic configurations for conditional row visibility.
|
|
471
|
+
* Only 'hidden' type logic is supported for rows.
|
|
291
472
|
*/
|
|
292
|
-
|
|
293
|
-
/** Not allowed for onChange trigger */
|
|
294
|
-
debounceMs?: never;
|
|
473
|
+
readonly logic?: ContainerLogicConfig[];
|
|
295
474
|
}
|
|
475
|
+
/** Type guard for RowField with proper type narrowing */
|
|
476
|
+
declare function isRowField(field: FieldDef<any>): field is RowField;
|
|
477
|
+
type RowComponent = FieldComponent<RowField<RowAllowedChildren[]>>;
|
|
478
|
+
|
|
296
479
|
/**
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
480
|
+
* Group field interface for creating logical field groupings that map to object values
|
|
481
|
+
* Groups create nested form structures where child field values are collected into an object
|
|
482
|
+
* This is a programmatic grouping only - users cannot customize this field type
|
|
300
483
|
*/
|
|
301
|
-
interface
|
|
484
|
+
interface GroupField<TFields extends readonly GroupAllowedChildren[] = readonly GroupAllowedChildren[]> extends FieldDef<never> {
|
|
485
|
+
type: 'group';
|
|
486
|
+
readonly fields: TFields;
|
|
487
|
+
/** Groups do not have a label property - they are logical containers only * */
|
|
488
|
+
readonly label?: never;
|
|
489
|
+
/** Groups do not support meta - they have no native form element * */
|
|
490
|
+
readonly meta?: never;
|
|
302
491
|
/**
|
|
303
|
-
*
|
|
304
|
-
*
|
|
492
|
+
* Logic configurations for conditional group visibility.
|
|
493
|
+
* Only 'hidden' type logic is supported for groups.
|
|
305
494
|
*/
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Debounce duration in milliseconds.
|
|
309
|
-
*
|
|
310
|
-
* @default 500
|
|
311
|
-
*/
|
|
312
|
-
debounceMs?: number;
|
|
495
|
+
readonly logic?: ContainerLogicConfig[];
|
|
313
496
|
}
|
|
314
|
-
/**
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
interface SharedDerivationFields {
|
|
324
|
-
/** Logic type identifier for value derivation. */
|
|
325
|
-
type: 'derivation';
|
|
326
|
-
/** Target property name for property derivation. */
|
|
327
|
-
targetProperty?: string;
|
|
328
|
-
/** Optional name for this derivation for debugging purposes. */
|
|
329
|
-
debugName?: string;
|
|
330
|
-
/** Condition that determines when this derivation applies. */
|
|
331
|
-
condition?: ConditionalExpression | boolean;
|
|
497
|
+
/** Type guard for GroupField with proper type narrowing */
|
|
498
|
+
declare function isGroupField(field: FieldDef<any>): field is GroupField;
|
|
499
|
+
type GroupComponent<T extends GroupAllowedChildren[]> = FieldComponent<GroupField<T>>;
|
|
500
|
+
|
|
501
|
+
/** Container field interface for wrapping child fields with UI chrome. */
|
|
502
|
+
interface ContainerField<TFields extends readonly ContainerAllowedChildren[] = readonly ContainerAllowedChildren[], TWrapperConfigs extends readonly WrapperConfig[] = readonly WrapperConfig[]> extends FieldDef<never> {
|
|
503
|
+
type: 'container';
|
|
504
|
+
/** Child definitions to render within this container */
|
|
505
|
+
readonly fields: TFields;
|
|
332
506
|
/**
|
|
333
|
-
*
|
|
334
|
-
*
|
|
507
|
+
* Wrapper components to chain around the children.
|
|
508
|
+
* Applied outermost-first: the first wrapper in the array is the outermost.
|
|
509
|
+
* Each wrapper component receives the subsequent wrapper (or children) inside
|
|
510
|
+
* its `#fieldComponent` ViewContainerRef slot.
|
|
335
511
|
*/
|
|
336
|
-
|
|
512
|
+
readonly wrappers: TWrapperConfigs;
|
|
513
|
+
/** Container fields do not have a label property */
|
|
514
|
+
readonly label?: never;
|
|
515
|
+
/** Containers do not support meta — they have no native form element */
|
|
516
|
+
readonly meta?: never;
|
|
337
517
|
/**
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
* allowing the derivation to run again.
|
|
518
|
+
* Logic configurations for conditional container visibility.
|
|
519
|
+
* Only 'hidden' type logic is supported for containers.
|
|
341
520
|
*/
|
|
342
|
-
|
|
521
|
+
readonly logic?: ContainerLogicConfig[];
|
|
343
522
|
}
|
|
523
|
+
/** Type guard for ContainerField with proper type narrowing. */
|
|
524
|
+
declare function isGenericContainerField(field: FieldDef<any>): field is ContainerField;
|
|
525
|
+
type ContainerComponent = FieldComponent<ContainerField<ContainerAllowedChildren[]>>;
|
|
526
|
+
|
|
344
527
|
/**
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
* @internal
|
|
528
|
+
* Type constraints for field nesting rules
|
|
529
|
+
* These ensure that container fields can only contain valid child field types
|
|
348
530
|
*/
|
|
349
|
-
type ImmediateDerivationTrigger = {
|
|
350
|
-
trigger?: 'onChange';
|
|
351
|
-
debounceMs?: never;
|
|
352
|
-
};
|
|
353
|
-
type DebouncedDerivationTrigger = {
|
|
354
|
-
trigger: 'debounced';
|
|
355
|
-
debounceMs?: number;
|
|
356
|
-
};
|
|
357
531
|
/**
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
* @internal
|
|
532
|
+
* Fields that are allowed as children of Page fields
|
|
533
|
+
* Pages can contain: rows, groups, arrays, and leaf fields (but NOT other pages)
|
|
362
534
|
*/
|
|
363
|
-
|
|
364
|
-
/** Identifies this derivation as HTTP-driven. */
|
|
365
|
-
source: 'http';
|
|
366
|
-
/** Forbidden on HTTP source */
|
|
367
|
-
fn?: never;
|
|
368
|
-
/** Forbidden on HTTP source */
|
|
369
|
-
asyncFn?: never;
|
|
370
|
-
/** HTTP request configuration for server-driven derivations. */
|
|
371
|
-
http: HttpRequestConfig;
|
|
372
|
-
/**
|
|
373
|
-
* Explicit field dependencies. Required for HTTP derivations to prevent
|
|
374
|
-
* wildcard triggering on every keystroke.
|
|
375
|
-
*/
|
|
376
|
-
dependsOn: string[];
|
|
377
|
-
/** Expression to extract the derived value from the HTTP response. */
|
|
378
|
-
responseExpression: string;
|
|
379
|
-
value?: never;
|
|
380
|
-
expression?: never;
|
|
381
|
-
functionName?: never;
|
|
382
|
-
asyncFunctionName?: never;
|
|
383
|
-
}
|
|
535
|
+
type PageAllowedChildren = LeafFieldTypes | RowField | GroupField | ArrayField | SimplifiedArrayField | ContainerField;
|
|
384
536
|
/**
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
* @internal
|
|
537
|
+
* Fields that are allowed as children of Group fields
|
|
538
|
+
* Groups can contain: rows, arrays, and leaf fields (but NOT pages or other groups)
|
|
388
539
|
*/
|
|
389
|
-
|
|
390
|
-
/** Identifies this derivation as async-function-driven. */
|
|
391
|
-
source: 'asyncFunction';
|
|
392
|
-
/** Forbidden on asyncFunction source */
|
|
393
|
-
fn?: never;
|
|
394
|
-
/**
|
|
395
|
-
* Explicit field dependencies. Required for async derivations to prevent
|
|
396
|
-
* wildcard triggering on every form change.
|
|
397
|
-
*/
|
|
398
|
-
dependsOn: string[];
|
|
399
|
-
value?: never;
|
|
400
|
-
expression?: never;
|
|
401
|
-
functionName?: never;
|
|
402
|
-
http?: never;
|
|
403
|
-
responseExpression?: never;
|
|
404
|
-
}
|
|
540
|
+
type GroupAllowedChildren = LeafFieldTypes | RowField | ArrayField | SimplifiedArrayField | ContainerField;
|
|
405
541
|
/**
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
*
|
|
409
|
-
*
|
|
410
|
-
* @internal
|
|
542
|
+
* Fields that are allowed as children of Array fields
|
|
543
|
+
* Arrays can contain: rows, groups, and leaf fields (but NOT pages or other arrays)
|
|
544
|
+
* Groups are used for creating object arrays where each array item is an object
|
|
411
545
|
*/
|
|
412
|
-
type
|
|
413
|
-
/** Name of a registered async derivation function. */
|
|
414
|
-
asyncFunctionName: string;
|
|
415
|
-
/** Inline form is forbidden when `asyncFunctionName` is set */
|
|
416
|
-
asyncFn?: never;
|
|
417
|
-
}) | (AsyncFunctionDerivationShared & {
|
|
418
|
-
/** Inline async derivation function. Mutually exclusive with `asyncFunctionName`. */
|
|
419
|
-
asyncFn: AsyncDerivationFunction;
|
|
420
|
-
/** Registered form is forbidden when `asyncFn` is set */
|
|
421
|
-
asyncFunctionName?: never;
|
|
422
|
-
});
|
|
546
|
+
type ArrayAllowedChildren = LeafFieldTypes | RowField | GroupField | ContainerField;
|
|
423
547
|
/**
|
|
424
|
-
*
|
|
425
|
-
*
|
|
426
|
-
*
|
|
548
|
+
* Fields that are allowed as children of Container fields.
|
|
549
|
+
* Containers are pure layout primitives that flatten their children into the
|
|
550
|
+
* parent form, so most registered field types may appear inside — including
|
|
551
|
+
* hidden fields and other containers — but NOT pages.
|
|
427
552
|
*/
|
|
428
|
-
|
|
429
|
-
source?: never;
|
|
430
|
-
/** Forbidden on expression mode */
|
|
431
|
-
fn?: never;
|
|
432
|
-
/** Forbidden on expression mode */
|
|
433
|
-
asyncFn?: never;
|
|
434
|
-
/** JavaScript expression to evaluate for the derived value. */
|
|
435
|
-
expression: string;
|
|
436
|
-
/** Explicit field dependencies for expressions. */
|
|
437
|
-
dependsOn?: string[];
|
|
438
|
-
value?: never;
|
|
439
|
-
functionName?: never;
|
|
440
|
-
http?: never;
|
|
441
|
-
asyncFunctionName?: never;
|
|
442
|
-
responseExpression?: never;
|
|
443
|
-
}
|
|
553
|
+
type ContainerAllowedChildren = LeafFieldTypes | RowField | GroupField | ArrayField | SimplifiedArrayField | ContainerField;
|
|
444
554
|
/**
|
|
445
|
-
*
|
|
446
|
-
*
|
|
447
|
-
* @internal
|
|
555
|
+
* Row is a synthetic field type that resolves to a Container at runtime, so
|
|
556
|
+
* it accepts the same children as a Container.
|
|
448
557
|
*/
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
/** Forbidden on value mode */
|
|
452
|
-
fn?: never;
|
|
453
|
-
/** Forbidden on value mode */
|
|
454
|
-
asyncFn?: never;
|
|
455
|
-
/** Static value to set on this field. */
|
|
456
|
-
value: unknown;
|
|
457
|
-
/** Explicit field dependencies for value derivations. */
|
|
458
|
-
dependsOn?: string[];
|
|
459
|
-
expression?: never;
|
|
460
|
-
functionName?: never;
|
|
461
|
-
http?: never;
|
|
462
|
-
asyncFunctionName?: never;
|
|
463
|
-
responseExpression?: never;
|
|
464
|
-
}
|
|
558
|
+
type RowAllowedChildren = ContainerAllowedChildren;
|
|
559
|
+
|
|
465
560
|
/**
|
|
466
|
-
*
|
|
467
|
-
*
|
|
468
|
-
* @internal
|
|
561
|
+
* An array item template is an array of allowed children that defines one OBJECT array item's fields.
|
|
562
|
+
* Used for object arrays where each item is `{ key1: value1, key2: value2, ... }`.
|
|
469
563
|
*/
|
|
470
|
-
|
|
471
|
-
source?: never;
|
|
472
|
-
/** Forbidden on function-derivation mode */
|
|
473
|
-
asyncFn?: never;
|
|
474
|
-
/** Explicit field dependencies for function derivations. */
|
|
475
|
-
dependsOn?: string[];
|
|
476
|
-
value?: never;
|
|
477
|
-
expression?: never;
|
|
478
|
-
http?: never;
|
|
479
|
-
asyncFunctionName?: never;
|
|
480
|
-
responseExpression?: never;
|
|
481
|
-
}
|
|
564
|
+
type ArrayItemTemplate = readonly ArrayAllowedChildren[];
|
|
482
565
|
/**
|
|
483
|
-
*
|
|
484
|
-
*
|
|
485
|
-
*
|
|
486
|
-
* @internal
|
|
566
|
+
* An array item definition can be either:
|
|
567
|
+
* - A single field (ArrayAllowedChildren) for PRIMITIVE array items - extracts field value directly
|
|
568
|
+
* - An array of fields (ArrayItemTemplate) for OBJECT array items - merges fields into object
|
|
487
569
|
*/
|
|
488
|
-
type
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
570
|
+
type ArrayItemDefinition = ArrayAllowedChildren | ArrayItemTemplate;
|
|
571
|
+
/** Array field interface for creating dynamic field collections that map to array values. */
|
|
572
|
+
interface ArrayField<TFields extends readonly ArrayItemDefinition[] = readonly ArrayItemDefinition[]> extends FieldDef<never> {
|
|
573
|
+
type: 'array';
|
|
574
|
+
/**
|
|
575
|
+
* Array of item definitions. Each element defines one array item:
|
|
576
|
+
* - Single FieldDef = primitive item (field's value is extracted directly)
|
|
577
|
+
* - Array of FieldDefs = object item (fields are merged into an object)
|
|
578
|
+
* - Empty array `[]` = no initial items (add via buttons with explicit templates)
|
|
579
|
+
* - Items can have different configurations (heterogeneous arrays supported)
|
|
580
|
+
* - Initial values are set via `value` property on each field definition
|
|
581
|
+
*/
|
|
582
|
+
readonly fields: TFields;
|
|
583
|
+
/** Array fields do not have a label property * */
|
|
584
|
+
readonly label?: never;
|
|
585
|
+
/** Arrays do not support meta - they have no native form element * */
|
|
586
|
+
readonly meta?: never;
|
|
587
|
+
/**
|
|
588
|
+
* Logic configurations for conditional array visibility.
|
|
589
|
+
* Only 'hidden' type logic is supported for arrays.
|
|
590
|
+
*/
|
|
591
|
+
readonly logic?: ContainerLogicConfig[];
|
|
592
|
+
/**
|
|
593
|
+
* Minimum number of items required in the array.
|
|
594
|
+
* Validation fails if the array has fewer items than this value.
|
|
595
|
+
*/
|
|
596
|
+
readonly minLength?: number;
|
|
597
|
+
/**
|
|
598
|
+
* Maximum number of items allowed in the array.
|
|
599
|
+
* Validation fails if the array has more items than this value.
|
|
600
|
+
*/
|
|
601
|
+
readonly maxLength?: number;
|
|
602
|
+
}
|
|
499
603
|
/**
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
604
|
+
* Type guard for ArrayField with proper type narrowing.
|
|
605
|
+
* Validates that the field is an array type with a fields property that is an array.
|
|
606
|
+
* Fields can contain either single FieldDefs (primitive items) or arrays of FieldDefs (object items).
|
|
503
607
|
*/
|
|
504
|
-
|
|
608
|
+
declare function isArrayField(field: FieldDef<any>): field is ArrayField;
|
|
609
|
+
type ArrayComponent<T extends ArrayItemTemplate[]> = FieldComponent<ArrayField<T>>;
|
|
610
|
+
/** Configuration for auto-generated add/remove buttons in simplified array fields. */
|
|
611
|
+
interface ArrayButtonConfig {
|
|
612
|
+
/** Custom label for the button */
|
|
613
|
+
readonly label?: string;
|
|
614
|
+
/** Additional properties passed to the button component */
|
|
615
|
+
readonly props?: Record<string, unknown>;
|
|
616
|
+
}
|
|
617
|
+
/** Simplified array field interface for common use cases. */
|
|
618
|
+
interface SimplifiedArrayField extends FieldDef<never> {
|
|
619
|
+
type: 'array';
|
|
620
|
+
/**
|
|
621
|
+
* Template defining the structure of a single array item.
|
|
622
|
+
* - Single field (ArrayAllowedChildren) → primitive array (each item is a single value)
|
|
623
|
+
* - Array of fields (readonly ArrayAllowedChildren[]) → object array (each item is an object)
|
|
624
|
+
*/
|
|
625
|
+
readonly template: ArrayAllowedChildren | readonly ArrayAllowedChildren[];
|
|
626
|
+
/** Initial values for the array. Each element creates one array item. */
|
|
627
|
+
readonly value?: readonly unknown[];
|
|
628
|
+
/**
|
|
629
|
+
* Configuration for the auto-generated "Add" button, or `false` to disable it.
|
|
630
|
+
* Defaults to a button with label "Add".
|
|
631
|
+
*/
|
|
632
|
+
readonly addButton?: ArrayButtonConfig | false;
|
|
633
|
+
/**
|
|
634
|
+
* Configuration for the auto-generated "Remove" button on each item, or `false` to disable it.
|
|
635
|
+
* Defaults to a button with label "Remove".
|
|
636
|
+
*/
|
|
637
|
+
readonly removeButton?: ArrayButtonConfig | false;
|
|
638
|
+
/** Simplified arrays do not support the label property */
|
|
639
|
+
readonly label?: never;
|
|
640
|
+
/** Simplified arrays do not support meta */
|
|
641
|
+
readonly meta?: never;
|
|
642
|
+
/**
|
|
643
|
+
* Logic configurations for conditional array visibility.
|
|
644
|
+
* Only 'hidden' type logic is supported for arrays.
|
|
645
|
+
*/
|
|
646
|
+
readonly logic?: ContainerLogicConfig[];
|
|
647
|
+
/**
|
|
648
|
+
* Minimum number of items required in the array.
|
|
649
|
+
* Validation fails if the array has fewer items than this value.
|
|
650
|
+
*/
|
|
651
|
+
readonly minLength?: number;
|
|
652
|
+
/**
|
|
653
|
+
* Maximum number of items allowed in the array.
|
|
654
|
+
* Validation fails if the array has more items than this value.
|
|
655
|
+
*/
|
|
656
|
+
readonly maxLength?: number;
|
|
657
|
+
/** Mutually exclusive with `template` — use `fields` for the full API instead */
|
|
658
|
+
readonly fields?: never;
|
|
659
|
+
}
|
|
505
660
|
/**
|
|
506
|
-
*
|
|
507
|
-
*
|
|
508
|
-
* @internal
|
|
661
|
+
* Type guard for SimplifiedArrayField.
|
|
662
|
+
* Checks for `type: 'array'` with a `template` property (discriminant from full ArrayField).
|
|
509
663
|
*/
|
|
510
|
-
|
|
664
|
+
declare function isSimplifiedArrayField(field: FieldDef<any>): field is SimplifiedArrayField;
|
|
665
|
+
|
|
511
666
|
/**
|
|
512
|
-
*
|
|
513
|
-
*
|
|
514
|
-
* @internal
|
|
667
|
+
* Scalar types supported by hidden fields.
|
|
668
|
+
* These are the primitive value types that can be stored.
|
|
515
669
|
*/
|
|
516
|
-
type
|
|
670
|
+
type HiddenScalar = string | number | boolean;
|
|
517
671
|
/**
|
|
518
|
-
*
|
|
519
|
-
*
|
|
520
|
-
*
|
|
672
|
+
* All value types supported by hidden fields.
|
|
673
|
+
* Supports both scalar values and arrays of scalars for storing
|
|
674
|
+
* multiple IDs or similar data.
|
|
521
675
|
*/
|
|
522
|
-
type
|
|
676
|
+
type HiddenValue = HiddenScalar | HiddenScalar[];
|
|
523
677
|
/**
|
|
524
|
-
*
|
|
678
|
+
* Hidden field definition for storing values without rendering UI.
|
|
525
679
|
*
|
|
526
|
-
* @
|
|
680
|
+
* @typeParam TValue - The type of value stored (must be HiddenValue compatible)
|
|
527
681
|
*/
|
|
528
|
-
|
|
682
|
+
interface HiddenField<TValue extends HiddenValue = HiddenValue> extends FieldDef<never> {
|
|
683
|
+
/** Discriminant for hidden field type */
|
|
684
|
+
type: 'hidden';
|
|
685
|
+
/**
|
|
686
|
+
* The value to store in the form.
|
|
687
|
+
* This is required - a hidden field without a value serves no purpose.
|
|
688
|
+
*/
|
|
689
|
+
value: TValue;
|
|
690
|
+
}
|
|
529
691
|
/**
|
|
530
|
-
*
|
|
692
|
+
* Type guard to check if a field is a hidden field.
|
|
531
693
|
*
|
|
532
|
-
* @
|
|
694
|
+
* @param field - The field to check
|
|
695
|
+
* @returns True if the field is a HiddenField
|
|
533
696
|
*/
|
|
534
|
-
|
|
697
|
+
declare function isHiddenField(field: FieldDef<unknown>): field is HiddenField;
|
|
698
|
+
|
|
535
699
|
/**
|
|
536
|
-
*
|
|
537
|
-
*
|
|
538
|
-
*
|
|
700
|
+
* Page field interface for creating top-level page layouts
|
|
701
|
+
* This is a special field type that contains other field definitions
|
|
702
|
+
* The page itself doesn't have a value - it's a layout container like row
|
|
703
|
+
* Pages can only be used at the top level and cannot be nested
|
|
704
|
+
* This is a programmatic field type only - users cannot customize this field type
|
|
539
705
|
*/
|
|
540
|
-
|
|
706
|
+
interface PageField<TFields extends readonly PageAllowedChildren[] = PageAllowedChildren[]> extends FieldDef<never> {
|
|
707
|
+
type: 'page';
|
|
708
|
+
/** Child field definitions to render within this page */
|
|
709
|
+
readonly fields: TFields;
|
|
710
|
+
/** Page fields do not have a label property * */
|
|
711
|
+
readonly label?: never;
|
|
712
|
+
/** Pages do not support meta - they have no native form element * */
|
|
713
|
+
readonly meta?: never;
|
|
714
|
+
/**
|
|
715
|
+
* Logic configurations for conditional page visibility.
|
|
716
|
+
* Only 'hidden' type logic is supported for pages.
|
|
717
|
+
*/
|
|
718
|
+
readonly logic?: ContainerLogicConfig[];
|
|
719
|
+
}
|
|
720
|
+
/** Type guard for PageField with proper type narrowing */
|
|
721
|
+
declare function isPageField(field: FieldDef<unknown>): field is PageField;
|
|
541
722
|
/**
|
|
542
|
-
*
|
|
723
|
+
* Validates that a page field doesn't contain nested page fields
|
|
543
724
|
*
|
|
544
|
-
* @
|
|
725
|
+
* @param pageField The page field to validate
|
|
726
|
+
* @returns true if valid (no nested pages), false otherwise
|
|
545
727
|
*/
|
|
546
|
-
|
|
728
|
+
declare function validatePageNesting(pageField: PageField): boolean;
|
|
729
|
+
|
|
547
730
|
/**
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
* @internal
|
|
731
|
+
* Helper type to convert union to intersection.
|
|
732
|
+
* Uses `U extends U` to trigger distributive conditional type behavior.
|
|
551
733
|
*/
|
|
552
|
-
type
|
|
734
|
+
type UnionToIntersection<U> = (U extends U ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
735
|
+
/** Depth counter for recursion limiting (prevents infinite type instantiation) */
|
|
736
|
+
type Depth = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
553
737
|
/**
|
|
554
|
-
*
|
|
555
|
-
*
|
|
556
|
-
* @internal
|
|
738
|
+
* Widens literal types to their primitive equivalents, recursively for objects and arrays.
|
|
739
|
+
* This prevents `as const` from over-narrowing types like `''` to literal `''` instead of `string`.
|
|
557
740
|
*/
|
|
558
|
-
type
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
/** Union type for all logic configurations. */
|
|
562
|
-
type LogicConfig = StateLogicConfig | DerivationLogicConfig;
|
|
563
|
-
/** Log level for derivation debug output. */
|
|
564
|
-
type DerivationLogLevel = 'none' | 'summary' | 'verbose';
|
|
565
|
-
/** Configuration for derivation debug logging. */
|
|
566
|
-
interface DerivationLogConfig {
|
|
567
|
-
/** Log level for derivation debugging. Defaults to 'none'. */
|
|
568
|
-
level: DerivationLogLevel;
|
|
569
|
-
}
|
|
741
|
+
type Widen<T, D extends number = 5> = [D] extends [never] ? T : T extends string ? string : T extends number ? number : T extends boolean ? boolean : T extends readonly (infer U)[] ? Widen<U, Depth[D]>[] : T extends Record<string, unknown> ? {
|
|
742
|
+
-readonly [K in keyof T]: Widen<T[K], Depth[D]>;
|
|
743
|
+
} : T;
|
|
570
744
|
/**
|
|
571
|
-
*
|
|
572
|
-
*
|
|
573
|
-
*
|
|
745
|
+
* Resolves the "underlying" non-null value type for a field, based on its `type`
|
|
746
|
+
* discriminator and (where it matters) its `value` literal. Used when we need a
|
|
747
|
+
* base type independent of whether the literal happens to be `null` — i.e., when
|
|
748
|
+
* computing the nullable widening for `value: null, nullable: true`.
|
|
574
749
|
*/
|
|
575
|
-
|
|
750
|
+
type ResolveBaseValueType<T, V> = T extends {
|
|
751
|
+
type: 'slider';
|
|
752
|
+
} ? number : T extends {
|
|
753
|
+
type: 'input';
|
|
754
|
+
props: {
|
|
755
|
+
type: 'number';
|
|
756
|
+
};
|
|
757
|
+
} ? number : T extends {
|
|
758
|
+
type: 'checkbox' | 'toggle';
|
|
759
|
+
} ? boolean : [V] extends [null] ? string : Widen<V>;
|
|
576
760
|
/**
|
|
577
|
-
*
|
|
578
|
-
*
|
|
579
|
-
*
|
|
580
|
-
*
|
|
581
|
-
*
|
|
761
|
+
* Infer value type based on field type, value literal, and the `nullable` flag.
|
|
762
|
+
* - Slider fields: always number
|
|
763
|
+
* - Input fields with props.type: 'number': number
|
|
764
|
+
* - Checkbox / toggle fields: always boolean
|
|
765
|
+
* - Other fields: widen the literal value type (default to string when value is null)
|
|
766
|
+
* - When `nullable: true` is declared, widens the result to `T | null`.
|
|
582
767
|
*/
|
|
583
|
-
|
|
768
|
+
type InferValueType<T, V> = T extends {
|
|
769
|
+
nullable: true;
|
|
770
|
+
} ? ResolveBaseValueType<T, V> | null : ResolveBaseValueType<T, V>;
|
|
584
771
|
/**
|
|
585
|
-
*
|
|
586
|
-
*
|
|
587
|
-
* @param condition - The condition to check
|
|
588
|
-
* @returns true if the condition is a FormStateCondition
|
|
772
|
+
* Make type optional if field is not required.
|
|
773
|
+
* Hidden fields are never optional since they require a value property.
|
|
589
774
|
*/
|
|
590
|
-
|
|
775
|
+
type MaybeOptional<T, V> = T extends {
|
|
776
|
+
type: 'hidden';
|
|
777
|
+
} ? V : T extends {
|
|
778
|
+
required: true;
|
|
779
|
+
} ? V : V | undefined;
|
|
591
780
|
/**
|
|
592
|
-
*
|
|
593
|
-
*
|
|
594
|
-
*
|
|
595
|
-
*
|
|
781
|
+
* Infers the value type from a single template field (for primitive arrays).
|
|
782
|
+
* Mirrors InferValueType logic: slider → number, input[number] → number,
|
|
783
|
+
* checkbox/toggle → boolean, else widen `value` (string fallback). Widens to
|
|
784
|
+
* `T | null` when `nullable: true` is declared on the template field.
|
|
596
785
|
*/
|
|
597
|
-
|
|
786
|
+
type InferSingleTemplateValueBase<T, D extends number> = T extends {
|
|
787
|
+
type: 'slider';
|
|
788
|
+
} ? number : T extends {
|
|
789
|
+
type: 'input';
|
|
790
|
+
props: {
|
|
791
|
+
type: 'number';
|
|
792
|
+
};
|
|
793
|
+
} ? number : T extends {
|
|
794
|
+
type: 'checkbox' | 'toggle';
|
|
795
|
+
} ? boolean : T extends {
|
|
796
|
+
value: infer V;
|
|
797
|
+
} ? [V] extends [null] ? string : Widen<V, Depth[D]> : string;
|
|
798
|
+
type InferSingleTemplateValue<T, D extends number> = T extends {
|
|
799
|
+
nullable: true;
|
|
800
|
+
} ? InferSingleTemplateValueBase<T, D> | null : InferSingleTemplateValueBase<T, D>;
|
|
598
801
|
/**
|
|
599
|
-
*
|
|
600
|
-
*
|
|
601
|
-
*
|
|
602
|
-
*
|
|
802
|
+
* Infers the value type for an array field.
|
|
803
|
+
* Handles four cases:
|
|
804
|
+
* 1. Simplified array with template + value → infer item type from value
|
|
805
|
+
* 2. Simplified array with array template (no value) → infer object type from template fields
|
|
806
|
+
* 3. Simplified array with single-field template (no value) → infer primitive type from template field
|
|
807
|
+
* 4. Full-API array with fields → infer from children
|
|
603
808
|
*/
|
|
604
|
-
|
|
809
|
+
type InferArrayValue<T, D extends number> = T extends {
|
|
810
|
+
template: unknown;
|
|
811
|
+
value: readonly (infer Item)[];
|
|
812
|
+
} ? Widen<Item>[] : T extends {
|
|
813
|
+
template: infer TArr;
|
|
814
|
+
} ? TArr extends readonly RegisteredFieldTypes[] ? InferFormValueWithDepth<[...TArr], Depth[D]>[] : InferSingleTemplateValue<TArr, D>[] : T extends {
|
|
815
|
+
fields: infer F;
|
|
816
|
+
} ? InferContainerChildren<F, Depth[D], unknown>[] : unknown[];
|
|
605
817
|
/**
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
*
|
|
609
|
-
*
|
|
818
|
+
* Recurse into a container's child fields, but only when they form a fixed-length
|
|
819
|
+
* tuple — i.e. a config authored with `as const`. A general `RegisteredFieldTypes[]`
|
|
820
|
+
* array (notably the base default `InferFormValue<RegisteredFieldTypes[]>` over the
|
|
821
|
+
* whole registry) bails to `TFallback`; recursing there would make the type explode
|
|
822
|
+
* past TypeScript's union-complexity limit (TS2590) and break consumers of the
|
|
823
|
+
* abstract `FormConfig`. `[...F]` re-mutabilises the readonly tuple for the inner
|
|
824
|
+
* `InferFormValueWithDepth` constraint.
|
|
610
825
|
*/
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
826
|
+
type InferContainerChildren<F, D extends number, TFallback> = F extends readonly RegisteredFieldTypes[] ? number extends F['length'] ? TFallback : InferFormValueWithDepth<[...F], D> : TFallback;
|
|
827
|
+
/** Process a single field and determine its contribution to the form value type */
|
|
828
|
+
type ProcessField<T, D extends number = 5> = [D] extends [never] ? Record<string, unknown> : T extends {
|
|
829
|
+
type: 'page' | 'row';
|
|
830
|
+
fields: infer F;
|
|
831
|
+
} ? InferContainerChildren<F, Depth[D], never> : T extends {
|
|
832
|
+
type: 'group';
|
|
833
|
+
key: infer K;
|
|
834
|
+
fields: infer F;
|
|
835
|
+
} ? K extends string ? {
|
|
836
|
+
[P in K]: InferContainerChildren<F, Depth[D], Record<string, unknown>>;
|
|
837
|
+
} : never : T extends {
|
|
838
|
+
type: 'array';
|
|
839
|
+
key: infer K;
|
|
840
|
+
} ? K extends string ? {
|
|
841
|
+
[P in K]: InferArrayValue<T, D>;
|
|
842
|
+
} : never : T extends {
|
|
843
|
+
type: 'text';
|
|
844
|
+
} ? never : T extends {
|
|
845
|
+
type: 'submit' | 'button' | 'next' | 'previous' | 'addArrayItem' | 'removeArrayItem';
|
|
846
|
+
} ? never : T extends {
|
|
847
|
+
key: infer K;
|
|
848
|
+
value: infer V;
|
|
849
|
+
} ? K extends string ? {
|
|
850
|
+
[P in K]: MaybeOptional<T, InferValueType<T, V>>;
|
|
851
|
+
} : never : T extends {
|
|
852
|
+
key: infer K;
|
|
853
|
+
} ? K extends string ? {
|
|
854
|
+
[P in K]: MaybeOptional<T, T extends {
|
|
855
|
+
nullable: true;
|
|
856
|
+
} ? string | null : string>;
|
|
857
|
+
} : never : never;
|
|
858
|
+
/** Internal helper with depth tracking */
|
|
859
|
+
type InferFormValueWithDepth<T extends RegisteredFieldTypes[], D extends number = 5> = UnionToIntersection<ProcessField<T[number], D>>;
|
|
860
|
+
/** Helper to extract fields from either fields array or FormConfig */
|
|
861
|
+
type ExtractFields<T> = T extends {
|
|
862
|
+
fields: infer TFields;
|
|
863
|
+
} ? TFields extends readonly RegisteredFieldTypes[] ? TFields : never : T extends readonly RegisteredFieldTypes[] ? T : never;
|
|
864
|
+
/**
|
|
865
|
+
* Infer form value type from fields array or FormConfig.
|
|
866
|
+
* Recursively processes nested structures and merges the results.
|
|
867
|
+
* Limited to 5 levels of nesting to prevent infinite type instantiation.
|
|
868
|
+
*/
|
|
869
|
+
type InferFormValue<T> = ExtractFields<T> extends readonly RegisteredFieldTypes[] ? InferFormValueWithDepth<ExtractFields<T> extends RegisteredFieldTypes[] ? ExtractFields<T> : [...ExtractFields<T>], 5> : never;
|
|
870
|
+
/**
|
|
871
|
+
* Default `TModel` for `DynamicForm` / `FormStateManager` generics.
|
|
872
|
+
*
|
|
873
|
+
* Equals `InferFormValue<T>` for any concrete config (an object type). Falls back
|
|
874
|
+
* to `Record<string, unknown>` only when inference yields a non-record — e.g. an
|
|
875
|
+
* empty `fields` array, where `InferFormValue` is `unknown` — so the `TModel
|
|
876
|
+
* extends Record<string, unknown>` bound always holds by construction.
|
|
877
|
+
*
|
|
878
|
+
* Crucially, unlike the older `InferFormValue<T> & Record<string, unknown>`
|
|
879
|
+
* default, this does NOT graft an index signature onto the model. That matters at
|
|
880
|
+
* the consumer call site: the index signature made `value['anyTypo']` resolve to
|
|
881
|
+
* `unknown` instead of erroring, silently defeating the typo-safety the inference
|
|
882
|
+
* is meant to provide.
|
|
883
|
+
*/
|
|
884
|
+
type InferFormModel<T, M = InferFormValue<T>> = M extends Record<string, unknown> ? M : Record<string, unknown>;
|
|
614
885
|
|
|
615
886
|
/**
|
|
616
887
|
* Custom validator function signature using Angular's public FieldContext API
|
|
@@ -797,629 +1068,753 @@ type ValidatorConfig = BuiltInValidatorConfig | CustomValidatorConfig | AsyncVal
|
|
|
797
1068
|
/** Type guard to distinguish function-based HTTP validators from declarative ones. */
|
|
798
1069
|
declare function isFunctionHttpValidator(config: FunctionHttpValidatorConfig | DeclarativeHttpValidatorConfig): config is FunctionHttpValidatorConfig;
|
|
799
1070
|
|
|
800
|
-
/**
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
}
|
|
811
|
-
/** Reusable schema definition that can be referenced by name */
|
|
812
|
-
interface SchemaDefinition {
|
|
813
|
-
/** Unique schema identifier */
|
|
814
|
-
name: string;
|
|
815
|
-
/** Schema description */
|
|
816
|
-
description?: string;
|
|
817
|
-
/** Field path pattern this schema applies to */
|
|
818
|
-
pathPattern?: string;
|
|
819
|
-
/** Validators to apply */
|
|
820
|
-
validators?: ValidatorConfig[];
|
|
821
|
-
/** Logic rules to apply */
|
|
822
|
-
logic?: LogicConfig[];
|
|
823
|
-
/** Nested schema applications */
|
|
824
|
-
subSchemas?: SchemaApplicationConfig[];
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
/** Context for cross-field detection, providing access to function scope information. */
|
|
828
|
-
interface CrossFieldDetectionContext {
|
|
829
|
-
/**
|
|
830
|
-
* Lookup function to get the scope of a registered custom function.
|
|
831
|
-
*
|
|
832
|
-
* @param functionName The name of the custom function
|
|
833
|
-
* @returns The function's scope, or undefined if not registered
|
|
834
|
-
*/
|
|
835
|
-
getFunctionScope?: (functionName: string) => CustomFunctionScope | undefined;
|
|
836
|
-
}
|
|
1071
|
+
/** Special form-state conditions for button disabled logic. */
|
|
1072
|
+
type FormStateCondition =
|
|
1073
|
+
/** True when form.valid() === false */
|
|
1074
|
+
'formInvalid'
|
|
1075
|
+
/** True when form.submitting() === true */
|
|
1076
|
+
| 'formSubmitting'
|
|
1077
|
+
/** True when fields on the current page are invalid (for paged forms) */
|
|
1078
|
+
| 'pageInvalid';
|
|
1079
|
+
/** Logic type for controlling field state (hidden, readonly, disabled, required). */
|
|
1080
|
+
type StateLogicType = 'hidden' | 'readonly' | 'disabled' | 'required';
|
|
837
1081
|
/**
|
|
838
|
-
*
|
|
1082
|
+
* Base configuration for conditional field state logic.
|
|
839
1083
|
*
|
|
840
|
-
* @
|
|
841
|
-
* @param context Optional context providing function scope lookup
|
|
842
|
-
* @returns true if the expression references other fields
|
|
1084
|
+
* @internal
|
|
843
1085
|
*/
|
|
844
|
-
|
|
1086
|
+
interface BaseStateLogicConfig {
|
|
1087
|
+
/** Logic type identifier for field state. */
|
|
1088
|
+
type: StateLogicType;
|
|
1089
|
+
/** Condition that determines when this logic applies. */
|
|
1090
|
+
condition: ConditionalExpression | boolean | FormStateCondition;
|
|
1091
|
+
}
|
|
845
1092
|
/**
|
|
846
|
-
*
|
|
1093
|
+
* State logic that evaluates immediately on change (default).
|
|
847
1094
|
*
|
|
848
|
-
* @
|
|
849
|
-
* @returns Array of field keys that this expression depends on
|
|
850
|
-
*/
|
|
851
|
-
declare function extractExpressionDependencies(expr: ConditionalExpression | boolean | undefined): string[];
|
|
852
|
-
/**
|
|
853
|
-
* Extracts field names from a JavaScript expression string.
|
|
854
|
-
* Handles both dot notation (formValue.field) and bracket notation (formValue['field']).
|
|
1095
|
+
* @internal
|
|
855
1096
|
*/
|
|
856
|
-
|
|
1097
|
+
interface ImmediateStateLogicConfig extends BaseStateLogicConfig {
|
|
1098
|
+
/**
|
|
1099
|
+
* Trigger for immediate evaluation.
|
|
1100
|
+
*
|
|
1101
|
+
* @default 'onChange'
|
|
1102
|
+
*/
|
|
1103
|
+
trigger?: 'onChange';
|
|
1104
|
+
/** Not allowed for onChange trigger */
|
|
1105
|
+
debounceMs?: never;
|
|
1106
|
+
}
|
|
857
1107
|
/**
|
|
858
|
-
*
|
|
1108
|
+
* State logic that evaluates after a debounce period.
|
|
859
1109
|
*
|
|
860
|
-
* @
|
|
861
|
-
* @returns true if the validator references formValue
|
|
1110
|
+
* @internal
|
|
862
1111
|
*/
|
|
863
|
-
|
|
1112
|
+
interface DebouncedStateLogicConfig extends BaseStateLogicConfig {
|
|
1113
|
+
/**
|
|
1114
|
+
* Trigger for debounced evaluation.
|
|
1115
|
+
* Evaluates after the value has stabilized for the debounce duration.
|
|
1116
|
+
*/
|
|
1117
|
+
trigger: 'debounced';
|
|
1118
|
+
/**
|
|
1119
|
+
* Debounce duration in milliseconds.
|
|
1120
|
+
*
|
|
1121
|
+
* @default 500
|
|
1122
|
+
*/
|
|
1123
|
+
debounceMs?: number;
|
|
1124
|
+
}
|
|
1125
|
+
/** Configuration for conditional field state logic. */
|
|
1126
|
+
type StateLogicConfig = ImmediateStateLogicConfig | DebouncedStateLogicConfig;
|
|
1127
|
+
/** Trigger timing for when logic is evaluated. */
|
|
1128
|
+
type LogicTrigger = 'onChange' | 'debounced';
|
|
864
1129
|
/**
|
|
865
|
-
*
|
|
1130
|
+
* Shared fields that appear on all derivation logic config variants.
|
|
866
1131
|
*
|
|
867
|
-
* @
|
|
868
|
-
* @returns true if the validator has a cross-field dynamic expression
|
|
1132
|
+
* @internal
|
|
869
1133
|
*/
|
|
870
|
-
|
|
871
|
-
/**
|
|
872
|
-
|
|
1134
|
+
interface SharedDerivationFields {
|
|
1135
|
+
/** Logic type identifier for value derivation. */
|
|
1136
|
+
type: 'derivation';
|
|
1137
|
+
/** Target property name for property derivation. */
|
|
1138
|
+
targetProperty?: string;
|
|
1139
|
+
/** Optional name for this derivation for debugging purposes. */
|
|
1140
|
+
debugName?: string;
|
|
1141
|
+
/** Condition that determines when this derivation applies. */
|
|
1142
|
+
condition?: ConditionalExpression | boolean;
|
|
1143
|
+
/**
|
|
1144
|
+
* When true, the derivation stops running after the user manually
|
|
1145
|
+
* edits the target field.
|
|
1146
|
+
*/
|
|
1147
|
+
stopOnUserOverride?: boolean;
|
|
1148
|
+
/**
|
|
1149
|
+
* When true (and `stopOnUserOverride` is also true), clears the
|
|
1150
|
+
* user-override flag when any dependency of this derivation changes,
|
|
1151
|
+
* allowing the derivation to run again.
|
|
1152
|
+
*/
|
|
1153
|
+
reEngageOnDependencyChange?: boolean;
|
|
1154
|
+
}
|
|
873
1155
|
/**
|
|
874
|
-
*
|
|
1156
|
+
* Trigger variants for derivation timing.
|
|
875
1157
|
*
|
|
876
|
-
* @
|
|
877
|
-
* @param context Optional context providing function scope lookup
|
|
878
|
-
* @returns true if the when condition references other fields
|
|
1158
|
+
* @internal
|
|
879
1159
|
*/
|
|
880
|
-
|
|
1160
|
+
type ImmediateDerivationTrigger = {
|
|
1161
|
+
trigger?: 'onChange';
|
|
1162
|
+
debounceMs?: never;
|
|
1163
|
+
};
|
|
1164
|
+
type DebouncedDerivationTrigger = {
|
|
1165
|
+
trigger: 'debounced';
|
|
1166
|
+
debounceMs?: number;
|
|
1167
|
+
};
|
|
881
1168
|
/**
|
|
882
|
-
*
|
|
1169
|
+
* Base for HTTP derivations. `source: 'http'` is required.
|
|
1170
|
+
* TypeScript enforces `dependsOn` and `responseExpression` at the type level.
|
|
883
1171
|
*
|
|
884
|
-
* @
|
|
885
|
-
* @param context Optional context providing function scope lookup
|
|
886
|
-
* @returns true if the logic condition references other fields
|
|
1172
|
+
* @internal
|
|
887
1173
|
*/
|
|
888
|
-
|
|
1174
|
+
interface HttpDerivationBase extends SharedDerivationFields {
|
|
1175
|
+
/** Identifies this derivation as HTTP-driven. */
|
|
1176
|
+
source: 'http';
|
|
1177
|
+
/** Forbidden on HTTP source */
|
|
1178
|
+
fn?: never;
|
|
1179
|
+
/** Forbidden on HTTP source */
|
|
1180
|
+
asyncFn?: never;
|
|
1181
|
+
/** HTTP request configuration for server-driven derivations. */
|
|
1182
|
+
http: HttpRequestConfig;
|
|
1183
|
+
/**
|
|
1184
|
+
* Explicit field dependencies. Required for HTTP derivations to prevent
|
|
1185
|
+
* wildcard triggering on every keystroke.
|
|
1186
|
+
*/
|
|
1187
|
+
dependsOn: string[];
|
|
1188
|
+
/** Expression to extract the derived value from the HTTP response. */
|
|
1189
|
+
responseExpression: string;
|
|
1190
|
+
value?: never;
|
|
1191
|
+
expression?: never;
|
|
1192
|
+
functionName?: never;
|
|
1193
|
+
asyncFunctionName?: never;
|
|
1194
|
+
}
|
|
889
1195
|
/**
|
|
890
|
-
*
|
|
1196
|
+
* Shared fields for both branches of {@link AsyncFunctionDerivationBase}.
|
|
891
1197
|
*
|
|
892
|
-
* @
|
|
893
|
-
* @param context Optional context providing function scope lookup
|
|
894
|
-
* @returns true if the schema condition references other fields
|
|
1198
|
+
* @internal
|
|
895
1199
|
*/
|
|
896
|
-
|
|
897
|
-
|
|
1200
|
+
interface AsyncFunctionDerivationShared extends SharedDerivationFields {
|
|
1201
|
+
/** Identifies this derivation as async-function-driven. */
|
|
1202
|
+
source: 'asyncFunction';
|
|
1203
|
+
/** Forbidden on asyncFunction source */
|
|
1204
|
+
fn?: never;
|
|
1205
|
+
/**
|
|
1206
|
+
* Explicit field dependencies. Required for async derivations to prevent
|
|
1207
|
+
* wildcard triggering on every form change.
|
|
1208
|
+
*/
|
|
1209
|
+
dependsOn: string[];
|
|
1210
|
+
value?: never;
|
|
1211
|
+
expression?: never;
|
|
1212
|
+
functionName?: never;
|
|
1213
|
+
http?: never;
|
|
1214
|
+
responseExpression?: never;
|
|
1215
|
+
}
|
|
898
1216
|
/**
|
|
899
|
-
*
|
|
1217
|
+
* Base for async function derivations. `source: 'asyncFunction'` is required.
|
|
1218
|
+
* TypeScript enforces `dependsOn` at the type level, and `asyncFunctionName` /
|
|
1219
|
+
* `asyncFn` are mutually exclusive (XOR).
|
|
900
1220
|
*
|
|
901
|
-
* @param fieldSource - A FieldTree or direct FieldState instance
|
|
902
|
-
* @param reactive - If true, reads signals reactively (creates dependencies).
|
|
903
|
-
* If false, reads signals with `untracked()` (no dependencies).
|
|
904
|
-
* @returns A FieldStateInfo proxy with lazy property access, or undefined if the source is invalid
|
|
905
1221
|
* @internal
|
|
906
1222
|
*/
|
|
907
|
-
|
|
1223
|
+
type AsyncFunctionDerivationBase = (AsyncFunctionDerivationShared & {
|
|
1224
|
+
/** Name of a registered async derivation function. */
|
|
1225
|
+
asyncFunctionName: string;
|
|
1226
|
+
/** Inline form is forbidden when `asyncFunctionName` is set */
|
|
1227
|
+
asyncFn?: never;
|
|
1228
|
+
}) | (AsyncFunctionDerivationShared & {
|
|
1229
|
+
/** Inline async derivation function. Mutually exclusive with `asyncFunctionName`. */
|
|
1230
|
+
asyncFn: AsyncDerivationFunction;
|
|
1231
|
+
/** Registered form is forbidden when `asyncFn` is set */
|
|
1232
|
+
asyncFunctionName?: never;
|
|
1233
|
+
});
|
|
908
1234
|
/**
|
|
909
|
-
*
|
|
1235
|
+
* Base for expression derivations.
|
|
910
1236
|
*
|
|
911
|
-
* @param rootForm - The root FieldTree of the form
|
|
912
|
-
* @param reactive - If true, reads signals reactively (creates dependencies).
|
|
913
|
-
* If false, reads signals with `untracked()` (no dependencies).
|
|
914
|
-
* @returns A FormFieldStateMap proxy
|
|
915
1237
|
* @internal
|
|
916
1238
|
*/
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
/**
|
|
920
|
-
|
|
921
|
-
/**
|
|
922
|
-
|
|
1239
|
+
interface ExpressionDerivationBase extends SharedDerivationFields {
|
|
1240
|
+
source?: never;
|
|
1241
|
+
/** Forbidden on expression mode */
|
|
1242
|
+
fn?: never;
|
|
1243
|
+
/** Forbidden on expression mode */
|
|
1244
|
+
asyncFn?: never;
|
|
1245
|
+
/** JavaScript expression to evaluate for the derived value. */
|
|
1246
|
+
expression: string;
|
|
1247
|
+
/** Explicit field dependencies for expressions. */
|
|
1248
|
+
dependsOn?: string[];
|
|
1249
|
+
value?: never;
|
|
1250
|
+
functionName?: never;
|
|
1251
|
+
http?: never;
|
|
1252
|
+
asyncFunctionName?: never;
|
|
1253
|
+
responseExpression?: never;
|
|
923
1254
|
}
|
|
924
|
-
|
|
925
|
-
/** Creates a logic function for an async condition. */
|
|
926
|
-
declare function createAsyncConditionLogicFunction<TValue>(condition: AsyncCondition): LogicFn<TValue, boolean>;
|
|
927
|
-
|
|
928
1255
|
/**
|
|
929
|
-
*
|
|
930
|
-
*
|
|
1256
|
+
* Base for value derivations.
|
|
1257
|
+
*
|
|
1258
|
+
* @internal
|
|
931
1259
|
*/
|
|
932
|
-
|
|
933
|
-
|
|
1260
|
+
interface ValueDerivationBase extends SharedDerivationFields {
|
|
1261
|
+
source?: never;
|
|
1262
|
+
/** Forbidden on value mode */
|
|
1263
|
+
fn?: never;
|
|
1264
|
+
/** Forbidden on value mode */
|
|
1265
|
+
asyncFn?: never;
|
|
1266
|
+
/** Static value to set on this field. */
|
|
1267
|
+
value: unknown;
|
|
1268
|
+
/** Explicit field dependencies for value derivations. */
|
|
1269
|
+
dependsOn?: string[];
|
|
1270
|
+
expression?: never;
|
|
1271
|
+
functionName?: never;
|
|
1272
|
+
http?: never;
|
|
1273
|
+
asyncFunctionName?: never;
|
|
1274
|
+
responseExpression?: never;
|
|
1275
|
+
}
|
|
934
1276
|
/**
|
|
935
|
-
*
|
|
1277
|
+
* Shared fields for both branches of {@link FunctionDerivationBase}.
|
|
936
1278
|
*
|
|
937
1279
|
* @internal
|
|
938
1280
|
*/
|
|
939
|
-
interface
|
|
940
|
-
|
|
941
|
-
|
|
1281
|
+
interface FunctionDerivationShared extends SharedDerivationFields {
|
|
1282
|
+
source?: never;
|
|
1283
|
+
/** Forbidden on function-derivation mode */
|
|
1284
|
+
asyncFn?: never;
|
|
1285
|
+
/** Explicit field dependencies for function derivations. */
|
|
1286
|
+
dependsOn?: string[];
|
|
1287
|
+
value?: never;
|
|
1288
|
+
expression?: never;
|
|
1289
|
+
http?: never;
|
|
1290
|
+
asyncFunctionName?: never;
|
|
1291
|
+
responseExpression?: never;
|
|
942
1292
|
}
|
|
943
1293
|
/**
|
|
944
|
-
*
|
|
1294
|
+
* Base for custom sync function derivations. `functionName` and `fn` are
|
|
1295
|
+
* mutually exclusive (XOR).
|
|
945
1296
|
*
|
|
946
1297
|
* @internal
|
|
947
1298
|
*/
|
|
948
|
-
|
|
949
|
-
/**
|
|
950
|
-
|
|
951
|
-
/**
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
/**
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
/**
|
|
960
|
-
* Called per LogicFn invocation. Returns one of:
|
|
961
|
-
* - `{ kind: 'trigger', key, payload }` — set the trigger to this and
|
|
962
|
-
* return the (potentially still-loading) resource value.
|
|
963
|
-
* - `{ kind: 'returnEarly', value }` — bypass the resource and return
|
|
964
|
-
* this value directly (used by HTTP for response-cache hits — the
|
|
965
|
-
* cached value is authoritative and overrides any sticky resource value).
|
|
966
|
-
* - `{ kind: 'holdPrevious' }` — bypass the resource update but return
|
|
967
|
-
* the resource's current sticky value (its last resolved value via
|
|
968
|
-
* `withPreviousValue`, or `pendingValue` if it never resolved). Used
|
|
969
|
-
* by HTTP when the request template is temporarily unresolvable so
|
|
970
|
-
* the UI doesn't flicker back to `pendingValue`.
|
|
971
|
-
*/
|
|
972
|
-
resolve: (ctx: FieldContext<TValue>) => {
|
|
973
|
-
kind: 'trigger';
|
|
974
|
-
key: string;
|
|
975
|
-
payload: TPayload;
|
|
976
|
-
} | {
|
|
977
|
-
kind: 'returnEarly';
|
|
978
|
-
value: TResult;
|
|
979
|
-
} | {
|
|
980
|
-
kind: 'holdPrevious';
|
|
981
|
-
};
|
|
982
|
-
}
|
|
1299
|
+
type FunctionDerivationBase = (FunctionDerivationShared & {
|
|
1300
|
+
/** Name of a registered custom derivation function. */
|
|
1301
|
+
functionName: string;
|
|
1302
|
+
/** Inline form is forbidden when `functionName` is set */
|
|
1303
|
+
fn?: never;
|
|
1304
|
+
}) | (FunctionDerivationShared & {
|
|
1305
|
+
/** Inline custom derivation function. Mutually exclusive with `functionName`. */
|
|
1306
|
+
fn: CustomFunction;
|
|
1307
|
+
/** Registered form is forbidden when `fn` is set */
|
|
1308
|
+
functionName?: never;
|
|
1309
|
+
});
|
|
983
1310
|
/**
|
|
984
|
-
*
|
|
1311
|
+
* HTTP derivation that evaluates immediately on change (default).
|
|
985
1312
|
*
|
|
986
1313
|
* @internal
|
|
987
1314
|
*/
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
/** DI-scoped cache for HTTP condition logic functions. */
|
|
991
|
-
declare class HttpConditionFunctionCacheService {
|
|
992
|
-
/** Cache for HTTP condition logic functions, keyed by serialized condition. */
|
|
993
|
-
readonly httpConditionFunctionCache: Map<string, LogicFn<unknown, boolean>>;
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
/** Creates a logic function for an HTTP condition. */
|
|
997
|
-
declare function createHttpConditionLogicFunction<TValue>(condition: HttpCondition): LogicFn<TValue, boolean>;
|
|
998
|
-
|
|
1315
|
+
type OnChangeHttpDerivationLogicConfig = HttpDerivationBase & ImmediateDerivationTrigger;
|
|
999
1316
|
/**
|
|
1000
|
-
*
|
|
1317
|
+
* HTTP derivation that evaluates after a debounce period.
|
|
1001
1318
|
*
|
|
1002
|
-
* @
|
|
1003
|
-
* @returns A LogicFn that evaluates the condition in the context of a field
|
|
1319
|
+
* @internal
|
|
1004
1320
|
*/
|
|
1005
|
-
|
|
1321
|
+
type DebouncedHttpDerivationLogicConfig = HttpDerivationBase & DebouncedDerivationTrigger;
|
|
1006
1322
|
/**
|
|
1007
|
-
*
|
|
1323
|
+
* Async function derivation that evaluates immediately on change (default).
|
|
1008
1324
|
*
|
|
1009
|
-
* @
|
|
1010
|
-
* @param debounceMs The debounce duration in milliseconds
|
|
1011
|
-
* @returns A LogicFn that evaluates the condition with debouncing
|
|
1325
|
+
* @internal
|
|
1012
1326
|
*/
|
|
1013
|
-
|
|
1014
|
-
|
|
1327
|
+
type OnChangeAsyncFunctionDerivationLogicConfig = AsyncFunctionDerivationBase & ImmediateDerivationTrigger;
|
|
1015
1328
|
/**
|
|
1016
|
-
*
|
|
1329
|
+
* Async function derivation that evaluates after a debounce period.
|
|
1017
1330
|
*
|
|
1018
|
-
* @
|
|
1019
|
-
* @param expected - The value to compare against
|
|
1020
|
-
* @param operator - Comparison operator to use
|
|
1021
|
-
* @returns True if the comparison succeeds, false otherwise
|
|
1331
|
+
* @internal
|
|
1022
1332
|
*/
|
|
1023
|
-
|
|
1333
|
+
type DebouncedAsyncFunctionDerivationLogicConfig = AsyncFunctionDerivationBase & DebouncedDerivationTrigger;
|
|
1024
1334
|
/**
|
|
1025
|
-
*
|
|
1335
|
+
* Expression derivation that evaluates immediately on change (default).
|
|
1026
1336
|
*
|
|
1027
|
-
* @
|
|
1028
|
-
* @param path - Dot-separated path to the desired property
|
|
1029
|
-
* @returns The value at the specified path, or undefined if not found
|
|
1337
|
+
* @internal
|
|
1030
1338
|
*/
|
|
1031
|
-
|
|
1339
|
+
type OnChangeExpressionDerivationLogicConfig = ExpressionDerivationBase & ImmediateDerivationTrigger;
|
|
1032
1340
|
/**
|
|
1033
|
-
*
|
|
1341
|
+
* Expression derivation that evaluates after a debounce period.
|
|
1034
1342
|
*
|
|
1035
|
-
* @
|
|
1036
|
-
* @param path - Dot-separated path to the property
|
|
1037
|
-
* @returns True if the property exists (even if its value is undefined)
|
|
1343
|
+
* @internal
|
|
1038
1344
|
*/
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
/**
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1345
|
+
type DebouncedExpressionDerivationLogicConfig = ExpressionDerivationBase & DebouncedDerivationTrigger;
|
|
1346
|
+
/**
|
|
1347
|
+
* Value derivation that evaluates immediately on change (default).
|
|
1348
|
+
*
|
|
1349
|
+
* @internal
|
|
1350
|
+
*/
|
|
1351
|
+
type OnChangeValueDerivationLogicConfig = ValueDerivationBase & ImmediateDerivationTrigger;
|
|
1352
|
+
/**
|
|
1353
|
+
* Value derivation that evaluates after a debounce period.
|
|
1354
|
+
*
|
|
1355
|
+
* @internal
|
|
1356
|
+
*/
|
|
1357
|
+
type DebouncedValueDerivationLogicConfig = ValueDerivationBase & DebouncedDerivationTrigger;
|
|
1358
|
+
/**
|
|
1359
|
+
* Function derivation that evaluates immediately on change (default).
|
|
1360
|
+
*
|
|
1361
|
+
* @internal
|
|
1362
|
+
*/
|
|
1363
|
+
type OnChangeFunctionDerivationLogicConfig = FunctionDerivationBase & ImmediateDerivationTrigger;
|
|
1364
|
+
/**
|
|
1365
|
+
* Function derivation that evaluates after a debounce period.
|
|
1366
|
+
*
|
|
1367
|
+
* @internal
|
|
1368
|
+
*/
|
|
1369
|
+
type DebouncedFunctionDerivationLogicConfig = FunctionDerivationBase & DebouncedDerivationTrigger;
|
|
1370
|
+
/** Configuration for value derivation logic. */
|
|
1371
|
+
type DerivationLogicConfig = OnChangeHttpDerivationLogicConfig | DebouncedHttpDerivationLogicConfig | OnChangeAsyncFunctionDerivationLogicConfig | DebouncedAsyncFunctionDerivationLogicConfig | OnChangeExpressionDerivationLogicConfig | DebouncedExpressionDerivationLogicConfig | OnChangeValueDerivationLogicConfig | DebouncedValueDerivationLogicConfig | OnChangeFunctionDerivationLogicConfig | DebouncedFunctionDerivationLogicConfig;
|
|
1372
|
+
/** Union type for all logic configurations. */
|
|
1373
|
+
type LogicConfig = StateLogicConfig | DerivationLogicConfig;
|
|
1374
|
+
/** Log level for derivation debug output. */
|
|
1375
|
+
type DerivationLogLevel = 'none' | 'summary' | 'verbose';
|
|
1376
|
+
/** Configuration for derivation debug logging. */
|
|
1377
|
+
interface DerivationLogConfig {
|
|
1378
|
+
/** Log level for derivation debugging. Defaults to 'none'. */
|
|
1379
|
+
level: DerivationLogLevel;
|
|
1060
1380
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
interface
|
|
1108
|
-
type
|
|
1109
|
-
|
|
1381
|
+
/**
|
|
1382
|
+
* Creates the default derivation log configuration.
|
|
1383
|
+
*
|
|
1384
|
+
* @returns Default DerivationLogConfig
|
|
1385
|
+
*/
|
|
1386
|
+
declare function createDefaultDerivationLogConfig(): DerivationLogConfig;
|
|
1387
|
+
/**
|
|
1388
|
+
* Checks if logging should occur at the specified level.
|
|
1389
|
+
*
|
|
1390
|
+
* @param config - Current log configuration
|
|
1391
|
+
* @param minLevel - Minimum level required for logging
|
|
1392
|
+
* @returns True if logging should occur
|
|
1393
|
+
*/
|
|
1394
|
+
declare function shouldLog(config: DerivationLogConfig, minLevel: 'summary' | 'verbose'): boolean;
|
|
1395
|
+
/**
|
|
1396
|
+
* Type guard to check if a condition is a FormStateCondition.
|
|
1397
|
+
*
|
|
1398
|
+
* @param condition - The condition to check
|
|
1399
|
+
* @returns true if the condition is a FormStateCondition
|
|
1400
|
+
*/
|
|
1401
|
+
declare function isFormStateCondition(condition: StateLogicConfig['condition'] | DerivationLogicConfig['condition']): condition is FormStateCondition;
|
|
1402
|
+
/**
|
|
1403
|
+
* Type guard to check if a logic config is a StateLogicConfig.
|
|
1404
|
+
*
|
|
1405
|
+
* @param config - The logic config to check
|
|
1406
|
+
* @returns true if the config is for field state logic
|
|
1407
|
+
*/
|
|
1408
|
+
declare function isStateLogicConfig(config: LogicConfig): config is StateLogicConfig;
|
|
1409
|
+
/**
|
|
1410
|
+
* Type guard to check if a logic config is a DerivationLogicConfig.
|
|
1411
|
+
*
|
|
1412
|
+
* @param config - The logic config to check
|
|
1413
|
+
* @returns true if the config is for value derivation
|
|
1414
|
+
*/
|
|
1415
|
+
declare function isDerivationLogicConfig(config: LogicConfig): config is DerivationLogicConfig;
|
|
1416
|
+
/**
|
|
1417
|
+
* Type guard to check if a derivation config targets a property rather than the field value.
|
|
1418
|
+
*
|
|
1419
|
+
* @param config - The derivation logic config to check
|
|
1420
|
+
* @returns true if the config has a targetProperty (property derivation)
|
|
1421
|
+
*/
|
|
1422
|
+
declare function hasTargetProperty(config: DerivationLogicConfig): config is DerivationLogicConfig & {
|
|
1423
|
+
targetProperty: string;
|
|
1424
|
+
};
|
|
1425
|
+
|
|
1426
|
+
/** Configuration for applying predefined schemas */
|
|
1427
|
+
interface SchemaApplicationConfig {
|
|
1428
|
+
/** Schema application type */
|
|
1429
|
+
type: 'apply' | 'applyWhen' | 'applyWhenValue' | 'applyEach';
|
|
1430
|
+
/** Schema identifier or inline schema definition */
|
|
1431
|
+
schema: string | SchemaDefinition;
|
|
1432
|
+
/** Condition for conditional application */
|
|
1433
|
+
condition?: ConditionalExpression;
|
|
1434
|
+
/** Type predicate for applyWhenValue */
|
|
1435
|
+
typePredicate?: string;
|
|
1110
1436
|
}
|
|
1111
|
-
|
|
1112
|
-
|
|
1437
|
+
/** Reusable schema definition that can be referenced by name */
|
|
1438
|
+
interface SchemaDefinition {
|
|
1439
|
+
/** Unique schema identifier */
|
|
1113
1440
|
name: string;
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
object: ASTNode;
|
|
1125
|
-
/** Expression evaluated at runtime to produce the property key. */
|
|
1126
|
-
property: ASTNode;
|
|
1127
|
-
/** True when this access used `?.[ ... ]` (optional chaining). */
|
|
1128
|
-
optional?: boolean;
|
|
1129
|
-
}
|
|
1130
|
-
interface ConditionalNode {
|
|
1131
|
-
type: 'Conditional';
|
|
1132
|
-
test: ASTNode;
|
|
1133
|
-
consequent: ASTNode;
|
|
1134
|
-
alternate: ASTNode;
|
|
1135
|
-
}
|
|
1136
|
-
interface BinaryOpNode {
|
|
1137
|
-
type: 'BinaryOp';
|
|
1138
|
-
operator: string;
|
|
1139
|
-
left: ASTNode;
|
|
1140
|
-
right: ASTNode;
|
|
1141
|
-
}
|
|
1142
|
-
interface UnaryOpNode {
|
|
1143
|
-
type: 'UnaryOp';
|
|
1144
|
-
operator: string;
|
|
1145
|
-
operand: ASTNode;
|
|
1146
|
-
}
|
|
1147
|
-
interface CallExpressionNode {
|
|
1148
|
-
type: 'CallExpression';
|
|
1149
|
-
callee: ASTNode;
|
|
1150
|
-
arguments: ASTNode[];
|
|
1151
|
-
/** True when this call used `?.( ... )` (optional chaining). */
|
|
1152
|
-
optional?: boolean;
|
|
1153
|
-
}
|
|
1154
|
-
interface ArrayLiteralNode {
|
|
1155
|
-
type: 'ArrayLiteral';
|
|
1156
|
-
elements: ASTNode[];
|
|
1157
|
-
}
|
|
1158
|
-
interface ObjectLiteralNode {
|
|
1159
|
-
type: 'ObjectLiteral';
|
|
1160
|
-
properties: Array<{
|
|
1161
|
-
key: string;
|
|
1162
|
-
value: ASTNode;
|
|
1163
|
-
}>;
|
|
1164
|
-
}
|
|
1165
|
-
interface ArrowFunctionNode {
|
|
1166
|
-
type: 'ArrowFunction';
|
|
1167
|
-
params: string[];
|
|
1168
|
-
body: ASTNode;
|
|
1169
|
-
}
|
|
1170
|
-
/** Parser error with position information */
|
|
1171
|
-
declare class ExpressionParserError extends DynamicFormError {
|
|
1172
|
-
position: number;
|
|
1173
|
-
expression: string;
|
|
1174
|
-
constructor(message: string, position: number, expression: string);
|
|
1441
|
+
/** Schema description */
|
|
1442
|
+
description?: string;
|
|
1443
|
+
/** Field path pattern this schema applies to */
|
|
1444
|
+
pathPattern?: string;
|
|
1445
|
+
/** Validators to apply */
|
|
1446
|
+
validators?: ValidatorConfig[];
|
|
1447
|
+
/** Logic rules to apply */
|
|
1448
|
+
logic?: LogicConfig[];
|
|
1449
|
+
/** Nested schema applications */
|
|
1450
|
+
subSchemas?: SchemaApplicationConfig[];
|
|
1175
1451
|
}
|
|
1176
1452
|
|
|
1177
|
-
/**
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
private evaluateBinaryOp;
|
|
1192
|
-
private evaluateUnaryOp;
|
|
1193
|
-
private evaluateCallExpression;
|
|
1194
|
-
private evaluateArrayLiteral;
|
|
1195
|
-
private evaluateObjectLiteral;
|
|
1196
|
-
private evaluateArrowFunction;
|
|
1197
|
-
private isMethodSafe;
|
|
1453
|
+
/**
|
|
1454
|
+
* Re-export Angular's ValidationError for consistency
|
|
1455
|
+
* This replaces our custom ValidationError interface
|
|
1456
|
+
*/
|
|
1457
|
+
type ValidationError = ValidationError$1;
|
|
1458
|
+
interface ValidationMessages {
|
|
1459
|
+
required?: DynamicText;
|
|
1460
|
+
email?: DynamicText;
|
|
1461
|
+
min?: DynamicText;
|
|
1462
|
+
max?: DynamicText;
|
|
1463
|
+
minLength?: DynamicText;
|
|
1464
|
+
maxLength?: DynamicText;
|
|
1465
|
+
pattern?: DynamicText;
|
|
1466
|
+
[key: string]: DynamicText | undefined;
|
|
1198
1467
|
}
|
|
1199
1468
|
|
|
1200
|
-
/**
|
|
1201
|
-
|
|
1469
|
+
/**
|
|
1470
|
+
* The result type for submission actions.
|
|
1471
|
+
* Can be either a Promise or an Observable.
|
|
1472
|
+
*/
|
|
1473
|
+
type SubmissionActionResult = Promise<TreeValidationResult> | Observable<TreeValidationResult | unknown>;
|
|
1474
|
+
/**
|
|
1475
|
+
* Configuration for form submission handling.
|
|
1476
|
+
*
|
|
1477
|
+
* @typeParam TValue - The form value type
|
|
1478
|
+
*/
|
|
1479
|
+
interface SubmissionConfig<TValue = unknown> {
|
|
1202
1480
|
/**
|
|
1203
|
-
*
|
|
1204
|
-
*
|
|
1481
|
+
* Action called when the form is submitted.
|
|
1482
|
+
*
|
|
1483
|
+
* @param form - The form's FieldTree instance
|
|
1484
|
+
* @returns Promise or Observable - for errors, return TreeValidationResult
|
|
1205
1485
|
*/
|
|
1206
|
-
|
|
1207
|
-
/** Evaluate an expression with a given scope */
|
|
1208
|
-
static evaluate(expression: string, scope: EvaluationScope): unknown;
|
|
1209
|
-
/** Clear the AST cache */
|
|
1210
|
-
static clearCache(): void;
|
|
1211
|
-
/** Get cache statistics */
|
|
1212
|
-
static getCacheStats(): {
|
|
1213
|
-
size: number;
|
|
1214
|
-
maxSize: number;
|
|
1215
|
-
};
|
|
1486
|
+
action: (form: FieldTree<TValue>) => SubmissionActionResult;
|
|
1216
1487
|
}
|
|
1217
1488
|
|
|
1218
1489
|
/**
|
|
1219
|
-
*
|
|
1220
|
-
*
|
|
1490
|
+
* Configuration interface for defining dynamic form structure and behavior.
|
|
1491
|
+
*
|
|
1492
|
+
* @typeParam TFields - Array of registered field types available for this form
|
|
1493
|
+
* @typeParam TValue - The strongly-typed interface for form values
|
|
1494
|
+
* @typeParam TProps - The type for form-level default props (library-specific)
|
|
1221
1495
|
*/
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
/** Parse the expression into an AST */
|
|
1228
|
-
parse(): ASTNode;
|
|
1229
|
-
private parseExpression;
|
|
1496
|
+
interface FormConfig<TFields extends NarrowFields | RegisteredFieldTypes[] = RegisteredFieldTypes[], TValue = InferFormValue<TFields extends readonly RegisteredFieldTypes[] ? TFields : RegisteredFieldTypes[]>, TProps extends object = Record<string, unknown>, TSchemaValue = unknown> {
|
|
1497
|
+
/** Array of field definitions that define the form structure. */
|
|
1498
|
+
fields: TFields;
|
|
1499
|
+
/** Optional form-level validation schema using Standard Schema spec. */
|
|
1500
|
+
schema?: FormSchema<TSchemaValue>;
|
|
1230
1501
|
/**
|
|
1231
|
-
*
|
|
1232
|
-
*
|
|
1502
|
+
* Global form configuration options.
|
|
1503
|
+
*
|
|
1504
|
+
* @value {}
|
|
1233
1505
|
*/
|
|
1234
|
-
|
|
1235
|
-
/**
|
|
1236
|
-
|
|
1237
|
-
|
|
1506
|
+
options?: FormOptions;
|
|
1507
|
+
/** Global schemas available to all fields. */
|
|
1508
|
+
schemas?: SchemaDefinition[];
|
|
1509
|
+
/** Form-level validation messages that act as fallback for field-level messages. */
|
|
1510
|
+
defaultValidationMessages?: ValidationMessages;
|
|
1511
|
+
/** Signal forms adapter configuration. */
|
|
1512
|
+
customFnConfig?: CustomFnConfig<TValue extends Record<string, unknown> ? TValue : Record<string, unknown>>;
|
|
1513
|
+
/** Form submission configuration. */
|
|
1514
|
+
submission?: SubmissionConfig<TValue>;
|
|
1515
|
+
/** Default props applied to all fields in the form. */
|
|
1516
|
+
defaultProps?: TProps;
|
|
1517
|
+
/** External data signals available to conditional logic and derivations. */
|
|
1518
|
+
externalData?: Record<string, Signal<unknown>>;
|
|
1519
|
+
/** Form-wide default wrappers applied to every field that does not explicitly opt out. */
|
|
1520
|
+
defaultWrappers?: readonly WrapperConfig[];
|
|
1521
|
+
}
|
|
1522
|
+
/** Signal forms adapter configuration for advanced form behavior. */
|
|
1523
|
+
interface CustomFnConfig<TFormValue extends Record<string, unknown> = Record<string, unknown>> {
|
|
1524
|
+
/** Custom evaluation functions for conditional expressions. */
|
|
1525
|
+
customFunctions?: Record<string, CustomFunction<TFormValue>>;
|
|
1526
|
+
/** Custom derivation functions for value derivation logic. */
|
|
1527
|
+
derivations?: Record<string, CustomFunction<TFormValue>>;
|
|
1528
|
+
/** Async derivation functions for asynchronous value derivation logic. */
|
|
1529
|
+
asyncDerivations?: Record<string, AsyncDerivationFunction<TFormValue>>;
|
|
1530
|
+
/** Async condition functions for asynchronous field state logic. */
|
|
1531
|
+
asyncConditions?: Record<string, AsyncConditionFunction<TFormValue>>;
|
|
1532
|
+
/** Custom validators using Angular's public FieldContext API */
|
|
1533
|
+
validators?: Record<string, CustomValidator>;
|
|
1534
|
+
/** Async custom validators using Angular's resource-based validateAsync() API */
|
|
1535
|
+
asyncValidators?: Record<string, AsyncCustomValidator>;
|
|
1536
|
+
/** HTTP validators using Angular's validateHttp() API. */
|
|
1537
|
+
httpValidators?: Record<string, HttpCustomValidator>;
|
|
1538
|
+
}
|
|
1539
|
+
/** Global form configuration options. */
|
|
1540
|
+
interface FormOptions {
|
|
1541
|
+
/**
|
|
1542
|
+
* Disable the entire form.
|
|
1543
|
+
*
|
|
1544
|
+
* @value false
|
|
1238
1545
|
*/
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1546
|
+
disabled?: boolean;
|
|
1547
|
+
/**
|
|
1548
|
+
* Prefix scoping every field's DOM `id` (and matching `for` / `data-testid` /
|
|
1549
|
+
* `aria-describedby`) to this form instance, as the outermost id segment:
|
|
1550
|
+
* `{idPrefix}_{group}_{key}_{index}`. Use it when rendering multiple forms
|
|
1551
|
+
* from the same config on one page so their ids don't collide.
|
|
1552
|
+
*
|
|
1553
|
+
* When omitted, a lone form stays unprefixed and a generated prefix (`df-1`,
|
|
1554
|
+
* `df-2`, …) is applied automatically once a second form is mounted. Characters
|
|
1555
|
+
* invalid in an id token (whitespace, punctuation) are replaced with `_`.
|
|
1556
|
+
*
|
|
1557
|
+
* @example
|
|
1558
|
+
* ```typescript
|
|
1559
|
+
* options: { idPrefix: 'billing' } // → id="billing_email-input"
|
|
1560
|
+
* ```
|
|
1561
|
+
*
|
|
1562
|
+
* @default undefined (auto-prefix only when multiple forms are mounted)
|
|
1563
|
+
*/
|
|
1564
|
+
idPrefix?: string;
|
|
1565
|
+
/**
|
|
1566
|
+
* Maximum number of iterations for derivation chain processing.
|
|
1567
|
+
*
|
|
1568
|
+
* @default 10
|
|
1569
|
+
*/
|
|
1570
|
+
maxDerivationIterations?: number;
|
|
1571
|
+
/** Default disabled behavior for submit buttons. */
|
|
1572
|
+
submitButton?: SubmitButtonOptions;
|
|
1573
|
+
/** Default disabled behavior for next page buttons. */
|
|
1574
|
+
nextButton?: NextButtonOptions;
|
|
1575
|
+
/**
|
|
1576
|
+
* Whether to exclude values of hidden fields from submission output.
|
|
1577
|
+
*
|
|
1578
|
+
* @default undefined (uses global setting)
|
|
1579
|
+
*/
|
|
1580
|
+
excludeValueIfHidden?: boolean;
|
|
1581
|
+
/**
|
|
1582
|
+
* Whether to exclude values of disabled fields from submission output.
|
|
1583
|
+
*
|
|
1584
|
+
* @default undefined (uses global setting)
|
|
1585
|
+
*/
|
|
1586
|
+
excludeValueIfDisabled?: boolean;
|
|
1587
|
+
/**
|
|
1588
|
+
* Whether to exclude values of readonly fields from submission output.
|
|
1589
|
+
*
|
|
1590
|
+
* @default undefined (uses global setting)
|
|
1591
|
+
*/
|
|
1592
|
+
excludeValueIfReadonly?: boolean;
|
|
1593
|
+
/**
|
|
1594
|
+
* Whether to run validation when a field is hidden.
|
|
1595
|
+
*
|
|
1596
|
+
* @default undefined (uses global setting, which defaults to `false`)
|
|
1597
|
+
*/
|
|
1598
|
+
validateWhenHidden?: boolean;
|
|
1599
|
+
/**
|
|
1600
|
+
* Whether to attach the current form value to all events dispatched through the EventBus.
|
|
1601
|
+
*
|
|
1602
|
+
* @default undefined (uses global setting)
|
|
1603
|
+
*/
|
|
1604
|
+
emitFormValueOnEvents?: boolean;
|
|
1260
1605
|
}
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1606
|
+
/** Options for controlling submit button disabled behavior. */
|
|
1607
|
+
interface SubmitButtonOptions {
|
|
1608
|
+
/**
|
|
1609
|
+
* Disable submit button when the form is invalid.
|
|
1610
|
+
*
|
|
1611
|
+
* @default true
|
|
1612
|
+
*/
|
|
1613
|
+
disableWhenInvalid?: boolean;
|
|
1614
|
+
/**
|
|
1615
|
+
* Disable submit button while the form is submitting.
|
|
1616
|
+
*
|
|
1617
|
+
* @default true
|
|
1618
|
+
*/
|
|
1619
|
+
disableWhileSubmitting?: boolean;
|
|
1620
|
+
}
|
|
1621
|
+
/** Options for controlling next page button disabled behavior. */
|
|
1622
|
+
interface NextButtonOptions {
|
|
1623
|
+
/**
|
|
1624
|
+
* Disable next button when the current page has invalid fields.
|
|
1625
|
+
*
|
|
1626
|
+
* @default true
|
|
1627
|
+
*/
|
|
1628
|
+
disableWhenPageInvalid?: boolean;
|
|
1629
|
+
/**
|
|
1630
|
+
* Disable next button while the form is submitting.
|
|
1631
|
+
*
|
|
1632
|
+
* @default true
|
|
1633
|
+
*/
|
|
1634
|
+
disableWhileSubmitting?: boolean;
|
|
1276
1635
|
}
|
|
1277
1636
|
|
|
1278
|
-
/**
|
|
1279
|
-
|
|
1637
|
+
/** Context for resolving button disabled state. */
|
|
1638
|
+
interface ButtonLogicContext {
|
|
1639
|
+
/** The form's FieldTree instance (supports both string and number keys for array indices) */
|
|
1640
|
+
form: FieldTree<unknown, string | number>;
|
|
1641
|
+
/** Form-level options */
|
|
1642
|
+
formOptions?: FormOptions;
|
|
1643
|
+
/** Field-level logic array (if provided) */
|
|
1644
|
+
fieldLogic?: LogicConfig[];
|
|
1645
|
+
/** Explicit disabled state from field definition */
|
|
1646
|
+
explicitlyDisabled?: boolean;
|
|
1647
|
+
/** Current page validity signal (for paged forms) */
|
|
1648
|
+
currentPageValid?: Signal<boolean>;
|
|
1649
|
+
/** Current form value for evaluating conditional expressions */
|
|
1650
|
+
formValue?: unknown;
|
|
1651
|
+
/** Optional logger for diagnostic output. Falls back to no-op logger if not provided. */
|
|
1652
|
+
logger?: Logger;
|
|
1653
|
+
}
|
|
1280
1654
|
/**
|
|
1281
|
-
*
|
|
1282
|
-
*
|
|
1655
|
+
* Allowed logic types for non-form-bound elements (buttons, text fields, etc.).
|
|
1656
|
+
* These elements only support hidden and disabled states - not readonly or required
|
|
1657
|
+
* since they don't participate in form validation.
|
|
1283
1658
|
*/
|
|
1284
|
-
type
|
|
1285
|
-
|
|
1659
|
+
type NonFieldLogicType = 'hidden' | 'disabled';
|
|
1660
|
+
/**
|
|
1661
|
+
* Logic config restricted to types valid for non-form-bound elements.
|
|
1662
|
+
* This is a subset of LogicConfig that only includes hidden and disabled types.
|
|
1663
|
+
*/
|
|
1664
|
+
type NonFieldLogicConfig = LogicConfig & {
|
|
1665
|
+
type: NonFieldLogicType;
|
|
1286
1666
|
};
|
|
1287
|
-
/**
|
|
1288
|
-
|
|
1289
|
-
/**
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1667
|
+
/** Context for resolving state (hidden/disabled) for non-form-bound elements. */
|
|
1668
|
+
interface NonFieldLogicContext {
|
|
1669
|
+
/** The form's FieldTree instance (supports both string and number keys for array indices) */
|
|
1670
|
+
form: FieldTree<unknown, string | number>;
|
|
1671
|
+
/**
|
|
1672
|
+
* Field-level logic array containing conditions.
|
|
1673
|
+
* Accepts full LogicConfig[] for compatibility, but only hidden and disabled types are processed.
|
|
1674
|
+
*/
|
|
1675
|
+
fieldLogic?: LogicConfig[];
|
|
1676
|
+
/** Explicit state from field definition (e.g., `hidden: true` or `disabled: true`) */
|
|
1677
|
+
explicitValue?: boolean;
|
|
1678
|
+
/** Current form value for evaluating conditional expressions */
|
|
1679
|
+
formValue?: unknown;
|
|
1680
|
+
/** Optional logger for diagnostic output. Falls back to no-op logger if not provided. */
|
|
1681
|
+
logger?: Logger;
|
|
1300
1682
|
}
|
|
1301
1683
|
/**
|
|
1302
|
-
*
|
|
1303
|
-
*
|
|
1304
|
-
*
|
|
1305
|
-
*
|
|
1684
|
+
* Resolves the disabled state for a submit button.
|
|
1685
|
+
*
|
|
1686
|
+
* @param ctx - The button logic context
|
|
1687
|
+
* @returns A computed signal that returns true when the button should be disabled
|
|
1306
1688
|
*/
|
|
1307
|
-
declare function
|
|
1689
|
+
declare function resolveSubmitButtonDisabled(ctx: ButtonLogicContext): Signal<boolean>;
|
|
1308
1690
|
/**
|
|
1309
|
-
*
|
|
1310
|
-
*
|
|
1311
|
-
*
|
|
1691
|
+
* Resolves the disabled state for a next page button.
|
|
1692
|
+
*
|
|
1693
|
+
* @param ctx - The button logic context
|
|
1694
|
+
* @returns A computed signal that returns true when the button should be disabled
|
|
1312
1695
|
*/
|
|
1313
|
-
declare function
|
|
1314
|
-
warn: (msg: string) => void;
|
|
1315
|
-
}): boolean;
|
|
1696
|
+
declare function resolveNextButtonDisabled(ctx: ButtonLogicContext): Signal<boolean>;
|
|
1316
1697
|
/**
|
|
1317
|
-
*
|
|
1318
|
-
* identity. A fresh WeakMap per root injector keeps renders isolated under SSR —
|
|
1319
|
-
* Angular creates a new root injector per request, so there's no shared state
|
|
1320
|
-
* between server renders (same pattern as `COMPONENT_CACHE`).
|
|
1698
|
+
* Evaluates the hidden state for non-form-bound elements synchronously.
|
|
1321
1699
|
*
|
|
1322
|
-
* @
|
|
1700
|
+
* @param ctx - The context containing form, logic array, and explicit hidden state
|
|
1701
|
+
* @returns true when the element should be hidden
|
|
1323
1702
|
*/
|
|
1324
|
-
declare
|
|
1703
|
+
declare function evaluateNonFieldHidden(ctx: NonFieldLogicContext): boolean;
|
|
1325
1704
|
/**
|
|
1326
|
-
*
|
|
1327
|
-
* stable reference for the lifetime of its form, so one `ReadonlyFieldTree`
|
|
1328
|
-
* view per tree is enough. Callers on hot paths (`pushInputs` on every mapper
|
|
1329
|
-
* emission) avoid re-allocating the nine-property view object.
|
|
1705
|
+
* Resolves the hidden state for non-form-bound elements as a reactive signal.
|
|
1330
1706
|
*
|
|
1331
|
-
* @
|
|
1707
|
+
* @param ctx - The context containing form, logic array, and explicit hidden state
|
|
1708
|
+
* @returns A computed signal that returns true when the element should be hidden
|
|
1332
1709
|
*/
|
|
1333
|
-
declare function
|
|
1334
|
-
|
|
1335
|
-
/** TTL cache for HTTP condition responses with max entries eviction. */
|
|
1336
|
-
declare class HttpConditionCache {
|
|
1337
|
-
private readonly cache;
|
|
1338
|
-
private readonly maxEntries;
|
|
1339
|
-
constructor(maxEntries?: number);
|
|
1340
|
-
get(key: string): boolean | undefined;
|
|
1341
|
-
set(key: string, value: boolean, ttlMs: number): void;
|
|
1342
|
-
clear(): void;
|
|
1343
|
-
}
|
|
1344
|
-
/** @internal */
|
|
1345
|
-
declare const HTTP_CONDITION_CACHE: InjectionToken<HttpConditionCache>;
|
|
1346
|
-
|
|
1710
|
+
declare function resolveNonFieldHidden(ctx: NonFieldLogicContext): Signal<boolean>;
|
|
1347
1711
|
/**
|
|
1348
|
-
*
|
|
1349
|
-
*
|
|
1712
|
+
* Evaluates the disabled state for non-form-bound elements synchronously.
|
|
1713
|
+
*
|
|
1714
|
+
* @param ctx - The context containing form, logic array, and explicit disabled state
|
|
1715
|
+
* @returns true when the element should be disabled
|
|
1350
1716
|
*/
|
|
1351
|
-
declare function
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1717
|
+
declare function evaluateNonFieldDisabled(ctx: NonFieldLogicContext): boolean;
|
|
1718
|
+
/**
|
|
1719
|
+
* Resolves the disabled state for non-form-bound elements as a reactive signal.
|
|
1720
|
+
*
|
|
1721
|
+
* @param ctx - The context containing form, logic array, and explicit disabled state
|
|
1722
|
+
* @returns A computed signal that returns true when the element should be disabled
|
|
1723
|
+
*/
|
|
1724
|
+
declare function resolveNonFieldDisabled(ctx: NonFieldLogicContext): Signal<boolean>;
|
|
1357
1725
|
|
|
1358
|
-
/**
|
|
1359
|
-
type
|
|
1726
|
+
/** Text element type for rendering different HTML text elements */
|
|
1727
|
+
type TextElementType = 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'span';
|
|
1728
|
+
/** Properties for text field configuration */
|
|
1729
|
+
type TextProps = {
|
|
1730
|
+
/** The HTML element type to render */
|
|
1731
|
+
elementType: TextElementType;
|
|
1732
|
+
};
|
|
1733
|
+
/** Text field definition for displaying translatable text content */
|
|
1734
|
+
interface TextField extends FieldDef<TextProps> {
|
|
1735
|
+
type: 'text';
|
|
1736
|
+
/**
|
|
1737
|
+
* Logic rules for conditional visibility.
|
|
1738
|
+
* Text fields only support 'hidden' logic type since they are display-only
|
|
1739
|
+
* and don't participate in form validation (no disabled/readonly/required).
|
|
1740
|
+
*/
|
|
1741
|
+
readonly logic?: NonFieldLogicConfig[];
|
|
1742
|
+
}
|
|
1360
1743
|
|
|
1361
|
-
/**
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1744
|
+
/** Configuration for the built-in 'css' wrapper type. */
|
|
1745
|
+
interface CssWrapper {
|
|
1746
|
+
readonly type: 'css';
|
|
1747
|
+
/** CSS classes to apply to the wrapper */
|
|
1748
|
+
readonly cssClasses?: DynamicText;
|
|
1365
1749
|
}
|
|
1366
|
-
/**
|
|
1367
|
-
* Union of every valid addon slot — universal slots plus any registered via
|
|
1368
|
-
* {@link DynamicFormAddonSlotRegistry} module augmentation.
|
|
1369
|
-
*/
|
|
1370
|
-
type AddonSlot = CommonAddonSlot | keyof DynamicFormAddonSlotRegistry;
|
|
1371
1750
|
|
|
1372
|
-
/**
|
|
1373
|
-
interface
|
|
1374
|
-
|
|
1375
|
-
readonly slot: TSlot;
|
|
1376
|
-
/** CSS class applied to the addon host element. */
|
|
1377
|
-
readonly className?: string;
|
|
1378
|
-
/** Reactive visibility — when `true`, the addon is removed from layout. */
|
|
1379
|
-
readonly hidden?: DynamicValue<boolean>;
|
|
1380
|
-
/** Reactive disabled state — primarily relevant for interactive kinds. */
|
|
1381
|
-
readonly disabled?: DynamicValue<boolean>;
|
|
1751
|
+
/** Configuration for the built-in 'row' wrapper type. */
|
|
1752
|
+
interface RowWrapper {
|
|
1753
|
+
readonly type: 'row';
|
|
1382
1754
|
}
|
|
1383
|
-
|
|
1384
|
-
interface
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1755
|
+
|
|
1756
|
+
/** Container fields registry - augment this interface to add custom container fields */
|
|
1757
|
+
interface FieldRegistryContainers {
|
|
1758
|
+
page: PageField;
|
|
1759
|
+
row: RowField;
|
|
1760
|
+
group: GroupField;
|
|
1761
|
+
array: ArrayField | SimplifiedArrayField;
|
|
1762
|
+
container: ContainerField;
|
|
1388
1763
|
}
|
|
1389
|
-
/**
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
readonly kind: 'text';
|
|
1394
|
-
readonly text: DynamicText;
|
|
1764
|
+
/** Leaf fields registry - augment this interface to add custom leaf fields */
|
|
1765
|
+
interface FieldRegistryLeaves {
|
|
1766
|
+
text: TextField;
|
|
1767
|
+
hidden: HiddenField;
|
|
1395
1768
|
}
|
|
1396
|
-
/**
|
|
1397
|
-
interface
|
|
1398
|
-
|
|
1399
|
-
|
|
1769
|
+
/** Wrapper type registry for module augmentation. */
|
|
1770
|
+
interface FieldRegistryWrappers {
|
|
1771
|
+
css: CssWrapper;
|
|
1772
|
+
row: RowWrapper;
|
|
1400
1773
|
}
|
|
1401
1774
|
/**
|
|
1402
|
-
*
|
|
1403
|
-
*
|
|
1404
|
-
* @codeOnly The `component` loader is a function and cannot survive
|
|
1405
|
-
* `JSON.stringify`/`parse`. The lenient validator drops this kind when the
|
|
1406
|
-
* config originated from JSON (set via `sanitizeFormConfig({ source: 'json' })`).
|
|
1775
|
+
* Global interface for dynamic form field definitions with categorization
|
|
1776
|
+
* This interface combines containers and leaves from their respective registries
|
|
1407
1777
|
*/
|
|
1408
|
-
interface
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1778
|
+
interface DynamicFormFieldRegistry {
|
|
1779
|
+
/** Container fields that hold other fields (no value, have children) */
|
|
1780
|
+
containers: FieldRegistryContainers;
|
|
1781
|
+
/** Leaf fields that have values or display content */
|
|
1782
|
+
leaves: FieldRegistryLeaves;
|
|
1783
|
+
/** Field wrappers types */
|
|
1784
|
+
wrappers: FieldRegistryWrappers;
|
|
1414
1785
|
}
|
|
1415
|
-
|
|
1416
|
-
type
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
type
|
|
1421
|
-
|
|
1422
|
-
|
|
1786
|
+
/** Union type of all registered container field definitions */
|
|
1787
|
+
type ContainerFieldTypes = DynamicFormFieldRegistry['containers'][keyof DynamicFormFieldRegistry['containers']];
|
|
1788
|
+
/** Union type of all registered leaf field definitions */
|
|
1789
|
+
type LeafFieldTypes = DynamicFormFieldRegistry['leaves'][keyof DynamicFormFieldRegistry['leaves']];
|
|
1790
|
+
/** Union type of all registered field definitions */
|
|
1791
|
+
type RegisteredFieldTypes = ContainerFieldTypes | LeafFieldTypes;
|
|
1792
|
+
/** Extract field types that are available in the registry */
|
|
1793
|
+
type AvailableFieldTypes = keyof DynamicFormFieldRegistry['containers'] | keyof DynamicFormFieldRegistry['leaves'];
|
|
1794
|
+
/** Extract wrapper types that are available in the registry */
|
|
1795
|
+
type RegisteredWrapperTypes = keyof DynamicFormFieldRegistry['wrappers'];
|
|
1796
|
+
/**
|
|
1797
|
+
* Combined registry mapping type names to field definitions.
|
|
1798
|
+
* This flattens containers and leaves into a single mapping.
|
|
1799
|
+
*/
|
|
1800
|
+
type FieldTypeMap = DynamicFormFieldRegistry['containers'] & DynamicFormFieldRegistry['leaves'];
|
|
1801
|
+
/**
|
|
1802
|
+
* Extract a specific field type from RegisteredFieldTypes based on the `type` discriminant.
|
|
1803
|
+
* This enables proper type narrowing when defining fields.
|
|
1804
|
+
*/
|
|
1805
|
+
type ExtractField<T extends AvailableFieldTypes> = T extends keyof FieldTypeMap ? FieldTypeMap[T] : never;
|
|
1806
|
+
/**
|
|
1807
|
+
* Narrow a field definition based on its `type` property.
|
|
1808
|
+
* Use this to get proper type inference when working with field unions.
|
|
1809
|
+
*/
|
|
1810
|
+
type NarrowField<T> = T extends {
|
|
1811
|
+
type: infer TType;
|
|
1812
|
+
} ? (TType extends AvailableFieldTypes ? ExtractField<TType> : T) : T;
|
|
1813
|
+
/**
|
|
1814
|
+
* Narrow each field in an array based on its `type` property.
|
|
1815
|
+
* Use with `satisfies` to get proper type inference for field arrays.
|
|
1816
|
+
*/
|
|
1817
|
+
type NarrowFields = readonly NarrowField<RegisteredFieldTypes>[];
|
|
1423
1818
|
|
|
1424
1819
|
/** Resolves a wrapper type name to its registered config interface. */
|
|
1425
1820
|
type WrapperConfig<TWrappers extends RegisteredWrapperTypes = RegisteredWrapperTypes> = TWrappers extends keyof FieldRegistryWrappers ? FieldRegistryWrappers[TWrappers] : {
|
|
@@ -1490,906 +1885,853 @@ declare const WRAPPER_COMPONENT_CACHE: InjectionToken<Map<string, Type<unknown>>
|
|
|
1490
1885
|
*/
|
|
1491
1886
|
declare const WRAPPER_AUTO_ASSOCIATIONS: InjectionToken<WrapperAutoAssociations>;
|
|
1492
1887
|
|
|
1493
|
-
/**
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1888
|
+
/**
|
|
1889
|
+
* Minimal JSON Schema fragment used by the MCP server to surface an addon
|
|
1890
|
+
* type's shape to AI form generators. Covers the common subset
|
|
1891
|
+
* (`type`/`properties`/`required`/`enum`/etc.) without pulling in a full JSON
|
|
1892
|
+
* Schema dependency. Extra keys are allowed via the `[key: string]` index so
|
|
1893
|
+
* vendor-specific annotations (`x-foo`, `markdownDescription`) still typecheck.
|
|
1894
|
+
*/
|
|
1895
|
+
interface AddonTypeSchema {
|
|
1896
|
+
readonly $ref?: string;
|
|
1897
|
+
readonly $schema?: string;
|
|
1898
|
+
readonly title?: string;
|
|
1899
|
+
readonly description?: string;
|
|
1900
|
+
readonly type?: 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null' | ReadonlyArray<'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null'>;
|
|
1901
|
+
readonly enum?: ReadonlyArray<unknown>;
|
|
1902
|
+
readonly const?: unknown;
|
|
1903
|
+
readonly properties?: Readonly<Record<string, AddonTypeSchema>>;
|
|
1904
|
+
readonly required?: ReadonlyArray<string>;
|
|
1905
|
+
readonly additionalProperties?: boolean | AddonTypeSchema;
|
|
1906
|
+
readonly items?: AddonTypeSchema | ReadonlyArray<AddonTypeSchema>;
|
|
1907
|
+
readonly oneOf?: ReadonlyArray<AddonTypeSchema>;
|
|
1908
|
+
readonly anyOf?: ReadonlyArray<AddonTypeSchema>;
|
|
1909
|
+
readonly allOf?: ReadonlyArray<AddonTypeSchema>;
|
|
1910
|
+
readonly not?: AddonTypeSchema;
|
|
1911
|
+
readonly default?: unknown;
|
|
1912
|
+
readonly examples?: ReadonlyArray<unknown>;
|
|
1913
|
+
readonly minimum?: number;
|
|
1914
|
+
readonly maximum?: number;
|
|
1915
|
+
readonly minLength?: number;
|
|
1916
|
+
readonly maxLength?: number;
|
|
1917
|
+
readonly pattern?: string;
|
|
1918
|
+
readonly format?: string;
|
|
1919
|
+
/** Vendor extensions and unrecognised keywords pass through untyped. */
|
|
1920
|
+
readonly [key: string]: unknown;
|
|
1501
1921
|
}
|
|
1502
|
-
|
|
1503
1922
|
/**
|
|
1504
|
-
*
|
|
1505
|
-
*
|
|
1506
|
-
*
|
|
1507
|
-
* @typeParam TMeta - Native HTML attributes interface (extends FieldMeta)
|
|
1923
|
+
* Optional shape validator a type ships to enforce its required fields at
|
|
1924
|
+
* runtime. Throws are caught by the validator and converted into lenient
|
|
1925
|
+
* warnings; the offending addon is dropped and the form keeps rendering.
|
|
1508
1926
|
*/
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
/**
|
|
1513
|
-
type:
|
|
1514
|
-
/**
|
|
1515
|
-
|
|
1516
|
-
/**
|
|
1517
|
-
|
|
1518
|
-
/**
|
|
1519
|
-
|
|
1520
|
-
/** Additional CSS classes for custom styling. */
|
|
1521
|
-
className?: string;
|
|
1522
|
-
/**
|
|
1523
|
-
* Whether the field is disabled and cannot be interacted with.
|
|
1524
|
-
*
|
|
1525
|
-
* @value false
|
|
1526
|
-
*/
|
|
1527
|
-
disabled?: boolean;
|
|
1528
|
-
/**
|
|
1529
|
-
* Whether the field is read-only.
|
|
1530
|
-
*
|
|
1531
|
-
* @value false
|
|
1532
|
-
*/
|
|
1533
|
-
readonly?: boolean;
|
|
1927
|
+
type AddonShapeValidator<T extends BaseAddon = BaseAddon> = (addon: T, fieldKey: string) => void;
|
|
1928
|
+
/** Per-type registration metadata. */
|
|
1929
|
+
interface AddonTypeDefinition<T extends BaseAddon = BaseAddon> {
|
|
1930
|
+
/** Discriminant matching `addon.type`. */
|
|
1931
|
+
readonly type: string;
|
|
1932
|
+
/** Lazy loader for the type's renderer component. */
|
|
1933
|
+
readonly loadComponent: LazyComponentLoader;
|
|
1934
|
+
/** Optional shape validator — throw `DynamicFormError` to drop the addon with a warning. */
|
|
1935
|
+
readonly validate?: AddonShapeValidator<T>;
|
|
1936
|
+
/** Optional JSON Schema fragment for MCP / pre-flight tooling. */
|
|
1937
|
+
readonly schema?: AddonTypeSchema;
|
|
1534
1938
|
/**
|
|
1535
|
-
* Whether the
|
|
1536
|
-
*
|
|
1537
|
-
*
|
|
1939
|
+
* Whether the type survives `JSON.stringify` / `JSON.parse`. Types whose
|
|
1940
|
+
* shape includes a function payload (e.g., the built-in `'component'`
|
|
1941
|
+
* loader, inline `prime-button` `action` handlers) declare `jsonSafe: false`
|
|
1942
|
+
* so the validator drops them when the config was loaded from a JSON
|
|
1943
|
+
* source (`sanitizeFormConfig(config, { source: 'json' })`). Defaults to
|
|
1944
|
+
* `true` — types are JSON-safe unless explicitly opted out.
|
|
1538
1945
|
*/
|
|
1539
|
-
|
|
1540
|
-
/** Tab index for keyboard navigation. */
|
|
1541
|
-
tabIndex?: number | undefined;
|
|
1542
|
-
/**
|
|
1543
|
-
* Whether to exclude this field's value from submission output when hidden.
|
|
1544
|
-
*
|
|
1545
|
-
* @default undefined (uses form-level or global setting)
|
|
1546
|
-
*/
|
|
1547
|
-
excludeValueIfHidden?: boolean;
|
|
1548
|
-
/**
|
|
1549
|
-
* Whether to exclude this field's value from submission output when disabled.
|
|
1550
|
-
*
|
|
1551
|
-
* @default undefined (uses form-level or global setting)
|
|
1552
|
-
*/
|
|
1553
|
-
excludeValueIfDisabled?: boolean;
|
|
1554
|
-
/**
|
|
1555
|
-
* Whether to exclude this field's value from submission output when readonly.
|
|
1556
|
-
*
|
|
1557
|
-
* @default undefined (uses form-level or global setting)
|
|
1558
|
-
*/
|
|
1559
|
-
excludeValueIfReadonly?: boolean;
|
|
1560
|
-
/**
|
|
1561
|
-
* Whether to run validation when this field is hidden — statically (`hidden: true`),
|
|
1562
|
-
* via a `hidden` logic rule, or via any hidden ancestor.
|
|
1563
|
-
*
|
|
1564
|
-
* @default undefined — inherits from parent / form / global default (which is `false`)
|
|
1565
|
-
*/
|
|
1566
|
-
validateWhenHidden?: boolean;
|
|
1567
|
-
/**
|
|
1568
|
-
* Column sizing configuration for responsive grid layout.
|
|
1569
|
-
*
|
|
1570
|
-
* @value 12
|
|
1571
|
-
*/
|
|
1572
|
-
col?: number;
|
|
1573
|
-
/** Wrapper components to chain around this field. */
|
|
1574
|
-
wrappers?: readonly WrapperConfig[] | null;
|
|
1575
|
-
/**
|
|
1576
|
-
* Skip the auto-association layer (`WrapperTypeDefinition.types`) while
|
|
1577
|
-
* keeping form-level defaults and any field-level `wrappers`. Use when a
|
|
1578
|
-
* global wrapper auto-applies to this field type but isn't wanted here.
|
|
1579
|
-
*/
|
|
1580
|
-
skipAutoWrappers?: boolean;
|
|
1581
|
-
/**
|
|
1582
|
-
* Skip the form-level `defaultWrappers` layer while keeping auto-associations
|
|
1583
|
-
* and any field-level `wrappers`.
|
|
1584
|
-
*/
|
|
1585
|
-
skipDefaultWrappers?: boolean;
|
|
1586
|
-
/** Addons rendered inside this field's slots (typically `prefix` / `suffix`). */
|
|
1587
|
-
addons?: ReadonlyArray<AnyAddon>;
|
|
1946
|
+
readonly jsonSafe?: boolean;
|
|
1588
1947
|
}
|
|
1589
|
-
type
|
|
1948
|
+
/** Per-field-type addon-support metadata declared at field registration. */
|
|
1949
|
+
interface FieldAddonSupport {
|
|
1950
|
+
/** Slots a field of this type accepts. */
|
|
1951
|
+
readonly slots: readonly AddonSlot[];
|
|
1952
|
+
/** Optional whitelist of allowed addon types. Omitted = any registered type. */
|
|
1953
|
+
readonly allowedTypes?: readonly string[];
|
|
1954
|
+
}
|
|
1955
|
+
/** Global registry of addon types. */
|
|
1956
|
+
declare const ADDON_TYPE_REGISTRY: InjectionToken<Map<string, AddonTypeDefinition<BaseAddon<AddonSlot>>>>;
|
|
1590
1957
|
/**
|
|
1591
|
-
*
|
|
1958
|
+
* Cache for resolved addon-type components. Provided at form scope by
|
|
1959
|
+
* `provideDynamicForm`.
|
|
1592
1960
|
*
|
|
1593
|
-
* @
|
|
1594
|
-
* export class MyFieldComponent implements FieldComponent<MyFieldDef> {
|
|
1595
|
-
* label = input<string>();
|
|
1596
|
-
* className = input<string>();
|
|
1597
|
-
* hidden = input<boolean>();
|
|
1598
|
-
* tabIndex = input<number>();
|
|
1599
|
-
* }
|
|
1600
|
-
* ```
|
|
1601
|
-
* @typeParam T - Field definition type to extract properties from
|
|
1602
|
-
*/
|
|
1603
|
-
type FieldComponent<T extends FieldDef<unknown, FieldMeta>> = Prettify<WithInputSignals<Pick<T, IncludedKeys>>>;
|
|
1604
|
-
|
|
1605
|
-
/**
|
|
1606
|
-
* Logic configuration for container fields (page, group, row, array).
|
|
1607
|
-
* Containers only support the 'hidden' logic type since they are layout containers,
|
|
1608
|
-
* not form controls (they can't be readonly, disabled, or required).
|
|
1961
|
+
* @internal
|
|
1609
1962
|
*/
|
|
1610
|
-
|
|
1611
|
-
/** Only 'hidden' is supported for container fields */
|
|
1612
|
-
type: 'hidden';
|
|
1613
|
-
/**
|
|
1614
|
-
* Condition that determines when this container is hidden.
|
|
1615
|
-
* Can be a boolean or a conditional expression evaluated against form values.
|
|
1616
|
-
*/
|
|
1617
|
-
condition: ConditionalExpression | boolean;
|
|
1618
|
-
}
|
|
1963
|
+
declare const ADDON_TYPE_COMPONENT_CACHE: InjectionToken<Map<string, Type<unknown>>>;
|
|
1619
1964
|
|
|
1620
1965
|
/**
|
|
1621
|
-
*
|
|
1622
|
-
*
|
|
1623
|
-
*
|
|
1624
|
-
*
|
|
1966
|
+
* Multi-provider token used by `withCustomAddon(...)` features to contribute
|
|
1967
|
+
* addon type definitions. `provideDynamicForm` aggregates all values into
|
|
1968
|
+
* the form-scoped `ADDON_TYPE_REGISTRY` map.
|
|
1969
|
+
*
|
|
1970
|
+
* @internal
|
|
1625
1971
|
*/
|
|
1626
|
-
|
|
1627
|
-
type: 'row';
|
|
1628
|
-
/** Child definitions to render within this row */
|
|
1629
|
-
readonly fields: TFields;
|
|
1630
|
-
/** Row fields do not have a label property * */
|
|
1631
|
-
readonly label?: never;
|
|
1632
|
-
/** Rows do not support meta - they have no native form element * */
|
|
1633
|
-
readonly meta?: never;
|
|
1634
|
-
/**
|
|
1635
|
-
* Logic configurations for conditional row visibility.
|
|
1636
|
-
* Only 'hidden' type logic is supported for rows.
|
|
1637
|
-
*/
|
|
1638
|
-
readonly logic?: ContainerLogicConfig[];
|
|
1639
|
-
}
|
|
1640
|
-
/** Type guard for RowField with proper type narrowing */
|
|
1641
|
-
declare function isRowField(field: FieldDef<any>): field is RowField;
|
|
1642
|
-
type RowComponent = FieldComponent<RowField<RowAllowedChildren[]>>;
|
|
1972
|
+
declare const ADDON_TYPE_DEFINITIONS: InjectionToken<readonly AddonTypeDefinition<_ng_forge_dynamic_forms_internal.BaseAddon<_ng_forge_dynamic_forms_internal.AddonSlot>>[]>;
|
|
1643
1973
|
|
|
1974
|
+
/** Represents a FieldTree node for dynamic bracket-access navigation. */
|
|
1975
|
+
type FieldTreeRecord = Record<string, FieldTree<unknown> | undefined>;
|
|
1644
1976
|
/**
|
|
1645
|
-
*
|
|
1646
|
-
*
|
|
1647
|
-
* This is a programmatic grouping only - users cannot customize this field type
|
|
1977
|
+
* Type representing a FieldTree for an array.
|
|
1978
|
+
* Extends FieldTree to add numeric indexing for accessing item FieldTrees.
|
|
1648
1979
|
*/
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
readonly
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
/** Container field interface for wrapping child fields with UI chrome. */
|
|
1667
|
-
interface ContainerField<TFields extends readonly ContainerAllowedChildren[] = readonly ContainerAllowedChildren[], TWrapperConfigs extends readonly WrapperConfig[] = readonly WrapperConfig[]> extends FieldDef<never> {
|
|
1668
|
-
type: 'container';
|
|
1669
|
-
/** Child definitions to render within this container */
|
|
1670
|
-
readonly fields: TFields;
|
|
1671
|
-
/**
|
|
1672
|
-
* Wrapper components to chain around the children.
|
|
1673
|
-
* Applied outermost-first: the first wrapper in the array is the outermost.
|
|
1674
|
-
* Each wrapper component receives the subsequent wrapper (or children) inside
|
|
1675
|
-
* its `#fieldComponent` ViewContainerRef slot.
|
|
1676
|
-
*/
|
|
1677
|
-
readonly wrappers: TWrapperConfigs;
|
|
1678
|
-
/** Container fields do not have a label property */
|
|
1679
|
-
readonly label?: never;
|
|
1680
|
-
/** Containers do not support meta — they have no native form element */
|
|
1681
|
-
readonly meta?: never;
|
|
1682
|
-
/**
|
|
1683
|
-
* Logic configurations for conditional container visibility.
|
|
1684
|
-
* Only 'hidden' type logic is supported for containers.
|
|
1685
|
-
*/
|
|
1686
|
-
readonly logic?: ContainerLogicConfig[];
|
|
1980
|
+
type ArrayFieldTree<T> = FieldTree<T[]> & {
|
|
1981
|
+
readonly [index: number]: FieldTree<T> | undefined;
|
|
1982
|
+
};
|
|
1983
|
+
/** Get the length of an array FieldTree. */
|
|
1984
|
+
declare function getArrayLength<T>(arrayFieldTree: ArrayFieldTree<T>): number;
|
|
1985
|
+
/** Read-only view of a single field's observable state. */
|
|
1986
|
+
interface ReadonlyFieldTree<TValue = unknown> {
|
|
1987
|
+
readonly value: Signal<TValue>;
|
|
1988
|
+
readonly valid: Signal<boolean>;
|
|
1989
|
+
readonly invalid: Signal<boolean>;
|
|
1990
|
+
readonly touched: Signal<boolean>;
|
|
1991
|
+
readonly dirty: Signal<boolean>;
|
|
1992
|
+
readonly required: Signal<boolean>;
|
|
1993
|
+
readonly disabled: Signal<boolean>;
|
|
1994
|
+
readonly hidden: Signal<boolean>;
|
|
1995
|
+
readonly errors: Signal<readonly unknown[]>;
|
|
1687
1996
|
}
|
|
1688
|
-
/** Type guard for ContainerField with proper type narrowing. */
|
|
1689
|
-
declare function isContainerTypedField(field: FieldDef<any>): field is ContainerField;
|
|
1690
|
-
type ContainerComponent = FieldComponent<ContainerField<ContainerAllowedChildren[]>>;
|
|
1691
|
-
|
|
1692
1997
|
/**
|
|
1693
|
-
*
|
|
1694
|
-
*
|
|
1998
|
+
* Build a `ReadonlyFieldTree` by extracting the whitelisted read signals from a
|
|
1999
|
+
* Signal Forms `FieldTree`. Returns a fresh plain object — no casting, no proxying,
|
|
2000
|
+
* so consumers only see the narrow surface and Angular's `WritableSignal` capability
|
|
2001
|
+
* on `value` is hidden.
|
|
1695
2002
|
*/
|
|
2003
|
+
declare function toReadonlyFieldTree<TValue>(field: FieldTree<TValue>): ReadonlyFieldTree<TValue>;
|
|
1696
2004
|
/**
|
|
1697
|
-
*
|
|
1698
|
-
*
|
|
2005
|
+
* Write a value into a FieldTree's underlying signal. Signal Forms stores
|
|
2006
|
+
* `FieldState.value` as a `WritableSignal`; this helper centralises the cast
|
|
2007
|
+
* and warns if that contract ever changes (vs a silent no-op).
|
|
1699
2008
|
*/
|
|
1700
|
-
|
|
2009
|
+
declare function writeToFieldValue<T>(value: Signal<T>, next: T, logger?: {
|
|
2010
|
+
warn: (msg: string) => void;
|
|
2011
|
+
}): boolean;
|
|
1701
2012
|
/**
|
|
1702
|
-
*
|
|
1703
|
-
*
|
|
2013
|
+
* DI-scoped cache for `ReadonlyFieldTree` views, keyed on the source FieldTree
|
|
2014
|
+
* identity. A fresh WeakMap per root injector keeps renders isolated under SSR —
|
|
2015
|
+
* Angular creates a new root injector per request, so there's no shared state
|
|
2016
|
+
* between server renders (same pattern as `COMPONENT_CACHE`).
|
|
2017
|
+
*
|
|
2018
|
+
* @internal
|
|
1704
2019
|
*/
|
|
1705
|
-
|
|
2020
|
+
declare const READONLY_FIELD_TREE_CACHE: InjectionToken<WeakMap<FieldTree<unknown>, ReadonlyFieldTree<unknown>>>;
|
|
1706
2021
|
/**
|
|
1707
|
-
*
|
|
1708
|
-
*
|
|
1709
|
-
*
|
|
2022
|
+
* Cached variant of {@link toReadonlyFieldTree}. Each FieldTree instance is a
|
|
2023
|
+
* stable reference for the lifetime of its form, so one `ReadonlyFieldTree`
|
|
2024
|
+
* view per tree is enough. Callers on hot paths (`pushInputs` on every mapper
|
|
2025
|
+
* emission) avoid re-allocating the nine-property view object.
|
|
2026
|
+
*
|
|
2027
|
+
* @internal
|
|
1710
2028
|
*/
|
|
1711
|
-
|
|
2029
|
+
declare function toReadonlyFieldTreeCached<TValue>(cache: WeakMap<FieldTree<unknown>, ReadonlyFieldTree<unknown>>, field: FieldTree<TValue>): ReadonlyFieldTree<TValue>;
|
|
2030
|
+
|
|
2031
|
+
/** Input shape passed to a wrapper component via the `fieldInputs` input. */
|
|
2032
|
+
interface WrapperFieldInputs {
|
|
2033
|
+
readonly key: string;
|
|
2034
|
+
/** Field-type discriminant (mirrors `FieldDef.type`) — useful for kind-aware addons. */
|
|
2035
|
+
readonly type?: string;
|
|
2036
|
+
readonly label?: string;
|
|
2037
|
+
readonly placeholder?: string;
|
|
2038
|
+
readonly className?: string;
|
|
2039
|
+
readonly props?: Record<string, unknown>;
|
|
2040
|
+
readonly validationMessages?: Record<string, string>;
|
|
2041
|
+
readonly defaultValidationMessages?: Record<string, string>;
|
|
2042
|
+
readonly field?: ReadonlyFieldTree;
|
|
2043
|
+
/**
|
|
2044
|
+
* Write a value into the wrapped field's tree. Provided by `buildFieldInputs`
|
|
2045
|
+
* when a `FieldTree` is present. Addons (e.g., `prime-button` presets) use this
|
|
2046
|
+
* to mutate the host field; wrappers should treat the field as read-only.
|
|
2047
|
+
*/
|
|
2048
|
+
readonly setValue?: (next: unknown) => void;
|
|
2049
|
+
readonly [key: string]: unknown;
|
|
2050
|
+
}
|
|
2051
|
+
|
|
1712
2052
|
/**
|
|
1713
|
-
*
|
|
1714
|
-
*
|
|
1715
|
-
* parent form, so most registered field types may appear inside — including
|
|
1716
|
-
* hidden fields and other containers — but NOT pages.
|
|
2053
|
+
* Dispatcher component that renders an addon by looking up its `type` in
|
|
2054
|
+
* `ADDON_TYPE_REGISTRY` and instantiating the registered component.
|
|
1717
2055
|
*/
|
|
1718
|
-
|
|
2056
|
+
declare class DfAddonSlot {
|
|
2057
|
+
private readonly registry;
|
|
2058
|
+
private readonly logger;
|
|
2059
|
+
private readonly hostInjector;
|
|
2060
|
+
readonly addon: i0.InputSignal<AnyAddon>;
|
|
2061
|
+
/**
|
|
2062
|
+
* Optional read-only view of the host field's mapped inputs — same shape
|
|
2063
|
+
* wrappers receive (`field?: ReadonlyFieldTree`, `key`, `props`, etc.).
|
|
2064
|
+
* Forwarded to type components so they can read field state without
|
|
2065
|
+
* re-injecting `FIELD_SIGNAL_CONTEXT` and rebuilding context themselves.
|
|
2066
|
+
*/
|
|
2067
|
+
readonly fieldInputs: i0.InputSignal<WrapperFieldInputs | undefined>;
|
|
2068
|
+
/**
|
|
2069
|
+
* Pre-resolved `hidden` signal supplied by the host field. When provided,
|
|
2070
|
+
* the dispatcher reads this instead of re-resolving `addon.hidden` —
|
|
2071
|
+
* lets the host (e.g., `prime-input`) share a single subscription per
|
|
2072
|
+
* Observable-typed `hidden` between its own visibility filter and the
|
|
2073
|
+
* slot's `[style.display]` binding.
|
|
2074
|
+
*/
|
|
2075
|
+
readonly hidden: i0.InputSignal<Signal<boolean> | undefined>;
|
|
2076
|
+
/** `slot` HTML attribute forwarded to host — needed for Ionic shadow projection. */
|
|
2077
|
+
protected readonly slotAttr: Signal<_ng_forge_dynamic_forms_internal.AddonSlot>;
|
|
2078
|
+
protected readonly className: Signal<string | null>;
|
|
2079
|
+
/**
|
|
2080
|
+
* Locally-resolved `hidden` signal — always reflects `addon.hidden`
|
|
2081
|
+
* regardless of whether the host supplied a pre-resolved signal.
|
|
2082
|
+
* Populated via `explicitEffect` so `resolveDynamicValue` (which may call
|
|
2083
|
+
* `toSignal` for Observable-typed values) does NOT run inside a reactive
|
|
2084
|
+
* context (NG0602). The WeakMap caches per `hidden`-value identity, so
|
|
2085
|
+
* swapping `addon` inputs that share the same Observable reuses the
|
|
2086
|
+
* subscription instead of leaking a fresh one per swap.
|
|
2087
|
+
*/
|
|
2088
|
+
private readonly _hiddenByValue;
|
|
2089
|
+
private readonly _resolvedHidden;
|
|
2090
|
+
/**
|
|
2091
|
+
* `hidden` resolved from `DynamicValue<boolean>` to a flat `Signal<boolean>`.
|
|
2092
|
+
* Prefers the host-supplied signal when present (avoids duplicate `toSignal`
|
|
2093
|
+
* subscriptions for Observable-typed `hidden`); falls back to the locally-
|
|
2094
|
+
* resolved signal, which is always populated by the addon-tracking effect.
|
|
2095
|
+
*/
|
|
2096
|
+
protected readonly isHidden: Signal<boolean>;
|
|
2097
|
+
/**
|
|
2098
|
+
* Latest async-loaded `{ type, component }` pair. Tagging the result with
|
|
2099
|
+
* its type lets `resolvedComponent` filter stale loads structurally — no
|
|
2100
|
+
* monotonic token needed. When `addon.type` changes mid-load, the prior
|
|
2101
|
+
* load still completes and writes here, but the computed ignores it
|
|
2102
|
+
* because the recorded type no longer matches the current one.
|
|
2103
|
+
*/
|
|
2104
|
+
private readonly asyncLoaded;
|
|
2105
|
+
/**
|
|
2106
|
+
* Resolved type component — composed declaratively from two sources of
|
|
2107
|
+
* truth: the registry's synchronous cache (warm hits, e.g., a second
|
|
2108
|
+
* `<df-addon-slot>` for an already-loaded type) and the type-tagged async
|
|
2109
|
+
* loader result. Reading `addon().type` first makes the computed react to
|
|
2110
|
+
* addon swaps and naturally invalidate stale async-load results.
|
|
2111
|
+
*/
|
|
2112
|
+
protected readonly resolvedComponent: Signal<Type<unknown> | undefined>;
|
|
2113
|
+
/** Inputs passed to the type component — addon plus the wrapper-style host bag. */
|
|
2114
|
+
protected readonly typeInputs: Signal<{
|
|
2115
|
+
addon: AnyAddon;
|
|
2116
|
+
fieldInputs: WrapperFieldInputs | undefined;
|
|
2117
|
+
}>;
|
|
2118
|
+
constructor();
|
|
2119
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<DfAddonSlot, never>;
|
|
2120
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<DfAddonSlot, "df-addon-slot", never, { "addon": { "alias": "addon"; "required": true; "isSignal": true; }; "fieldInputs": { "alias": "fieldInputs"; "required": false; "isSignal": true; }; "hidden": { "alias": "hidden"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
2121
|
+
}
|
|
2122
|
+
|
|
1719
2123
|
/**
|
|
1720
|
-
*
|
|
1721
|
-
*
|
|
2124
|
+
* Public shape returned by {@link injectAddonTypeRegistry}. Pinned explicitly
|
|
2125
|
+
* so the API extractor doesn't churn between versions when the inner factory
|
|
2126
|
+
* gets refactored.
|
|
1722
2127
|
*/
|
|
1723
|
-
|
|
2128
|
+
interface AddonTypeRegistryRef {
|
|
2129
|
+
getType(type: string): AddonTypeDefinition | undefined;
|
|
2130
|
+
hasType(type: string): boolean;
|
|
2131
|
+
getTypeNames(): string[];
|
|
2132
|
+
loadTypeComponent(type: string): Promise<Type<unknown>>;
|
|
2133
|
+
getLoadedTypeComponent(type: string): Type<unknown> | undefined;
|
|
2134
|
+
readonly raw: ReadonlyMap<string, AddonTypeDefinition>;
|
|
2135
|
+
}
|
|
2136
|
+
/** Injection function for accessing the addon type registry. */
|
|
2137
|
+
declare function injectAddonTypeRegistry(): AddonTypeRegistryRef;
|
|
1724
2138
|
|
|
2139
|
+
/** One entry per field type that declares addon support. */
|
|
2140
|
+
interface FieldAddonSupportEntry {
|
|
2141
|
+
readonly name: string;
|
|
2142
|
+
readonly slots: FieldAddonSupport['slots'];
|
|
2143
|
+
readonly allowedTypes: FieldAddonSupport['allowedTypes'];
|
|
2144
|
+
}
|
|
1725
2145
|
/**
|
|
1726
|
-
*
|
|
1727
|
-
*
|
|
2146
|
+
* Walk `FIELD_REGISTRY` and return every field type that opted into addons
|
|
2147
|
+
* (i.e., declared `addons` on its `FieldTypeDefinition`).
|
|
2148
|
+
*
|
|
2149
|
+
* @Component({ ... })
|
|
2150
|
+
* class FormBuilder {
|
|
2151
|
+
* protected readonly addonable = injectFieldsSupportingAddons();
|
|
2152
|
+
*
|
|
2153
|
+
* constructor() {
|
|
2154
|
+
* // -> [{ name: 'prime-input', slots: ['prefix', 'suffix'], allowedTypes: [...] }, ...]
|
|
2155
|
+
* }
|
|
2156
|
+
* }
|
|
2157
|
+
* ```
|
|
1728
2158
|
*/
|
|
1729
|
-
|
|
2159
|
+
declare function injectFieldsSupportingAddons(): FieldAddonSupportEntry[];
|
|
2160
|
+
|
|
1730
2161
|
/**
|
|
1731
|
-
*
|
|
1732
|
-
*
|
|
1733
|
-
* - An array of fields (ArrayItemTemplate) for OBJECT array items - merges fields into object
|
|
2162
|
+
* Fields every addon-action context carries, regardless of whether the
|
|
2163
|
+
* addon is bound to a host field or rendered orphaned.
|
|
1734
2164
|
*/
|
|
1735
|
-
|
|
1736
|
-
/** Array field interface for creating dynamic field collections that map to array values. */
|
|
1737
|
-
interface ArrayField<TFields extends readonly ArrayItemDefinition[] = readonly ArrayItemDefinition[]> extends FieldDef<never> {
|
|
1738
|
-
type: 'array';
|
|
2165
|
+
interface AddonActionContextBase<TValue> {
|
|
1739
2166
|
/**
|
|
1740
|
-
*
|
|
1741
|
-
*
|
|
1742
|
-
*
|
|
1743
|
-
*
|
|
1744
|
-
* - Items can have different configurations (heterogeneous arrays supported)
|
|
1745
|
-
* - Initial values are set via `value` property on each field definition
|
|
1746
|
-
*/
|
|
1747
|
-
readonly fields: TFields;
|
|
1748
|
-
/** Array fields do not have a label property * */
|
|
1749
|
-
readonly label?: never;
|
|
1750
|
-
/** Arrays do not support meta - they have no native form element * */
|
|
1751
|
-
readonly meta?: never;
|
|
1752
|
-
/**
|
|
1753
|
-
* Logic configurations for conditional array visibility.
|
|
1754
|
-
* Only 'hidden' type logic is supported for arrays.
|
|
1755
|
-
*/
|
|
1756
|
-
readonly logic?: ContainerLogicConfig[];
|
|
1757
|
-
/**
|
|
1758
|
-
* Minimum number of items required in the array.
|
|
1759
|
-
* Validation fails if the array has fewer items than this value.
|
|
2167
|
+
* Identity of the host field this addon is attached to. Empty strings
|
|
2168
|
+
* indicate the addon is rendered outside an active field context (rare).
|
|
2169
|
+
* Use {@link isFieldBoundContext} or the `form !== null` check to
|
|
2170
|
+
* narrow before relying on field identity.
|
|
1760
2171
|
*/
|
|
1761
|
-
readonly
|
|
2172
|
+
readonly field: {
|
|
2173
|
+
readonly key: string;
|
|
2174
|
+
readonly type: string;
|
|
2175
|
+
};
|
|
1762
2176
|
/**
|
|
1763
|
-
*
|
|
1764
|
-
*
|
|
2177
|
+
* Current value of the host field at the time the action fires.
|
|
2178
|
+
* `undefined` when the host field has no value yet (initial render before
|
|
2179
|
+
* defaultValue resolution) or when the addon is rendered outside a field.
|
|
1765
2180
|
*/
|
|
1766
|
-
readonly
|
|
2181
|
+
readonly value: TValue | undefined;
|
|
1767
2182
|
}
|
|
1768
2183
|
/**
|
|
1769
|
-
*
|
|
1770
|
-
*
|
|
1771
|
-
*
|
|
2184
|
+
* Field-bound variant — the addon is attached to a real field and has a
|
|
2185
|
+
* working value-writer. The common case for `pi-button` / `mat-button` /
|
|
2186
|
+
* `bs-button` / `ion-button` inside an adapter input field.
|
|
1772
2187
|
*/
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
readonly label?: string;
|
|
1779
|
-
/** Additional properties passed to the button component */
|
|
1780
|
-
readonly props?: Record<string, unknown>;
|
|
2188
|
+
interface FieldBoundAddonActionContext<TValue = unknown> extends AddonActionContextBase<TValue> {
|
|
2189
|
+
/** Read-only view of the host field's tree — same view wrappers receive. */
|
|
2190
|
+
readonly form: ReadonlyFieldTree<TValue>;
|
|
2191
|
+
/** Push a new value into the host field. */
|
|
2192
|
+
readonly setValue: (next: TValue) => void;
|
|
1781
2193
|
}
|
|
1782
|
-
/**
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
readonly
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
2194
|
+
/**
|
|
2195
|
+
* Orphan variant — the addon is rendered outside any field component (rare;
|
|
2196
|
+
* happens when consumers compose `<df-addon-slot>` directly without a host
|
|
2197
|
+
* field). No writer is reachable; reading `value` may also yield `undefined`.
|
|
2198
|
+
*/
|
|
2199
|
+
interface OrphanAddonActionContext<TValue = unknown> extends AddonActionContextBase<TValue> {
|
|
2200
|
+
readonly form: null;
|
|
2201
|
+
/** Always absent in the orphan variant — distinguishes the union members. */
|
|
2202
|
+
readonly setValue?: undefined;
|
|
2203
|
+
}
|
|
2204
|
+
/** Context handed to inline addon actions and registered handler functions. */
|
|
2205
|
+
type AddonActionContext<TValue = unknown> = FieldBoundAddonActionContext<TValue> | OrphanAddonActionContext<TValue>;
|
|
2206
|
+
/** Type guard narrowing {@link AddonActionContext} to its field-bound variant. */
|
|
2207
|
+
declare function isFieldBoundContext<TValue>(ctx: AddonActionContext<TValue>): ctx is FieldBoundAddonActionContext<TValue>;
|
|
2208
|
+
/** Built-in preset actions shared across adapters. */
|
|
2209
|
+
type CommonAddonActionPreset = 'clear' | 'reset' | 'paste' | 'copy' | 'toggle-password-visibility';
|
|
2210
|
+
/** Module-augmentable registry of adapter-specific preset names. */
|
|
2211
|
+
interface DynamicFormAddonActionPresetRegistry {
|
|
2212
|
+
}
|
|
2213
|
+
/**
|
|
2214
|
+
* Union of every preset name an addon may reference — universal presets
|
|
2215
|
+
* plus any contributed via {@link DynamicFormAddonActionPresetRegistry}.
|
|
2216
|
+
*/
|
|
2217
|
+
type AddonActionPreset = CommonAddonActionPreset | keyof DynamicFormAddonActionPresetRegistry | (string & {});
|
|
2218
|
+
/** Module-augmentable registry of user-defined named action handlers. */
|
|
2219
|
+
interface DynamicFormActionRegistry {
|
|
2220
|
+
}
|
|
2221
|
+
/**
|
|
2222
|
+
* Typed string handle to a registered action handler. The empty registry
|
|
2223
|
+
* resolves to `never`; augmenting `DynamicFormActionRegistry` populates the
|
|
2224
|
+
* union and unlocks autocomplete.
|
|
2225
|
+
*/
|
|
2226
|
+
type RegisteredActionRef = keyof DynamicFormActionRegistry;
|
|
2227
|
+
|
|
2228
|
+
/**
|
|
2229
|
+
* Optional collaborators a preset may need beyond the base context. Passed
|
|
2230
|
+
* by the button kind component which has access to its own DI scope.
|
|
2231
|
+
*/
|
|
2232
|
+
interface PresetCollaborators {
|
|
2233
|
+
/** Per-field input-type override signal — populated only inside an input field. */
|
|
2234
|
+
readonly typeOverride?: WritableSignal<string | undefined>;
|
|
2235
|
+
/** Writer that pushes a value into the host field's tree. */
|
|
2236
|
+
readonly fieldValueSetter?: (next: unknown) => void;
|
|
1807
2237
|
/**
|
|
1808
|
-
*
|
|
1809
|
-
*
|
|
2238
|
+
* Read the host field's configured default value (from the form's
|
|
2239
|
+
* `defaultValues` map keyed by `field.key`). Used by the `'reset'`
|
|
2240
|
+
* preset; absent when the addon is rendered outside an active field
|
|
2241
|
+
* context, in which case `'reset'` falls back to clearing.
|
|
1810
2242
|
*/
|
|
1811
|
-
readonly
|
|
2243
|
+
readonly fieldDefaultValueGetter?: () => unknown;
|
|
1812
2244
|
/**
|
|
1813
|
-
*
|
|
1814
|
-
*
|
|
2245
|
+
* Baseline configured input type (from `props().type`), read at preset-run
|
|
2246
|
+
* time. Used by `toggle-password-visibility` to refuse to corrupt
|
|
2247
|
+
* `'email'`/`'number'`/etc. inputs into `'password'` when no override is
|
|
2248
|
+
* yet set.
|
|
1815
2249
|
*/
|
|
1816
|
-
readonly
|
|
2250
|
+
readonly baselineType?: () => string | undefined;
|
|
2251
|
+
/** Logger for warnings about presets that can't be fulfilled in this context. */
|
|
2252
|
+
readonly logger: Logger;
|
|
2253
|
+
}
|
|
2254
|
+
/**
|
|
2255
|
+
* Apply a built-in preset action against the addon's host field. Shared
|
|
2256
|
+
* across all adapters — each adapter's `ADDON_PRESET_HANDLER` provider
|
|
2257
|
+
* delegates here.
|
|
2258
|
+
*
|
|
2259
|
+
* @param adapterLabel Used in warnings — `'Material'` / `'Bootstrap'` / etc.
|
|
2260
|
+
* @param fieldLabel Used in warnings — `'mat-input'` / `'bs-input'` / etc.
|
|
2261
|
+
*/
|
|
2262
|
+
declare function runPresetAction(preset: AddonActionPreset, ctx: AddonActionContext, collaborators: PresetCollaborators, adapterLabel: string, fieldLabel: string): Promise<void>;
|
|
2263
|
+
|
|
2264
|
+
/** Context for cross-field detection, providing access to function scope information. */
|
|
2265
|
+
interface CrossFieldDetectionContext {
|
|
1817
2266
|
/**
|
|
1818
|
-
*
|
|
1819
|
-
*
|
|
2267
|
+
* Lookup function to get the scope of a registered custom function.
|
|
2268
|
+
*
|
|
2269
|
+
* @param functionName The name of the custom function
|
|
2270
|
+
* @returns The function's scope, or undefined if not registered
|
|
1820
2271
|
*/
|
|
1821
|
-
|
|
1822
|
-
/** Mutually exclusive with `template` — use `fields` for the full API instead */
|
|
1823
|
-
readonly fields?: never;
|
|
2272
|
+
getFunctionScope?: (functionName: string) => CustomFunctionScope | undefined;
|
|
1824
2273
|
}
|
|
1825
2274
|
/**
|
|
1826
|
-
*
|
|
1827
|
-
*
|
|
2275
|
+
* Detects if a ConditionalExpression references other fields (cross-field).
|
|
2276
|
+
*
|
|
2277
|
+
* @param expr The conditional expression to analyze
|
|
2278
|
+
* @param context Optional context providing function scope lookup
|
|
2279
|
+
* @returns true if the expression references other fields
|
|
1828
2280
|
*/
|
|
1829
|
-
declare function
|
|
1830
|
-
|
|
2281
|
+
declare function isCrossFieldExpression(expr: ConditionalExpression | boolean | FormStateCondition | undefined, context?: CrossFieldDetectionContext): boolean;
|
|
1831
2282
|
/**
|
|
1832
|
-
*
|
|
1833
|
-
*
|
|
2283
|
+
* Extracts field dependencies from a ConditionalExpression.
|
|
2284
|
+
*
|
|
2285
|
+
* @param expr The conditional expression to analyze
|
|
2286
|
+
* @returns Array of field keys that this expression depends on
|
|
1834
2287
|
*/
|
|
1835
|
-
|
|
2288
|
+
declare function extractExpressionDependencies(expr: ConditionalExpression | boolean | undefined): string[];
|
|
1836
2289
|
/**
|
|
1837
|
-
*
|
|
1838
|
-
*
|
|
1839
|
-
* multiple IDs or similar data.
|
|
2290
|
+
* Extracts field names from a JavaScript expression string.
|
|
2291
|
+
* Handles both dot notation (formValue.field) and bracket notation (formValue['field']).
|
|
1840
2292
|
*/
|
|
1841
|
-
|
|
2293
|
+
declare function extractStringDependencies(expression: string): string[];
|
|
1842
2294
|
/**
|
|
1843
|
-
*
|
|
2295
|
+
* Detects if a custom validator configuration references formValue (cross-field validation).
|
|
1844
2296
|
*
|
|
1845
|
-
* @
|
|
2297
|
+
* @param config The custom validator configuration to check
|
|
2298
|
+
* @returns true if the validator references formValue
|
|
1846
2299
|
*/
|
|
1847
|
-
|
|
1848
|
-
/** Discriminant for hidden field type */
|
|
1849
|
-
type: 'hidden';
|
|
1850
|
-
/**
|
|
1851
|
-
* The value to store in the form.
|
|
1852
|
-
* This is required - a hidden field without a value serves no purpose.
|
|
1853
|
-
*/
|
|
1854
|
-
value: TValue;
|
|
1855
|
-
}
|
|
2300
|
+
declare function isCrossFieldValidator(config: CustomValidatorConfig): boolean;
|
|
1856
2301
|
/**
|
|
1857
|
-
*
|
|
2302
|
+
* Detects if a built-in validator has a dynamic expression that references formValue.
|
|
1858
2303
|
*
|
|
1859
|
-
* @param
|
|
1860
|
-
* @returns
|
|
2304
|
+
* @param config The validator configuration to check
|
|
2305
|
+
* @returns true if the validator has a cross-field dynamic expression
|
|
1861
2306
|
*/
|
|
1862
|
-
declare function
|
|
2307
|
+
declare function isCrossFieldBuiltInValidator(config: ValidatorConfig): boolean;
|
|
2308
|
+
/** Checks if a validator uses Angular's resource API (validateHttp / validateAsync). */
|
|
2309
|
+
declare function isResourceBasedValidator(config: ValidatorConfig): boolean;
|
|
2310
|
+
/**
|
|
2311
|
+
* Detects if a validator's `when` condition is cross-field.
|
|
2312
|
+
*
|
|
2313
|
+
* @param config The validator configuration to check
|
|
2314
|
+
* @param context Optional context providing function scope lookup
|
|
2315
|
+
* @returns true if the when condition references other fields
|
|
2316
|
+
*/
|
|
2317
|
+
declare function hasCrossFieldWhenCondition(config: ValidatorConfig, context?: CrossFieldDetectionContext): boolean;
|
|
2318
|
+
/**
|
|
2319
|
+
* Detects if a StateLogicConfig has a cross-field condition.
|
|
2320
|
+
*
|
|
2321
|
+
* @param config The state logic configuration to check
|
|
2322
|
+
* @param context Optional context providing function scope lookup
|
|
2323
|
+
* @returns true if the logic condition references other fields
|
|
2324
|
+
*/
|
|
2325
|
+
declare function isCrossFieldStateLogic(config: StateLogicConfig, context?: CrossFieldDetectionContext): boolean;
|
|
2326
|
+
/**
|
|
2327
|
+
* Detects if a SchemaApplicationConfig has a cross-field condition.
|
|
2328
|
+
*
|
|
2329
|
+
* @param config The schema application configuration to check
|
|
2330
|
+
* @param context Optional context providing function scope lookup
|
|
2331
|
+
* @returns true if the schema condition references other fields
|
|
2332
|
+
*/
|
|
2333
|
+
declare function isCrossFieldSchema(config: SchemaApplicationConfig, context?: CrossFieldDetectionContext): boolean;
|
|
1863
2334
|
|
|
1864
2335
|
/**
|
|
1865
|
-
*
|
|
1866
|
-
*
|
|
1867
|
-
*
|
|
1868
|
-
*
|
|
1869
|
-
*
|
|
2336
|
+
* Creates a lazy FieldStateInfo that only reads state properties when accessed.
|
|
2337
|
+
*
|
|
2338
|
+
* @param fieldSource - A FieldTree or direct FieldState instance
|
|
2339
|
+
* @param reactive - If true, reads signals reactively (creates dependencies).
|
|
2340
|
+
* If false, reads signals with `untracked()` (no dependencies).
|
|
2341
|
+
* @returns A FieldStateInfo proxy with lazy property access, or undefined if the source is invalid
|
|
2342
|
+
* @internal
|
|
1870
2343
|
*/
|
|
1871
|
-
|
|
1872
|
-
type: 'page';
|
|
1873
|
-
/** Child field definitions to render within this page */
|
|
1874
|
-
readonly fields: TFields;
|
|
1875
|
-
/** Page fields do not have a label property * */
|
|
1876
|
-
readonly label?: never;
|
|
1877
|
-
/** Pages do not support meta - they have no native form element * */
|
|
1878
|
-
readonly meta?: never;
|
|
1879
|
-
/**
|
|
1880
|
-
* Logic configurations for conditional page visibility.
|
|
1881
|
-
* Only 'hidden' type logic is supported for pages.
|
|
1882
|
-
*/
|
|
1883
|
-
readonly logic?: ContainerLogicConfig[];
|
|
1884
|
-
}
|
|
1885
|
-
/** Type guard for PageField with proper type narrowing */
|
|
1886
|
-
declare function isPageField(field: FieldDef<unknown>): field is PageField;
|
|
2344
|
+
declare function readFieldStateInfo(fieldSource: FieldTree<unknown> | ReadonlyFieldState<unknown> | undefined, reactive: boolean): FieldStateInfo | undefined;
|
|
1887
2345
|
/**
|
|
1888
|
-
*
|
|
2346
|
+
* Creates a Proxy-based FormFieldStateMap for accessing any field's state by key.
|
|
1889
2347
|
*
|
|
1890
|
-
* @param
|
|
1891
|
-
* @
|
|
2348
|
+
* @param rootForm - The root FieldTree of the form
|
|
2349
|
+
* @param reactive - If true, reads signals reactively (creates dependencies).
|
|
2350
|
+
* If false, reads signals with `untracked()` (no dependencies).
|
|
2351
|
+
* @returns A FormFieldStateMap proxy
|
|
2352
|
+
* @internal
|
|
1892
2353
|
*/
|
|
1893
|
-
declare function
|
|
2354
|
+
declare function createFormFieldStateMap(rootForm: FieldTree<unknown>, reactive: boolean): FormFieldStateMap;
|
|
1894
2355
|
|
|
1895
|
-
/**
|
|
1896
|
-
|
|
1897
|
-
/**
|
|
1898
|
-
|
|
1899
|
-
/** The HTML element type to render */
|
|
1900
|
-
elementType: TextElementType;
|
|
1901
|
-
};
|
|
1902
|
-
/** Text field definition for displaying translatable text content */
|
|
1903
|
-
interface TextField extends FieldDef<TextProps> {
|
|
1904
|
-
type: 'text';
|
|
1905
|
-
/**
|
|
1906
|
-
* Logic rules for conditional visibility.
|
|
1907
|
-
* Text fields only support 'hidden' logic type since they are display-only
|
|
1908
|
-
* and don't participate in form validation (no disabled/readonly/required).
|
|
1909
|
-
*/
|
|
1910
|
-
readonly logic?: NonFieldLogicConfig[];
|
|
1911
|
-
}
|
|
1912
|
-
|
|
1913
|
-
/** Configuration for the built-in 'css' wrapper type. */
|
|
1914
|
-
interface CssWrapper {
|
|
1915
|
-
readonly type: 'css';
|
|
1916
|
-
/** CSS classes to apply to the wrapper */
|
|
1917
|
-
readonly cssClasses?: DynamicText;
|
|
2356
|
+
/** DI-scoped cache for async condition logic functions. */
|
|
2357
|
+
declare class AsyncConditionFunctionCacheService {
|
|
2358
|
+
/** Cache for async condition logic functions, keyed by serialized condition. */
|
|
2359
|
+
readonly asyncConditionFunctionCache: Map<string, LogicFn<unknown, boolean>>;
|
|
1918
2360
|
}
|
|
1919
2361
|
|
|
1920
|
-
/**
|
|
1921
|
-
|
|
1922
|
-
readonly type: 'row';
|
|
1923
|
-
}
|
|
2362
|
+
/** Creates a logic function for an async condition. */
|
|
2363
|
+
declare function createAsyncConditionLogicFunction<TValue>(condition: AsyncCondition): LogicFn<TValue, boolean>;
|
|
1924
2364
|
|
|
1925
|
-
/** Container fields registry - augment this interface to add custom container fields */
|
|
1926
|
-
interface FieldRegistryContainers {
|
|
1927
|
-
page: PageField;
|
|
1928
|
-
row: RowField;
|
|
1929
|
-
group: GroupField;
|
|
1930
|
-
array: ArrayField | SimplifiedArrayField;
|
|
1931
|
-
container: ContainerField;
|
|
1932
|
-
}
|
|
1933
|
-
/** Leaf fields registry - augment this interface to add custom leaf fields */
|
|
1934
|
-
interface FieldRegistryLeaves {
|
|
1935
|
-
text: TextField;
|
|
1936
|
-
hidden: HiddenField;
|
|
1937
|
-
}
|
|
1938
|
-
/** Wrapper type registry for module augmentation. */
|
|
1939
|
-
interface FieldRegistryWrappers {
|
|
1940
|
-
css: CssWrapper;
|
|
1941
|
-
row: RowWrapper;
|
|
1942
|
-
}
|
|
1943
|
-
/**
|
|
1944
|
-
* Global interface for dynamic form field definitions with categorization
|
|
1945
|
-
* This interface combines containers and leaves from their respective registries
|
|
1946
|
-
*/
|
|
1947
|
-
interface DynamicFormFieldRegistry {
|
|
1948
|
-
/** Container fields that hold other fields (no value, have children) */
|
|
1949
|
-
containers: FieldRegistryContainers;
|
|
1950
|
-
/** Leaf fields that have values or display content */
|
|
1951
|
-
leaves: FieldRegistryLeaves;
|
|
1952
|
-
/** Field wrappers types */
|
|
1953
|
-
wrappers: FieldRegistryWrappers;
|
|
1954
|
-
}
|
|
1955
|
-
/** Union type of all registered container field definitions */
|
|
1956
|
-
type ContainerFieldTypes = DynamicFormFieldRegistry['containers'][keyof DynamicFormFieldRegistry['containers']];
|
|
1957
|
-
/** Union type of all registered leaf field definitions */
|
|
1958
|
-
type LeafFieldTypes = DynamicFormFieldRegistry['leaves'][keyof DynamicFormFieldRegistry['leaves']];
|
|
1959
|
-
/** Union type of all registered field definitions */
|
|
1960
|
-
type RegisteredFieldTypes = ContainerFieldTypes | LeafFieldTypes;
|
|
1961
|
-
/** Extract field types that are available in the registry */
|
|
1962
|
-
type AvailableFieldTypes = keyof DynamicFormFieldRegistry['containers'] | keyof DynamicFormFieldRegistry['leaves'];
|
|
1963
|
-
/** Extract wrapper types that are available in the registry */
|
|
1964
|
-
type RegisteredWrapperTypes = keyof DynamicFormFieldRegistry['wrappers'];
|
|
1965
2365
|
/**
|
|
1966
|
-
*
|
|
1967
|
-
*
|
|
2366
|
+
* Evaluate conditional expression
|
|
2367
|
+
* Uses secure AST-based parsing for JavaScript expressions
|
|
1968
2368
|
*/
|
|
1969
|
-
|
|
2369
|
+
declare function evaluateCondition(expression: ConditionalExpression, context: EvaluationContext): boolean;
|
|
2370
|
+
|
|
1970
2371
|
/**
|
|
1971
|
-
*
|
|
1972
|
-
*
|
|
2372
|
+
* Trigger value carried through the debounced reactive pipeline.
|
|
2373
|
+
*
|
|
2374
|
+
* @internal
|
|
1973
2375
|
*/
|
|
1974
|
-
|
|
2376
|
+
interface Trigger<TPayload> {
|
|
2377
|
+
key: string;
|
|
2378
|
+
payload: TPayload;
|
|
2379
|
+
}
|
|
1975
2380
|
/**
|
|
1976
|
-
*
|
|
1977
|
-
*
|
|
2381
|
+
* Configuration passed to {@link createDebouncedResourceLogicFn}.
|
|
2382
|
+
*
|
|
2383
|
+
* @internal
|
|
1978
2384
|
*/
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
2385
|
+
interface DebouncedResourceLogicFnConfig<TValue, TPayload, TResult> {
|
|
2386
|
+
/** Default value returned by the resource while loading / pending. */
|
|
2387
|
+
pendingValue: TResult;
|
|
2388
|
+
/** Debounce window (ms) applied to the trigger signal before the resource sees it. */
|
|
2389
|
+
debounceMs: number;
|
|
2390
|
+
injector: Injector;
|
|
2391
|
+
/**
|
|
2392
|
+
* Builds the per-emission inner observable. Called every time the debounced
|
|
2393
|
+
* trigger key changes; the resource swaps to the new stream automatically.
|
|
2394
|
+
*/
|
|
2395
|
+
buildStream: (payload: TPayload) => Observable<TResult>;
|
|
2396
|
+
/**
|
|
2397
|
+
* Called per LogicFn invocation. Returns one of:
|
|
2398
|
+
* - `{ kind: 'trigger', key, payload }` — set the trigger to this and
|
|
2399
|
+
* return the (potentially still-loading) resource value.
|
|
2400
|
+
* - `{ kind: 'returnEarly', value }` — bypass the resource and return
|
|
2401
|
+
* this value directly (used by HTTP for response-cache hits — the
|
|
2402
|
+
* cached value is authoritative and overrides any sticky resource value).
|
|
2403
|
+
* - `{ kind: 'holdPrevious' }` — bypass the resource update but return
|
|
2404
|
+
* the resource's current sticky value (its last resolved value via
|
|
2405
|
+
* `withPreviousValue`, or `pendingValue` if it never resolved). Used
|
|
2406
|
+
* by HTTP when the request template is temporarily unresolvable so
|
|
2407
|
+
* the UI doesn't flicker back to `pendingValue`.
|
|
2408
|
+
*/
|
|
2409
|
+
resolve: (ctx: FieldContext<TValue>) => {
|
|
2410
|
+
kind: 'trigger';
|
|
2411
|
+
key: string;
|
|
2412
|
+
payload: TPayload;
|
|
2413
|
+
} | {
|
|
2414
|
+
kind: 'returnEarly';
|
|
2415
|
+
value: TResult;
|
|
2416
|
+
} | {
|
|
2417
|
+
kind: 'holdPrevious';
|
|
2418
|
+
};
|
|
2419
|
+
}
|
|
1982
2420
|
/**
|
|
1983
|
-
*
|
|
1984
|
-
*
|
|
2421
|
+
* Shared scaffolding for both async-function and HTTP condition LogicFns.
|
|
2422
|
+
*
|
|
2423
|
+
* @internal
|
|
1985
2424
|
*/
|
|
1986
|
-
|
|
2425
|
+
declare function createDebouncedResourceLogicFn<TValue, TPayload, TResult>(config: DebouncedResourceLogicFnConfig<TValue, TPayload, TResult>): LogicFn<TValue, TResult>;
|
|
2426
|
+
|
|
2427
|
+
/** DI-scoped cache for HTTP condition logic functions. */
|
|
2428
|
+
declare class HttpConditionFunctionCacheService {
|
|
2429
|
+
/** Cache for HTTP condition logic functions, keyed by serialized condition. */
|
|
2430
|
+
readonly httpConditionFunctionCache: Map<string, LogicFn<unknown, boolean>>;
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
/** Creates a logic function for an HTTP condition. */
|
|
2434
|
+
declare function createHttpConditionLogicFunction<TValue>(condition: HttpCondition): LogicFn<TValue, boolean>;
|
|
1987
2435
|
|
|
1988
2436
|
/**
|
|
1989
|
-
*
|
|
1990
|
-
*
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
/** Depth counter for recursion limiting (prevents infinite type instantiation) */
|
|
1994
|
-
type Depth = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
1995
|
-
/**
|
|
1996
|
-
* Widens literal types to their primitive equivalents, recursively for objects and arrays.
|
|
1997
|
-
* This prevents `as const` from over-narrowing types like `''` to literal `''` instead of `string`.
|
|
1998
|
-
*/
|
|
1999
|
-
type Widen<T, D extends number = 5> = [D] extends [never] ? T : T extends string ? string : T extends number ? number : T extends boolean ? boolean : T extends readonly (infer U)[] ? Widen<U, Depth[D]>[] : T extends Record<string, unknown> ? {
|
|
2000
|
-
-readonly [K in keyof T]: Widen<T[K], Depth[D]>;
|
|
2001
|
-
} : T;
|
|
2002
|
-
/**
|
|
2003
|
-
* Resolves the "underlying" non-null value type for a field, based on its `type`
|
|
2004
|
-
* discriminator and (where it matters) its `value` literal. Used when we need a
|
|
2005
|
-
* base type independent of whether the literal happens to be `null` — i.e., when
|
|
2006
|
-
* computing the nullable widening for `value: null, nullable: true`.
|
|
2437
|
+
* Create a logic function from a conditional expression.
|
|
2438
|
+
*
|
|
2439
|
+
* @param expression The conditional expression to evaluate
|
|
2440
|
+
* @returns A LogicFn that evaluates the condition in the context of a field
|
|
2007
2441
|
*/
|
|
2008
|
-
|
|
2009
|
-
type: 'slider';
|
|
2010
|
-
} ? number : T extends {
|
|
2011
|
-
type: 'input';
|
|
2012
|
-
props: {
|
|
2013
|
-
type: 'number';
|
|
2014
|
-
};
|
|
2015
|
-
} ? number : T extends {
|
|
2016
|
-
type: 'checkbox' | 'toggle';
|
|
2017
|
-
} ? boolean : [V] extends [null] ? string : Widen<V>;
|
|
2442
|
+
declare function createLogicFunction<TValue>(expression: ConditionalExpression): LogicFn<TValue, boolean>;
|
|
2018
2443
|
/**
|
|
2019
|
-
*
|
|
2020
|
-
*
|
|
2021
|
-
*
|
|
2022
|
-
*
|
|
2023
|
-
*
|
|
2024
|
-
* - When `nullable: true` is declared, widens the result to `T | null`.
|
|
2444
|
+
* Create a debounced logic function from a conditional expression.
|
|
2445
|
+
*
|
|
2446
|
+
* @param expression The conditional expression to evaluate
|
|
2447
|
+
* @param debounceMs The debounce duration in milliseconds
|
|
2448
|
+
* @returns A LogicFn that evaluates the condition with debouncing
|
|
2025
2449
|
*/
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
} ? ResolveBaseValueType<T, V> | null : ResolveBaseValueType<T, V>;
|
|
2450
|
+
declare function createDebouncedLogicFunction<TValue>(expression: ConditionalExpression, debounceMs: number): LogicFn<TValue, boolean>;
|
|
2451
|
+
|
|
2029
2452
|
/**
|
|
2030
|
-
*
|
|
2031
|
-
*
|
|
2453
|
+
* Compares two values using the specified comparison operator.
|
|
2454
|
+
*
|
|
2455
|
+
* @param actual - The value to compare
|
|
2456
|
+
* @param expected - The value to compare against
|
|
2457
|
+
* @param operator - Comparison operator to use
|
|
2458
|
+
* @returns True if the comparison succeeds, false otherwise
|
|
2032
2459
|
*/
|
|
2033
|
-
|
|
2034
|
-
type: 'hidden';
|
|
2035
|
-
} ? V : T extends {
|
|
2036
|
-
required: true;
|
|
2037
|
-
} ? V : V | undefined;
|
|
2460
|
+
declare function compareValues(actual: unknown, expected: unknown, operator: string): boolean;
|
|
2038
2461
|
/**
|
|
2039
|
-
*
|
|
2040
|
-
*
|
|
2041
|
-
*
|
|
2042
|
-
*
|
|
2462
|
+
* Retrieves a nested value from an object using dot notation path.
|
|
2463
|
+
*
|
|
2464
|
+
* @param obj - The object to traverse
|
|
2465
|
+
* @param path - Dot-separated path to the desired property
|
|
2466
|
+
* @returns The value at the specified path, or undefined if not found
|
|
2043
2467
|
*/
|
|
2044
|
-
|
|
2045
|
-
type: 'slider';
|
|
2046
|
-
} ? number : T extends {
|
|
2047
|
-
type: 'input';
|
|
2048
|
-
props: {
|
|
2049
|
-
type: 'number';
|
|
2050
|
-
};
|
|
2051
|
-
} ? number : T extends {
|
|
2052
|
-
type: 'checkbox' | 'toggle';
|
|
2053
|
-
} ? boolean : T extends {
|
|
2054
|
-
value: infer V;
|
|
2055
|
-
} ? [V] extends [null] ? string : Widen<V, Depth[D]> : string;
|
|
2056
|
-
type InferSingleTemplateValue<T, D extends number> = T extends {
|
|
2057
|
-
nullable: true;
|
|
2058
|
-
} ? InferSingleTemplateValueBase<T, D> | null : InferSingleTemplateValueBase<T, D>;
|
|
2468
|
+
declare function getNestedValue(obj: unknown, path: string): unknown;
|
|
2059
2469
|
/**
|
|
2060
|
-
*
|
|
2061
|
-
*
|
|
2062
|
-
*
|
|
2063
|
-
*
|
|
2064
|
-
*
|
|
2065
|
-
* 4. Full-API array with fields → infer from children
|
|
2470
|
+
* Checks whether a nested property exists in an object using dot notation path.
|
|
2471
|
+
*
|
|
2472
|
+
* @param obj - The object to check
|
|
2473
|
+
* @param path - Dot-separated path to the property
|
|
2474
|
+
* @returns True if the property exists (even if its value is undefined)
|
|
2066
2475
|
*/
|
|
2067
|
-
|
|
2068
|
-
template: unknown;
|
|
2069
|
-
value: readonly (infer Item)[];
|
|
2070
|
-
} ? Widen<Item>[] : T extends {
|
|
2071
|
-
template: infer TArr;
|
|
2072
|
-
} ? TArr extends readonly RegisteredFieldTypes[] ? InferFormValueWithDepth<[...TArr], Depth[D]>[] : InferSingleTemplateValue<TArr, D>[] : T extends {
|
|
2073
|
-
fields: infer F;
|
|
2074
|
-
} ? F extends RegisteredFieldTypes[] ? InferFormValueWithDepth<F, Depth[D]>[] : unknown[] : unknown[];
|
|
2075
|
-
/** Process a single field and determine its contribution to the form value type */
|
|
2076
|
-
type ProcessField<T, D extends number = 5> = [D] extends [never] ? Record<string, unknown> : T extends {
|
|
2077
|
-
type: 'page' | 'row';
|
|
2078
|
-
fields: infer F;
|
|
2079
|
-
} ? F extends RegisteredFieldTypes[] ? InferFormValueWithDepth<F, Depth[D]> : never : T extends {
|
|
2080
|
-
type: 'group';
|
|
2081
|
-
key: infer K;
|
|
2082
|
-
fields: infer F;
|
|
2083
|
-
} ? K extends string ? F extends RegisteredFieldTypes[] ? {
|
|
2084
|
-
[P in K]: InferFormValueWithDepth<F, Depth[D]>;
|
|
2085
|
-
} : {
|
|
2086
|
-
[P in K]: Record<string, unknown>;
|
|
2087
|
-
} : never : T extends {
|
|
2088
|
-
type: 'array';
|
|
2089
|
-
key: infer K;
|
|
2090
|
-
} ? K extends string ? {
|
|
2091
|
-
[P in K]: InferArrayValue<T, D>;
|
|
2092
|
-
} : never : T extends {
|
|
2093
|
-
type: 'text';
|
|
2094
|
-
} ? never : T extends {
|
|
2095
|
-
type: 'submit' | 'button' | 'next' | 'previous' | 'addArrayItem' | 'removeArrayItem';
|
|
2096
|
-
} ? never : T extends {
|
|
2097
|
-
key: infer K;
|
|
2098
|
-
value: infer V;
|
|
2099
|
-
} ? K extends string ? {
|
|
2100
|
-
[P in K]: MaybeOptional<T, InferValueType<T, V>>;
|
|
2101
|
-
} : never : T extends {
|
|
2102
|
-
key: infer K;
|
|
2103
|
-
} ? K extends string ? {
|
|
2104
|
-
[P in K]: MaybeOptional<T, T extends {
|
|
2105
|
-
nullable: true;
|
|
2106
|
-
} ? string | null : string>;
|
|
2107
|
-
} : never : never;
|
|
2108
|
-
/** Internal helper with depth tracking */
|
|
2109
|
-
type InferFormValueWithDepth<T extends RegisteredFieldTypes[], D extends number = 5> = UnionToIntersection<ProcessField<T[number], D>>;
|
|
2110
|
-
/** Helper to extract fields from either fields array or FormConfig */
|
|
2111
|
-
type ExtractFields<T> = T extends {
|
|
2112
|
-
fields: infer TFields;
|
|
2113
|
-
} ? TFields extends readonly RegisteredFieldTypes[] ? TFields : never : T extends readonly RegisteredFieldTypes[] ? T : never;
|
|
2114
|
-
/**
|
|
2115
|
-
* Infer form value type from fields array or FormConfig.
|
|
2116
|
-
* Recursively processes nested structures and merges the results.
|
|
2117
|
-
* Limited to 5 levels of nesting to prevent infinite type instantiation.
|
|
2118
|
-
*/
|
|
2119
|
-
type InferFormValue<T> = ExtractFields<T> extends readonly RegisteredFieldTypes[] ? InferFormValueWithDepth<ExtractFields<T> extends RegisteredFieldTypes[] ? ExtractFields<T> : [...ExtractFields<T>], 5> : never;
|
|
2476
|
+
declare function hasNestedProperty(obj: unknown, path: string): boolean;
|
|
2120
2477
|
|
|
2121
|
-
/**
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
[key: string]: DynamicText | undefined;
|
|
2478
|
+
/** Per-field debounced signal pair. */
|
|
2479
|
+
interface DebouncedSignalPair {
|
|
2480
|
+
immediateValue: WritableSignal<boolean>;
|
|
2481
|
+
debouncedValue: Signal<boolean | undefined>;
|
|
2482
|
+
}
|
|
2483
|
+
/** DI-scoped cache for logic functions and debounced signals. */
|
|
2484
|
+
declare class LogicFunctionCacheService {
|
|
2485
|
+
/** Cache for memoized logic functions, keyed by serialized expression. */
|
|
2486
|
+
readonly logicFunctionCache: Map<string, LogicFn<unknown, boolean>>;
|
|
2487
|
+
/** Cache for debounced logic functions, keyed by serialized expression + debounceMs. */
|
|
2488
|
+
readonly debouncedLogicFunctionCache: Map<string, LogicFn<unknown, boolean>>;
|
|
2489
|
+
/** Per-field signal store for debounced logic, keyed by field path. */
|
|
2490
|
+
readonly debouncedSignalStore: Map<string, DebouncedSignalPair>;
|
|
2135
2491
|
}
|
|
2136
2492
|
|
|
2137
|
-
/**
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
type SubmissionActionResult = Promise<TreeValidationResult> | Observable<TreeValidationResult | unknown>;
|
|
2142
|
-
/**
|
|
2143
|
-
* Configuration for form submission handling.
|
|
2144
|
-
*
|
|
2145
|
-
* @typeParam TValue - The form value type
|
|
2146
|
-
*/
|
|
2147
|
-
interface SubmissionConfig<TValue = unknown> {
|
|
2148
|
-
/**
|
|
2149
|
-
* Action called when the form is submitted.
|
|
2150
|
-
*
|
|
2151
|
-
* @param form - The form's FieldTree instance
|
|
2152
|
-
* @returns Promise or Observable - for errors, return TreeValidationResult
|
|
2153
|
-
*/
|
|
2154
|
-
action: (form: FieldTree<TValue>) => SubmissionActionResult;
|
|
2493
|
+
/** Base error class for all Dynamic Forms errors. */
|
|
2494
|
+
declare class DynamicFormError extends Error {
|
|
2495
|
+
private static readonly PREFIX;
|
|
2496
|
+
constructor(message: string);
|
|
2155
2497
|
}
|
|
2156
2498
|
|
|
2157
|
-
/**
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2499
|
+
/** Token types for expression parsing */
|
|
2500
|
+
declare enum TokenType {
|
|
2501
|
+
NUMBER = "NUMBER",
|
|
2502
|
+
STRING = "STRING",
|
|
2503
|
+
TRUE = "TRUE",
|
|
2504
|
+
FALSE = "FALSE",
|
|
2505
|
+
NULL = "NULL",
|
|
2506
|
+
UNDEFINED = "UNDEFINED",
|
|
2507
|
+
IDENTIFIER = "IDENTIFIER",
|
|
2508
|
+
PLUS = "PLUS",
|
|
2509
|
+
MINUS = "MINUS",
|
|
2510
|
+
MULTIPLY = "MULTIPLY",
|
|
2511
|
+
DIVIDE = "DIVIDE",
|
|
2512
|
+
MODULO = "MODULO",
|
|
2513
|
+
EQUAL = "EQUAL",
|
|
2514
|
+
NOT_EQUAL = "NOT_EQUAL",
|
|
2515
|
+
GREATER = "GREATER",
|
|
2516
|
+
LESS = "LESS",
|
|
2517
|
+
GREATER_EQUAL = "GREATER_EQUAL",
|
|
2518
|
+
LESS_EQUAL = "LESS_EQUAL",
|
|
2519
|
+
AND = "AND",
|
|
2520
|
+
OR = "OR",
|
|
2521
|
+
NOT = "NOT",
|
|
2522
|
+
DOT = "DOT",
|
|
2523
|
+
COMMA = "COMMA",
|
|
2524
|
+
COLON = "COLON",
|
|
2525
|
+
LPAREN = "LPAREN",
|
|
2526
|
+
RPAREN = "RPAREN",
|
|
2527
|
+
LBRACKET = "LBRACKET",
|
|
2528
|
+
RBRACKET = "RBRACKET",
|
|
2529
|
+
LBRACE = "LBRACE",
|
|
2530
|
+
RBRACE = "RBRACE",
|
|
2531
|
+
ARROW = "ARROW",
|
|
2532
|
+
QUESTION = "QUESTION",
|
|
2533
|
+
OPTIONAL_DOT = "OPTIONAL_DOT",
|
|
2534
|
+
EOF = "EOF"
|
|
2189
2535
|
}
|
|
2190
|
-
/**
|
|
2191
|
-
interface
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
derivations?: Record<string, CustomFunction<TFormValue>>;
|
|
2196
|
-
/** Async derivation functions for asynchronous value derivation logic. */
|
|
2197
|
-
asyncDerivations?: Record<string, AsyncDerivationFunction<TFormValue>>;
|
|
2198
|
-
/** Async condition functions for asynchronous field state logic. */
|
|
2199
|
-
asyncConditions?: Record<string, AsyncConditionFunction<TFormValue>>;
|
|
2200
|
-
/** Custom validators using Angular's public FieldContext API */
|
|
2201
|
-
validators?: Record<string, CustomValidator>;
|
|
2202
|
-
/** Async custom validators using Angular's resource-based validateAsync() API */
|
|
2203
|
-
asyncValidators?: Record<string, AsyncCustomValidator>;
|
|
2204
|
-
/** HTTP validators using Angular's validateHttp() API. */
|
|
2205
|
-
httpValidators?: Record<string, HttpCustomValidator>;
|
|
2536
|
+
/** Token with type, value, and position */
|
|
2537
|
+
interface Token {
|
|
2538
|
+
type: TokenType;
|
|
2539
|
+
value: string;
|
|
2540
|
+
position: number;
|
|
2206
2541
|
}
|
|
2207
|
-
/**
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
* @value false
|
|
2213
|
-
*/
|
|
2214
|
-
disabled?: boolean;
|
|
2215
|
-
/**
|
|
2216
|
-
* Prefix scoping every field's DOM `id` (and matching `for` / `data-testid` /
|
|
2217
|
-
* `aria-describedby`) to this form instance, as the outermost id segment:
|
|
2218
|
-
* `{idPrefix}_{group}_{key}_{index}`. Use it when rendering multiple forms
|
|
2219
|
-
* from the same config on one page so their ids don't collide.
|
|
2220
|
-
*
|
|
2221
|
-
* When omitted, a lone form stays unprefixed and a generated prefix (`df-1`,
|
|
2222
|
-
* `df-2`, …) is applied automatically once a second form is mounted. Characters
|
|
2223
|
-
* invalid in an id token (whitespace, punctuation) are replaced with `_`.
|
|
2224
|
-
*
|
|
2225
|
-
* @example
|
|
2226
|
-
* ```typescript
|
|
2227
|
-
* options: { idPrefix: 'billing' } // → id="billing_email-input"
|
|
2228
|
-
* ```
|
|
2229
|
-
*
|
|
2230
|
-
* @default undefined (auto-prefix only when multiple forms are mounted)
|
|
2231
|
-
*/
|
|
2232
|
-
idPrefix?: string;
|
|
2233
|
-
/**
|
|
2234
|
-
* Maximum number of iterations for derivation chain processing.
|
|
2235
|
-
*
|
|
2236
|
-
* @default 10
|
|
2237
|
-
*/
|
|
2238
|
-
maxDerivationIterations?: number;
|
|
2239
|
-
/** Default disabled behavior for submit buttons. */
|
|
2240
|
-
submitButton?: SubmitButtonOptions;
|
|
2241
|
-
/** Default disabled behavior for next page buttons. */
|
|
2242
|
-
nextButton?: NextButtonOptions;
|
|
2243
|
-
/**
|
|
2244
|
-
* Whether to exclude values of hidden fields from submission output.
|
|
2245
|
-
*
|
|
2246
|
-
* @default undefined (uses global setting)
|
|
2247
|
-
*/
|
|
2248
|
-
excludeValueIfHidden?: boolean;
|
|
2249
|
-
/**
|
|
2250
|
-
* Whether to exclude values of disabled fields from submission output.
|
|
2251
|
-
*
|
|
2252
|
-
* @default undefined (uses global setting)
|
|
2253
|
-
*/
|
|
2254
|
-
excludeValueIfDisabled?: boolean;
|
|
2255
|
-
/**
|
|
2256
|
-
* Whether to exclude values of readonly fields from submission output.
|
|
2257
|
-
*
|
|
2258
|
-
* @default undefined (uses global setting)
|
|
2259
|
-
*/
|
|
2260
|
-
excludeValueIfReadonly?: boolean;
|
|
2261
|
-
/**
|
|
2262
|
-
* Whether to run validation when a field is hidden.
|
|
2263
|
-
*
|
|
2264
|
-
* @default undefined (uses global setting, which defaults to `false`)
|
|
2265
|
-
*/
|
|
2266
|
-
validateWhenHidden?: boolean;
|
|
2267
|
-
/**
|
|
2268
|
-
* Whether to attach the current form value to all events dispatched through the EventBus.
|
|
2269
|
-
*
|
|
2270
|
-
* @default undefined (uses global setting)
|
|
2271
|
-
*/
|
|
2272
|
-
emitFormValueOnEvents?: boolean;
|
|
2542
|
+
/** AST Node types */
|
|
2543
|
+
type ASTNode = LiteralNode | IdentifierNode | MemberAccessNode | ComputedMemberAccessNode | BinaryOpNode | UnaryOpNode | CallExpressionNode | ConditionalNode | ArrayLiteralNode | ObjectLiteralNode | ArrowFunctionNode;
|
|
2544
|
+
interface LiteralNode {
|
|
2545
|
+
type: 'Literal';
|
|
2546
|
+
value: string | number | boolean | null | undefined;
|
|
2273
2547
|
}
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2548
|
+
interface IdentifierNode {
|
|
2549
|
+
type: 'Identifier';
|
|
2550
|
+
name: string;
|
|
2551
|
+
}
|
|
2552
|
+
interface MemberAccessNode {
|
|
2553
|
+
type: 'MemberAccess';
|
|
2554
|
+
object: ASTNode;
|
|
2555
|
+
property: string;
|
|
2556
|
+
/** True when this access used `?.` (optional chaining). */
|
|
2557
|
+
optional?: boolean;
|
|
2558
|
+
}
|
|
2559
|
+
interface ComputedMemberAccessNode {
|
|
2560
|
+
type: 'ComputedMemberAccess';
|
|
2561
|
+
object: ASTNode;
|
|
2562
|
+
/** Expression evaluated at runtime to produce the property key. */
|
|
2563
|
+
property: ASTNode;
|
|
2564
|
+
/** True when this access used `?.[ ... ]` (optional chaining). */
|
|
2565
|
+
optional?: boolean;
|
|
2566
|
+
}
|
|
2567
|
+
interface ConditionalNode {
|
|
2568
|
+
type: 'Conditional';
|
|
2569
|
+
test: ASTNode;
|
|
2570
|
+
consequent: ASTNode;
|
|
2571
|
+
alternate: ASTNode;
|
|
2572
|
+
}
|
|
2573
|
+
interface BinaryOpNode {
|
|
2574
|
+
type: 'BinaryOp';
|
|
2575
|
+
operator: string;
|
|
2576
|
+
left: ASTNode;
|
|
2577
|
+
right: ASTNode;
|
|
2578
|
+
}
|
|
2579
|
+
interface UnaryOpNode {
|
|
2580
|
+
type: 'UnaryOp';
|
|
2581
|
+
operator: string;
|
|
2582
|
+
operand: ASTNode;
|
|
2583
|
+
}
|
|
2584
|
+
interface CallExpressionNode {
|
|
2585
|
+
type: 'CallExpression';
|
|
2586
|
+
callee: ASTNode;
|
|
2587
|
+
arguments: ASTNode[];
|
|
2588
|
+
/** True when this call used `?.( ... )` (optional chaining). */
|
|
2589
|
+
optional?: boolean;
|
|
2590
|
+
}
|
|
2591
|
+
interface ArrayLiteralNode {
|
|
2592
|
+
type: 'ArrayLiteral';
|
|
2593
|
+
elements: ASTNode[];
|
|
2594
|
+
}
|
|
2595
|
+
interface ObjectLiteralNode {
|
|
2596
|
+
type: 'ObjectLiteral';
|
|
2597
|
+
properties: Array<{
|
|
2598
|
+
key: string;
|
|
2599
|
+
value: ASTNode;
|
|
2600
|
+
}>;
|
|
2601
|
+
}
|
|
2602
|
+
interface ArrowFunctionNode {
|
|
2603
|
+
type: 'ArrowFunction';
|
|
2604
|
+
params: string[];
|
|
2605
|
+
body: ASTNode;
|
|
2606
|
+
}
|
|
2607
|
+
/** Parser error with position information */
|
|
2608
|
+
declare class ExpressionParserError extends DynamicFormError {
|
|
2609
|
+
position: number;
|
|
2610
|
+
expression: string;
|
|
2611
|
+
constructor(message: string, position: number, expression: string);
|
|
2612
|
+
}
|
|
2613
|
+
|
|
2614
|
+
/** Evaluation context for safe expression evaluation */
|
|
2615
|
+
interface EvaluationScope {
|
|
2616
|
+
[key: string]: unknown;
|
|
2617
|
+
}
|
|
2618
|
+
/** Safely evaluates an AST node with a given context */
|
|
2619
|
+
declare class Evaluator {
|
|
2620
|
+
private readonly scope;
|
|
2621
|
+
private readonly expression;
|
|
2622
|
+
constructor(scope: EvaluationScope, expression: string);
|
|
2623
|
+
/** Evaluate an AST node */
|
|
2624
|
+
evaluate(node: ASTNode): unknown;
|
|
2625
|
+
private evaluateIdentifier;
|
|
2626
|
+
private evaluateMemberAccess;
|
|
2627
|
+
private evaluateComputedMemberAccess;
|
|
2628
|
+
private evaluateBinaryOp;
|
|
2629
|
+
private evaluateUnaryOp;
|
|
2630
|
+
private evaluateCallExpression;
|
|
2631
|
+
private evaluateArrayLiteral;
|
|
2632
|
+
private evaluateObjectLiteral;
|
|
2633
|
+
private evaluateArrowFunction;
|
|
2634
|
+
private isMethodSafe;
|
|
2635
|
+
}
|
|
2636
|
+
|
|
2637
|
+
/** Secure expression parser that uses AST-based evaluation */
|
|
2638
|
+
declare class ExpressionParser {
|
|
2282
2639
|
/**
|
|
2283
|
-
*
|
|
2284
|
-
*
|
|
2285
|
-
* @default true
|
|
2640
|
+
* Parse an expression string into an AST
|
|
2641
|
+
* Results are cached for performance using LRU eviction
|
|
2286
2642
|
*/
|
|
2287
|
-
|
|
2643
|
+
static parse(expression: string): ASTNode;
|
|
2644
|
+
/** Evaluate an expression with a given scope */
|
|
2645
|
+
static evaluate(expression: string, scope: EvaluationScope): unknown;
|
|
2646
|
+
/** Clear the AST cache */
|
|
2647
|
+
static clearCache(): void;
|
|
2648
|
+
/** Get cache statistics */
|
|
2649
|
+
static getCacheStats(): {
|
|
2650
|
+
size: number;
|
|
2651
|
+
maxSize: number;
|
|
2652
|
+
};
|
|
2288
2653
|
}
|
|
2289
|
-
|
|
2290
|
-
|
|
2654
|
+
|
|
2655
|
+
/**
|
|
2656
|
+
* Parses tokens into an Abstract Syntax Tree (AST)
|
|
2657
|
+
* Uses recursive descent parsing with operator precedence
|
|
2658
|
+
*/
|
|
2659
|
+
declare class Parser {
|
|
2660
|
+
private tokens;
|
|
2661
|
+
private current;
|
|
2662
|
+
private readonly expression;
|
|
2663
|
+
constructor(expression: string);
|
|
2664
|
+
/** Parse the expression into an AST */
|
|
2665
|
+
parse(): ASTNode;
|
|
2666
|
+
private parseExpression;
|
|
2291
2667
|
/**
|
|
2292
|
-
*
|
|
2293
|
-
*
|
|
2294
|
-
* @default true
|
|
2668
|
+
* Ternary `test ? consequent : alternate` — right-associative, sits between
|
|
2669
|
+
* the arrow-function check and logical-or in precedence.
|
|
2295
2670
|
*/
|
|
2296
|
-
|
|
2671
|
+
private parseConditional;
|
|
2297
2672
|
/**
|
|
2298
|
-
*
|
|
2299
|
-
*
|
|
2300
|
-
* @default true
|
|
2673
|
+
* Attempts to parse an arrow function. Returns null and leaves position
|
|
2674
|
+
* unchanged if the next tokens don't form an arrow function head.
|
|
2301
2675
|
*/
|
|
2302
|
-
|
|
2676
|
+
private tryParseArrowFunction;
|
|
2677
|
+
private checkAt;
|
|
2678
|
+
private parseLogicalOr;
|
|
2679
|
+
private parseLogicalAnd;
|
|
2680
|
+
private parseEquality;
|
|
2681
|
+
private parseComparison;
|
|
2682
|
+
private parseAddition;
|
|
2683
|
+
private parseMultiplication;
|
|
2684
|
+
private parseUnary;
|
|
2685
|
+
private parsePostfix;
|
|
2686
|
+
private parsePrimary;
|
|
2687
|
+
private parseArgumentList;
|
|
2688
|
+
private parseArrayElements;
|
|
2689
|
+
private parseObjectProperties;
|
|
2690
|
+
private match;
|
|
2691
|
+
private check;
|
|
2692
|
+
private advance;
|
|
2693
|
+
private isAtEnd;
|
|
2694
|
+
private peek;
|
|
2695
|
+
private previous;
|
|
2696
|
+
private consume;
|
|
2303
2697
|
}
|
|
2304
2698
|
|
|
2305
|
-
/**
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
/** Optional logger for diagnostic output. Falls back to no-op logger if not provided. */
|
|
2320
|
-
logger?: Logger;
|
|
2699
|
+
/** Tokenizes an expression string into tokens */
|
|
2700
|
+
declare class Tokenizer {
|
|
2701
|
+
private position;
|
|
2702
|
+
private readonly expression;
|
|
2703
|
+
constructor(expression: string);
|
|
2704
|
+
/** Tokenize the entire expression */
|
|
2705
|
+
tokenize(): Token[];
|
|
2706
|
+
private skipWhitespace;
|
|
2707
|
+
private nextToken;
|
|
2708
|
+
private readString;
|
|
2709
|
+
private readNumber;
|
|
2710
|
+
private readIdentifierOrKeyword;
|
|
2711
|
+
private getKeywordType;
|
|
2712
|
+
private readOperatorOrPunctuation;
|
|
2321
2713
|
}
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
*/
|
|
2332
|
-
type NonFieldLogicConfig = LogicConfig & {
|
|
2333
|
-
type: NonFieldLogicType;
|
|
2334
|
-
};
|
|
2335
|
-
/** Context for resolving state (hidden/disabled) for non-form-bound elements. */
|
|
2336
|
-
interface NonFieldLogicContext {
|
|
2337
|
-
/** The form's FieldTree instance (supports both string and number keys for array indices) */
|
|
2338
|
-
form: FieldTree<unknown, string | number>;
|
|
2339
|
-
/**
|
|
2340
|
-
* Field-level logic array containing conditions.
|
|
2341
|
-
* Accepts full LogicConfig[] for compatibility, but only hidden and disabled types are processed.
|
|
2342
|
-
*/
|
|
2343
|
-
fieldLogic?: LogicConfig[];
|
|
2344
|
-
/** Explicit state from field definition (e.g., `hidden: true` or `disabled: true`) */
|
|
2345
|
-
explicitValue?: boolean;
|
|
2346
|
-
/** Current form value for evaluating conditional expressions */
|
|
2347
|
-
formValue?: unknown;
|
|
2348
|
-
/** Optional logger for diagnostic output. Falls back to no-op logger if not provided. */
|
|
2349
|
-
logger?: Logger;
|
|
2714
|
+
|
|
2715
|
+
/** TTL cache for HTTP condition responses with max entries eviction. */
|
|
2716
|
+
declare class HttpConditionCache {
|
|
2717
|
+
private readonly cache;
|
|
2718
|
+
private readonly maxEntries;
|
|
2719
|
+
constructor(maxEntries?: number);
|
|
2720
|
+
get(key: string): boolean | undefined;
|
|
2721
|
+
set(key: string, value: boolean, ttlMs: number): void;
|
|
2722
|
+
clear(): void;
|
|
2350
2723
|
}
|
|
2724
|
+
/** @internal */
|
|
2725
|
+
declare const HTTP_CONDITION_CACHE: InjectionToken<HttpConditionCache>;
|
|
2726
|
+
|
|
2351
2727
|
/**
|
|
2352
|
-
* Resolves
|
|
2353
|
-
*
|
|
2354
|
-
* @param ctx - The button logic context
|
|
2355
|
-
* @returns A computed signal that returns true when the button should be disabled
|
|
2356
|
-
*/
|
|
2357
|
-
declare function resolveSubmitButtonDisabled(ctx: ButtonLogicContext): Signal<boolean>;
|
|
2358
|
-
/**
|
|
2359
|
-
* Resolves the disabled state for a next page button.
|
|
2360
|
-
*
|
|
2361
|
-
* @param ctx - The button logic context
|
|
2362
|
-
* @returns A computed signal that returns true when the button should be disabled
|
|
2363
|
-
*/
|
|
2364
|
-
declare function resolveNextButtonDisabled(ctx: ButtonLogicContext): Signal<boolean>;
|
|
2365
|
-
/**
|
|
2366
|
-
* Evaluates the hidden state for non-form-bound elements synchronously.
|
|
2367
|
-
*
|
|
2368
|
-
* @param ctx - The context containing form, logic array, and explicit hidden state
|
|
2369
|
-
* @returns true when the element should be hidden
|
|
2370
|
-
*/
|
|
2371
|
-
declare function evaluateNonFieldHidden(ctx: NonFieldLogicContext): boolean;
|
|
2372
|
-
/**
|
|
2373
|
-
* Resolves the hidden state for non-form-bound elements as a reactive signal.
|
|
2374
|
-
*
|
|
2375
|
-
* @param ctx - The context containing form, logic array, and explicit hidden state
|
|
2376
|
-
* @returns A computed signal that returns true when the element should be hidden
|
|
2377
|
-
*/
|
|
2378
|
-
declare function resolveNonFieldHidden(ctx: NonFieldLogicContext): Signal<boolean>;
|
|
2379
|
-
/**
|
|
2380
|
-
* Evaluates the disabled state for non-form-bound elements synchronously.
|
|
2381
|
-
*
|
|
2382
|
-
* @param ctx - The context containing form, logic array, and explicit disabled state
|
|
2383
|
-
* @returns true when the element should be disabled
|
|
2384
|
-
*/
|
|
2385
|
-
declare function evaluateNonFieldDisabled(ctx: NonFieldLogicContext): boolean;
|
|
2386
|
-
/**
|
|
2387
|
-
* Resolves the disabled state for non-form-bound elements as a reactive signal.
|
|
2388
|
-
*
|
|
2389
|
-
* @param ctx - The context containing form, logic array, and explicit disabled state
|
|
2390
|
-
* @returns A computed signal that returns true when the element should be disabled
|
|
2728
|
+
* Resolves an `HttpRequestConfig` into an `HttpResourceRequest` by evaluating
|
|
2729
|
+
* expression-based query params and (optionally) body values.
|
|
2391
2730
|
*/
|
|
2392
|
-
declare function
|
|
2731
|
+
declare function resolveHttpRequest(config: HttpRequestConfig, context: EvaluationContext): HttpResourceRequest | null;
|
|
2732
|
+
|
|
2733
|
+
/** Evaluates an HTTP response against a `HttpValidationResponseMapping` to produce a validation result. */
|
|
2734
|
+
declare function evaluateHttpValidationResponse(response: unknown, mapping: HttpValidationResponseMapping, logger: Logger): ValidationError$1 | null;
|
|
2393
2735
|
|
|
2394
2736
|
/**
|
|
2395
2737
|
* Service that provides field evaluation context by combining
|
|
@@ -2903,142 +3245,22 @@ declare function pageFieldMapper(fieldDef: PageField): Signal<Record<string, unk
|
|
|
2903
3245
|
*/
|
|
2904
3246
|
declare function textFieldMapper(fieldDef: TextField): Signal<Record<string, unknown>>;
|
|
2905
3247
|
|
|
3248
|
+
/** Handler signature for user-registered addon actions. */
|
|
3249
|
+
type AddonActionHandler<TValue = unknown> = (ctx: AddonActionContext<TValue>) => void;
|
|
2906
3250
|
/**
|
|
2907
|
-
*
|
|
2908
|
-
*
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
/**
|
|
2912
|
-
* Identity of the host field this addon is attached to. Empty strings
|
|
2913
|
-
* indicate the addon is rendered outside an active field context (rare).
|
|
2914
|
-
* Use {@link isFieldBoundContext} or the `form !== null` check to
|
|
2915
|
-
* narrow before relying on field identity.
|
|
2916
|
-
*/
|
|
2917
|
-
readonly field: {
|
|
2918
|
-
readonly key: string;
|
|
2919
|
-
readonly type: string;
|
|
2920
|
-
};
|
|
2921
|
-
/**
|
|
2922
|
-
* Current value of the host field at the time the action fires.
|
|
2923
|
-
* `undefined` when the host field has no value yet (initial render before
|
|
2924
|
-
* defaultValue resolution) or when the addon is rendered outside a field.
|
|
2925
|
-
*/
|
|
2926
|
-
readonly value: TValue | undefined;
|
|
2927
|
-
}
|
|
2928
|
-
/**
|
|
2929
|
-
* Field-bound variant — the addon is attached to a real field and has a
|
|
2930
|
-
* working value-writer. The common case for `pi-button` / `mat-button` /
|
|
2931
|
-
* `bs-button` / `ion-button` inside an adapter input field.
|
|
2932
|
-
*/
|
|
2933
|
-
interface FieldBoundAddonActionContext<TValue = unknown> extends AddonActionContextBase<TValue> {
|
|
2934
|
-
/** Read-only view of the host field's tree — same view wrappers receive. */
|
|
2935
|
-
readonly form: ReadonlyFieldTree<TValue>;
|
|
2936
|
-
/** Push a new value into the host field. */
|
|
2937
|
-
readonly setValue: (next: TValue) => void;
|
|
2938
|
-
}
|
|
2939
|
-
/**
|
|
2940
|
-
* Orphan variant — the addon is rendered outside any field component (rare;
|
|
2941
|
-
* happens when consumers compose `<df-addon-slot>` directly without a host
|
|
2942
|
-
* field). No writer is reachable; reading `value` may also yield `undefined`.
|
|
2943
|
-
*/
|
|
2944
|
-
interface OrphanAddonActionContext<TValue = unknown> extends AddonActionContextBase<TValue> {
|
|
2945
|
-
readonly form: null;
|
|
2946
|
-
/** Always absent in the orphan variant — distinguishes the union members. */
|
|
2947
|
-
readonly setValue?: undefined;
|
|
2948
|
-
}
|
|
2949
|
-
/** Context handed to inline addon actions and registered handler functions. */
|
|
2950
|
-
type AddonActionContext<TValue = unknown> = FieldBoundAddonActionContext<TValue> | OrphanAddonActionContext<TValue>;
|
|
2951
|
-
/** Type guard narrowing {@link AddonActionContext} to its field-bound variant. */
|
|
2952
|
-
declare function isFieldBoundContext<TValue>(ctx: AddonActionContext<TValue>): ctx is FieldBoundAddonActionContext<TValue>;
|
|
2953
|
-
/** Built-in preset actions shared across adapters. */
|
|
2954
|
-
type CommonAddonActionPreset = 'clear' | 'reset' | 'paste' | 'copy' | 'toggle-password-visibility';
|
|
2955
|
-
/** Module-augmentable registry of adapter-specific preset names. */
|
|
2956
|
-
interface DynamicFormAddonActionPresetRegistry {
|
|
2957
|
-
}
|
|
2958
|
-
/**
|
|
2959
|
-
* Union of every preset name an addon may reference — universal presets
|
|
2960
|
-
* plus any contributed via {@link DynamicFormAddonActionPresetRegistry}.
|
|
2961
|
-
*/
|
|
2962
|
-
type AddonActionPreset = CommonAddonActionPreset | keyof DynamicFormAddonActionPresetRegistry | (string & {});
|
|
2963
|
-
/** Module-augmentable registry of user-defined named action handlers. */
|
|
2964
|
-
interface DynamicFormActionRegistry {
|
|
2965
|
-
}
|
|
2966
|
-
/**
|
|
2967
|
-
* Typed string handle to a registered action handler. The empty registry
|
|
2968
|
-
* resolves to `never`; augmenting `DynamicFormActionRegistry` populates the
|
|
2969
|
-
* union and unlocks autocomplete.
|
|
2970
|
-
*/
|
|
2971
|
-
type RegisteredActionRef = keyof DynamicFormActionRegistry;
|
|
2972
|
-
|
|
2973
|
-
/**
|
|
2974
|
-
* Minimal JSON Schema fragment used by the MCP server to surface an addon
|
|
2975
|
-
* kind's shape to AI form generators. Covers the common subset
|
|
2976
|
-
* (`type`/`properties`/`required`/`enum`/etc.) without pulling in a full JSON
|
|
2977
|
-
* Schema dependency. Extra keys are allowed via the `[key: string]` index so
|
|
2978
|
-
* vendor-specific annotations (`x-foo`, `markdownDescription`) still typecheck.
|
|
3251
|
+
* Multi-provider token populated by `withAddonActions({...})` calls.
|
|
3252
|
+
* `ADDON_ACTION_REGISTRY` aggregates these into a single name → handler map.
|
|
3253
|
+
*
|
|
3254
|
+
* @internal
|
|
2979
3255
|
*/
|
|
2980
|
-
|
|
2981
|
-
readonly $ref?: string;
|
|
2982
|
-
readonly $schema?: string;
|
|
2983
|
-
readonly title?: string;
|
|
2984
|
-
readonly description?: string;
|
|
2985
|
-
readonly type?: 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null' | ReadonlyArray<'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null'>;
|
|
2986
|
-
readonly enum?: ReadonlyArray<unknown>;
|
|
2987
|
-
readonly const?: unknown;
|
|
2988
|
-
readonly properties?: Readonly<Record<string, AddonKindSchema>>;
|
|
2989
|
-
readonly required?: ReadonlyArray<string>;
|
|
2990
|
-
readonly additionalProperties?: boolean | AddonKindSchema;
|
|
2991
|
-
readonly items?: AddonKindSchema | ReadonlyArray<AddonKindSchema>;
|
|
2992
|
-
readonly oneOf?: ReadonlyArray<AddonKindSchema>;
|
|
2993
|
-
readonly anyOf?: ReadonlyArray<AddonKindSchema>;
|
|
2994
|
-
readonly allOf?: ReadonlyArray<AddonKindSchema>;
|
|
2995
|
-
readonly not?: AddonKindSchema;
|
|
2996
|
-
readonly default?: unknown;
|
|
2997
|
-
readonly examples?: ReadonlyArray<unknown>;
|
|
2998
|
-
readonly minimum?: number;
|
|
2999
|
-
readonly maximum?: number;
|
|
3000
|
-
readonly minLength?: number;
|
|
3001
|
-
readonly maxLength?: number;
|
|
3002
|
-
readonly pattern?: string;
|
|
3003
|
-
readonly format?: string;
|
|
3004
|
-
/** Vendor extensions and unrecognised keywords pass through untyped. */
|
|
3005
|
-
readonly [key: string]: unknown;
|
|
3006
|
-
}
|
|
3256
|
+
declare const ADDON_ACTION_HANDLERS: InjectionToken<readonly Record<string, AddonActionHandler<unknown>>[]>;
|
|
3007
3257
|
/**
|
|
3008
|
-
*
|
|
3009
|
-
*
|
|
3010
|
-
*
|
|
3258
|
+
* Form-scoped name → handler map. Read by adapter button types at click
|
|
3259
|
+
* time for `actionRef: 'name'` lookups. Provided at form scope (not root)
|
|
3260
|
+
* because `ADDON_ACTION_HANDLERS` is form-scoped via `withAddonActions`.
|
|
3011
3261
|
*/
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
interface AddonKindDefinition<T extends BaseAddon = BaseAddon> {
|
|
3015
|
-
/** Discriminant matching `addon.kind`. */
|
|
3016
|
-
readonly kind: string;
|
|
3017
|
-
/** Lazy loader for the kind's renderer component. */
|
|
3018
|
-
readonly loadComponent: LazyComponentLoader;
|
|
3019
|
-
/** Optional shape validator — throw `DynamicFormError` to drop the addon with a warning. */
|
|
3020
|
-
readonly validate?: AddonShapeValidator<T>;
|
|
3021
|
-
/** Optional JSON Schema fragment for MCP / pre-flight tooling. */
|
|
3022
|
-
readonly schema?: AddonKindSchema;
|
|
3023
|
-
/**
|
|
3024
|
-
* Whether the kind survives `JSON.stringify` / `JSON.parse`. Kinds whose
|
|
3025
|
-
* shape includes a function payload (e.g., the built-in `'component'`
|
|
3026
|
-
* loader, inline `prime-button` `action` handlers) declare `jsonSafe: false`
|
|
3027
|
-
* so the validator drops them when the config was loaded from a JSON
|
|
3028
|
-
* source (`sanitizeFormConfig(config, { source: 'json' })`). Defaults to
|
|
3029
|
-
* `true` — kinds are JSON-safe unless explicitly opted out.
|
|
3030
|
-
*/
|
|
3031
|
-
readonly jsonSafe?: boolean;
|
|
3032
|
-
}
|
|
3033
|
-
/** Per-field-type addon-support metadata declared at field registration. */
|
|
3034
|
-
interface FieldAddonSupport {
|
|
3035
|
-
/** Slots a field of this type accepts. */
|
|
3036
|
-
readonly slots: readonly AddonSlot[];
|
|
3037
|
-
/** Optional whitelist of allowed addon kinds. Omitted = any registered kind. */
|
|
3038
|
-
readonly allowedKinds?: readonly string[];
|
|
3039
|
-
}
|
|
3040
|
-
/** Global registry of addon kinds. */
|
|
3041
|
-
declare const ADDON_KIND_REGISTRY: InjectionToken<Map<string, AddonKindDefinition<BaseAddon<AddonSlot>>>>;
|
|
3262
|
+
declare const ADDON_ACTION_REGISTRY: InjectionToken<ReadonlyMap<string, AddonActionHandler<unknown>>>;
|
|
3263
|
+
declare function createAddonActionRegistry(): ReadonlyMap<string, AddonActionHandler>;
|
|
3042
3264
|
|
|
3043
3265
|
/**
|
|
3044
3266
|
* Map of named `TemplateRef`s collected by `<df-dynamic-form>` from
|
|
@@ -3483,26 +3705,5 @@ declare function safeReadPathKeys(fieldContext: FieldContext<unknown>): readonly
|
|
|
3483
3705
|
*/
|
|
3484
3706
|
declare function stableStringify(value: unknown): string;
|
|
3485
3707
|
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
readonly key: string;
|
|
3489
|
-
/** Field-type discriminant (mirrors `FieldDef.type`) — useful for kind-aware addons. */
|
|
3490
|
-
readonly type?: string;
|
|
3491
|
-
readonly label?: string;
|
|
3492
|
-
readonly placeholder?: string;
|
|
3493
|
-
readonly className?: string;
|
|
3494
|
-
readonly props?: Record<string, unknown>;
|
|
3495
|
-
readonly validationMessages?: Record<string, string>;
|
|
3496
|
-
readonly defaultValidationMessages?: Record<string, string>;
|
|
3497
|
-
readonly field?: ReadonlyFieldTree;
|
|
3498
|
-
/**
|
|
3499
|
-
* Write a value into the wrapped field's tree. Provided by `buildFieldInputs`
|
|
3500
|
-
* when a `FieldTree` is present. Addons (e.g., `prime-button` presets) use this
|
|
3501
|
-
* to mutate the host field; wrappers should treat the field as read-only.
|
|
3502
|
-
*/
|
|
3503
|
-
readonly setValue?: (next: unknown) => void;
|
|
3504
|
-
readonly [key: string]: unknown;
|
|
3505
|
-
}
|
|
3506
|
-
|
|
3507
|
-
export { ADDON_KIND_REGISTRY, ARRAY_CONTEXT, AsyncConditionFunctionCacheService, ComponentInitializedEvent, DEFAULT_PROPS, DEFAULT_VALIDATION_MESSAGES, DEFAULT_WRAPPERS, DEPRECATION_WARNING_TRACKER, DF_FIELD_TEMPLATES, DynamicFormError, DynamicFormLogger, DynamicTextPipe, DynamicValueFunctionCacheService, EMIT_FORM_VALUE_ON_EVENTS, EXTERNAL_DATA, Evaluator, EventBus, ExpressionParser, ExpressionParserError, FIELD_REGISTRY, FIELD_SIGNAL_CONTEXT, FORM_ID_PREFIX, FORM_OPTIONS, FieldContextRegistryService, FunctionRegistryService, GROUP_CONTEXT, HTTP_CONDITION_CACHE, HttpConditionCache, HttpConditionFunctionCacheService, INITIALIZATION_TIMEOUT_MS, LogicFunctionCacheService, NoopLogger, Parser, READONLY_FIELD_TREE_CACHE, RootFormRegistryService, TokenType, Tokenizer, WRAPPER_AUTO_ASSOCIATIONS, WRAPPER_COMPONENT_CACHE, WRAPPER_REGISTRY, applyHiddenLogic, applyMetaToElement, applyValidator, applyValidators, arrayFieldMapper, assertNever, baseFieldMapper, buildBaseInputs, buildClassName, compareValues, containerFieldMapper, createAsyncConditionLogicFunction, createDebouncedLogicFunction, createDebouncedResourceLogicFn, createDefaultDerivationLogConfig, createDynamicValueFunction, createFormFieldStateMap, createHttpConditionLogicFunction, createInitializationTracker, createLogicFunction, createWarningTracker, deepMergeDefaults, derivedFromDeferred, detectFormMode, dynamicTextToObservable, evaluateCondition, evaluateHttpValidationResponse, evaluateNonFieldDisabled, evaluateNonFieldHidden, extractExpressionDependencies, extractStringDependencies, getArrayLength, getChangedKeys, getFieldValueHandling, getGridClassString, getNestedValue, groupFieldMapper, hasChildFields, hasCrossFieldWhenCondition, hasFormValue, hasNestedProperty, hasTargetProperty, injectFieldSignalContext, interpolateParams, isArrayField, isCheckedField, isContainerField, isContainerTypedField, isCrossFieldBuiltInValidator, isCrossFieldExpression, isCrossFieldSchema, isCrossFieldStateLogic, isCrossFieldValidator, isDerivationLogicConfig, isDisplayOnlyField, isEqual, isFieldBoundContext, isFormStateCondition, isFunctionHttpValidator, isGroupField, isHiddenField, isLeafField, isNonPagedForm, isPageField, isPagedForm, isResourceBasedValidator, isRowField, isSimplifiedArrayField, isStateLogicConfig, isValidNonPagedForm, isValidPagedForm, isValueBearingField, isValueField, isWrapperTypeDefinition, keyBy, mapValues, memoize, normalizeFieldsArray, omit, pageFieldMapper, readFieldStateInfo, resolveDynamicValue, resolveHttpRequest, resolveNextButtonDisabled, resolveNonFieldDisabled, resolveNonFieldHidden, resolveSubmitButtonDisabled, resolveTokens, rowFieldMapper, safeReadPathKeys, setupInitializationTracking, shouldLog, stableStringify, textFieldMapper, toReadonlyFieldTree, toReadonlyFieldTreeCached, validatePageNesting, withPreviousValue, writeToFieldValue };
|
|
3508
|
-
export type { ASTNode, AddonActionContext, AddonActionPreset, AddonKindDefinition, AddonKindSchema, AddonShapeValidator, AddonSlot, AndCondition, AnyAddon, ArrayAllowedChildren, ArrayButtonConfig, ArrayComponent, ArrayContext, ArrayField, ArrayFieldTree, ArrayItemDefinition, ArrayItemTemplate, ArrayLiteralNode, ArrowFunctionNode, AsyncCondition, AsyncConditionFunction, AsyncCustomValidator, AsyncDerivationFunction, AsyncValidatorConfig, AvailableFieldTypes, BaseAddon, BaseCheckedField, BaseValidatorConfig, BaseValueField, BinaryOpNode, BuiltInValidatorConfig, ButtonLogicContext, CallExpressionNode, CheckedFieldComponent, CommonAddonActionPreset, CommonAddonSlot, ComparisonOperator, ComponentAddon, ComputedMemberAccessNode, ConditionalExpression, ConditionalNode, ContainerAllowedChildren, ContainerComponent, ContainerField, ContainerFieldTypes, ContainerLogicConfig, CrossFieldDetectionContext, CssWrapper, CustomCondition, CustomFnConfig, CustomFunction, CustomFunctionOptions, CustomFunctionScope, CustomValidator, CustomValidatorConfig, DebouncedResourceLogicFnConfig, DeclarativeHttpValidatorConfig, DerivationLogConfig, DerivationLogLevel, DerivationLogicConfig, DerivedFromDeferredOptions, DynamicFormActionRegistry, DynamicFormAddonActionPresetRegistry, DynamicFormAddonRegistry, DynamicFormAddonSlotRegistry, DynamicFormFieldRegistry, DynamicText, DynamicValue, EvaluationContext, EvaluationScope, ExtractField, FieldAddonSupport, FieldBoundAddonActionContext, FieldComponent, FieldDef, FieldMeta, FieldOption, FieldPathAccess, FieldRegistryContainers, FieldRegistryLeaves, FieldRegistryWrappers, FieldScope, FieldSignalContext, FieldStateContext, FieldStateInfo, FieldTreeRecord, FieldTypeDefinition, FieldValueCondition, FieldWithValidation, FieldWrapper, FormConfig, FormEvent, FormEventConstructor, FormFieldStateMap, FormMode, FormModeDetectionResult, FormOptions, FormStateCondition, FunctionHttpValidatorConfig, GroupAllowedChildren, GroupComponent, GroupContext, GroupField, HiddenField, HiddenScalar, HiddenValue, HttpCondition, HttpCustomValidator, HttpRequestConfig, HttpResourceRequest, HttpValidationResponseMapping, IdentifierNode, InferFormValue, InitializationTrackingOptions, JavascriptCondition, LazyComponentLoader, LeafFieldTypes, LiteralNode, Logger, LogicConfig, LogicTrigger, MapperFn, MemberAccessNode, MemoizeOptions, NarrowField, NarrowFields, NextButtonOptions, NonFieldLogicConfig, NonFieldLogicContext, NonFieldLogicType, ObjectLiteralNode, OrCondition, OrphanAddonActionContext, PageAllowedChildren, PageField, Prettify, ReadonlyFieldTree, RegisteredActionRef, RegisteredFieldTypes, RegisteredWrapperTypes, RenderReadyInput, ResolvedValidationExecutionConfig, ResolvedValueExclusionConfig, RowAllowedChildren, RowComponent, RowField, RowWrapper, SchemaApplicationConfig, SchemaDefinition, SimplifiedArrayField, StateLogicConfig, StateLogicType, SubmissionActionResult, SubmissionConfig, SubmitButtonOptions, TemplateAddon, TextAddon, TextElementType, TextField, TextProps, Token, TokenContext, Trigger, UnaryOpNode, ValidationError, ValidationExecutionConfig, ValidationMessages, ValidatorConfig, ValueExclusionConfig, ValueFieldComponent, ValueHandlingMode, ValueType, WarningTracker, WithInputSignals, WrapperAutoAssociations, WrapperConfig, WrapperFieldInputs, WrapperTypeDefinition };
|
|
3708
|
+
export { ADDON_ACTION_HANDLERS, ADDON_ACTION_REGISTRY, ADDON_TYPE_COMPONENT_CACHE, ADDON_TYPE_DEFINITIONS, ADDON_TYPE_REGISTRY, ARRAY_CONTEXT, AsyncConditionFunctionCacheService, ComponentInitializedEvent, DEFAULT_PROPS, DEFAULT_VALIDATION_MESSAGES, DEFAULT_WRAPPERS, DEPRECATION_WARNING_TRACKER, DF_FIELD_TEMPLATES, DfAddonSlot, DynamicFormError, DynamicFormLogger, DynamicTextPipe, DynamicValueFunctionCacheService, EMIT_FORM_VALUE_ON_EVENTS, EXTERNAL_DATA, Evaluator, EventBus, ExpressionParser, ExpressionParserError, FIELD_REGISTRY, FIELD_SIGNAL_CONTEXT, FORM_ID_PREFIX, FORM_OPTIONS, FieldContextRegistryService, FunctionRegistryService, GROUP_CONTEXT, HTTP_CONDITION_CACHE, HttpConditionCache, HttpConditionFunctionCacheService, INITIALIZATION_TIMEOUT_MS, LogicFunctionCacheService, NoopLogger, Parser, READONLY_FIELD_TREE_CACHE, RootFormRegistryService, TokenType, Tokenizer, WRAPPER_AUTO_ASSOCIATIONS, WRAPPER_COMPONENT_CACHE, WRAPPER_REGISTRY, applyHiddenLogic, applyMetaToElement, applyValidator, applyValidators, arrayFieldMapper, assertNever, baseFieldMapper, buildBaseInputs, buildClassName, compareValues, containerFieldMapper, createAddonActionRegistry, createAsyncConditionLogicFunction, createDebouncedLogicFunction, createDebouncedResourceLogicFn, createDefaultDerivationLogConfig, createDynamicValueFunction, createFormFieldStateMap, createHttpConditionLogicFunction, createInitializationTracker, createLogicFunction, createWarningTracker, deepMergeDefaults, derivedFromDeferred, detectFormMode, dynamicTextToObservable, evaluateCondition, evaluateHttpValidationResponse, evaluateNonFieldDisabled, evaluateNonFieldHidden, extractExpressionDependencies, extractStringDependencies, getArrayLength, getChangedKeys, getFieldValueHandling, getGridClassString, getNestedValue, groupFieldMapper, hasChildFields, hasCrossFieldWhenCondition, hasFormValue, hasNestedProperty, hasTargetProperty, injectAddonTypeRegistry, injectFieldSignalContext, injectFieldsSupportingAddons, interpolateParams, isArrayField, isCheckedField, isContainerField, isCrossFieldBuiltInValidator, isCrossFieldExpression, isCrossFieldSchema, isCrossFieldStateLogic, isCrossFieldValidator, isDerivationLogicConfig, isDisplayOnlyField, isEqual, isFieldBoundContext, isFormStateCondition, isFunctionHttpValidator, isGenericContainerField, isGroupField, isHiddenField, isLeafField, isNonPagedForm, isPageField, isPagedForm, isResourceBasedValidator, isRowField, isSimplifiedArrayField, isStateLogicConfig, isValidNonPagedForm, isValidPagedForm, isValueBearingField, isValueField, isWrapperTypeDefinition, keyBy, mapValues, memoize, normalizeFieldsArray, omit, pageFieldMapper, readFieldStateInfo, resolveDynamicValue, resolveHttpRequest, resolveNextButtonDisabled, resolveNonFieldDisabled, resolveNonFieldHidden, resolveSubmitButtonDisabled, resolveTokens, rowFieldMapper, runPresetAction, safeReadPathKeys, setupInitializationTracking, shouldLog, stableStringify, textFieldMapper, toReadonlyFieldTree, toReadonlyFieldTreeCached, validatePageNesting, withPreviousValue, writeToFieldValue };
|
|
3709
|
+
export type { ASTNode, AddonActionContext, AddonActionHandler, AddonActionPreset, AddonShapeValidator, AddonSlot, AddonTypeDefinition, AddonTypeRegistryRef, AddonTypeSchema, AndCondition, AnyAddon, ArrayAllowedChildren, ArrayButtonConfig, ArrayComponent, ArrayContext, ArrayField, ArrayFieldTree, ArrayItemDefinition, ArrayItemTemplate, ArrayLiteralNode, ArrowFunctionNode, AsyncCondition, AsyncConditionFunction, AsyncCustomValidator, AsyncDerivationFunction, AsyncValidatorConfig, AvailableFieldTypes, BaseAddon, BaseCheckedField, BaseValidatorConfig, BaseValueField, BinaryOpNode, BuiltInValidatorConfig, ButtonLogicContext, CallExpressionNode, CheckedFieldComponent, CommonAddonActionPreset, CommonAddonSlot, ComparisonOperator, ComponentAddon, ComputedMemberAccessNode, ConditionalExpression, ConditionalNode, ContainerAllowedChildren, ContainerComponent, ContainerField, ContainerFieldTypes, ContainerLogicConfig, CrossFieldDetectionContext, CssWrapper, CustomCondition, CustomFnConfig, CustomFunction, CustomFunctionOptions, CustomFunctionScope, CustomValidator, CustomValidatorConfig, DebouncedResourceLogicFnConfig, DeclarativeHttpValidatorConfig, DerivationLogConfig, DerivationLogLevel, DerivationLogicConfig, DerivedFromDeferredOptions, DynamicFormActionRegistry, DynamicFormAddonActionPresetRegistry, DynamicFormAddonRegistry, DynamicFormAddonSlotRegistry, DynamicFormFieldRegistry, DynamicText, DynamicValue, EvaluationContext, EvaluationScope, ExtractField, FieldAddonSupport, FieldAddonSupportEntry, FieldBoundAddonActionContext, FieldComponent, FieldDef, FieldMeta, FieldOption, FieldPathAccess, FieldRegistryContainers, FieldRegistryLeaves, FieldRegistryWrappers, FieldScope, FieldSignalContext, FieldStateContext, FieldStateInfo, FieldTreeRecord, FieldTypeDefinition, FieldValueCondition, FieldWithValidation, FieldWrapper, FormConfig, FormEvent, FormEventConstructor, FormFieldStateMap, FormMode, FormModeDetectionResult, FormOptions, FormStateCondition, FunctionHttpValidatorConfig, GroupAllowedChildren, GroupComponent, GroupContext, GroupField, HiddenField, HiddenScalar, HiddenValue, HttpCondition, HttpCustomValidator, HttpRequestConfig, HttpResourceRequest, HttpValidationResponseMapping, IdentifierNode, InferFormModel, InferFormValue, InitializationTrackingOptions, JavascriptCondition, LazyComponentLoader, LeafFieldTypes, LiteralNode, Logger, LogicConfig, LogicTrigger, MapperFn, MemberAccessNode, MemoizeOptions, NarrowField, NarrowFields, NextButtonOptions, NonFieldLogicConfig, NonFieldLogicContext, NonFieldLogicType, ObjectLiteralNode, OrCondition, OrphanAddonActionContext, PageAllowedChildren, PageField, PresetCollaborators, Prettify, ReadonlyFieldTree, RegisteredActionRef, RegisteredFieldTypes, RegisteredWrapperTypes, RenderReadyInput, ResolvedValidationExecutionConfig, ResolvedValueExclusionConfig, RowAllowedChildren, RowComponent, RowField, RowWrapper, SchemaApplicationConfig, SchemaDefinition, SimplifiedArrayField, StateLogicConfig, StateLogicType, SubmissionActionResult, SubmissionConfig, SubmitButtonOptions, TemplateAddon, TextAddon, TextElementType, TextField, TextProps, Token, TokenContext, Trigger, UnaryOpNode, ValidationError, ValidationExecutionConfig, ValidationMessages, ValidatorConfig, ValueExclusionConfig, ValueFieldComponent, ValueHandlingMode, ValueType, WarningTracker, WithInputSignals, WrapperAutoAssociations, WrapperConfig, WrapperFieldInputs, WrapperTypeDefinition };
|