@ng-forge/dynamic-forms 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3462 @@
1
+ import * as rxjs from 'rxjs';
2
+ import { Observable } from 'rxjs';
3
+ import * as _angular_forms from '@angular/forms';
4
+ import * as _angular_forms_signals from '@angular/forms/signals';
5
+ import { ValidationError as ValidationError$1, FieldContext, TreeValidationResult, FieldTree, Schema, form, SchemaPath, SchemaPathTree } from '@angular/forms/signals';
6
+ import * as _ng_forge_dynamic_forms from '@ng-forge/dynamic-forms';
7
+ import * as _angular_core from '@angular/core';
8
+ import { Signal, ResourceRef, Injector, WritableSignal, InjectionToken, Type, OnDestroy, InputSignal, EnvironmentProviders, PipeTransform } from '@angular/core';
9
+
10
+ type WithInputSignals<T> = {
11
+ readonly [K in keyof T]-?: Signal<T[K]>;
12
+ };
13
+
14
+ type Prettify<T> = {
15
+ [K in keyof T]: T[K];
16
+ } & {};
17
+
18
+ type DynamicText = string | Observable<string> | Signal<string>;
19
+
20
+ /**
21
+ * Base interface for all dynamic form field definitions.
22
+ *
23
+ * This interface defines the common properties that all field types must implement.
24
+ * Field-specific properties are defined through the generic TProps parameter,
25
+ * providing type safety for field-specific configuration.
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * // Basic text input field
30
+ * const textField: FieldDef<{ placeholder: string }> = {
31
+ * key: 'email',
32
+ * type: 'input',
33
+ * label: 'Email Address',
34
+ * props: { placeholder: 'Enter your email' },
35
+ * col: 12
36
+ * };
37
+ * ```
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * // Complex field with conditional logic
42
+ * const conditionalField: FieldDef<SelectProps> = {
43
+ * key: 'country',
44
+ * type: 'select',
45
+ * label: 'Country',
46
+ * props: {
47
+ * options: [
48
+ * { label: 'United States', value: 'us' },
49
+ * { label: 'Canada', value: 'ca' }
50
+ * ]
51
+ * },
52
+ * hidden: false,
53
+ * disabled: false,
54
+ * col: 6
55
+ * };
56
+ * ```
57
+ *
58
+ * @typeParam TProps - Field-specific properties interface
59
+ *
60
+ * @public
61
+ */
62
+ interface FieldDef<TProps> {
63
+ /**
64
+ * Unique field identifier used for form binding and value tracking.
65
+ *
66
+ * This key is used to associate the field with form values and must be
67
+ * unique within the form. It follows object property naming conventions.
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * // Simple field key
72
+ * key: 'email'
73
+ *
74
+ * // Nested object notation
75
+ * key: 'address.street'
76
+ *
77
+ * // Array notation
78
+ * key: 'hobbies[0]'
79
+ * ```
80
+ */
81
+ key: string;
82
+ /**
83
+ * Field type identifier for component selection.
84
+ *
85
+ * Determines which component will be rendered for this field.
86
+ * Must match a registered field type name in the field registry.
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * type: 'input' // Text input field
91
+ * type: 'select' // Dropdown selection
92
+ * type: 'checkbox' // Boolean checkbox
93
+ * type: 'group' // Field group container
94
+ * ```
95
+ */
96
+ type: string;
97
+ /**
98
+ * Human-readable field label displayed to users.
99
+ *
100
+ * Provides accessible labeling for form fields and is typically
101
+ * displayed above or beside the field input. Supports static strings,
102
+ * translation keys, Observables, and Signals for dynamic content.
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * // Static string
107
+ * label: 'Email Address'
108
+ *
109
+ * // Translation key (auto-detected)
110
+ * label: 'form.email.label'
111
+ *
112
+ * // Observable from translation service
113
+ * label: this.transloco.selectTranslate('form.email.label')
114
+ *
115
+ * // Signal-based
116
+ * label: computed(() => this.translations().email.label)
117
+ * ```
118
+ */
119
+ label?: DynamicText;
120
+ /**
121
+ * Field-specific properties and configuration options.
122
+ *
123
+ * Contains type-specific configuration that varies based on the field type.
124
+ * The shape is defined by the TProps generic parameter.
125
+ *
126
+ * @example
127
+ * ```typescript
128
+ * // Input field props
129
+ * props: { placeholder: 'Enter email', type: 'email' }
130
+ *
131
+ * // Select field props
132
+ * props: { options: [{ label: 'Yes', value: true }], multiple: false }
133
+ *
134
+ * // Button field props
135
+ * props: { buttonType: 'submit', variant: 'primary' }
136
+ * ```
137
+ */
138
+ props?: TProps;
139
+ /**
140
+ * Additional CSS classes for custom styling.
141
+ *
142
+ * Space-separated string of CSS class names that will be applied
143
+ * to the field container for custom styling.
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * className: 'highlight required-field'
148
+ * className: 'mt-4 text-center'
149
+ * ```
150
+ */
151
+ className?: string;
152
+ /**
153
+ * Whether the field is disabled and cannot be interacted with.
154
+ *
155
+ * When true, the field is rendered in a disabled state and cannot
156
+ * receive user input. The value can still be modified programmatically.
157
+ *
158
+ * @value false
159
+ */
160
+ disabled?: boolean;
161
+ /**
162
+ * Whether the field is read-only.
163
+ *
164
+ * When true, the field displays its value but cannot be modified
165
+ * by user interaction. Differs from disabled in styling and accessibility.
166
+ *
167
+ * @value false
168
+ */
169
+ readonly?: boolean;
170
+ /**
171
+ * Whether the field is hidden from view.
172
+ *
173
+ * When true, the field is not rendered in the UI but still participates
174
+ * in form state and validation. Useful for conditional field display.
175
+ *
176
+ * @value false
177
+ */
178
+ hidden?: boolean;
179
+ /**
180
+ * Tab index for keyboard navigation.
181
+ *
182
+ * Controls the order in which fields receive focus when navigating
183
+ * with the Tab key. Follows standard HTML tabindex behavior.
184
+ *
185
+ * @example
186
+ * ```typescript
187
+ * tabIndex: 1 // First field in tab order
188
+ * tabIndex: -1 // Excluded from tab navigation
189
+ * tabIndex: 0 // Natural tab order
190
+ * ```
191
+ */
192
+ tabIndex?: number | undefined;
193
+ /**
194
+ * Column sizing configuration for responsive grid layout.
195
+ *
196
+ * Specifies how many columns this field should span in a 12-column
197
+ * grid system. Supports responsive behavior and field arrangement.
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * col: 12 // Full width
202
+ * col: 6 // Half width
203
+ * col: 4 // One third width
204
+ * col: 3 // Quarter width
205
+ * ```
206
+ *
207
+ * @value 12
208
+ */
209
+ col?: number;
210
+ }
211
+ type IncludedKeys = 'label' | 'className' | 'hidden' | 'tabIndex';
212
+ /**
213
+ * Type utility for extracting component input properties from field definitions.
214
+ *
215
+ * Transforms field definition properties into Angular component input signals,
216
+ * enabling type-safe component binding with automatic signal creation.
217
+ *
218
+ * @example
219
+ * ```typescript
220
+ * // Field definition
221
+ * interface MyFieldDef extends FieldDef<MyProps> {
222
+ * customProp: string;
223
+ * }
224
+ *
225
+ * // Component using FieldComponent type
226
+ * @Component({...})
227
+ * export class MyFieldComponent implements FieldComponent<MyFieldDef> {
228
+ * label = input<string>();
229
+ * className = input<string>();
230
+ * hidden = input<boolean>();
231
+ * tabIndex = input<number>();
232
+ * }
233
+ * ```
234
+ *
235
+ * @typeParam T - Field definition type to extract properties from
236
+ *
237
+ * @public
238
+ */
239
+ type FieldComponent<T extends FieldDef<any>> = Prettify<WithInputSignals<Pick<T, IncludedKeys>>>;
240
+
241
+ /**
242
+ * Re-export Angular's ValidationError for consistency
243
+ * This replaces our custom ValidationError interface
244
+ */
245
+ type ValidationError = ValidationError$1;
246
+ interface ValidationMessages {
247
+ required?: DynamicText;
248
+ email?: DynamicText;
249
+ min?: DynamicText;
250
+ max?: DynamicText;
251
+ minLength?: DynamicText;
252
+ maxLength?: DynamicText;
253
+ pattern?: DynamicText;
254
+ [key: string]: DynamicText | undefined;
255
+ }
256
+
257
+ /**
258
+ * Row field interface for creating horizontal layouts
259
+ * This is a special field type that contains other definitions arranged horizontally
260
+ * The row itself doesn't have a value - it's a layout container
261
+ * This is a programmatic field type only - users cannot customize this field type
262
+ *
263
+ * TypeScript cannot enforce field nesting rules due to circular dependency limitations.
264
+ * For documentation: Rows should contain groups and leaf fields, but NOT pages or other rows.
265
+ * Runtime validation enforces these rules.
266
+ */
267
+ interface RowField<TFields extends readonly RowAllowedChildren[] = readonly RowAllowedChildren[]> extends FieldDef<never> {
268
+ type: 'row';
269
+ /** Child definitions to render within this row */
270
+ readonly fields: TFields;
271
+ /** Row fields do not have a label property **/
272
+ readonly label?: never;
273
+ }
274
+ /**
275
+ * Type guard for RowField with proper type narrowing
276
+ */
277
+ declare function isRowField(field: FieldDef<any>): field is RowField;
278
+
279
+ /**
280
+ * Group field interface for creating logical field groupings that map to object values
281
+ * Groups create nested form structures where child field values are collected into an object
282
+ * This is a programmatic grouping only - users cannot customize this field type
283
+ *
284
+ * TypeScript cannot enforce field nesting rules due to circular dependency limitations.
285
+ * For documentation: Groups should contain rows and leaf fields, but NOT pages or other groups.
286
+ * Runtime validation enforces these rules.
287
+ */
288
+ interface GroupField<TFields extends readonly GroupAllowedChildren[] = readonly GroupAllowedChildren[]> extends FieldDef<never> {
289
+ type: 'group';
290
+ readonly fields: TFields;
291
+ /** Groups do not have a label property - they are logical containers only **/
292
+ readonly label?: never;
293
+ }
294
+ /**
295
+ * Type guard for GroupField with proper type narrowing
296
+ */
297
+ declare function isGroupField(field: FieldDef<any>): field is GroupField;
298
+
299
+ /**
300
+ * Type constraints for field nesting rules
301
+ * These ensure that container fields can only contain valid child field types
302
+ *
303
+ * Note: We explicitly list types instead of using Exclude to avoid circular dependencies
304
+ */
305
+ /**
306
+ * Fields that are allowed as children of Page fields
307
+ * Pages can contain: rows, groups, arrays, and leaf fields (but NOT other pages)
308
+ */
309
+ type PageAllowedChildren = LeafFieldTypes | RowField | GroupField | ArrayField;
310
+ /**
311
+ * Fields that are allowed as children of Row fields
312
+ * Rows can contain: groups, arrays, and leaf fields (but NOT pages or other rows)
313
+ */
314
+ type RowAllowedChildren = LeafFieldTypes | GroupField | ArrayField;
315
+ /**
316
+ * Fields that are allowed as children of Group fields
317
+ * Groups can contain: rows and leaf fields (but NOT pages or other groups)
318
+ */
319
+ type GroupAllowedChildren = LeafFieldTypes | RowField;
320
+ /**
321
+ * Fields that are allowed as children of Array fields
322
+ * Arrays can contain: rows, groups, and leaf fields (but NOT pages or other arrays)
323
+ * Groups are used for creating object arrays where each array item is an object
324
+ */
325
+ type ArrayAllowedChildren = LeafFieldTypes | RowField | GroupField;
326
+
327
+ /**
328
+ * Array field interface for creating dynamic field collections that map to array values.
329
+ *
330
+ * Key concepts:
331
+ * - The `fields` array defines the TEMPLATE (single field definition), not instances
332
+ * - Array items are created/removed dynamically at runtime via event bus
333
+ * - For primitive arrays: Use a leaf field as template → `['value1', 'value2']`
334
+ * - For object arrays: Use a group field as template → `[{key1: val1}, {key2: val2}]`
335
+ *
336
+ * @example
337
+ * // Primitive array (flat values)
338
+ * {
339
+ * key: 'tags',
340
+ * type: 'array',
341
+ * fields: [{ key: 'tag', type: 'input' }]
342
+ * }
343
+ * // Creates: { tags: ['tag1', 'tag2', 'tag3'] }
344
+ *
345
+ * @example
346
+ * // Object array (nested groups)
347
+ * {
348
+ * key: 'contacts',
349
+ * type: 'array',
350
+ * fields: [{
351
+ * type: 'group',
352
+ * fields: [
353
+ * { key: 'name', type: 'input' },
354
+ * { key: 'email', type: 'input' }
355
+ * ]
356
+ * }]
357
+ * }
358
+ * // Creates: { contacts: [{name: '', email: ''}, {name: '', email: ''}] }
359
+ *
360
+ * Nesting constraints: Arrays can contain rows, leaf fields, or groups (for object arrays),
361
+ * but NOT pages or other arrays. Runtime validation enforces these rules.
362
+ */
363
+ interface ArrayField<TFields extends readonly ArrayAllowedChildren[] = readonly ArrayAllowedChildren[]> extends FieldDef<never> {
364
+ type: 'array';
365
+ /**
366
+ * Template field definition(s) that will be cloned for each array item.
367
+ * Typically contains a single field definition:
368
+ * - For flat arrays: A leaf field (input, select, checkbox, etc.)
369
+ * - For object arrays: A group field containing multiple child fields
370
+ */
371
+ readonly fields: TFields;
372
+ /** Array fields do not have a label property **/
373
+ readonly label?: never;
374
+ }
375
+ /**
376
+ * Type guard for ArrayField with proper type narrowing
377
+ */
378
+ declare function isArrayField(field: FieldDef<any>): field is ArrayField;
379
+
380
+ interface ConditionalExpression {
381
+ /** Expression type */
382
+ type: 'fieldValue' | 'formValue' | 'custom' | 'javascript' | 'and' | 'or';
383
+ /** Field path for fieldValue type */
384
+ fieldPath?: string;
385
+ /** Comparison operator */
386
+ operator?: 'equals' | 'notEquals' | 'greater' | 'less' | 'greaterOrEqual' | 'lessOrEqual' | 'contains' | 'startsWith' | 'endsWith' | 'matches';
387
+ /** Value to compare against */
388
+ value?: unknown;
389
+ /** JavaScript expression for custom logic */
390
+ expression?: string;
391
+ /** Array of sub-conditions for 'and' and 'or' types */
392
+ conditions?: ConditionalExpression[];
393
+ }
394
+
395
+ /**
396
+ * Logic configuration for page fields.
397
+ * Pages only support the 'hidden' logic type since they are layout containers,
398
+ * not form controls (they can't be readonly, disabled, or required).
399
+ */
400
+ interface PageLogicConfig {
401
+ /** Only 'hidden' is supported for pages */
402
+ type: 'hidden';
403
+ /**
404
+ * Condition that determines when this page is hidden.
405
+ * Can be a boolean or a conditional expression evaluated against form values.
406
+ */
407
+ condition: ConditionalExpression | boolean;
408
+ }
409
+ /**
410
+ * Page field interface for creating top-level page layouts
411
+ * This is a special field type that contains other field definitions
412
+ * The page itself doesn't have a value - it's a layout container like row
413
+ * Pages can only be used at the top level and cannot be nested
414
+ * This is a programmatic field type only - users cannot customize this field type
415
+ *
416
+ * TypeScript cannot enforce field nesting rules due to circular dependency limitations.
417
+ * For documentation: Pages should contain rows, groups, and leaf fields, but NOT other pages.
418
+ * Runtime validation enforces these rules.
419
+ */
420
+ interface PageField<TFields extends readonly PageAllowedChildren[] = PageAllowedChildren[]> extends FieldDef<never> {
421
+ type: 'page';
422
+ /** Child field definitions to render within this page */
423
+ readonly fields: TFields;
424
+ /** Page fields do not have a label property **/
425
+ readonly label?: never;
426
+ /**
427
+ * Logic configurations for conditional page visibility.
428
+ * Only 'hidden' type logic is supported for pages.
429
+ *
430
+ * @example
431
+ * ```typescript
432
+ * {
433
+ * key: 'businessPage',
434
+ * type: 'page',
435
+ * logic: [{
436
+ * type: 'hidden',
437
+ * condition: {
438
+ * type: 'fieldValue',
439
+ * fieldPath: 'accountType',
440
+ * operator: 'notEquals',
441
+ * value: 'business',
442
+ * },
443
+ * }],
444
+ * fields: [...]
445
+ * }
446
+ * ```
447
+ */
448
+ readonly logic?: PageLogicConfig[];
449
+ }
450
+ /**
451
+ * Type guard for PageField with proper type narrowing
452
+ */
453
+ declare function isPageField(field: FieldDef<unknown>): field is PageField;
454
+
455
+ /**
456
+ * Special form-state conditions for button disabled logic.
457
+ *
458
+ * These conditions evaluate form or page-level state rather than field values,
459
+ * and are primarily used for controlling button disabled states.
460
+ *
461
+ * @example
462
+ * ```typescript
463
+ * // Disable submit button when form is invalid or submitting
464
+ * {
465
+ * key: 'submit',
466
+ * type: 'submit',
467
+ * label: 'Submit',
468
+ * logic: [
469
+ * { type: 'disabled', condition: 'formInvalid' },
470
+ * { type: 'disabled', condition: 'formSubmitting' },
471
+ * ]
472
+ * }
473
+ *
474
+ * // Disable next button when current page is invalid
475
+ * nextButton({
476
+ * key: 'next',
477
+ * label: 'Next',
478
+ * logic: [
479
+ * { type: 'disabled', condition: 'pageInvalid' },
480
+ * ]
481
+ * })
482
+ * ```
483
+ *
484
+ * @public
485
+ */
486
+ type FormStateCondition =
487
+ /** True when form.valid() === false */
488
+ 'formInvalid'
489
+ /** True when form.submitting() === true */
490
+ | 'formSubmitting'
491
+ /** True when fields on the current page are invalid (for paged forms) */
492
+ | 'pageInvalid';
493
+ /**
494
+ * Configuration for conditional field logic.
495
+ *
496
+ * Defines how field behavior changes based on conditions.
497
+ * Supports hiding, disabling, making readonly, or requiring fields
498
+ * based on form state or field values.
499
+ *
500
+ * @example
501
+ * ```typescript
502
+ * // Hide email field when contact method is not email
503
+ * {
504
+ * type: 'hidden',
505
+ * condition: {
506
+ * type: 'fieldValue',
507
+ * fieldPath: 'contactMethod',
508
+ * operator: 'notEquals',
509
+ * value: 'email'
510
+ * }
511
+ * }
512
+ *
513
+ * // Disable button when form is submitting
514
+ * {
515
+ * type: 'disabled',
516
+ * condition: 'formSubmitting'
517
+ * }
518
+ * ```
519
+ *
520
+ * @public
521
+ */
522
+ interface LogicConfig {
523
+ /**
524
+ * Logic type identifier.
525
+ *
526
+ * - `hidden`: Hide the field from view (still participates in form state)
527
+ * - `readonly`: Make the field read-only
528
+ * - `disabled`: Disable user interaction
529
+ * - `required`: Make the field required
530
+ */
531
+ type: 'hidden' | 'readonly' | 'disabled' | 'required';
532
+ /**
533
+ * Condition that determines when this logic applies.
534
+ *
535
+ * Can be:
536
+ * - `boolean`: Static value (always applies or never applies)
537
+ * - `ConditionalExpression`: Expression evaluated against field/form values
538
+ * - `FormStateCondition`: Special form/page state check (for buttons)
539
+ *
540
+ * @example
541
+ * ```typescript
542
+ * // Static condition
543
+ * condition: true
544
+ *
545
+ * // Field value condition
546
+ * condition: {
547
+ * type: 'fieldValue',
548
+ * fieldPath: 'status',
549
+ * operator: 'equals',
550
+ * value: 'locked'
551
+ * }
552
+ *
553
+ * // Form state condition (for buttons)
554
+ * condition: 'formSubmitting'
555
+ * ```
556
+ */
557
+ condition: ConditionalExpression | boolean | FormStateCondition;
558
+ }
559
+ /**
560
+ * Type guard to check if a condition is a FormStateCondition.
561
+ *
562
+ * @param condition - The condition to check
563
+ * @returns true if the condition is a FormStateCondition
564
+ *
565
+ * @public
566
+ */
567
+ declare function isFormStateCondition(condition: LogicConfig['condition']): condition is FormStateCondition;
568
+
569
+ /**
570
+ * Text element type for rendering different HTML text elements
571
+ */
572
+ type TextElementType = 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'span';
573
+ /**
574
+ * Properties for text field configuration
575
+ */
576
+ type TextProps = {
577
+ /** The HTML element type to render */
578
+ elementType: TextElementType;
579
+ };
580
+ /**
581
+ * Text field definition for displaying translatable text content
582
+ */
583
+ interface TextField extends FieldDef<TextProps> {
584
+ type: 'text';
585
+ /** Logic rules for conditional visibility (hidden, readonly, disabled) */
586
+ readonly logic?: LogicConfig[];
587
+ }
588
+
589
+ /**
590
+ * Container fields registry - augment this interface to add custom container fields
591
+ *
592
+ * @example
593
+ * ```typescript
594
+ * declare module '@ng-forge/dynamic-forms' {
595
+ * interface FieldRegistryContainers {
596
+ * 'my-container': MyContainerFieldDef;
597
+ * }
598
+ * }
599
+ * ```
600
+ */
601
+ interface FieldRegistryContainers {
602
+ page: PageField;
603
+ row: RowField;
604
+ group: GroupField;
605
+ array: ArrayField;
606
+ }
607
+ /**
608
+ * Leaf fields registry - augment this interface to add custom leaf fields
609
+ *
610
+ * @example
611
+ * ```typescript
612
+ * declare module '@ng-forge/dynamic-forms' {
613
+ * interface FieldRegistryLeaves {
614
+ * 'my-input': MyInputFieldDef;
615
+ * }
616
+ * }
617
+ * ```
618
+ */
619
+ interface FieldRegistryLeaves {
620
+ text: TextField;
621
+ }
622
+ /**
623
+ * Global interface for dynamic form field definitions with categorization
624
+ * This interface combines containers and leaves from their respective registries
625
+ *
626
+ * Container fields: Layout fields that contain other fields (page, row, group, array)
627
+ * Leaf fields: Fields that can hold values or display content (input, text, etc.)
628
+ *
629
+ * To add custom fields, augment FieldRegistryContainers or FieldRegistryLeaves
630
+ */
631
+ interface DynamicFormFieldRegistry {
632
+ /**
633
+ * Container fields that hold other fields (no value, have children)
634
+ */
635
+ containers: FieldRegistryContainers;
636
+ /**
637
+ * Leaf fields that have values or display content
638
+ */
639
+ leaves: FieldRegistryLeaves;
640
+ }
641
+ /**
642
+ * Union type of all registered container field definitions
643
+ */
644
+ type ContainerFieldTypes = DynamicFormFieldRegistry['containers'][keyof DynamicFormFieldRegistry['containers']];
645
+ /**
646
+ * Union type of all registered leaf field definitions
647
+ */
648
+ type LeafFieldTypes = DynamicFormFieldRegistry['leaves'][keyof DynamicFormFieldRegistry['leaves']];
649
+ /**
650
+ * Union type of all registered field definitions
651
+ */
652
+ type RegisteredFieldTypes = ContainerFieldTypes | LeafFieldTypes;
653
+ /**
654
+ * Extract field types that are available in the registry
655
+ */
656
+ type AvailableFieldTypes = keyof DynamicFormFieldRegistry['containers'] | keyof DynamicFormFieldRegistry['leaves'];
657
+
658
+ /**
659
+ * Helper type to convert union to intersection
660
+ * Note: `any` is necessary for distributive conditional types
661
+ */
662
+ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
663
+ /**
664
+ * Depth counter for recursion limiting (prevents infinite type instantiation)
665
+ */
666
+ type Depth = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
667
+ /**
668
+ * Process a single field and determine its contribution to the form value type
669
+ * Handles:
670
+ * - Page fields: flatten children (valueHandling: 'flatten')
671
+ * - Row fields: flatten children (valueHandling: 'flatten')
672
+ * - Group fields: nest children under group key (valueHandling: 'include')
673
+ * - Text fields: exclude from values (valueHandling: 'exclude')
674
+ * - Value fields: include with their key and value type
675
+ */
676
+ type ProcessField<T, D extends number = 5> = [D] extends [never] ? Record<string, unknown> : T extends {
677
+ type: 'page';
678
+ fields: infer TFields;
679
+ } ? TFields extends RegisteredFieldTypes[] ? InferFormValueWithDepth<TFields, Depth[D]> : never : T extends {
680
+ type: 'row';
681
+ fields: infer TFields;
682
+ } ? TFields extends RegisteredFieldTypes[] ? InferFormValueWithDepth<TFields, Depth[D]> : never : T extends {
683
+ type: 'group';
684
+ key: infer K;
685
+ fields: infer TFields;
686
+ } ? K extends string ? TFields extends RegisteredFieldTypes[] ? {
687
+ [P in K]: InferFormValueWithDepth<TFields, Depth[D]>;
688
+ } : {
689
+ [P in K]: Record<string, unknown>;
690
+ } : never : T extends {
691
+ type: 'text';
692
+ } ? never : T extends {
693
+ key: infer K;
694
+ value: infer V;
695
+ required: true;
696
+ } ? K extends string ? {
697
+ [P in K]: V;
698
+ } : never : T extends {
699
+ key: infer K;
700
+ value: infer V;
701
+ } ? K extends string ? {
702
+ [P in K]: V | undefined;
703
+ } : never : never;
704
+ /**
705
+ * Internal helper with depth tracking
706
+ */
707
+ type InferFormValueWithDepth<T extends RegisteredFieldTypes[], D extends number = 5> = UnionToIntersection<ProcessField<T[number], D>>;
708
+ /**
709
+ * Infer form value type from an array of field definitions
710
+ * Recursively processes nested structures and merges the results
711
+ * Limited to 5 levels of nesting to prevent infinite type instantiation
712
+ *
713
+ * @example
714
+ * ```typescript
715
+ * const fields = [
716
+ * { type: 'input', key: 'email', value: '', required: true },
717
+ * { type: 'group', key: 'address', fields: [
718
+ * { type: 'input', key: 'street', value: '' },
719
+ * { type: 'input', key: 'city', value: '' }
720
+ * ]}
721
+ * ] as const;
722
+ *
723
+ * type FormValue = InferFormValue<typeof fields>;
724
+ * // Result: { email: string; address: { street?: string; city?: string } }
725
+ * ```
726
+ */
727
+ type InferFormValue$1<T extends RegisteredFieldTypes[]> = InferFormValueWithDepth<T, 5>;
728
+
729
+ /**
730
+ * Base configuration shared by all validators
731
+ */
732
+ interface BaseValidatorConfig {
733
+ /** Conditional logic for when validator applies */
734
+ when?: ConditionalExpression;
735
+ }
736
+ /**
737
+ * Built-in validator configuration (required, email, min, max, etc.)
738
+ */
739
+ interface BuiltInValidatorConfig extends BaseValidatorConfig {
740
+ /** Validator type identifier */
741
+ type: 'required' | 'email' | 'min' | 'max' | 'minLength' | 'maxLength' | 'pattern';
742
+ /** Static value for the validator (e.g., min value, pattern) */
743
+ value?: number | string | RegExp;
744
+ /** Dynamic value expression that evaluates to validator parameter */
745
+ expression?: string;
746
+ }
747
+ /**
748
+ * Custom validator configuration using Angular's public FieldContext API
749
+ * Returns ValidationError | ValidationError[] | null synchronously
750
+ *
751
+ * Supports two patterns:
752
+ * 1. Function-based: { type: 'custom', functionName: 'myValidator' }
753
+ * 2. Expression-based: { type: 'custom', expression: 'fieldValue === formValue.password', kind: 'passwordMismatch' }
754
+ */
755
+ interface CustomValidatorConfig extends BaseValidatorConfig {
756
+ /** Validator type identifier */
757
+ type: 'custom';
758
+ /** Name of registered validator function (function-based pattern) */
759
+ functionName?: string;
760
+ /** Optional parameters to pass to validator function */
761
+ params?: Record<string, unknown>;
762
+ /** JavaScript expression to evaluate (expression-based pattern) */
763
+ expression?: string;
764
+ /** Error kind for expression-based validators - links to validationMessages */
765
+ kind?: string;
766
+ /**
767
+ * Parameters to include in error object for message interpolation (expression-based pattern)
768
+ * Map of parameter names to expressions that will be evaluated in the same context as the validation expression
769
+ *
770
+ * @example
771
+ * errorParams: {
772
+ * minValue: 'formValue.minValue',
773
+ * maxValue: 'formValue.maxValue'
774
+ * }
775
+ * // Allows message template: "Value must be between {{minValue}} and {{maxValue}}"
776
+ */
777
+ errorParams?: Record<string, string>;
778
+ }
779
+ /**
780
+ * Async custom validator configuration using Angular's validateAsync API
781
+ * Returns Observable<ValidationError | ValidationError[] | null>
782
+ */
783
+ interface AsyncValidatorConfig extends BaseValidatorConfig {
784
+ /** Validator type identifier */
785
+ type: 'customAsync';
786
+ /** Name of registered async validator function */
787
+ functionName: string;
788
+ /** Optional parameters to pass to validator function */
789
+ params?: Record<string, unknown>;
790
+ }
791
+ /**
792
+ * HTTP validator configuration using Angular's validateHttp API
793
+ * Provides optimized HTTP validation with automatic request cancellation
794
+ */
795
+ interface HttpValidatorConfig extends BaseValidatorConfig {
796
+ /** Validator type identifier */
797
+ type: 'customHttp';
798
+ /** Name of registered HTTP validator configuration */
799
+ functionName: string;
800
+ /** Optional parameters to pass to HTTP validator */
801
+ params?: Record<string, unknown>;
802
+ }
803
+ /**
804
+ * Configuration for signal forms validator functions that can be serialized from API
805
+ * Discriminated union type for type-safe validator configuration
806
+ */
807
+ type ValidatorConfig = BuiltInValidatorConfig | CustomValidatorConfig | AsyncValidatorConfig | HttpValidatorConfig;
808
+
809
+ /**
810
+ * Configuration for applying predefined schemas
811
+ */
812
+ interface SchemaApplicationConfig {
813
+ /** Schema application type */
814
+ type: 'apply' | 'applyWhen' | 'applyWhenValue' | 'applyEach';
815
+ /** Schema identifier or inline schema definition */
816
+ schema: string | SchemaDefinition;
817
+ /** Condition for conditional application */
818
+ condition?: ConditionalExpression;
819
+ /** Type predicate for applyWhenValue */
820
+ typePredicate?: string;
821
+ }
822
+ /**
823
+ * Reusable schema definition that can be referenced by name
824
+ */
825
+ interface SchemaDefinition {
826
+ /** Unique schema identifier */
827
+ name: string;
828
+ /** Schema description */
829
+ description?: string;
830
+ /** Field path pattern this schema applies to */
831
+ pathPattern?: string;
832
+ /** Validators to apply */
833
+ validators?: ValidatorConfig[];
834
+ /** Logic rules to apply */
835
+ logic?: LogicConfig[];
836
+ /** Nested schema applications */
837
+ subSchemas?: SchemaApplicationConfig[];
838
+ }
839
+
840
+ /**
841
+ * Custom validator function signature using Angular's public FieldContext API
842
+ *
843
+ * Takes FieldContext (full Angular context) and optional params, returns validation error(s) or null.
844
+ * Provides access to field state, form hierarchy, and other fields for validation logic.
845
+ *
846
+ * **Use FieldContext public APIs to access:**
847
+ * - Current field value: `ctx.value()`
848
+ * - Field state: `ctx.state` (errors, touched, dirty, etc.)
849
+ * - Other field values: `ctx.valueOf(path)` where path is a FieldPath
850
+ * - Other field states: `ctx.stateOf(path)`
851
+ * - Other fields: `ctx.fieldOf(path)`
852
+ * - Current field tree: `ctx.field`
853
+ *
854
+ * **Return Types:**
855
+ * - Single error: `{ kind: 'errorKind' }` for field-level validation
856
+ * - Multiple errors: `[{ kind: 'error1' }, { kind: 'error2' }]` for cross-field validation
857
+ * - No error: `null` when validation passes
858
+ *
859
+ * **Best Practice - Return Only Error Kind:**
860
+ * Validators should focus on validation logic, not presentation.
861
+ * Return just the error `kind` and configure messages at field level for i18n support.
862
+ *
863
+ * @example Single Field Validation
864
+ * ```typescript
865
+ * const noSpaces: CustomValidator<string> = (ctx) => {
866
+ * const value = ctx.value();
867
+ * if (typeof value === 'string' && value.includes(' ')) {
868
+ * return { kind: 'noSpaces' };
869
+ * }
870
+ * return null;
871
+ * };
872
+ *
873
+ * // Field configuration
874
+ * {
875
+ * key: 'username',
876
+ * validators: [{ type: 'custom', functionName: 'noSpaces' }],
877
+ * validationMessages: {
878
+ * noSpaces: 'Spaces are not allowed'
879
+ * }
880
+ * }
881
+ * ```
882
+ *
883
+ * @example Cross-Field Validation with valueOf()
884
+ * ```typescript
885
+ * // Compare two fields using public API
886
+ * const lessThan: CustomValidator<number> = (ctx, params) => {
887
+ * const value = ctx.value();
888
+ * const compareToPath = params?.field as string;
889
+ *
890
+ * // Use valueOf() to access other field - public API!
891
+ * const otherValue = ctx.valueOf(compareToPath as any);
892
+ *
893
+ * if (otherValue !== undefined && value >= otherValue) {
894
+ * return { kind: 'notLessThan' };
895
+ * }
896
+ * return null;
897
+ * };
898
+ * ```
899
+ *
900
+ * @example Multiple Errors (Cross-Field Validation)
901
+ * ```typescript
902
+ * const validateDateRange: CustomValidator = (ctx) => {
903
+ * const errors: ValidationError[] = [];
904
+ *
905
+ * const startDate = ctx.valueOf('startDate' as any);
906
+ * const endDate = ctx.valueOf('endDate' as any);
907
+ *
908
+ * if (!startDate) errors.push({ kind: 'startDateRequired' });
909
+ * if (!endDate) errors.push({ kind: 'endDateRequired' });
910
+ * if (startDate && endDate && startDate > endDate) {
911
+ * errors.push({ kind: 'invalidDateRange' });
912
+ * }
913
+ *
914
+ * return errors.length > 0 ? errors : null;
915
+ * };
916
+ * ```
917
+ *
918
+ * **Message Resolution Priority:**
919
+ * 1. Field-level `validationMessages[kind]` (highest priority - per-field customization)
920
+ * 2. Form-level `defaultValidationMessages[kind]` (fallback for common messages)
921
+ * 3. **No message configured = Warning logged + error NOT displayed**
922
+ *
923
+ * **Important:** Validator-returned messages are NOT used. All messages MUST be explicitly configured.
924
+ *
925
+ * @template TValue The type of value stored in the field being validated
926
+ */
927
+ type CustomValidator<TValue = unknown> = (ctx: FieldContext<TValue>, params?: Record<string, unknown>) => ValidationError$1 | ValidationError$1[] | null;
928
+ /**
929
+ * Async custom validator configuration using Angular's resource-based API
930
+ *
931
+ * Angular's validateAsync uses the resource API for async validation,
932
+ * which provides better integration with Signal Forms lifecycle management.
933
+ *
934
+ * **Structure:**
935
+ * - `params`: Function that computes params from field context
936
+ * - `factory`: Function that creates a ResourceRef from params signal
937
+ * - `onSuccess`: Maps successful resource result to validation errors
938
+ * - `onError`: Optional handler for resource errors (network failures, etc.)
939
+ *
940
+ * **Use Cases:**
941
+ * - Database lookups via services with resource API
942
+ * - Complex async business logic with Angular resources
943
+ * - Any async operation using Angular's resource pattern
944
+ *
945
+ * **Note:** For HTTP validation, prefer `HttpCustomValidator` which provides
946
+ * a simpler API specifically designed for HTTP requests.
947
+ *
948
+ * @example Database Lookup with Resource
949
+ * ```typescript
950
+ * const checkUsernameAvailable: AsyncCustomValidator<string> = {
951
+ * params: (ctx) => ({ username: ctx.value() }),
952
+ * factory: (params) => {
953
+ * const injector = inject(Injector);
954
+ * return resource({
955
+ * request: () => params(),
956
+ * loader: ({ request }) => {
957
+ * if (!request?.username) return null;
958
+ * const service = injector.get(UserService);
959
+ * return firstValueFrom(service.checkAvailability(request.username));
960
+ * }
961
+ * });
962
+ * },
963
+ * onSuccess: (result, ctx) => {
964
+ * if (!result) return null;
965
+ * return result.available ? null : { kind: 'usernameTaken' };
966
+ * },
967
+ * onError: (error, ctx) => {
968
+ * console.error('Availability check failed:', error);
969
+ * return null; // Don't block form on network errors
970
+ * }
971
+ * };
972
+ * ```
973
+ *
974
+ * @template TValue The type of value stored in the field being validated
975
+ * @template TParams The type of params passed to the resource
976
+ * @template TResult The type of result returned by the resource
977
+ */
978
+ interface AsyncCustomValidator<TValue = unknown, TParams = unknown, TResult = unknown> {
979
+ /**
980
+ * Function that receives field context and returns resource params.
981
+ * Params will be tracked as a signal and trigger resource reload when changed.
982
+ */
983
+ readonly params: (ctx: FieldContext<TValue>, config?: Record<string, unknown>) => TParams;
984
+ /**
985
+ * Function that creates a ResourceRef from the params signal.
986
+ * The resource will be automatically managed by Angular's lifecycle.
987
+ */
988
+ readonly factory: (params: Signal<TParams | undefined>) => ResourceRef<TResult | undefined>;
989
+ /**
990
+ * Optional function to map successful resource result to validation errors.
991
+ * Return null if validation passes, or ValidationError/ValidationError[] if validation fails.
992
+ */
993
+ readonly onSuccess?: (result: TResult, ctx: FieldContext<TValue>) => TreeValidationResult;
994
+ /**
995
+ * Optional error handler for resource errors (network failures, etc.).
996
+ * Return null to ignore the error, or ValidationError to display it to the user.
997
+ */
998
+ readonly onError?: (error: unknown, ctx: FieldContext<TValue>) => ValidationError$1 | ValidationError$1[] | null;
999
+ }
1000
+ /**
1001
+ * HTTP request configuration for validateHttp API
1002
+ */
1003
+ interface HttpResourceRequest {
1004
+ url: string;
1005
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
1006
+ body?: any;
1007
+ headers?: Record<string, string | string[]>;
1008
+ }
1009
+ /**
1010
+ * HTTP-based validator configuration for Angular's validateHttp API
1011
+ *
1012
+ * Angular's validateHttp provides optimized HTTP validation with automatic
1013
+ * request cancellation and integration with the resource API.
1014
+ *
1015
+ * **Benefits:**
1016
+ * - Automatic request cancellation when field value changes
1017
+ * - Built-in integration with Angular's resource management
1018
+ * - Simpler than AsyncCustomValidator for HTTP use cases
1019
+ *
1020
+ * **Structure:**
1021
+ * - `request`: Function that returns URL string or HttpResourceRequest
1022
+ * - `onSuccess`: REQUIRED - Maps HTTP response to validation errors (inverted logic!)
1023
+ * - `onError`: Optional handler for HTTP errors (network failures, 4xx/5xx)
1024
+ *
1025
+ * **Important:** `onSuccess` uses inverted logic - it maps SUCCESSFUL HTTP responses
1026
+ * to validation errors. For example, if the API returns `{ available: false }`,
1027
+ * your `onSuccess` should return `{ kind: 'usernameTaken' }`.
1028
+ *
1029
+ * @example Username Availability Check (GET)
1030
+ * ```typescript
1031
+ * const checkUsername: HttpCustomValidator<string> = {
1032
+ * request: (ctx) => {
1033
+ * const username = ctx.value();
1034
+ * if (!username) return undefined; // Skip validation if empty
1035
+ * return `/api/users/check-username?username=${encodeURIComponent(username)}`;
1036
+ * },
1037
+ * onSuccess: (response, ctx) => {
1038
+ * // Inverted logic: successful response may indicate validation failure
1039
+ * return response.available ? null : { kind: 'usernameTaken' };
1040
+ * },
1041
+ * onError: (error, ctx) => {
1042
+ * console.error('Availability check failed:', error);
1043
+ * return null; // Don't block form on network errors
1044
+ * }
1045
+ * };
1046
+ * ```
1047
+ *
1048
+ * @example Address Validation (POST with Body)
1049
+ * ```typescript
1050
+ * const validateAddress: HttpCustomValidator = {
1051
+ * request: (ctx) => {
1052
+ * const zipCode = ctx.value();
1053
+ * if (!zipCode) return undefined;
1054
+ *
1055
+ * return {
1056
+ * url: '/api/validate-address',
1057
+ * method: 'POST',
1058
+ * body: {
1059
+ * street: ctx.valueOf('street' as any),
1060
+ * city: ctx.valueOf('city' as any),
1061
+ * zipCode: zipCode
1062
+ * },
1063
+ * headers: { 'Content-Type': 'application/json' }
1064
+ * };
1065
+ * },
1066
+ * onSuccess: (response) => {
1067
+ * return response.valid ? null : { kind: 'invalidAddress' };
1068
+ * }
1069
+ * };
1070
+ * ```
1071
+ *
1072
+ * @template TValue The type of value stored in the field being validated
1073
+ * @template TResult The type of HTTP response
1074
+ */
1075
+ interface HttpCustomValidator<TValue = unknown, TResult = unknown> {
1076
+ /**
1077
+ * Function that returns the HTTP request configuration.
1078
+ * Can return:
1079
+ * - `undefined` to skip validation (e.g., if field is empty)
1080
+ * - `string` for simple GET requests (just the URL)
1081
+ * - `HttpResourceRequest` for full control (method, body, headers)
1082
+ */
1083
+ readonly request: (ctx: FieldContext<TValue>, config?: Record<string, unknown>) => string | HttpResourceRequest | undefined;
1084
+ /**
1085
+ * REQUIRED function to map successful HTTP response to validation errors.
1086
+ *
1087
+ * **Inverted Logic:** This is called on successful HTTP responses.
1088
+ * Return null if validation passes, or ValidationError/ValidationError[] if validation fails.
1089
+ *
1090
+ * Example: API returns `{ available: false }` → return `{ kind: 'usernameTaken' }`
1091
+ */
1092
+ readonly onSuccess: (result: TResult, ctx: FieldContext<TValue>) => TreeValidationResult;
1093
+ /**
1094
+ * Optional error handler for HTTP errors (network failures, 4xx/5xx status codes).
1095
+ * Return null to ignore the error, or ValidationError to display it to the user.
1096
+ *
1097
+ * Common pattern: Log the error and return null to avoid blocking form submission
1098
+ * on network issues.
1099
+ */
1100
+ readonly onError?: (error: unknown, ctx: FieldContext<TValue>) => ValidationError$1 | ValidationError$1[] | null;
1101
+ }
1102
+
1103
+ interface EvaluationContext<TValue = unknown> {
1104
+ /** Current field value */
1105
+ fieldValue: TValue;
1106
+ /** Complete form value */
1107
+ formValue: Record<string, unknown>;
1108
+ /** Field path for relative references */
1109
+ fieldPath: string;
1110
+ /** Custom evaluation functions */
1111
+ customFunctions?: Record<string, (context: EvaluationContext) => unknown>;
1112
+ /** Allow additional properties for flexible expression evaluation */
1113
+ [key: string]: unknown;
1114
+ }
1115
+
1116
+ /**
1117
+ * Custom function signature for conditional expressions
1118
+ *
1119
+ * Custom functions are used for conditional logic in:
1120
+ * - `when` conditions (field visibility, conditional validation)
1121
+ * - `readonly` logic (dynamic readonly state)
1122
+ * - `disabled` logic (dynamic disabled state)
1123
+ * - Dynamic value calculations
1124
+ *
1125
+ * Unlike validators, custom functions:
1126
+ * - Return any value (typically boolean for conditions, but could be strings, numbers, etc.)
1127
+ * - Do NOT return ValidationError objects
1128
+ * - Receive EvaluationContext (field values) not FieldContext (field state)
1129
+ *
1130
+ * @example
1131
+ * ```typescript
1132
+ * // Boolean condition function
1133
+ * const isAdult: CustomFunction = (ctx) => {
1134
+ * return ctx.age >= 18;
1135
+ * };
1136
+ *
1137
+ * // Used in field configuration:
1138
+ * {
1139
+ * key: 'alcoholPreference',
1140
+ * type: 'select',
1141
+ * when: { function: 'isAdult' } // Only show if isAdult returns true
1142
+ * }
1143
+ * ```
1144
+ *
1145
+ * @example
1146
+ * ```typescript
1147
+ * // Calculation function
1148
+ * const calculateDiscount: CustomFunction = (ctx) => {
1149
+ * const price = ctx.price || 0;
1150
+ * const isVip = ctx.isVip || false;
1151
+ * return isVip ? price * 0.8 : price * 0.9;
1152
+ * };
1153
+ * ```
1154
+ */
1155
+ type CustomFunction = (context: EvaluationContext) => unknown;
1156
+
1157
+ /**
1158
+ * The result type for submission actions.
1159
+ * Can be either a Promise or an Observable.
1160
+ *
1161
+ * For success: return `undefined`, `null`, `void`, or any non-TreeValidationResult value.
1162
+ * For server errors: return `TreeValidationResult` (array of field errors).
1163
+ */
1164
+ type SubmissionActionResult = Promise<TreeValidationResult> | Observable<TreeValidationResult | unknown>;
1165
+ /**
1166
+ * Configuration for form submission handling.
1167
+ *
1168
+ * When provided, enables integration with Angular Signal Forms' native `submit()` function.
1169
+ * The submission mechanism is **optional** - you can still handle submission manually
1170
+ * via the `(submitted)` output if you prefer.
1171
+ *
1172
+ * Supports both Promise-based and Observable-based submission actions. When an Observable
1173
+ * is returned, it will be automatically converted using `firstValueFrom`.
1174
+ *
1175
+ * @example
1176
+ * ```typescript
1177
+ * // Using Observable (recommended for HTTP calls)
1178
+ * // Simply return the HTTP observable - no need to map the result
1179
+ * const config: FormConfig = {
1180
+ * fields: [...],
1181
+ * submission: {
1182
+ * action: (form) => this.http.post('/api/submit', form().value())
1183
+ * }
1184
+ * };
1185
+ *
1186
+ * // With error handling for server validation errors
1187
+ * const config: FormConfig = {
1188
+ * fields: [...],
1189
+ * submission: {
1190
+ * action: (form) => {
1191
+ * return this.http.post('/api/submit', form().value()).pipe(
1192
+ * catchError((error) => {
1193
+ * if (error.error?.code === 'EMAIL_EXISTS') {
1194
+ * return of([{ field: form.email, error: { kind: 'server', message: 'Email already exists' }}]);
1195
+ * }
1196
+ * throw error;
1197
+ * })
1198
+ * );
1199
+ * }
1200
+ * }
1201
+ * };
1202
+ *
1203
+ * // Using Promise (also supported)
1204
+ * const config: FormConfig = {
1205
+ * fields: [...],
1206
+ * submission: {
1207
+ * action: async (form) => {
1208
+ * const value = form().value();
1209
+ * try {
1210
+ * await this.api.submit(value);
1211
+ * return undefined;
1212
+ * } catch (error) {
1213
+ * if (error.code === 'EMAIL_EXISTS') {
1214
+ * return [{ field: form.email, error: { kind: 'server', message: 'Email already exists' }}];
1215
+ * }
1216
+ * throw error;
1217
+ * }
1218
+ * }
1219
+ * }
1220
+ * };
1221
+ * ```
1222
+ *
1223
+ * @typeParam TValue - The form value type
1224
+ *
1225
+ * @public
1226
+ * @experimental
1227
+ */
1228
+ interface SubmissionConfig<TValue = unknown> {
1229
+ /**
1230
+ * Action called when the form is submitted.
1231
+ *
1232
+ * This function receives the form's `FieldTree` and should return either a Promise or
1233
+ * an Observable. For Observable returns, it will be automatically converted using `firstValueFrom`.
1234
+ *
1235
+ * **Return values:**
1236
+ * - For success: return `undefined`, `null`, or simply let the Observable complete (the emitted value is ignored unless it's a TreeValidationResult)
1237
+ * - For server errors: return `TreeValidationResult` (array of field/error pairs)
1238
+ *
1239
+ * **Observable support:** You can return an HttpClient observable directly without mapping the result.
1240
+ * The form will treat Observable completion as success. Only return `TreeValidationResult` if you need
1241
+ * to report server-side validation errors.
1242
+ *
1243
+ * Server errors returned will be automatically applied to the corresponding form fields.
1244
+ *
1245
+ * While this action is executing, `form().submitting()` will be `true`, enabling
1246
+ * automatic button disabling and loading states.
1247
+ *
1248
+ * @param form - The form's FieldTree instance
1249
+ * @returns Promise or Observable - for errors, return TreeValidationResult
1250
+ *
1251
+ * @example
1252
+ * ```typescript
1253
+ * // Simple - just return the HTTP observable
1254
+ * action: (form) => this.http.post('/api/register', form().value())
1255
+ *
1256
+ * // With server error handling
1257
+ * action: (form) => {
1258
+ * return this.http.post('/api/register', form().value()).pipe(
1259
+ * catchError((error) => {
1260
+ * if (error.status === 409) {
1261
+ * return of([{
1262
+ * field: form.email,
1263
+ * error: { kind: 'server', message: 'Email already exists' }
1264
+ * }]);
1265
+ * }
1266
+ * throw error;
1267
+ * })
1268
+ * );
1269
+ * }
1270
+ *
1271
+ * // Promise-based alternative
1272
+ * action: async (form) => {
1273
+ * await fetch('/api/register', {
1274
+ * method: 'POST',
1275
+ * body: JSON.stringify(form().value())
1276
+ * });
1277
+ * // Return undefined for success, or TreeValidationResult for errors
1278
+ * }
1279
+ * ```
1280
+ */
1281
+ action: (form: FieldTree<TValue>) => SubmissionActionResult;
1282
+ }
1283
+
1284
+ /**
1285
+ * Configuration interface for defining dynamic form structure and behavior.
1286
+ *
1287
+ * This interface defines the complete form schema including field definitions,
1288
+ * validation rules, conditional logic, and submission handling using Angular's
1289
+ * signal-based reactive forms.
1290
+ *
1291
+ * @example
1292
+ * ```typescript
1293
+ * const formConfig: FormConfig = {
1294
+ * fields: [
1295
+ * { type: 'input', key: 'email', value: '', label: 'Email', required: true, email: true },
1296
+ * { type: 'group', key: 'address', label: 'Address', fields: [
1297
+ * { type: 'input', key: 'street', value: '', label: 'Street' },
1298
+ * { type: 'input', key: 'city', value: '', label: 'City' }
1299
+ * ]},
1300
+ * { type: 'button', key: 'submit', label: 'Submit', buttonType: 'submit' }
1301
+ * ],
1302
+ * schemas: [
1303
+ * { name: 'emailSchema', schema: { email: validators.email } }
1304
+ * ]
1305
+ * };
1306
+ * ```
1307
+ *
1308
+ * @typeParam TFields - Array of registered field types available for this form
1309
+ * @typeParam TValue - The strongly-typed interface for form values
1310
+ *
1311
+ * @public
1312
+ */
1313
+ interface FormConfig<TFields extends RegisteredFieldTypes[] = RegisteredFieldTypes[], TValue = InferFormValue$1<TFields>> {
1314
+ /**
1315
+ * Array of field definitions that define the form structure.
1316
+ *
1317
+ * Fields are rendered in the order they appear in this array.
1318
+ * Supports nested groups and conditional field visibility.
1319
+ *
1320
+ * @example
1321
+ * ```typescript
1322
+ * fields: [
1323
+ * { type: 'input', key: 'firstName', label: 'First Name' },
1324
+ * { type: 'group', key: 'address', label: 'Address', fields: [
1325
+ * { type: 'input', key: 'street', label: 'Street' }
1326
+ * ]}
1327
+ * ]
1328
+ * ```
1329
+ */
1330
+ fields: TFields;
1331
+ /**
1332
+ * Optional form-level validation schema.
1333
+ *
1334
+ * Provides additional validation beyond field-level validation.
1335
+ * Useful for cross-field validation rules.
1336
+ *
1337
+ * @example
1338
+ * ```typescript
1339
+ * schema: {
1340
+ * passwordConfirm: validators.equals('password')
1341
+ * }
1342
+ * ```
1343
+ */
1344
+ schema?: Schema<TValue>;
1345
+ /**
1346
+ * Global form configuration options.
1347
+ *
1348
+ * Controls form-wide behavior like validation timing and disabled state.
1349
+ *
1350
+ * @value {}
1351
+ */
1352
+ options?: FormOptions;
1353
+ /**
1354
+ * Global schemas available to all fields.
1355
+ *
1356
+ * Reusable validation schemas that can be referenced by field definitions.
1357
+ * Promotes consistency and reduces duplication.
1358
+ *
1359
+ * @example
1360
+ * ```typescript
1361
+ * schemas: [
1362
+ * { name: 'addressSchema', schema: {
1363
+ * street: validators.required,
1364
+ * zipCode: validators.pattern(/^\d{5}$/)
1365
+ * }}
1366
+ * ]
1367
+ * ```
1368
+ */
1369
+ schemas?: SchemaDefinition[];
1370
+ /**
1371
+ * Form-level validation messages that act as fallback for field-level messages.
1372
+ *
1373
+ * These messages are used when a field has validation errors but no
1374
+ * field-level `validationMessages` are defined for that specific error.
1375
+ * This allows you to define common validation messages once at the form level
1376
+ * instead of repeating them for each field.
1377
+ *
1378
+ * @example
1379
+ * ```typescript
1380
+ * defaultValidationMessages: {
1381
+ * required: 'This field is required',
1382
+ * email: 'Please enter a valid email address',
1383
+ * minLength: 'Must be at least {{requiredLength}} characters'
1384
+ * }
1385
+ * ```
1386
+ */
1387
+ defaultValidationMessages?: ValidationMessages;
1388
+ /**
1389
+ * Signal forms adapter configuration.
1390
+ */
1391
+ customFnConfig?: CustomFnConfig;
1392
+ /**
1393
+ * Form submission configuration.
1394
+ *
1395
+ * When provided, enables integration with Angular Signal Forms' native `submit()` function.
1396
+ * The submission mechanism is **optional** - you can still handle submission manually
1397
+ * via the `(submitted)` output if you prefer.
1398
+ *
1399
+ * While the submission action is executing, `form().submitting()` will be `true`,
1400
+ * which automatically disables submit buttons (unless configured otherwise).
1401
+ *
1402
+ * Server errors returned from the action will be automatically applied to the
1403
+ * corresponding form fields.
1404
+ *
1405
+ * @example
1406
+ * ```typescript
1407
+ * const config: FormConfig = {
1408
+ * fields: [...],
1409
+ * submission: {
1410
+ * action: async (form) => {
1411
+ * const value = form().value();
1412
+ * try {
1413
+ * await this.api.submit(value);
1414
+ * return undefined;
1415
+ * } catch (error) {
1416
+ * return [{ field: form.email, error: { kind: 'server', message: 'Email exists' }}];
1417
+ * }
1418
+ * }
1419
+ * }
1420
+ * };
1421
+ * ```
1422
+ */
1423
+ submission?: SubmissionConfig<TValue>;
1424
+ }
1425
+ /**
1426
+ * Signal forms adapter configuration for advanced form behavior.
1427
+ *
1428
+ * Provides configuration options for signal forms integration including
1429
+ * legacy migration, custom functions, and custom validators.
1430
+ *
1431
+ * @example
1432
+ * ```typescript
1433
+ * customFnConfig: {
1434
+ * customFunctions: {
1435
+ * isAdult: (context) => context.age >= 18,
1436
+ * formatCurrency: (context) => new Intl.NumberFormat('en-US', {
1437
+ * style: 'currency',
1438
+ * currency: 'USD'
1439
+ * }).format(context.value)
1440
+ * },
1441
+ * simpleValidators: {
1442
+ * noSpaces: (value) => {
1443
+ * return typeof value === 'string' && value.includes(' ')
1444
+ * ? { kind: 'noSpaces', message: 'Spaces not allowed' }
1445
+ * : null;
1446
+ * }
1447
+ * },
1448
+ * contextValidators: {
1449
+ * lessThanField: (ctx, params) => {
1450
+ * const value = ctx.value();
1451
+ * const otherField = params?.field as string;
1452
+ * const otherValue = ctx.root()[otherField]?.value();
1453
+ * if (otherValue !== undefined && value >= otherValue) {
1454
+ * return { kind: 'notLessThan', message: `Must be less than ${otherField}` };
1455
+ * }
1456
+ * return null;
1457
+ * }
1458
+ * }
1459
+ * }
1460
+ * ```
1461
+ *
1462
+ * @public
1463
+ */
1464
+ interface CustomFnConfig {
1465
+ /**
1466
+ * Custom evaluation functions for conditional expressions.
1467
+ *
1468
+ * Used for: when/readonly/disabled logic
1469
+ * Return type: any value (typically boolean)
1470
+ *
1471
+ * @example
1472
+ * ```typescript
1473
+ * customFunctions: {
1474
+ * isAdult: (context) => context.age >= 18,
1475
+ * calculateAge: (context) => {
1476
+ * const birthDate = new Date(context.birthDate);
1477
+ * return new Date().getFullYear() - birthDate.getFullYear();
1478
+ * }
1479
+ * }
1480
+ * ```
1481
+ */
1482
+ customFunctions?: Record<string, CustomFunction>;
1483
+ /**
1484
+ * Custom validators using Angular's public FieldContext API
1485
+ *
1486
+ * (ctx, params?) => ValidationError | ValidationError[] | null
1487
+ *
1488
+ * Validators receive FieldContext which provides access to:
1489
+ * - Current field value: `ctx.value()`
1490
+ * - Field state: `ctx.state` (errors, touched, dirty, etc.)
1491
+ * - Other field values: `ctx.valueOf(path)` - public API!
1492
+ * - Other field states: `ctx.stateOf(path)`
1493
+ * - Parameters from JSON configuration
1494
+ *
1495
+ * **Return Types:**
1496
+ * - Single error: `{ kind: 'errorKind' }` for field-level validation
1497
+ * - Multiple errors: `[{ kind: 'error1' }, { kind: 'error2' }]` for cross-field validation
1498
+ * - No error: `null` when validation passes
1499
+ *
1500
+ * @example Single Field Validation
1501
+ * ```typescript
1502
+ * validators: {
1503
+ * noSpaces: (ctx) => {
1504
+ * const value = ctx.value();
1505
+ * if (typeof value === 'string' && value.includes(' ')) {
1506
+ * return { kind: 'noSpaces' };
1507
+ * }
1508
+ * return null;
1509
+ * }
1510
+ * }
1511
+ * ```
1512
+ *
1513
+ * @example Cross-Field Validation (Public API)
1514
+ * ```typescript
1515
+ * validators: {
1516
+ * lessThan: (ctx, params) => {
1517
+ * const value = ctx.value();
1518
+ * const compareToPath = params?.field as string;
1519
+ *
1520
+ * // Use valueOf() to access other field - public API!
1521
+ * const otherValue = ctx.valueOf(compareToPath as any);
1522
+ *
1523
+ * if (otherValue !== undefined && value >= otherValue) {
1524
+ * return { kind: 'notLessThan' };
1525
+ * }
1526
+ * return null;
1527
+ * }
1528
+ * }
1529
+ * ```
1530
+ *
1531
+ * @example Multiple Errors
1532
+ * ```typescript
1533
+ * validators: {
1534
+ * validateDateRange: (ctx) => {
1535
+ * const errors: ValidationError[] = [];
1536
+ * const startDate = ctx.valueOf('startDate' as any);
1537
+ * const endDate = ctx.valueOf('endDate' as any);
1538
+ *
1539
+ * if (!startDate) errors.push({ kind: 'startDateRequired' });
1540
+ * if (!endDate) errors.push({ kind: 'endDateRequired' });
1541
+ * if (startDate && endDate && startDate > endDate) {
1542
+ * errors.push({ kind: 'invalidDateRange' });
1543
+ * }
1544
+ *
1545
+ * return errors.length > 0 ? errors : null;
1546
+ * }
1547
+ * }
1548
+ * ```
1549
+ */
1550
+ validators?: Record<string, CustomValidator>;
1551
+ /**
1552
+ * Async custom validators using Angular's resource-based validateAsync() API
1553
+ *
1554
+ * Angular's validateAsync uses the resource API for async validation.
1555
+ * Validators must provide params, factory, onSuccess, and optional onError callbacks.
1556
+ *
1557
+ * **Structure:**
1558
+ * - `params`: Function that computes params from field context
1559
+ * - `factory`: Function that creates ResourceRef from params signal
1560
+ * - `onSuccess`: Maps resource result to validation errors
1561
+ * - `onError`: Optional handler for resource errors
1562
+ *
1563
+ * **Use Cases:**
1564
+ * - Database lookups via services with resource API
1565
+ * - Complex async business logic with Angular resources
1566
+ *
1567
+ * **Note:** For HTTP validation, prefer `httpValidators` which provides
1568
+ * a simpler API specifically designed for HTTP requests.
1569
+ *
1570
+ * @example Database Lookup with Resource
1571
+ * ```typescript
1572
+ * asyncValidators: {
1573
+ * checkUsernameAvailable: {
1574
+ * params: (ctx) => ({ username: ctx.value() }),
1575
+ * factory: (params) => {
1576
+ * const injector = inject(Injector);
1577
+ * return resource({
1578
+ * request: () => params(),
1579
+ * loader: ({ request }) => {
1580
+ * if (!request?.username) return null;
1581
+ * const service = injector.get(UserService);
1582
+ * return firstValueFrom(service.checkAvailability(request.username));
1583
+ * }
1584
+ * });
1585
+ * },
1586
+ * onSuccess: (result, ctx) => {
1587
+ * if (!result) return null;
1588
+ * return result.available ? null : { kind: 'usernameTaken' };
1589
+ * },
1590
+ * onError: (error, ctx) => {
1591
+ * console.error('Availability check failed:', error);
1592
+ * return null; // Don't block form on network errors
1593
+ * }
1594
+ * }
1595
+ * }
1596
+ * ```
1597
+ */
1598
+ asyncValidators?: Record<string, AsyncCustomValidator>;
1599
+ /**
1600
+ * HTTP validators using Angular's validateHttp() API
1601
+ *
1602
+ * Angular's validateHttp provides HTTP validation with automatic request
1603
+ * cancellation and integration with the resource API.
1604
+ *
1605
+ * **Structure:**
1606
+ * - `request`: Function that returns URL string or HttpResourceRequest
1607
+ * - `onSuccess`: REQUIRED - Maps HTTP response to validation errors (inverted logic!)
1608
+ * - `onError`: Optional handler for HTTP errors
1609
+ *
1610
+ * **Benefits:**
1611
+ * - Automatic request cancellation when field value changes
1612
+ * - Built-in integration with Angular's resource management
1613
+ * - Simpler than asyncValidators for HTTP use cases
1614
+ *
1615
+ * **Important:** `onSuccess` uses inverted logic - it maps SUCCESSFUL HTTP responses
1616
+ * to validation errors. For example, if the API returns `{ available: false }`,
1617
+ * your `onSuccess` should return `{ kind: 'usernameTaken' }`.
1618
+ *
1619
+ * @example Username Availability Check (GET)
1620
+ * ```typescript
1621
+ * httpValidators: {
1622
+ * checkUsername: {
1623
+ * request: (ctx) => {
1624
+ * const username = ctx.value();
1625
+ * if (!username) return undefined; // Skip validation if empty
1626
+ * return `/api/users/check-username?username=${encodeURIComponent(username)}`;
1627
+ * },
1628
+ * onSuccess: (response, ctx) => {
1629
+ * // Inverted logic: successful response may indicate validation failure
1630
+ * return response.available ? null : { kind: 'usernameTaken' };
1631
+ * },
1632
+ * onError: (error, ctx) => {
1633
+ * console.error('Availability check failed:', error);
1634
+ * return null; // Don't block form on network errors
1635
+ * }
1636
+ * }
1637
+ * }
1638
+ * ```
1639
+ *
1640
+ * @example Address Validation (POST with Body)
1641
+ * ```typescript
1642
+ * httpValidators: {
1643
+ * validateAddress: {
1644
+ * request: (ctx) => {
1645
+ * const zipCode = ctx.value();
1646
+ * if (!zipCode) return undefined;
1647
+ *
1648
+ * return {
1649
+ * url: '/api/validate-address',
1650
+ * method: 'POST',
1651
+ * body: {
1652
+ * street: ctx.valueOf('street' as any),
1653
+ * city: ctx.valueOf('city' as any),
1654
+ * zipCode: zipCode
1655
+ * },
1656
+ * headers: { 'Content-Type': 'application/json' }
1657
+ * };
1658
+ * },
1659
+ * onSuccess: (response) => {
1660
+ * return response.valid ? null : { kind: 'invalidAddress' };
1661
+ * }
1662
+ * }
1663
+ * }
1664
+ * ```
1665
+ */
1666
+ httpValidators?: Record<string, HttpCustomValidator>;
1667
+ }
1668
+ /**
1669
+ * Global form configuration options.
1670
+ *
1671
+ * Controls form-wide behavior including disabled state
1672
+ * and button behavior configuration.
1673
+ *
1674
+ * @example
1675
+ * ```typescript
1676
+ * options: {
1677
+ * disabled: false,
1678
+ * submitButton: { disableWhenInvalid: true }
1679
+ * }
1680
+ * ```
1681
+ *
1682
+ * @public
1683
+ */
1684
+ interface FormOptions {
1685
+ /**
1686
+ * Disable the entire form.
1687
+ *
1688
+ * When enabled, all form fields become read-only and cannot
1689
+ * be modified by user interaction.
1690
+ *
1691
+ * @value false
1692
+ */
1693
+ disabled?: boolean;
1694
+ /**
1695
+ * Default disabled behavior for submit buttons.
1696
+ *
1697
+ * Controls when submit buttons are automatically disabled.
1698
+ * Can be overridden per-button via the `logic` array on individual button fields.
1699
+ *
1700
+ * @example
1701
+ * ```typescript
1702
+ * options: {
1703
+ * submitButton: {
1704
+ * disableWhenInvalid: true, // Disable when form is invalid
1705
+ * disableWhileSubmitting: true, // Disable during submission
1706
+ * }
1707
+ * }
1708
+ * ```
1709
+ */
1710
+ submitButton?: SubmitButtonOptions;
1711
+ /**
1712
+ * Default disabled behavior for next page buttons.
1713
+ *
1714
+ * Controls when next page buttons are automatically disabled in paged forms.
1715
+ * Can be overridden per-button via the `logic` array on individual button fields.
1716
+ *
1717
+ * @example
1718
+ * ```typescript
1719
+ * options: {
1720
+ * nextButton: {
1721
+ * disableWhenPageInvalid: true, // Disable when current page is invalid
1722
+ * disableWhileSubmitting: true, // Disable during submission
1723
+ * }
1724
+ * }
1725
+ * ```
1726
+ */
1727
+ nextButton?: NextButtonOptions;
1728
+ }
1729
+ /**
1730
+ * Options for controlling submit button disabled behavior.
1731
+ *
1732
+ * @public
1733
+ */
1734
+ interface SubmitButtonOptions {
1735
+ /**
1736
+ * Disable submit button when the form is invalid.
1737
+ *
1738
+ * @default true
1739
+ */
1740
+ disableWhenInvalid?: boolean;
1741
+ /**
1742
+ * Disable submit button while the form is submitting.
1743
+ *
1744
+ * Requires `submission.action` to be configured for automatic detection.
1745
+ *
1746
+ * @default true
1747
+ */
1748
+ disableWhileSubmitting?: boolean;
1749
+ }
1750
+ /**
1751
+ * Options for controlling next page button disabled behavior.
1752
+ *
1753
+ * @public
1754
+ */
1755
+ interface NextButtonOptions {
1756
+ /**
1757
+ * Disable next button when the current page has invalid fields.
1758
+ *
1759
+ * @default true
1760
+ */
1761
+ disableWhenPageInvalid?: boolean;
1762
+ /**
1763
+ * Disable next button while the form is submitting.
1764
+ *
1765
+ * @default true
1766
+ */
1767
+ disableWhileSubmitting?: boolean;
1768
+ }
1769
+
1770
+ /**
1771
+ * Field signal context - the "nervous system" of the dynamic form.
1772
+ * Provided via FIELD_SIGNAL_CONTEXT injection token.
1773
+ *
1774
+ * Gives mappers and components access to form state, values, and configuration.
1775
+ * Container fields (Group, Array) create scoped contexts with nested forms.
1776
+ */
1777
+ interface FieldSignalContext<TModel = unknown> {
1778
+ injector: Injector;
1779
+ value: WritableSignal<Partial<TModel> | undefined>;
1780
+ defaultValues: () => TModel;
1781
+ form: ReturnType<typeof form<TModel>>;
1782
+ defaultValidationMessages?: ValidationMessages;
1783
+ /** Form-level options used by button mappers to determine disabled state defaults. */
1784
+ formOptions?: FormOptions;
1785
+ /** Current page validity signal for paged forms. Used by next button to determine disabled state. */
1786
+ currentPageValid?: Signal<boolean>;
1787
+ }
1788
+ /**
1789
+ * Array context for fields rendered within arrays.
1790
+ * Provides position and parent array information for components inside array fields.
1791
+ */
1792
+ interface ArrayContext {
1793
+ /** The key of the parent array field. */
1794
+ arrayKey: string;
1795
+ /**
1796
+ * The index of this item within the array.
1797
+ * Uses linkedSignal to automatically update when items are added/removed,
1798
+ * allowing index-dependent logic to react without component recreation.
1799
+ */
1800
+ index: Signal<number>;
1801
+ /** The current form value for token resolution. */
1802
+ formValue: unknown;
1803
+ /** The array field definition. */
1804
+ field: FieldDef<unknown>;
1805
+ }
1806
+ /**
1807
+ * Mapper function that converts a field definition to component inputs.
1808
+ *
1809
+ * Mappers run within an injection context and can inject FIELD_SIGNAL_CONTEXT.
1810
+ * Returns a Signal to enable reactive updates when dependencies change.
1811
+ */
1812
+ type MapperFn<T extends FieldDef<unknown>> = (input: T) => Signal<Record<string, unknown>>;
1813
+
1814
+ /**
1815
+ * Defines how a field type handles form values and data collection.
1816
+ *
1817
+ * - 'include': Field contributes to form values (default for input fields)
1818
+ * - 'exclude': Field is excluded from form values (for display/layout fields)
1819
+ * - 'flatten': Field's children are flattened to parent level (for container fields)
1820
+ */
1821
+ type ValueHandlingMode = 'include' | 'exclude' | 'flatten';
1822
+ /**
1823
+ * Configuration interface for registering custom field types.
1824
+ *
1825
+ * Defines how a field type should be handled by the dynamic form system,
1826
+ * including its component loading strategy and field-to-component mapping logic.
1827
+ * Supports both eager-loaded and lazy-loaded components.
1828
+ *
1829
+ * @typeParam T - The field definition type this field type handles
1830
+ *
1831
+ * @example
1832
+ * ```typescript
1833
+ * const CustomInputType: FieldTypeDefinition<InputFieldDef> = {
1834
+ * name: 'custom-input',
1835
+ * loadComponent: () => import('./custom-input.component').then(m => m.CustomInputComponent),
1836
+ * mapper: customInputMapper
1837
+ * };
1838
+ *
1839
+ * // Register with providers
1840
+ * provideDynamicForm(CustomInputType)
1841
+ * ```
1842
+ */
1843
+ interface FieldTypeDefinition<T extends FieldDef<any> = any> {
1844
+ /** Unique identifier for the field type */
1845
+ name: string;
1846
+ /** Field definition type marker (internal use) */
1847
+ _fieldDef?: T;
1848
+ /** Function to load the component (supports lazy loading) */
1849
+ loadComponent?: () => Promise<any>;
1850
+ /** Mapper function that converts field definition to component bindings */
1851
+ mapper: MapperFn<T>;
1852
+ /** How this field type handles form values and data collection (defaults to 'include') */
1853
+ valueHandling?: ValueHandlingMode;
1854
+ }
1855
+ /**
1856
+ * Injection token for the global field type registry.
1857
+ *
1858
+ * Provides access to the map of registered field types throughout the application.
1859
+ * The registry is populated by the provideDynamicForm function and used by
1860
+ * field rendering components to resolve field types to their implementations.
1861
+ *
1862
+ * @example
1863
+ * ```typescript
1864
+ * constructor(@Inject(FIELD_REGISTRY) private registry: Map<string, FieldTypeDefinition>) {
1865
+ * const inputType = registry.get('input');
1866
+ * }
1867
+ * ```
1868
+ */
1869
+ declare const FIELD_REGISTRY: InjectionToken<Map<string, FieldTypeDefinition<any>>>;
1870
+ /**
1871
+ * Gets the value handling mode for a specific field type from the registry.
1872
+ *
1873
+ * @param fieldType - The field type identifier
1874
+ * @param registry - The field type registry
1875
+ * @returns The value handling mode ('include' is the default if not specified)
1876
+ */
1877
+ declare function getFieldValueHandling(fieldType: string, registry: Map<string, FieldTypeDefinition>): ValueHandlingMode;
1878
+
1879
+ /**
1880
+ * Resolved field ready for rendering with ngComponentOutlet.
1881
+ */
1882
+ interface ResolvedField {
1883
+ key: string;
1884
+ component: Type<unknown>;
1885
+ injector: Injector;
1886
+ inputs: Signal<Record<string, unknown>>;
1887
+ }
1888
+
1889
+ /**
1890
+ * Form mode enumeration distinguishing between paged and non-paged forms
1891
+ */
1892
+ type FormMode = 'paged' | 'non-paged';
1893
+ /**
1894
+ * Result of form mode detection with validation details
1895
+ */
1896
+ interface FormModeDetectionResult {
1897
+ /** The detected form mode */
1898
+ mode: FormMode;
1899
+ /** Whether the form configuration is valid for the detected mode */
1900
+ isValid: boolean;
1901
+ /** Array of validation errors if form is invalid */
1902
+ errors: string[];
1903
+ }
1904
+
1905
+ /**
1906
+ * Type guard to check if a field is a container field (page, row, group, or array)
1907
+ * Container fields have a 'fields' property and don't contribute values directly.
1908
+ * This overload works with RegisteredFieldTypes for full type narrowing.
1909
+ */
1910
+ declare function isContainerField(field: RegisteredFieldTypes): field is ContainerFieldTypes;
1911
+ /**
1912
+ * Type guard to check if a field is a container field (page, row, group, or array).
1913
+ * This overload works with any FieldDef for looser type checking.
1914
+ */
1915
+ declare function isContainerField(field: FieldDef<unknown>): boolean;
1916
+ /**
1917
+ * Type guard to check if a field is a leaf field (value or display field)
1918
+ * Leaf fields don't have children and either contribute values or display content
1919
+ */
1920
+ declare function isLeafField(field: RegisteredFieldTypes): field is LeafFieldTypes;
1921
+ /**
1922
+ * Type guard to check if a field has a value property (value-bearing field)
1923
+ * These fields contribute to the form value output
1924
+ * Note: Using `unknown` in the Extract condition to match any value type
1925
+ */
1926
+ declare function isValueBearingField(field: RegisteredFieldTypes): field is Extract<RegisteredFieldTypes, {
1927
+ value: unknown;
1928
+ }>;
1929
+ /**
1930
+ * Type guard to check if a field is excluded from form values (display-only field)
1931
+ * Currently this includes text fields and any other fields without a value property
1932
+ */
1933
+ declare function isDisplayOnlyField(field: RegisteredFieldTypes): boolean;
1934
+
1935
+ /**
1936
+ * Helper types for creating type-safe field configurations with proper nesting constraints
1937
+ */
1938
+
1939
+ /**
1940
+ * Type helper for accessing nested field paths safely
1941
+ * This allows accessing child paths while maintaining some type safety
1942
+ */
1943
+ type FieldPathAccess<TValue> = {
1944
+ [K in keyof TValue]: SchemaPath<TValue[K]> | SchemaPathTree<TValue[K]>;
1945
+ };
1946
+
1947
+ /**
1948
+ * Base interface for all form events in the dynamic form system.
1949
+ *
1950
+ * All form events must implement this interface to be compatible with
1951
+ * the event bus system. The type property is used for event filtering
1952
+ * and type-safe subscriptions.
1953
+ *
1954
+ * @example
1955
+ * ```typescript
1956
+ * export class SubmitEvent implements FormEvent {
1957
+ * readonly type = 'submit';
1958
+ * }
1959
+ *
1960
+ * export class ValidationErrorEvent implements FormEvent {
1961
+ * readonly type = 'validation-error';
1962
+ * constructor(public errors: ValidationErrors) {}
1963
+ * }
1964
+ * ```
1965
+ */
1966
+ interface FormEvent {
1967
+ /** Unique identifier for the event type used for filtering and subscriptions */
1968
+ readonly type: string;
1969
+ }
1970
+ /**
1971
+ * Constructor type for form event classes.
1972
+ *
1973
+ * Defines the shape of event class constructors that can be used with
1974
+ * the event bus dispatch system. Supports both parameterless and
1975
+ * parameterized event constructors.
1976
+ *
1977
+ * @typeParam T - The form event type being constructed
1978
+ *
1979
+ * @example
1980
+ * ```typescript
1981
+ * // Parameterless event constructor
1982
+ * const SubmitEventCtor: FormEventConstructor<SubmitEvent> = SubmitEvent;
1983
+ *
1984
+ * // Parameterized event constructor
1985
+ * const ErrorEventCtor: FormEventConstructor<ErrorEvent> = ErrorEvent;
1986
+ * eventBus.dispatch(ErrorEventCtor);
1987
+ * ```
1988
+ */
1989
+ type FormEventConstructor<T extends FormEvent = FormEvent> = new (...args: any[]) => T;
1990
+
1991
+ /**
1992
+ * Event dispatched when the form should be cleared.
1993
+ *
1994
+ * This event instructs the dynamic form component to clear all field values,
1995
+ * resetting them to empty/undefined state regardless of their default values.
1996
+ *
1997
+ * @example
1998
+ * ```typescript
1999
+ * // Dispatch from a button component
2000
+ * eventBus.dispatch(FormClearEvent);
2001
+ * ```
2002
+ *
2003
+ * @example
2004
+ * ```typescript
2005
+ * // Listen for clear events
2006
+ * eventBus.on<FormClearEvent>('form-clear').subscribe(() => {
2007
+ * console.log('Form was cleared');
2008
+ * });
2009
+ * ```
2010
+ */
2011
+ declare class FormClearEvent implements FormEvent {
2012
+ readonly type: "form-clear";
2013
+ }
2014
+
2015
+ /**
2016
+ * Event dispatched when the form should be reset to its default values.
2017
+ *
2018
+ * This event instructs the dynamic form component to restore all field values
2019
+ * to their initial default values as defined in the form configuration.
2020
+ *
2021
+ * @example
2022
+ * ```typescript
2023
+ * // Dispatch from a button component
2024
+ * eventBus.dispatch(FormResetEvent);
2025
+ * ```
2026
+ *
2027
+ * @example
2028
+ * ```typescript
2029
+ * // Listen for reset events
2030
+ * eventBus.on<FormResetEvent>('form-reset').subscribe(() => {
2031
+ * console.log('Form was reset to defaults');
2032
+ * });
2033
+ * ```
2034
+ */
2035
+ declare class FormResetEvent implements FormEvent {
2036
+ readonly type: "form-reset";
2037
+ }
2038
+
2039
+ declare class PageChangeEvent implements FormEvent {
2040
+ /** The current page index (0-based) */
2041
+ readonly currentPageIndex: number;
2042
+ /** Total number of pages */
2043
+ readonly totalPages: number;
2044
+ /** Previous page index (0-based), undefined if first navigation */
2045
+ readonly previousPageIndex?: number | undefined;
2046
+ readonly type: "page-change";
2047
+ constructor(
2048
+ /** The current page index (0-based) */
2049
+ currentPageIndex: number,
2050
+ /** Total number of pages */
2051
+ totalPages: number,
2052
+ /** Previous page index (0-based), undefined if first navigation */
2053
+ previousPageIndex?: number | undefined);
2054
+ }
2055
+
2056
+ /**
2057
+ * State interface for the page orchestrator
2058
+ */
2059
+ interface PageOrchestratorState {
2060
+ /** Current page index (0-based) */
2061
+ currentPageIndex: number;
2062
+ /** Total number of pages */
2063
+ totalPages: number;
2064
+ /** Whether the current page is the first page */
2065
+ isFirstPage: boolean;
2066
+ /** Whether the current page is the last page */
2067
+ isLastPage: boolean;
2068
+ /** Whether navigation is currently disabled */
2069
+ navigationDisabled: boolean;
2070
+ }
2071
+
2072
+ declare class PageNavigationStateChangeEvent implements FormEvent {
2073
+ state: PageOrchestratorState;
2074
+ type: "page-navigation-state-change";
2075
+ constructor(state: PageOrchestratorState);
2076
+ }
2077
+
2078
+ /**
2079
+ * Dynamic form component that renders a complete form based on configuration.
2080
+ *
2081
+ * This is the main entry point for the dynamic form system. It handles form state management,
2082
+ * validation, field rendering, and event coordination using Angular's signal-based reactive forms.
2083
+ *
2084
+ * @typeParam TFields - Array of registered field types available for this form
2085
+ * @typeParam TModel - The strongly-typed interface for form values
2086
+ *
2087
+ * @example
2088
+ *```html
2089
+ * <form
2090
+ * [dynamic-form]="formConfig"
2091
+ * [(value)]="formData"
2092
+ * (submitted)="handleSubmit($event)"
2093
+ * (validityChange)="handleValidityChange($event)">
2094
+ * </form>
2095
+ * ```
2096
+ */
2097
+ declare class DynamicForm<TFields extends RegisteredFieldTypes[] = RegisteredFieldTypes[], TModel = InferFormValue$1<TFields>> implements OnDestroy {
2098
+ private readonly destroyRef;
2099
+ private readonly fieldRegistry;
2100
+ private readonly injector;
2101
+ private readonly eventBus;
2102
+ private readonly rootFormRegistry;
2103
+ private readonly functionRegistry;
2104
+ private readonly schemaRegistry;
2105
+ /** Form configuration defining the structure, validation, and behavior. */
2106
+ config: InputSignal<FormConfig<TFields>>;
2107
+ /** Runtime form options that override config options when provided. */
2108
+ formOptions: InputSignal<FormOptions | undefined>;
2109
+ /** Form values for two-way data binding. */
2110
+ value: _angular_core.ModelSignal<Partial<TModel> | undefined>;
2111
+ private readonly memoizedFlattenFields;
2112
+ private readonly memoizedFlattenFieldsForRendering;
2113
+ private readonly memoizedKeyBy;
2114
+ private readonly memoizedDefaultValues;
2115
+ private readonly rawFieldRegistry;
2116
+ readonly formModeDetection: Signal<FormModeDetectionResult>;
2117
+ private readonly formSetup;
2118
+ readonly pageFieldDefinitions: Signal<PageField<_ng_forge_dynamic_forms.PageAllowedChildren[]>[]>;
2119
+ readonly effectiveFormOptions: Signal<{
2120
+ disabled?: boolean;
2121
+ submitButton?: _ng_forge_dynamic_forms.SubmitButtonOptions;
2122
+ nextButton?: _ng_forge_dynamic_forms.NextButtonOptions;
2123
+ }>;
2124
+ readonly fieldSignalContext: Signal<FieldSignalContext<TModel>>;
2125
+ private readonly fieldInjector;
2126
+ readonly defaultValues: _angular_core.WritableSignal<TModel>;
2127
+ private readonly entity;
2128
+ readonly form: Signal<_angular_forms_signals.FieldTree<TModel, string | number>>;
2129
+ private readonly componentId;
2130
+ private readonly totalComponentsCount;
2131
+ private readonly fieldsSource;
2132
+ /** Collects errors from async field component loading for error boundary patterns. */
2133
+ readonly fieldLoadingErrors: _angular_core.WritableSignal<{
2134
+ fieldType: string;
2135
+ fieldKey: string;
2136
+ error: Error;
2137
+ }[]>;
2138
+ /** Current form values (reactive). */
2139
+ readonly formValue: Signal<TModel | (TModel extends infer T ? T extends TModel ? T extends _angular_forms.AbstractControl<unknown, infer TValue extends unknown, any> ? TValue : never : never : never)>;
2140
+ /** Whether the form is currently valid. */
2141
+ readonly valid: Signal<boolean>;
2142
+ /** Whether the form is currently invalid. */
2143
+ readonly invalid: Signal<boolean>;
2144
+ /** Whether any form field has been modified. */
2145
+ readonly dirty: Signal<boolean>;
2146
+ /** Whether any form field has been touched (blurred). */
2147
+ readonly touched: Signal<boolean>;
2148
+ /** Current validation errors from all fields. */
2149
+ readonly errors: Signal<_angular_forms_signals.ValidationError.WithField[]>;
2150
+ /** Whether the form is disabled (from options or form state). */
2151
+ readonly disabled: Signal<boolean>;
2152
+ /** Whether the form is currently submitting. */
2153
+ readonly submitting: Signal<boolean>;
2154
+ /**
2155
+ * Announcement message for screen readers.
2156
+ * Updates when form submission fails due to validation errors.
2157
+ */
2158
+ readonly errorAnnouncement: _angular_core.WritableSignal<string>;
2159
+ readonly initialized$: rxjs.Observable<boolean>;
2160
+ /** Emits when form validity changes. */
2161
+ readonly validityChange: _angular_core.OutputRef<boolean>;
2162
+ /** Emits when form dirty state changes. */
2163
+ readonly dirtyChange: _angular_core.OutputRef<boolean>;
2164
+ /**
2165
+ * Emits form values when submitted (via SubmitEvent).
2166
+ * Note: Does not emit when `submission.action` is configured - use one or the other.
2167
+ */
2168
+ readonly submitted: _angular_core.OutputRef<Partial<TModel> | undefined>;
2169
+ /** Emits when form is reset to default values. */
2170
+ readonly reset: _angular_core.OutputRef<FormResetEvent>;
2171
+ /** Emits when form is cleared to empty state. */
2172
+ readonly cleared: _angular_core.OutputRef<FormClearEvent>;
2173
+ /** Emits all form events for custom event handling. */
2174
+ readonly events: _angular_core.OutputRef<_ng_forge_dynamic_forms.FormEvent>;
2175
+ /**
2176
+ * Emits when all form components are initialized and ready for interaction.
2177
+ * Useful for E2E testing to ensure the form is fully rendered before interaction.
2178
+ */
2179
+ readonly initialized: _angular_core.OutputRef<boolean>;
2180
+ /** Emits when the current page changes in paged forms. */
2181
+ readonly onPageChange: _angular_core.OutputRef<PageChangeEvent>;
2182
+ /** Emits when page navigation state changes (canGoNext, canGoPrevious, etc.). */
2183
+ readonly onPageNavigationStateChange: _angular_core.OutputRef<PageNavigationStateChangeEvent>;
2184
+ protected readonly resolvedFields: Signal<ResolvedField[]>;
2185
+ private readonly syncEntityToValue;
2186
+ private readonly clearErrorsOnConfigChange;
2187
+ private readonly emitPagedFormInitialized;
2188
+ private readonly emitNonPagedFormInitialized;
2189
+ private readonly handleFormReset;
2190
+ private readonly handleFormClear;
2191
+ /**
2192
+ * Announces form validation errors to screen readers when submission is attempted
2193
+ * on an invalid form.
2194
+ */
2195
+ private readonly handleErrorAnnouncement;
2196
+ private readonly handleSubmission;
2197
+ /**
2198
+ * Handles native form submission triggered by:
2199
+ * - Pressing Enter in an input field
2200
+ * - Clicking a button with type="submit"
2201
+ * - Programmatic form.submit() calls
2202
+ *
2203
+ * This method prevents the default form submission behavior (page reload)
2204
+ * and dispatches a SubmitEvent through the EventBus for processing.
2205
+ *
2206
+ * @param event - The native submit event from the form element
2207
+ */
2208
+ protected onNativeSubmit(event: Event): void;
2209
+ private registerValidatorsFromConfig;
2210
+ private createFormSetupFromConfig;
2211
+ private createEmptyFormSetup;
2212
+ private onFormReset;
2213
+ private onFormClear;
2214
+ /**
2215
+ * Counts the total number of validation errors across all fields.
2216
+ * Used for screen reader announcements.
2217
+ */
2218
+ private countErrors;
2219
+ ngOnDestroy(): void;
2220
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DynamicForm<any, any>, never>;
2221
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DynamicForm<any, any>, "form[dynamic-form]", never, { "config": { "alias": "dynamic-form"; "required": true; "isSignal": true; }; "formOptions": { "alias": "formOptions"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "validityChange": "validityChange"; "dirtyChange": "dirtyChange"; "submitted": "submitted"; "reset": "reset"; "cleared": "cleared"; "events": "events"; "initialized": "initialized"; "onPageChange": "onPageChange"; "onPageNavigationStateChange": "onPageNavigationStateChange"; }, never, never, true, never>;
2222
+ }
2223
+
2224
+ /**
2225
+ * Extract FieldDef type from FieldTypeDefinition
2226
+ */
2227
+ type ExtractFieldDef<T> = T extends FieldTypeDefinition<infer F> ? F : never;
2228
+ /**
2229
+ * Union of all FieldDef types from provided field types
2230
+ */
2231
+ type FieldDefUnion<T extends FieldTypeDefinition[]> = ExtractFieldDef<T[number]>;
2232
+ /**
2233
+ * Infer form value type from field definitions
2234
+ */
2235
+ type InferFormValue<TFieldDefs extends FieldDef<any>[]> = {
2236
+ [K in TFieldDefs[number]['key']]: any;
2237
+ };
2238
+ /**
2239
+ * Provider result with type inference
2240
+ */
2241
+ type ProvideDynamicFormResult<T extends FieldTypeDefinition[]> = EnvironmentProviders & {
2242
+ __fieldDefs?: FieldDefUnion<T>;
2243
+ __formValue?: InferFormValue<FieldDefUnion<T>[]>;
2244
+ };
2245
+ /**
2246
+ * Provider function to configure the dynamic form system with field types and options.
2247
+ *
2248
+ * This function creates environment providers that can be used at application or route level
2249
+ * to register field types. It provides type-safe field registration with automatic type inference.
2250
+ *
2251
+ * @param fieldTypes - Custom field type definitions to register alongside built-in types
2252
+ * @returns Environment providers for dependency injection with type inference
2253
+ *
2254
+ * @example
2255
+ * ```typescript
2256
+ * // Application-level setup
2257
+ * bootstrapApplication(AppComponent, {
2258
+ * providers: [
2259
+ * provideDynamicForm(...withMaterialFields())
2260
+ * ]
2261
+ * });
2262
+ * ```
2263
+ *
2264
+ * @example
2265
+ * ```typescript
2266
+ * // Route-level setup
2267
+ * const routes: Routes = [
2268
+ * {
2269
+ * path: 'form',
2270
+ * component: FormComponent,
2271
+ * providers: [provideDynamicForm(...withMaterialFields())]
2272
+ * }
2273
+ * ];
2274
+ * ```
2275
+ *
2276
+ * @example
2277
+ * ```typescript
2278
+ * // Custom field types with type inference
2279
+ * import { CustomFieldType, AnotherFieldType } from './custom-fields';
2280
+ *
2281
+ * export const appConfig: ApplicationConfig = {
2282
+ * providers: [
2283
+ * provideDynamicForm(CustomFieldType, AnotherFieldType)
2284
+ * ]
2285
+ * };
2286
+ * ```
2287
+ *
2288
+ * @typeParam T - Array of field type definitions for type inference
2289
+ *
2290
+ * @public
2291
+ */
2292
+ declare function provideDynamicForm<const T extends FieldTypeDefinition[]>(...fieldTypes: T): ProvideDynamicFormResult<T>;
2293
+ /**
2294
+ * Extract FieldDef types from provider result
2295
+ */
2296
+ type ExtractFieldDefs<T> = T extends {
2297
+ __fieldDefs?: infer F;
2298
+ } ? F : never;
2299
+ /**
2300
+ * Extract form value type from provider result
2301
+ */
2302
+ type ExtractFormValue<T> = T extends {
2303
+ __formValue?: infer V;
2304
+ } ? V : never;
2305
+
2306
+ /**
2307
+ * Built-in field types provided by the dynamic form library.
2308
+ *
2309
+ * These core field types handle form structure and layout. They are automatically
2310
+ * registered when using provideDynamicForm() and form the foundation for building
2311
+ * complex form layouts with nested fields and multi-step flows.
2312
+ *
2313
+ * @example
2314
+ * ```typescript
2315
+ * // Row field for horizontal layout
2316
+ * { type: 'row', fields: [
2317
+ * { type: 'input', key: 'firstName' },
2318
+ * { type: 'input', key: 'lastName' }
2319
+ * ]}
2320
+ *
2321
+ * // Group field for nested form sections
2322
+ * { type: 'group', key: 'address', fields: [
2323
+ * { type: 'input', key: 'street' },
2324
+ * { type: 'input', key: 'city' }
2325
+ * ]}
2326
+ *
2327
+ * // Array field for array-based form sections
2328
+ * { type: 'array', key: 'items', fields: [
2329
+ * { type: 'input', key: 'name' },
2330
+ * { type: 'input', key: 'quantity' }
2331
+ * ]}
2332
+ *
2333
+ * // Page field for multi-step forms
2334
+ * { type: 'page', key: 'step1', fields: [...] }
2335
+ * ```
2336
+ */
2337
+ declare const BUILT_IN_FIELDS: FieldTypeDefinition[];
2338
+
2339
+ interface FieldOption<T = unknown> {
2340
+ label: DynamicText;
2341
+ value: T;
2342
+ disabled?: boolean;
2343
+ [key: string]: unknown;
2344
+ }
2345
+
2346
+ /**
2347
+ * Injection token for providing field signal context to mappers and components.
2348
+ *
2349
+ * The field signal context is the "nervous system" of the dynamic form library,
2350
+ * providing access to:
2351
+ * - The form instance and structure
2352
+ * - Current form values (as signals)
2353
+ * - Default values
2354
+ * - Validation messages
2355
+ * - The injector for creating components
2356
+ *
2357
+ * This token is provided by the DynamicForm component and can be scoped
2358
+ * for nested forms (Groups, Arrays) via child injectors.
2359
+ *
2360
+ * @example
2361
+ * ```typescript
2362
+ * // In a mapper function
2363
+ * export function mapValueField(fieldDef: BaseValueField<any, any>): Binding[] {
2364
+ * const context = inject(FIELD_SIGNAL_CONTEXT);
2365
+ * const form = context.form();
2366
+ * // ... use context
2367
+ * }
2368
+ *
2369
+ * // In a component
2370
+ * export class MyFieldComponent {
2371
+ * private context = inject(FIELD_SIGNAL_CONTEXT);
2372
+ * }
2373
+ * ```
2374
+ */
2375
+ declare const FIELD_SIGNAL_CONTEXT: InjectionToken<FieldSignalContext<unknown>>;
2376
+ /**
2377
+ * Injection token for providing array context metadata to mappers and components.
2378
+ *
2379
+ * This token is optionally provided by ArrayFieldComponent when creating injectors
2380
+ * for array items. It contains metadata about the array item's position and parent.
2381
+ *
2382
+ * Mappers can inject this token with {optional: true} to access array context:
2383
+ *
2384
+ * @example
2385
+ * ```typescript
2386
+ * // In a mapper function
2387
+ * export function buttonMapper(fieldDef: FieldDef<any>): Binding[] {
2388
+ * const arrayContext = inject(ARRAY_CONTEXT, { optional: true });
2389
+ * if (arrayContext) {
2390
+ * // Use arrayContext.index, arrayContext.arrayKey, etc.
2391
+ * }
2392
+ * }
2393
+ * ```
2394
+ */
2395
+ declare const ARRAY_CONTEXT: InjectionToken<ArrayContext>;
2396
+
2397
+ /**
2398
+ * Context for resolving button disabled state.
2399
+ *
2400
+ * @public
2401
+ */
2402
+ interface ButtonLogicContext {
2403
+ /** The form's FieldTree instance */
2404
+ form: FieldTree<unknown>;
2405
+ /** Form-level options */
2406
+ formOptions?: FormOptions;
2407
+ /** Field-level logic array (if provided) */
2408
+ fieldLogic?: LogicConfig[];
2409
+ /** Explicit disabled state from field definition */
2410
+ explicitlyDisabled?: boolean;
2411
+ /** Current page validity signal (for paged forms) */
2412
+ currentPageValid?: Signal<boolean>;
2413
+ /** Current form value for evaluating conditional expressions */
2414
+ formValue?: unknown;
2415
+ }
2416
+ /**
2417
+ * Resolves the disabled state for a submit button.
2418
+ *
2419
+ * The disabled state is determined by (in order of precedence):
2420
+ * 1. Explicit `disabled: true` on the field definition
2421
+ * 2. Field-level `logic` array (if present, overrides form-level defaults)
2422
+ * 3. Form-level `options.submitButton` defaults
2423
+ *
2424
+ * @param ctx - The button logic context
2425
+ * @returns A computed signal that returns true when the button should be disabled
2426
+ *
2427
+ * @example
2428
+ * ```typescript
2429
+ * const disabled = resolveSubmitButtonDisabled({
2430
+ * form: formInstance,
2431
+ * formOptions: config.options,
2432
+ * fieldLogic: buttonField.logic,
2433
+ * explicitlyDisabled: buttonField.disabled,
2434
+ * });
2435
+ *
2436
+ * // Use in template
2437
+ * <button [disabled]="disabled()">Submit</button>
2438
+ * ```
2439
+ *
2440
+ * @public
2441
+ */
2442
+ declare function resolveSubmitButtonDisabled(ctx: ButtonLogicContext): Signal<boolean>;
2443
+ /**
2444
+ * Resolves the disabled state for a next page button.
2445
+ *
2446
+ * The disabled state is determined by (in order of precedence):
2447
+ * 1. Explicit `disabled: true` on the field definition
2448
+ * 2. Field-level `logic` array (if present, overrides form-level defaults)
2449
+ * 3. Form-level `options.nextButton` defaults
2450
+ *
2451
+ * @param ctx - The button logic context
2452
+ * @returns A computed signal that returns true when the button should be disabled
2453
+ *
2454
+ * @example
2455
+ * ```typescript
2456
+ * const disabled = resolveNextButtonDisabled({
2457
+ * form: formInstance,
2458
+ * formOptions: config.options,
2459
+ * fieldLogic: buttonField.logic,
2460
+ * explicitlyDisabled: buttonField.disabled,
2461
+ * currentPageValid: pageOrchestrator.currentPageValid,
2462
+ * });
2463
+ * ```
2464
+ *
2465
+ * @public
2466
+ */
2467
+ declare function resolveNextButtonDisabled(ctx: ButtonLogicContext): Signal<boolean>;
2468
+
2469
+ interface FieldWithValidation {
2470
+ readonly required?: boolean;
2471
+ readonly email?: boolean;
2472
+ readonly min?: number;
2473
+ readonly max?: number;
2474
+ readonly minLength?: number;
2475
+ readonly maxLength?: number;
2476
+ readonly pattern?: string | RegExp;
2477
+ readonly validators?: ValidatorConfig[];
2478
+ readonly validationMessages?: ValidationMessages;
2479
+ readonly logic?: LogicConfig[];
2480
+ readonly schemas?: SchemaApplicationConfig[];
2481
+ }
2482
+
2483
+ /**
2484
+ * Supported primitive value types for form fields.
2485
+ * This type represents all possible value types that can be used in form fields.
2486
+ */
2487
+ type ValueType = string | number | boolean | Date | object | unknown[];
2488
+ interface BaseValueField<TProps, TValue> extends FieldDef<TProps>, FieldWithValidation {
2489
+ value?: TValue;
2490
+ /**
2491
+ * Placeholder text displayed when the field is empty.
2492
+ * Supports static strings, Observables, and Signals for dynamic content.
2493
+ */
2494
+ placeholder?: DynamicText;
2495
+ required?: boolean;
2496
+ }
2497
+ declare function isValueField<TProps>(field: FieldDef<TProps>): field is BaseValueField<TProps, ValueType>;
2498
+ type ExcludedKeys$1 = 'type' | 'conditionals' | 'value' | 'valueType' | 'disabled' | 'readonly' | 'hidden' | 'col' | 'minValue' | 'maxValue' | 'step' | 'required' | 'email' | 'min' | 'max' | 'minLength' | 'maxLength' | 'pattern' | 'validators' | 'logic' | 'schemas';
2499
+ type ValueFieldComponent<T extends BaseValueField<any, unknown>> = Prettify<WithInputSignals<Omit<T, ExcludedKeys$1>>>;
2500
+
2501
+ interface BaseCheckedField<TProps> extends FieldDef<TProps>, FieldWithValidation {
2502
+ value?: boolean;
2503
+ /**
2504
+ * Placeholder text displayed when the field is empty.
2505
+ * Supports static strings, Observables, and Signals for dynamic content.
2506
+ */
2507
+ placeholder?: DynamicText;
2508
+ required?: boolean;
2509
+ }
2510
+ declare function isCheckedField<TProps>(field: FieldDef<TProps>): field is BaseCheckedField<TProps>;
2511
+ type ExcludedKeys = 'type' | 'conditionals' | 'value' | 'disabled' | 'readonly' | 'hidden' | 'col' | keyof FieldWithValidation;
2512
+ type CheckedFieldComponent<T extends BaseCheckedField<any>> = Prettify<WithInputSignals<Omit<T, ExcludedKeys>>>;
2513
+
2514
+ /**
2515
+ * HTML input types supported by input fields
2516
+ */
2517
+ type InputType = 'text' | 'email' | 'password' | 'number' | 'tel' | 'url';
2518
+ /**
2519
+ * Props for input fields with optional inputType specification.
2520
+ * This is a generic interface that can be extended by framework-specific implementations.
2521
+ */
2522
+ interface InputProps<T extends InputType = InputType> {
2523
+ /**
2524
+ * The HTML input type. Determines the value type:
2525
+ * - 'number': value will be number
2526
+ * - 'text', 'email', 'password', 'tel', 'url': value will be string
2527
+ */
2528
+ type?: T;
2529
+ placeholder?: DynamicText;
2530
+ }
2531
+ /**
2532
+ * Number input field with strict number value type.
2533
+ * When props.type is 'number', value must be number.
2534
+ */
2535
+ interface NumberInputField<TProps extends {
2536
+ type?: string;
2537
+ } = {
2538
+ type: 'number';
2539
+ placeholder?: DynamicText;
2540
+ }> extends BaseValueField<TProps, number> {
2541
+ type: 'input';
2542
+ props?: TProps;
2543
+ }
2544
+ /**
2545
+ * String input field with strict string value type.
2546
+ * When props.type is text/email/etc, value must be string.
2547
+ */
2548
+ interface StringInputField<TProps extends {
2549
+ type?: string;
2550
+ } = {
2551
+ type: 'text' | 'email' | 'password' | 'tel' | 'url';
2552
+ placeholder?: DynamicText;
2553
+ }> extends BaseValueField<TProps, string> {
2554
+ type: 'input';
2555
+ props?: TProps;
2556
+ }
2557
+ /**
2558
+ * Helper type to extract the input type from props
2559
+ */
2560
+ type ExtractInputType<TProps> = TProps extends {
2561
+ type?: infer T;
2562
+ } ? T : InputType;
2563
+ /**
2564
+ * Fallback variant when props is undefined - allows both string and number values
2565
+ */
2566
+ interface UndefinedPropsInputField extends BaseValueField<undefined, string | number> {
2567
+ type: 'input';
2568
+ props?: never;
2569
+ }
2570
+ /**
2571
+ * Builds discriminated union based on what input types are possible in TProps
2572
+ */
2573
+ type BuildInputFieldUnion<TProps extends {
2574
+ type?: string;
2575
+ }> = (ExtractInputType<TProps> extends infer T ? T extends string ? ('number' extends T ? NumberInputField<TProps> : never) | (Exclude<T, 'number'> extends never ? never : StringInputField<TProps>) : StringInputField<TProps> : never) | UndefinedPropsInputField;
2576
+ /**
2577
+ * Input field with automatic type-safe value inference.
2578
+ * TypeScript automatically infers the correct value type based on props.type.
2579
+ *
2580
+ * @example
2581
+ * // Direct usage - automatic strict type safety
2582
+ * const numberField: InputField = {
2583
+ * type: 'input',
2584
+ * key: 'age',
2585
+ * props: { type: 'number' },
2586
+ * value: 25 // ✓ number only (string is type error!)
2587
+ * };
2588
+ *
2589
+ * const textField: InputField = {
2590
+ * type: 'input',
2591
+ * key: 'name',
2592
+ * props: { type: 'text' },
2593
+ * value: 'hello' // ✓ string only (number is type error!)
2594
+ * };
2595
+ *
2596
+ * @example
2597
+ * // Framework usage - extend with custom props
2598
+ * interface MatInputProps extends InputProps {
2599
+ * appearance?: 'fill' | 'outline';
2600
+ * hint?: string;
2601
+ * }
2602
+ * type MatInputField = InputField<MatInputProps>; // Automatically gets discriminated union
2603
+ */
2604
+ type InputField<TProps extends {
2605
+ type?: string;
2606
+ } = InputProps> = BuildInputFieldUnion<TProps>;
2607
+
2608
+ interface CheckboxField<TProps> extends BaseCheckedField<TProps> {
2609
+ type: 'checkbox';
2610
+ }
2611
+
2612
+ interface SelectProps {
2613
+ placeholder?: DynamicText;
2614
+ }
2615
+ interface SelectField<T, TProps = SelectProps> extends BaseValueField<TProps, T> {
2616
+ type: 'select';
2617
+ readonly options: readonly FieldOption<T>[];
2618
+ }
2619
+
2620
+ /**
2621
+ * Event arguments that can contain static values or tokens to be resolved at runtime
2622
+ * Tokens supported: $key, $index, $arrayKey, formValue
2623
+ */
2624
+ type EventArgs = readonly (string | number | boolean | null | undefined)[];
2625
+ /**
2626
+ * Interface for button fields
2627
+ */
2628
+ interface ButtonField<TProps, TEvent extends FormEvent> extends FieldDef<TProps> {
2629
+ type: 'button';
2630
+ event: FormEventConstructor<TEvent>;
2631
+ /**
2632
+ * Optional arguments to pass to the event constructor.
2633
+ * Can contain special tokens that will be resolved at runtime:
2634
+ * - $key: The current field key
2635
+ * - $index: The array index (if inside an array field)
2636
+ * - $arrayKey: The parent array field key (if inside an array field)
2637
+ * - formValue: Access to the current form value for indexing
2638
+ *
2639
+ * @example
2640
+ * eventArgs: ['$arrayKey', '$index']
2641
+ * eventArgs: ['contacts', 0]
2642
+ */
2643
+ eventArgs?: EventArgs;
2644
+ }
2645
+
2646
+ interface TextareaProps {
2647
+ placeholder?: DynamicText;
2648
+ rows?: number;
2649
+ cols?: number | undefined;
2650
+ }
2651
+ interface TextareaField<TProps = TextareaProps> extends BaseValueField<TProps, string> {
2652
+ type: 'textarea';
2653
+ maxLength?: number | undefined;
2654
+ }
2655
+
2656
+ interface RadioField<T, TProps> extends BaseValueField<TProps, T> {
2657
+ type: 'radio';
2658
+ options: FieldOption<T>[];
2659
+ }
2660
+
2661
+ /**
2662
+ * Multi-checkbox field for selecting multiple values from a list of options.
2663
+ * The value is an array of selected option values.
2664
+ *
2665
+ * @example
2666
+ * const tagsField: MultiCheckboxField<string> = {
2667
+ * type: 'multi-checkbox',
2668
+ * key: 'tags',
2669
+ * value: ['tag1', 'tag2'], // Array of selected values
2670
+ * options: [
2671
+ * { label: 'Tag 1', value: 'tag1' },
2672
+ * { label: 'Tag 2', value: 'tag2' },
2673
+ * { label: 'Tag 3', value: 'tag3' }
2674
+ * ]
2675
+ * };
2676
+ */
2677
+ interface MultiCheckboxField<TValue, TProps = object> extends BaseValueField<TProps, TValue[]> {
2678
+ type: 'multi-checkbox';
2679
+ options: FieldOption<TValue>[];
2680
+ }
2681
+
2682
+ interface DatepickerProps {
2683
+ placeholder?: DynamicText;
2684
+ }
2685
+ interface DatepickerField<TProps> extends BaseValueField<TProps, Date | string> {
2686
+ type: 'datepicker';
2687
+ minDate?: Date | string | null;
2688
+ maxDate?: Date | string | null;
2689
+ startAt?: Date | null;
2690
+ }
2691
+
2692
+ interface SliderField<TProps> extends BaseValueField<TProps, number> {
2693
+ type: 'slider';
2694
+ minValue?: number;
2695
+ maxValue?: number;
2696
+ step?: number;
2697
+ }
2698
+
2699
+ interface ToggleField<TProps> extends BaseCheckedField<TProps> {
2700
+ type: 'toggle';
2701
+ }
2702
+
2703
+ /**
2704
+ * Apply validator configuration to field path, following the logic pattern.
2705
+ *
2706
+ * Accepts both SchemaPath and SchemaPathTree to support being called from both
2707
+ * individual field mappings and schema functions.
2708
+ *
2709
+ * Note: ValidatorConfig is runtime configuration that doesn't encode the field's
2710
+ * TypeScript type. The type assertions to specific types (string, number) are safe
2711
+ * because Angular's validators perform runtime value checks regardless of the static
2712
+ * type parameter.
2713
+ *
2714
+ * Cross-field validators (those referencing formValue.*) are skipped at field level.
2715
+ * They are collected by the parent form component using collectCrossFieldEntries
2716
+ * and executed at form level using validateTree.
2717
+ *
2718
+ * @param config The validator configuration
2719
+ * @param fieldPath The field path to apply the validator to
2720
+ * @param fieldKey Optional field key (used for logging)
2721
+ */
2722
+ declare function applyValidator(config: ValidatorConfig, fieldPath: SchemaPath<any> | SchemaPathTree<any>, fieldKey?: string): void;
2723
+ /**
2724
+ * Apply multiple validators to a field path
2725
+ *
2726
+ * @param configs Array of validator configurations
2727
+ * @param fieldPath The field path to apply validators to
2728
+ * @param fieldKey Optional field key (used for logging)
2729
+ */
2730
+ declare function applyValidators(configs: ValidatorConfig[], fieldPath: SchemaPath<any> | SchemaPathTree<any>, fieldKey?: string): void;
2731
+
2732
+ declare class SubmitEvent implements FormEvent {
2733
+ readonly type: "submit";
2734
+ }
2735
+
2736
+ declare class NextPageEvent implements FormEvent {
2737
+ readonly type: "next-page";
2738
+ }
2739
+
2740
+ declare class PreviousPageEvent implements FormEvent {
2741
+ readonly type: "previous-page";
2742
+ }
2743
+
2744
+ /**
2745
+ * Event dispatched to add a new item to an array field.
2746
+ *
2747
+ * This event is used to dynamically add items to array fields at runtime.
2748
+ * The array field component listens for this event and adds a new item
2749
+ * based on the provided field template, or uses the array's own template if not provided.
2750
+ *
2751
+ * @example
2752
+ * ```typescript
2753
+ * // Add item using array's own template
2754
+ * eventBus.dispatch(AddArrayItemEvent, 'contacts');
2755
+ *
2756
+ * // Add item with explicit field template
2757
+ * const fieldTemplate = { key: 'email', type: 'input' };
2758
+ * eventBus.dispatch(AddArrayItemEvent, 'contacts', fieldTemplate);
2759
+ *
2760
+ * // Add item at specific index
2761
+ * eventBus.dispatch(AddArrayItemEvent, 'contacts', fieldTemplate, 2);
2762
+ * ```
2763
+ */
2764
+ declare class AddArrayItemEvent implements FormEvent {
2765
+ /** The key of the array field to add an item to */
2766
+ readonly arrayKey: string;
2767
+ /**
2768
+ * Optional field template definition to render for the new array item.
2769
+ * If not provided, the array field component will use its own template.
2770
+ */
2771
+ readonly field?: ArrayAllowedChildren | undefined;
2772
+ /** Optional index where to insert the item (defaults to end of array) */
2773
+ readonly index?: number | undefined;
2774
+ readonly type: "add-array-item";
2775
+ constructor(
2776
+ /** The key of the array field to add an item to */
2777
+ arrayKey: string,
2778
+ /**
2779
+ * Optional field template definition to render for the new array item.
2780
+ * If not provided, the array field component will use its own template.
2781
+ */
2782
+ field?: ArrayAllowedChildren | undefined,
2783
+ /** Optional index where to insert the item (defaults to end of array) */
2784
+ index?: number | undefined);
2785
+ }
2786
+
2787
+ /**
2788
+ * Event dispatched to remove an item from an array field.
2789
+ *
2790
+ * This event is used to dynamically remove items from array fields at runtime.
2791
+ * The array field component listens for this event and removes the item
2792
+ * at the specified index.
2793
+ *
2794
+ * @example
2795
+ * ```typescript
2796
+ * // Remove item at index 1 from 'contacts' array
2797
+ * eventBus.dispatch(RemoveArrayItemEvent, 'contacts', 1);
2798
+ *
2799
+ * // Remove last item
2800
+ * eventBus.dispatch(RemoveArrayItemEvent, 'contacts');
2801
+ * ```
2802
+ */
2803
+ declare class RemoveArrayItemEvent implements FormEvent {
2804
+ /** The key of the array field to remove an item from */
2805
+ readonly arrayKey: string;
2806
+ /** Index of the item to remove (defaults to last item) */
2807
+ readonly index?: number | undefined;
2808
+ readonly type: "remove-array-item";
2809
+ constructor(
2810
+ /** The key of the array field to remove an item from */
2811
+ arrayKey: string,
2812
+ /** Index of the item to remove (defaults to last item) */
2813
+ index?: number | undefined);
2814
+ }
2815
+
2816
+ /**
2817
+ * Event bus service for form-wide event communication.
2818
+ *
2819
+ * Provides type-safe event dispatching and subscription for form components
2820
+ * to communicate without direct coupling. Uses RxJS observables for reactive
2821
+ * event handling and supports both single event type and multiple event type subscriptions.
2822
+ *
2823
+ * @example
2824
+ * ```typescript
2825
+ * @Component({
2826
+ * providers: [EventBus]
2827
+ * })
2828
+ * export class MyFormComponent {
2829
+ * constructor(private eventBus: EventBus) {
2830
+ * // Subscribe to form submission events
2831
+ * this.eventBus.on<SubmitEvent>('submit').subscribe(() => {
2832
+ * console.log('Form was submitted');
2833
+ * });
2834
+ *
2835
+ * // Subscribe to multiple event types
2836
+ * this.eventBus.on<SubmitEvent | FormResetEvent>(['submit', 'form-reset']).subscribe(event => {
2837
+ * console.log('Form event:', event.type);
2838
+ * });
2839
+ * }
2840
+ *
2841
+ * onSubmit() {
2842
+ * // Dispatch a submit event
2843
+ * this.eventBus.dispatch(SubmitEvent);
2844
+ * }
2845
+ * }
2846
+ * ```
2847
+ */
2848
+ declare class EventBus {
2849
+ private pipeline$;
2850
+ events$: Observable<FormEvent>;
2851
+ /**
2852
+ * Dispatches an event to all subscribers.
2853
+ *
2854
+ * Creates an instance of the provided event constructor and broadcasts it
2855
+ * through the event pipeline to all active subscribers.
2856
+ *
2857
+ * @param eventConstructor - Constructor function for the event to dispatch
2858
+ *
2859
+ * @example
2860
+ * ```typescript
2861
+ * // Dispatch a submit event
2862
+ * eventBus.dispatch(SubmitEvent);
2863
+ *
2864
+ * // Dispatch a custom event
2865
+ * eventBus.dispatch(CustomFormEvent);
2866
+ * ```
2867
+ */
2868
+ dispatch<T extends FormEventConstructor>(eventConstructor: T, ...args: any[]): void;
2869
+ /**
2870
+ * Subscribes to events of a specific type.
2871
+ *
2872
+ * @param eventType - The type of event to subscribe to
2873
+ * @returns Observable that emits events of the specified type
2874
+ */
2875
+ on<T extends FormEvent>(eventType: T['type']): Observable<T>;
2876
+ /**
2877
+ * Subscribes to events of multiple types.
2878
+ *
2879
+ * @param eventType - Array of event types to subscribe to
2880
+ * @returns Observable that emits events matching any of the specified types
2881
+ */
2882
+ on<T extends FormEvent>(eventType: Array<T['type']>): Observable<T>;
2883
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<EventBus, never>;
2884
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<EventBus>;
2885
+ }
2886
+
2887
+ /**
2888
+ * Context for token resolution in event args
2889
+ */
2890
+ interface TokenContext {
2891
+ /** Current field key */
2892
+ key?: string;
2893
+ /** Array index if field is inside an array */
2894
+ index?: number;
2895
+ /** Parent array field key if field is inside an array */
2896
+ arrayKey?: string;
2897
+ /** Current form value for complex indexing */
2898
+ formValue?: unknown;
2899
+ }
2900
+ /**
2901
+ * Resolves special tokens in event arguments to their actual values
2902
+ *
2903
+ * Supported tokens:
2904
+ * - $key: The current field key
2905
+ * - $index: The array index (if inside an array field)
2906
+ * - $arrayKey: The parent array field key (if inside an array field)
2907
+ * - formValue: Reference to the current form value for indexing
2908
+ *
2909
+ * @param args - Array of arguments that may contain tokens
2910
+ * @param context - Context object containing token values
2911
+ * @returns Array with resolved values
2912
+ *
2913
+ * @example
2914
+ * resolveTokens(['$arrayKey', '$index'], { arrayKey: 'contacts', index: 2 })
2915
+ * // Returns: ['contacts', 2]
2916
+ *
2917
+ * @example
2918
+ * resolveTokens(['$key', 'static'], { key: 'myField' })
2919
+ * // Returns: ['myField', 'static']
2920
+ */
2921
+ declare function resolveTokens(args: readonly (string | number | boolean | null | undefined)[], context: TokenContext): (string | number | boolean | null | undefined | unknown)[];
2922
+
2923
+ /**
2924
+ * Context object for array item operations (add/remove)
2925
+ * Provides the necessary information to resolve tokens in array item event arguments
2926
+ */
2927
+ interface ArrayItemContext {
2928
+ /** The key of the field */
2929
+ key: string;
2930
+ /** Array index for the item */
2931
+ index?: number;
2932
+ /** Parent array field key */
2933
+ arrayKey?: string;
2934
+ /** Form value for token resolution */
2935
+ formValue?: unknown;
2936
+ }
2937
+
2938
+ /**
2939
+ * Maps a value field definition to component inputs.
2940
+ *
2941
+ * Value fields are input fields that contribute to the form's value (text, number, etc.).
2942
+ * This mapper injects FIELD_SIGNAL_CONTEXT to access the form structure and retrieve the field proxy.
2943
+ *
2944
+ * For fields with specific properties (select, datepicker, textarea, slider), use the specialized mappers:
2945
+ * - selectFieldMapper: for fields with options (select, radio, multi-checkbox)
2946
+ * - datepickerFieldMapper: for fields with minDate, maxDate, startAt
2947
+ * - textareaFieldMapper: for fields with rows, cols
2948
+ * - sliderFieldMapper: for fields with minValue, maxValue, step
2949
+ *
2950
+ * @param fieldDef The value field definition
2951
+ * @returns Signal containing Record of input names to values for ngComponentOutlet
2952
+ */
2953
+ declare function valueFieldMapper<TProps = unknown, TValue = unknown>(fieldDef: BaseValueField<TProps, TValue>): Signal<Record<string, unknown>>;
2954
+
2955
+ /**
2956
+ * Builds base input properties from a field definition.
2957
+ *
2958
+ * This is a helper function that extracts common field properties.
2959
+ * Used by mappers to build the inputs record.
2960
+ *
2961
+ * @param fieldDef The field definition to extract properties from
2962
+ * @returns Record of input names to values
2963
+ */
2964
+ declare function buildBaseInputs(fieldDef: FieldDef<unknown>): Record<string, unknown>;
2965
+ /**
2966
+ * Base field mapper that extracts common field properties into component inputs.
2967
+ *
2968
+ * Returns a Signal containing the Record of input names to values that will be
2969
+ * passed to ngComponentOutlet. The signal enables reactive updates.
2970
+ *
2971
+ * @param fieldDef The field definition to map
2972
+ * @returns Signal containing Record of input names to values
2973
+ */
2974
+ declare function baseFieldMapper(fieldDef: FieldDef<unknown>): Signal<Record<string, unknown>>;
2975
+
2976
+ /**
2977
+ * Maps a checkbox/toggle field definition to component inputs.
2978
+ *
2979
+ * Checkbox fields are checked fields that contribute to the form's value as boolean.
2980
+ * This mapper injects FIELD_SIGNAL_CONTEXT to access the form structure and retrieve the field proxy.
2981
+ *
2982
+ * @param fieldDef The checkbox field definition
2983
+ * @returns Signal containing Record of input names to values for ngComponentOutlet
2984
+ */
2985
+ declare function checkboxFieldMapper(fieldDef: BaseCheckedField<unknown>): Signal<Record<string, unknown>>;
2986
+
2987
+ /**
2988
+ * Maps a row field definition to component inputs.
2989
+ *
2990
+ * Row components are layout containers that don't change the form shape.
2991
+ * The row component will inject FIELD_SIGNAL_CONTEXT directly.
2992
+ *
2993
+ * @param fieldDef The row field definition
2994
+ * @returns Signal containing Record of input names to values for ngComponentOutlet
2995
+ */
2996
+ declare function rowFieldMapper(fieldDef: RowField): Signal<Record<string, unknown>>;
2997
+
2998
+ /**
2999
+ * Maps a group field definition to component inputs.
3000
+ *
3001
+ * Group components create nested form structures under the group's key.
3002
+ * The group component will inject the parent FIELD_SIGNAL_CONTEXT and create
3003
+ * a scoped child injector for its nested fields.
3004
+ *
3005
+ * @param fieldDef The group field definition
3006
+ * @returns Signal containing Record of input names to values for ngComponentOutlet
3007
+ */
3008
+ declare function groupFieldMapper(fieldDef: GroupField): Signal<Record<string, unknown>>;
3009
+
3010
+ /**
3011
+ * Maps an array field definition to component inputs.
3012
+ *
3013
+ * Array components create nested form structures under the array's key.
3014
+ * The array component will inject the parent FIELD_SIGNAL_CONTEXT and create
3015
+ * a scoped child injector for its array item fields.
3016
+ *
3017
+ * @param fieldDef The array field definition
3018
+ * @returns Signal containing Record of input names to values for ngComponentOutlet
3019
+ */
3020
+ declare function arrayFieldMapper(fieldDef: ArrayField): Signal<Record<string, unknown>>;
3021
+
3022
+ /**
3023
+ * Maps a page field definition to component inputs.
3024
+ *
3025
+ * Page fields are layout containers that don't modify the form context.
3026
+ * The page component will inject FIELD_SIGNAL_CONTEXT directly.
3027
+ *
3028
+ * @param fieldDef The page field definition
3029
+ * @returns Signal containing Record of input names to values for ngComponentOutlet
3030
+ */
3031
+ declare function pageFieldMapper(fieldDef: PageField): Signal<Record<string, unknown>>;
3032
+
3033
+ /**
3034
+ * Field types that have an options property.
3035
+ */
3036
+ type FieldWithOptions<T = unknown, TProps = unknown> = SelectField<T, TProps> | RadioField<T, TProps> | MultiCheckboxField<T, TProps>;
3037
+ /**
3038
+ * Maps a field with options (select, radio, multi-checkbox) to component inputs.
3039
+ *
3040
+ * Extends the base value field mapper by adding the options property.
3041
+ *
3042
+ * @param fieldDef The field definition with options
3043
+ * @returns Signal containing Record of input names to values for ngComponentOutlet
3044
+ */
3045
+ declare function optionsFieldMapper<T, TProps>(fieldDef: FieldWithOptions<T, TProps>): Signal<Record<string, unknown>>;
3046
+
3047
+ /**
3048
+ * Maps a datepicker field to component inputs.
3049
+ *
3050
+ * Extends the base value field mapper by adding datepicker-specific properties:
3051
+ * - minDate: Minimum selectable date
3052
+ * - maxDate: Maximum selectable date
3053
+ * - startAt: Initial date to display when opening the picker
3054
+ *
3055
+ * @param fieldDef The datepicker field definition
3056
+ * @returns Signal containing Record of input names to values for ngComponentOutlet
3057
+ */
3058
+ declare function datepickerFieldMapper<TProps>(fieldDef: DatepickerField<TProps>): Signal<Record<string, unknown>>;
3059
+
3060
+ /**
3061
+ * Converts DynamicText (string | Observable | Signal) to Observable<string>
3062
+ * Unifies all three types into a consistent Observable stream
3063
+ *
3064
+ * @param value - The dynamic text value to convert
3065
+ * @param injector - Optional injector for signal conversion
3066
+ * @returns Observable<string> - The value as an observable stream
3067
+ */
3068
+ declare function dynamicTextToObservable(value: DynamicText | undefined, injector?: Injector): Observable<string>;
3069
+
3070
+ /**
3071
+ * Computed signal that determines if errors should be displayed
3072
+ * Based on field's invalid, touched, and error count
3073
+ *
3074
+ * @param field - Signal containing FieldTree
3075
+ * @returns Signal<boolean> - True if errors should be displayed
3076
+ */
3077
+ declare function shouldShowErrors<T>(field: Signal<FieldTree<T>>): Signal<boolean>;
3078
+
3079
+ /**
3080
+ * Resolved validation error with interpolated message
3081
+ */
3082
+ interface ResolvedError {
3083
+ kind: string;
3084
+ message: string;
3085
+ }
3086
+ /**
3087
+ * Factory function that creates a signal of resolved validation errors
3088
+ * Handles async resolution of DynamicText validation messages
3089
+ *
3090
+ * @param field - Signal containing FieldTree
3091
+ * @param validationMessages - Signal containing custom field-level validation messages
3092
+ * @param defaultValidationMessages - Signal containing default validation messages (fallback)
3093
+ * @param injector - Optional injector for DynamicText resolution
3094
+ * @returns Signal<ResolvedError[]> - Reactively resolved error messages
3095
+ *
3096
+ * @example
3097
+ * ```typescript
3098
+ * readonly resolvedErrors = createResolvedErrorsSignal(
3099
+ * this.field,
3100
+ * this.validationMessages,
3101
+ * this.defaultValidationMessages
3102
+ * );
3103
+ * ```
3104
+ */
3105
+ declare function createResolvedErrorsSignal<T>(field: Signal<FieldTree<T>>, validationMessages: Signal<ValidationMessages | undefined>, defaultValidationMessages?: Signal<ValidationMessages | undefined>, injector?: Injector): Signal<ResolvedError[]>;
3106
+
3107
+ /**
3108
+ * Internal Angular Signal Forms structure interface.
3109
+ *
3110
+ * WARNING: These properties are internal Angular APIs and may change between versions.
3111
+ * This interface documents our dependency on Angular internals for form structure access.
3112
+ *
3113
+ * Used to access:
3114
+ * - `structure.childrenMap()` - Map of child field keys to their FieldTree instances
3115
+ * - `fieldProxy` - The FieldTree proxy for a FieldNode
3116
+ */
3117
+ interface FormInternals<T = unknown> {
3118
+ /**
3119
+ * Internal structure containing form graph information.
3120
+ * Present on forms created via `form()` function.
3121
+ */
3122
+ structure?: {
3123
+ /**
3124
+ * Returns a Map of child field keys to their FieldTree instances.
3125
+ * Keys are strings for object properties or stringified indices for arrays.
3126
+ */
3127
+ childrenMap?: () => Map<string, FieldTree<unknown>>;
3128
+ };
3129
+ /**
3130
+ * The FieldTree proxy for navigating the form graph.
3131
+ * Present on FieldNode instances.
3132
+ */
3133
+ fieldProxy?: FieldTree<T>;
3134
+ }
3135
+ /**
3136
+ * Type guard for checking if a form-like object has the internal structure property.
3137
+ *
3138
+ * @param form - The form object to check
3139
+ * @returns True if the form has a structure property with childrenMap
3140
+ */
3141
+ declare function hasFormStructure(form: unknown): form is FormInternals;
3142
+ /**
3143
+ * Safely retrieves the childrenMap from a form's internal structure.
3144
+ *
3145
+ * @param form - The form object (from `form()` function or FieldTree)
3146
+ * @returns The childrenMap or null if not available
3147
+ */
3148
+ declare function getChildrenMap(form: unknown): Map<string, FieldTree<unknown>> | null;
3149
+ /**
3150
+ * Safely retrieves the fieldProxy from a form node.
3151
+ *
3152
+ * @param node - The form node (FieldNode or similar)
3153
+ * @returns The fieldProxy FieldTree or null if not available
3154
+ */
3155
+ declare function getFieldProxy<T = unknown>(node: unknown): FieldTree<T> | null;
3156
+ /**
3157
+ * Retrieves a child FieldTree from a form by key.
3158
+ *
3159
+ * @param form - The parent form
3160
+ * @param key - The child field key
3161
+ * @returns The child FieldTree or null if not found
3162
+ */
3163
+ declare function getChildFieldTree(form: unknown, key: string): FieldTree<unknown> | null;
3164
+
3165
+ /**
3166
+ * Pipe that handles dynamic text resolution with support for static strings,
3167
+ * Observables, and Signals.
3168
+ *
3169
+ * Supports:
3170
+ * - Static strings (pass-through)
3171
+ * - Observables (subscribed internally)
3172
+ * - Signals (converted to Observable using toObservable for reactivity)
3173
+ *
3174
+ * @example
3175
+ * ```html
3176
+ * <!-- Static string -->
3177
+ * {{ 'Hello World' | dynamicText | async }}
3178
+ *
3179
+ * <!-- Observable -->
3180
+ * {{ transloco.selectTranslate('key') | dynamicText | async }}
3181
+ *
3182
+ * <!-- Signal -->
3183
+ * {{ myTextSignal | dynamicText | async }}
3184
+ * ```
3185
+ *
3186
+ * @public
3187
+ */
3188
+ declare class DynamicTextPipe implements PipeTransform {
3189
+ private readonly injector;
3190
+ /**
3191
+ * Transforms dynamic text input into a resolved string value
3192
+ *
3193
+ * @param value - The dynamic text value to resolve
3194
+ * @returns The resolved string value as an Observable
3195
+ */
3196
+ transform(value: DynamicText | undefined): Observable<string>;
3197
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DynamicTextPipe, never>;
3198
+ static ɵpipe: _angular_core.ɵɵPipeDeclaration<DynamicTextPipe, "dynamicText", true>;
3199
+ }
3200
+
3201
+ /**
3202
+ * Layout container for horizontal field arrangement.
3203
+ *
3204
+ * Does not create a new form context - fields share the parent's context.
3205
+ * Field values are flattened into the parent form (no nesting under row key).
3206
+ * Purely a visual/layout container with no impact on form structure.
3207
+ */
3208
+ declare class RowFieldComponent {
3209
+ private readonly destroyRef;
3210
+ private readonly fieldRegistry;
3211
+ private readonly injector;
3212
+ private readonly eventBus;
3213
+ field: _angular_core.InputSignal<RowField<readonly _ng_forge_dynamic_forms.RowAllowedChildren[]>>;
3214
+ key: _angular_core.InputSignal<string>;
3215
+ readonly disabled: _angular_core.Signal<boolean>;
3216
+ private readonly rawFieldRegistry;
3217
+ private readonly fieldsSource;
3218
+ protected readonly resolvedFields: _angular_core.Signal<ResolvedField[]>;
3219
+ private readonly emitInitializedOnFieldsResolved;
3220
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<RowFieldComponent, never>;
3221
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<RowFieldComponent, "div[row-field]", never, { "field": { "alias": "field"; "required": true; "isSignal": true; }; "key": { "alias": "key"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
3222
+ }
3223
+
3224
+ /**
3225
+ * Container component for rendering nested form groups.
3226
+ *
3227
+ * Creates a scoped form context with its own validation state.
3228
+ * Child fields receive a FIELD_SIGNAL_CONTEXT scoped to this group's form instance.
3229
+ * Group values are nested under the group's key in the parent form.
3230
+ */
3231
+ declare class GroupFieldComponent<TModel = Record<string, unknown>> {
3232
+ private readonly destroyRef;
3233
+ private readonly fieldRegistry;
3234
+ private readonly parentFieldSignalContext;
3235
+ private readonly injector;
3236
+ private readonly eventBus;
3237
+ private readonly memoizedFlattenFields;
3238
+ private readonly memoizedKeyBy;
3239
+ private readonly memoizedDefaultValues;
3240
+ field: _angular_core.InputSignal<GroupField<readonly _ng_forge_dynamic_forms.GroupAllowedChildren[]>>;
3241
+ key: _angular_core.InputSignal<string>;
3242
+ private readonly rawFieldRegistry;
3243
+ private readonly formSetup;
3244
+ readonly defaultValues: _angular_core.WritableSignal<Record<string, unknown>>;
3245
+ private readonly entity;
3246
+ private readonly form;
3247
+ readonly formValue: _angular_core.Signal<{}>;
3248
+ readonly valid: _angular_core.Signal<boolean>;
3249
+ readonly invalid: _angular_core.Signal<boolean>;
3250
+ readonly dirty: _angular_core.Signal<boolean>;
3251
+ readonly touched: _angular_core.Signal<boolean>;
3252
+ readonly errors: _angular_core.Signal<_angular_forms_signals.ValidationError.WithField[]>;
3253
+ readonly disabled: _angular_core.Signal<boolean>;
3254
+ /**
3255
+ * Get the nested FieldTree from the parent form for this group.
3256
+ * This allows child fields to update the parent form directly,
3257
+ * avoiding the need for separate form synchronization.
3258
+ */
3259
+ private readonly nestedFieldTree;
3260
+ private readonly groupInjector;
3261
+ readonly validityChange: _angular_core.OutputRef<boolean>;
3262
+ readonly dirtyChange: _angular_core.OutputRef<boolean>;
3263
+ readonly submitted: _angular_core.OutputRef<SubmitEvent>;
3264
+ private readonly fieldsSource;
3265
+ protected readonly resolvedFields: _angular_core.Signal<ResolvedField[]>;
3266
+ private readonly emitInitializedOnFieldsResolved;
3267
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<GroupFieldComponent<any>, never>;
3268
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<GroupFieldComponent<any>, "fieldset[group-field]", never, { "field": { "alias": "field"; "required": true; "isSignal": true; }; "key": { "alias": "key"; "required": true; "isSignal": true; }; }, { "validityChange": "validityChange"; "dirtyChange": "dirtyChange"; "submitted": "submitted"; }, never, never, true, never>;
3269
+ }
3270
+
3271
+ /**
3272
+ * Resolved array item ready for declarative rendering with ngComponentOutlet.
3273
+ * Each item has a stable unique ID and a linkedSignal-based index that
3274
+ * automatically updates when items are added/removed.
3275
+ */
3276
+ interface ResolvedArrayItem {
3277
+ /** Unique identifier for this item (stable across position changes). */
3278
+ id: string;
3279
+ /** The loaded component type. */
3280
+ component: Type<unknown>;
3281
+ /** Injector providing ARRAY_CONTEXT and FIELD_SIGNAL_CONTEXT. */
3282
+ injector: Injector;
3283
+ /** Inputs signal for ngComponentOutlet - evaluated in template for reactivity. */
3284
+ inputs: Signal<Record<string, unknown>>;
3285
+ }
3286
+
3287
+ /**
3288
+ * Container component for rendering dynamic arrays of fields.
3289
+ *
3290
+ * Supports add/remove operations via AddArrayItemEvent and RemoveArrayItemEvent.
3291
+ * Uses differential updates to optimize rendering - only recreates items when necessary.
3292
+ * Each item gets a scoped injector with ARRAY_CONTEXT for position-aware operations.
3293
+ */
3294
+ declare class ArrayFieldComponent<TModel = Record<string, unknown>> {
3295
+ private readonly destroyRef;
3296
+ private readonly fieldRegistry;
3297
+ private readonly parentFieldSignalContext;
3298
+ private readonly parentInjector;
3299
+ private readonly eventBus;
3300
+ field: _angular_core.InputSignal<ArrayField<readonly _ng_forge_dynamic_forms.ArrayAllowedChildren[]>>;
3301
+ key: _angular_core.InputSignal<string>;
3302
+ private readonly rawFieldRegistry;
3303
+ private readonly fieldTemplate;
3304
+ private readonly arrayFieldTrees;
3305
+ private readonly resolvedItemsSignal;
3306
+ private readonly updateVersion;
3307
+ private readonly itemOrderSignal;
3308
+ readonly resolvedItems: _angular_core.WritableSignal<ResolvedArrayItem[]>;
3309
+ private readonly syncFieldsOnArrayChange;
3310
+ private readonly handleAddItem;
3311
+ private readonly handleRemoveItem;
3312
+ private performDifferentialUpdate;
3313
+ private resolveAllItems;
3314
+ private appendItems;
3315
+ private createResolveItemObservable;
3316
+ private addItem;
3317
+ private removeItem;
3318
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ArrayFieldComponent<any>, never>;
3319
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ArrayFieldComponent<any>, "array-field", never, { "field": { "alias": "field"; "required": true; "isSignal": true; }; "key": { "alias": "key"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
3320
+ }
3321
+
3322
+ /**
3323
+ * Injection function for accessing the dynamic form field registry.
3324
+ *
3325
+ * Provides a convenient API for interacting with registered field types,
3326
+ * including type checking, component loading, and registration management.
3327
+ * Must be called within an injection context.
3328
+ *
3329
+ * @returns Object with methods for field registry interaction
3330
+ *
3331
+ * @example
3332
+ * ```typescript
3333
+ * @Component({...})
3334
+ * export class MyComponent {
3335
+ * private fieldRegistry = injectFieldRegistry();
3336
+ *
3337
+ * async loadCustomField() {
3338
+ * if (this.fieldRegistry.hasType('custom-input')) {
3339
+ * const component = await this.fieldRegistry.loadTypeComponent('custom-input');
3340
+ * // Use component...
3341
+ * }
3342
+ * }
3343
+ * }
3344
+ * ```
3345
+ *
3346
+ * @example
3347
+ * ```typescript
3348
+ * // In a service
3349
+ * @Injectable()
3350
+ * export class FormBuilderService {
3351
+ * private fieldRegistry = injectFieldRegistry();
3352
+ *
3353
+ * getAvailableFieldTypes(): string[] {
3354
+ * return this.fieldRegistry.getTypes().map(type => type.name);
3355
+ * }
3356
+ * }
3357
+ * ```
3358
+ *
3359
+ * @public
3360
+ */
3361
+ declare function injectFieldRegistry(): {
3362
+ /**
3363
+ * Retrieves a field type definition by its registered name.
3364
+ *
3365
+ * @param name - The registered name of the field type
3366
+ * @returns The field type definition if found, undefined otherwise
3367
+ *
3368
+ * @example
3369
+ * ```typescript
3370
+ * const inputType = fieldRegistry.getType('input');
3371
+ * if (inputType) {
3372
+ * console.log('Input field type found:', inputType.name);
3373
+ * }
3374
+ * ```
3375
+ */
3376
+ getType(name: string): FieldTypeDefinition | undefined;
3377
+ /**
3378
+ * Checks if a field type is registered in the registry.
3379
+ *
3380
+ * @param name - The name of the field type to check
3381
+ * @returns True if the field type exists, false otherwise
3382
+ *
3383
+ * @example
3384
+ * ```typescript
3385
+ * if (fieldRegistry.hasType('custom-input')) {
3386
+ * // Safe to use custom-input field type
3387
+ * const component = await fieldRegistry.loadTypeComponent('custom-input');
3388
+ * }
3389
+ * ```
3390
+ */
3391
+ hasType(name: string): boolean;
3392
+ /**
3393
+ * Loads a field type component with support for lazy loading.
3394
+ *
3395
+ * Handles both synchronous component references and asynchronous
3396
+ * dynamic imports. Automatically extracts default exports from ES modules.
3397
+ *
3398
+ * @param name - The name of the field type to load
3399
+ * @returns Promise resolving to the component constructor
3400
+ * @throws {Error} When field type is not registered or loading fails
3401
+ *
3402
+ * @example
3403
+ * ```typescript
3404
+ * try {
3405
+ * const InputComponent = await fieldRegistry.loadTypeComponent('input');
3406
+ * const componentRef = vcr.createComponent(InputComponent);
3407
+ * } catch (error) {
3408
+ * console.error('Failed to load component:', error);
3409
+ * }
3410
+ * ```
3411
+ */
3412
+ loadTypeComponent(name: string): Promise<Type<unknown>>;
3413
+ /**
3414
+ * Gets all registered field type definitions.
3415
+ *
3416
+ * @returns Array of all field type definitions in the registry
3417
+ *
3418
+ * @example
3419
+ * ```typescript
3420
+ * const allTypes = fieldRegistry.getTypes();
3421
+ * const typeNames = allTypes.map(type => type.name);
3422
+ * console.log('Available field types:', typeNames);
3423
+ * ```
3424
+ */
3425
+ getTypes(): FieldTypeDefinition[];
3426
+ /**
3427
+ * Registers multiple field types at once.
3428
+ *
3429
+ * Useful for bulk registration of custom field types. Overwrites
3430
+ * existing registrations with the same name.
3431
+ *
3432
+ * @param types - Array of field type definitions to register
3433
+ *
3434
+ * @example
3435
+ * ```typescript
3436
+ * fieldRegistry.registerTypes([
3437
+ * CustomInputType,
3438
+ * CustomSelectType,
3439
+ * CustomDatePickerType
3440
+ * ]);
3441
+ * ```
3442
+ */
3443
+ registerTypes(types: FieldTypeDefinition[]): void;
3444
+ /**
3445
+ * Provides direct access to the underlying registry Map.
3446
+ *
3447
+ * Use with caution - direct modification can affect form behavior.
3448
+ * Primarily intended for advanced use cases and debugging.
3449
+ *
3450
+ * @returns The raw Map containing field type registrations
3451
+ *
3452
+ * @example
3453
+ * ```typescript
3454
+ * const rawRegistry = fieldRegistry.raw;
3455
+ * console.log('Registry size:', rawRegistry.size);
3456
+ * ```
3457
+ */
3458
+ readonly raw: Map<string, FieldTypeDefinition<any>>;
3459
+ };
3460
+
3461
+ export { ARRAY_CONTEXT, AddArrayItemEvent, ArrayFieldComponent, BUILT_IN_FIELDS, DynamicForm, DynamicTextPipe, EventBus, FIELD_REGISTRY, FIELD_SIGNAL_CONTEXT, FormClearEvent, FormResetEvent, GroupFieldComponent, NextPageEvent, PageChangeEvent, PreviousPageEvent, RemoveArrayItemEvent, RowFieldComponent, SubmitEvent, applyValidator, applyValidators, arrayFieldMapper, baseFieldMapper, buildBaseInputs, checkboxFieldMapper, createResolvedErrorsSignal, datepickerFieldMapper, dynamicTextToObservable, getChildFieldTree, getChildrenMap, getFieldProxy, getFieldValueHandling, groupFieldMapper, hasFormStructure, injectFieldRegistry, isArrayField, isCheckedField, isContainerField, isDisplayOnlyField, isFormStateCondition, isGroupField, isLeafField, isPageField, isRowField, isValueBearingField, isValueField, optionsFieldMapper, pageFieldMapper, provideDynamicForm, resolveNextButtonDisabled, resolveSubmitButtonDisabled, resolveTokens, rowFieldMapper, shouldShowErrors, valueFieldMapper };
3462
+ export type { ArrayAllowedChildren, ArrayContext, ArrayField, ArrayItemContext, AsyncCustomValidator, AsyncValidatorConfig, AvailableFieldTypes, BaseCheckedField, BaseValidatorConfig, BaseValueField, BuiltInValidatorConfig, ButtonField, ButtonLogicContext, CheckboxField, CheckedFieldComponent, ConditionalExpression, ContainerFieldTypes, CustomFnConfig, CustomValidator, CustomValidatorConfig, DatepickerField, DatepickerProps, DynamicFormFieldRegistry, DynamicText, EvaluationContext, EventArgs, ExtractFieldDefs, ExtractFormValue, FieldComponent, FieldDef, FieldOption, FieldPathAccess, FieldRegistryContainers, FieldRegistryLeaves, FieldSignalContext, FieldTypeDefinition, FieldWithValidation, FormConfig, FormEvent, FormEventConstructor, FormInternals, FormMode, FormModeDetectionResult, FormOptions, FormStateCondition, GroupAllowedChildren, GroupField, HttpCustomValidator, HttpResourceRequest, HttpValidatorConfig, InferFormValue$1 as InferFormValue, InputField, InputProps, LeafFieldTypes, LogicConfig, MapperFn, MultiCheckboxField, NextButtonOptions, PageAllowedChildren, PageField, Prettify, RadioField, RegisteredFieldTypes, ResolvedError, RowAllowedChildren, RowField, SchemaApplicationConfig, SchemaDefinition, SelectField, SelectProps, SliderField, SubmissionActionResult, SubmissionConfig, SubmitButtonOptions, TextElementType, TextField, TextProps, TextareaField, TextareaProps, ToggleField, TokenContext, ValidationError, ValidationMessages, ValidatorConfig, ValueFieldComponent, ValueHandlingMode, ValueType, WithInputSignals };