@ng-forge/dynamic-forms 0.9.0-next.11 → 0.9.0-next.12

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.
Files changed (26) hide show
  1. package/fesm2022/{ng-forge-dynamic-forms-array-field.component-DJ-LiLm_.mjs → ng-forge-dynamic-forms-array-field.component-BgCrTME1.mjs} +154 -69
  2. package/fesm2022/ng-forge-dynamic-forms-array-field.component-BgCrTME1.mjs.map +1 -0
  3. package/fesm2022/{ng-forge-dynamic-forms-container-field.component-Pcxg5PQu.mjs → ng-forge-dynamic-forms-container-field.component-VHaBk_1l.mjs} +9 -5
  4. package/fesm2022/ng-forge-dynamic-forms-container-field.component-VHaBk_1l.mjs.map +1 -0
  5. package/fesm2022/{ng-forge-dynamic-forms-container-utils-a4RstR2Z.mjs → ng-forge-dynamic-forms-container-utils-CGJiiKBY.mjs} +2 -2
  6. package/fesm2022/{ng-forge-dynamic-forms-container-utils-a4RstR2Z.mjs.map → ng-forge-dynamic-forms-container-utils-CGJiiKBY.mjs.map} +1 -1
  7. package/fesm2022/{ng-forge-dynamic-forms-css-wrapper.component-CJACCIEK.mjs → ng-forge-dynamic-forms-css-wrapper.component-BOdw40ZF.mjs} +2 -2
  8. package/fesm2022/{ng-forge-dynamic-forms-css-wrapper.component-CJACCIEK.mjs.map → ng-forge-dynamic-forms-css-wrapper.component-BOdw40ZF.mjs.map} +1 -1
  9. package/fesm2022/{ng-forge-dynamic-forms-emit-initialization-Bjf_I0D_.mjs → ng-forge-dynamic-forms-emit-initialization-D72mQxlX.mjs} +2 -2
  10. package/fesm2022/{ng-forge-dynamic-forms-emit-initialization-Bjf_I0D_.mjs.map → ng-forge-dynamic-forms-emit-initialization-D72mQxlX.mjs.map} +1 -1
  11. package/fesm2022/{ng-forge-dynamic-forms-group-field.component-fzKwPrQr.mjs → ng-forge-dynamic-forms-group-field.component-BvTQwoLg.mjs} +9 -5
  12. package/fesm2022/ng-forge-dynamic-forms-group-field.component-BvTQwoLg.mjs.map +1 -0
  13. package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-o3rJX4vG.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-BAPGCjUs.mjs} +396 -248
  14. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-BAPGCjUs.mjs.map +1 -0
  15. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-BX4R9GGa.mjs → ng-forge-dynamic-forms-page-field.component-DDzmhJNn.mjs} +9 -5
  16. package/fesm2022/ng-forge-dynamic-forms-page-field.component-DDzmhJNn.mjs.map +1 -0
  17. package/fesm2022/{ng-forge-dynamic-forms-text-field.component-B9SK8Vun.mjs → ng-forge-dynamic-forms-text-field.component-Bo4zNJXY.mjs} +2 -2
  18. package/fesm2022/{ng-forge-dynamic-forms-text-field.component-B9SK8Vun.mjs.map → ng-forge-dynamic-forms-text-field.component-Bo4zNJXY.mjs.map} +1 -1
  19. package/fesm2022/ng-forge-dynamic-forms.mjs +1 -1
  20. package/package.json +1 -1
  21. package/types/ng-forge-dynamic-forms.d.ts +488 -468
  22. package/fesm2022/ng-forge-dynamic-forms-array-field.component-DJ-LiLm_.mjs.map +0 -1
  23. package/fesm2022/ng-forge-dynamic-forms-container-field.component-Pcxg5PQu.mjs.map +0 -1
  24. package/fesm2022/ng-forge-dynamic-forms-group-field.component-fzKwPrQr.mjs.map +0 -1
  25. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-o3rJX4vG.mjs.map +0 -1
  26. package/fesm2022/ng-forge-dynamic-forms-page-field.component-BX4R9GGa.mjs.map +0 -1
@@ -16,8 +16,6 @@ type Prettify<T> = {
16
16
  [K in keyof T]: T[K];
17
17
  } & {};
18
18
 
19
- type DynamicText = string | Observable<string> | Signal<string>;
20
-
21
19
  /**
22
20
  * Interface for dynamic forms logger implementations.
23
21
  * Allows custom logging integrations (Sentry, DataDog, etc.)
@@ -589,214 +587,31 @@ interface ContainerLogicConfig {
589
587
  }
590
588
 
591
589
  /**
592
- * An array item template is an array of allowed children that defines one OBJECT array item's fields.
593
- * Used for object arrays where each item is `{ key1: value1, key2: value2, ... }`.
594
- */
595
- type ArrayItemTemplate = readonly ArrayAllowedChildren[];
596
- /**
597
- * An array item definition can be either:
598
- * - A single field (ArrayAllowedChildren) for PRIMITIVE array items - extracts field value directly
599
- * - An array of fields (ArrayItemTemplate) for OBJECT array items - merges fields into object
600
- *
601
- * This allows support for:
602
- * - Primitive arrays: `['tag1', 'tag2']`
603
- * - Object arrays: `[{ name: 'Alice', email: '...' }]`
604
- * - Heterogeneous arrays: `[{ value: 'x' }, 'y']` (mixed primitives and objects)
605
- */
606
- type ArrayItemDefinition = ArrayAllowedChildren | ArrayItemTemplate;
607
- /**
608
- * Array field interface for creating dynamic field collections that map to array values.
609
- *
610
- * Key concepts:
611
- * - The outer `fields` array defines INITIAL ITEMS (each element is one array item to render)
612
- * - Each element can be either:
613
- * - A single FieldDef (primitive item) - the field's value is extracted directly
614
- * - An array of FieldDefs (object item) - fields are merged into an object
615
- * - Items can have different field configurations (heterogeneous arrays supported)
616
- * - Empty `fields: []` means no initial items - user adds via buttons with explicit templates
617
- * - Initial values are declared via `value` property on each field definition
618
- *
619
- * @example
620
- * // Primitive array: ['angular', 'typescript']
621
- * {
622
- * key: 'tags',
623
- * type: 'array',
624
- * fields: [
625
- * { key: 'tag', type: 'input', value: 'angular' }, // Single field = primitive
626
- * { key: 'tag', type: 'input', value: 'typescript' },
627
- * ]
628
- * }
629
- *
630
- * @example
631
- * // Object array: [{ name: 'Alice', email: '...' }]
632
- * {
633
- * key: 'contacts',
634
- * type: 'array',
635
- * fields: [
636
- * [ // Array = object
637
- * { key: 'name', type: 'input', value: 'Alice' },
638
- * { key: 'email', type: 'input', value: 'alice@example.com' }
639
- * ],
640
- * ]
641
- * }
642
- *
643
- * @example
644
- * // Heterogeneous array: [{ label: 'Structured' }, 'Simple']
645
- * {
646
- * key: 'items',
647
- * type: 'array',
648
- * fields: [
649
- * [{ key: 'label', type: 'input', value: 'Structured' }], // Object item
650
- * { key: 'value', type: 'input', value: 'Simple' }, // Primitive item
651
- * ]
652
- * }
653
- *
654
- * @example
655
- * // Empty array (add items via buttons)
656
- * {
657
- * key: 'tags',
658
- * type: 'array',
659
- * fields: [] // No initial items - user adds via button with template
660
- * }
661
- *
662
- * Nesting constraints: Arrays can contain rows, leaf fields, or groups (for object arrays),
663
- * but NOT pages or other arrays. Runtime validation enforces these rules.
590
+ * Row field interface for creating horizontal layouts.
591
+ * A row is a synthetic field type that resolves to a Container at runtime,
592
+ * with a synthesized `{ type: 'row' }` wrapper applied for layout. The row
593
+ * itself does not hold a value — its children flatten into the parent form.
664
594
  *
665
- * Note: Arrays are container fields and do not support `meta` since they have no native form element.
595
+ * Note: Rows do not support `meta` since they have no native form element.
666
596
  */
667
- interface ArrayField<TFields extends readonly ArrayItemDefinition[] = readonly ArrayItemDefinition[]> extends FieldDef<never> {
668
- type: 'array';
669
- /**
670
- * Array of item definitions. Each element defines one array item:
671
- * - Single FieldDef = primitive item (field's value is extracted directly)
672
- * - Array of FieldDefs = object item (fields are merged into an object)
673
- * - Empty array `[]` = no initial items (add via buttons with explicit templates)
674
- * - Items can have different configurations (heterogeneous arrays supported)
675
- * - Initial values are set via `value` property on each field definition
676
- */
597
+ interface RowField<TFields extends readonly RowAllowedChildren[] = readonly RowAllowedChildren[]> extends FieldDef<never> {
598
+ type: 'row';
599
+ /** Child definitions to render within this row */
677
600
  readonly fields: TFields;
678
- /** Array fields do not have a label property **/
679
- readonly label?: never;
680
- /** Arrays do not support meta - they have no native form element **/
681
- readonly meta?: never;
682
- /**
683
- * Logic configurations for conditional array visibility.
684
- * Only 'hidden' type logic is supported for arrays.
685
- */
686
- readonly logic?: ContainerLogicConfig[];
687
- /**
688
- * Minimum number of items required in the array.
689
- * Validation fails if the array has fewer items than this value.
690
- */
691
- readonly minLength?: number;
692
- /**
693
- * Maximum number of items allowed in the array.
694
- * Validation fails if the array has more items than this value.
695
- */
696
- readonly maxLength?: number;
697
- }
698
- /**
699
- * Type guard for ArrayField with proper type narrowing.
700
- * Validates that the field is an array type with a fields property that is an array.
701
- * Fields can contain either single FieldDefs (primitive items) or arrays of FieldDefs (object items).
702
- */
703
- declare function isArrayField(field: FieldDef<any>): field is ArrayField;
704
- /**
705
- * Configuration for auto-generated add/remove buttons in simplified array fields.
706
- */
707
- interface ArrayButtonConfig {
708
- /** Custom label for the button */
709
- readonly label?: string;
710
- /** Additional properties passed to the button component */
711
- readonly props?: Record<string, unknown>;
712
- }
713
- /**
714
- * Simplified array field interface for common use cases.
715
- *
716
- * Instead of manually specifying each item in `fields`, provide a `template` that defines
717
- * the structure of a single item, and a `value` array with initial data.
718
- * The library auto-generates add/remove buttons.
719
- *
720
- * Discriminant: `template` presence → simplified API; `Array.isArray(template)` → object vs primitive.
721
- *
722
- * @example
723
- * // Primitive array: ['angular', 'typescript']
724
- * {
725
- * key: 'tags',
726
- * type: 'array',
727
- * template: { key: 'value', type: 'input', label: 'Tag', required: true },
728
- * value: ['angular', 'typescript']
729
- * }
730
- *
731
- * @example
732
- * // Object array: [{ name: 'Jane', phone: '555' }]
733
- * {
734
- * key: 'contacts',
735
- * type: 'array',
736
- * template: [
737
- * { key: 'name', type: 'input', label: 'Contact Name', required: true },
738
- * { key: 'phone', type: 'input', label: 'Phone Number' },
739
- * ],
740
- * value: [{ name: 'Jane', phone: '555' }]
741
- * }
742
- *
743
- * @example
744
- * // Button customization / opt-out
745
- * {
746
- * key: 'tags',
747
- * type: 'array',
748
- * template: { key: 'value', type: 'input', label: 'Tag' },
749
- * addButton: { label: 'Add Tag', props: { color: 'primary' } },
750
- * removeButton: false
751
- * }
752
- */
753
- interface SimplifiedArrayField extends FieldDef<never> {
754
- type: 'array';
755
- /**
756
- * Template defining the structure of a single array item.
757
- * - Single field (ArrayAllowedChildren) → primitive array (each item is a single value)
758
- * - Array of fields (readonly ArrayAllowedChildren[]) → object array (each item is an object)
759
- */
760
- readonly template: ArrayAllowedChildren | readonly ArrayAllowedChildren[];
761
- /** Initial values for the array. Each element creates one array item. */
762
- readonly value?: readonly unknown[];
763
- /**
764
- * Configuration for the auto-generated "Add" button, or `false` to disable it.
765
- * Defaults to a button with label "Add".
766
- */
767
- readonly addButton?: ArrayButtonConfig | false;
768
- /**
769
- * Configuration for the auto-generated "Remove" button on each item, or `false` to disable it.
770
- * Defaults to a button with label "Remove".
771
- */
772
- readonly removeButton?: ArrayButtonConfig | false;
773
- /** Simplified arrays do not support the label property */
601
+ /** Row fields do not have a label property **/
774
602
  readonly label?: never;
775
- /** Simplified arrays do not support meta */
603
+ /** Rows do not support meta - they have no native form element **/
776
604
  readonly meta?: never;
777
605
  /**
778
- * Logic configurations for conditional array visibility.
779
- * Only 'hidden' type logic is supported for arrays.
606
+ * Logic configurations for conditional row visibility.
607
+ * Only 'hidden' type logic is supported for rows.
780
608
  */
781
609
  readonly logic?: ContainerLogicConfig[];
782
- /**
783
- * Minimum number of items required in the array.
784
- * Validation fails if the array has fewer items than this value.
785
- */
786
- readonly minLength?: number;
787
- /**
788
- * Maximum number of items allowed in the array.
789
- * Validation fails if the array has more items than this value.
790
- */
791
- readonly maxLength?: number;
792
- /** Mutually exclusive with `template` — use `fields` for the full API instead */
793
- readonly fields?: never;
794
610
  }
795
611
  /**
796
- * Type guard for SimplifiedArrayField.
797
- * Checks for `type: 'array'` with a `template` property (discriminant from full ArrayField).
612
+ * Type guard for RowField with proper type narrowing
798
613
  */
799
- declare function isSimplifiedArrayField(field: FieldDef<any>): field is SimplifiedArrayField;
614
+ declare function isRowField(field: FieldDef<any>): field is RowField;
800
615
 
801
616
  /**
802
617
  * Group field interface for creating logical field groupings that map to object values
@@ -828,67 +643,15 @@ interface GroupField<TFields extends readonly GroupAllowedChildren[] = readonly
828
643
  declare function isGroupField(field: FieldDef<any>): field is GroupField;
829
644
 
830
645
  /**
831
- * Scalar types supported by hidden fields.
832
- * These are the primitive value types that can be stored.
833
- */
834
- type HiddenScalar = string | number | boolean;
835
- /**
836
- * All value types supported by hidden fields.
837
- * Supports both scalar values and arrays of scalars for storing
838
- * multiple IDs or similar data.
839
- */
840
- type HiddenValue = HiddenScalar | HiddenScalar[];
841
- /**
842
- * Hidden field definition for storing values without rendering UI.
843
- *
844
- * Hidden fields participate in the form schema and contribute to form values,
845
- * but do not render any visible component. They are useful for:
846
- * - Storing IDs when updating existing records
847
- * - Persisting metadata that shouldn't be user-editable
848
- * - Tracking computed values that need to be submitted
849
- *
850
- * Unlike the `hidden` property on other fields (which hides a rendered field),
851
- * this field type renders nothing at all - it's a componentless field.
646
+ * Page field interface for creating top-level page layouts
647
+ * This is a special field type that contains other field definitions
648
+ * The page itself doesn't have a value - it's a layout container like row
649
+ * Pages can only be used at the top level and cannot be nested
650
+ * This is a programmatic field type only - users cannot customize this field type
852
651
  *
853
- * @example
854
- * ```typescript
855
- * // Store a record ID for updates
856
- * const idField: HiddenField<string> = {
857
- * type: 'hidden',
858
- * key: 'id',
859
- * value: '550e8400-e29b-41d4-a716-446655440000',
860
- * };
861
- *
862
- * // Store multiple tag IDs
863
- * const tagIdsField: HiddenField<number[]> = {
864
- * type: 'hidden',
865
- * key: 'tagIds',
866
- * value: [1, 2, 3],
867
- * };
868
- * ```
869
- *
870
- * @typeParam TValue - The type of value stored (must be HiddenValue compatible)
871
- */
872
- interface HiddenField<TValue extends HiddenValue = HiddenValue> extends FieldDef<never> {
873
- /** Discriminant for hidden field type */
874
- type: 'hidden';
875
- /**
876
- * The value to store in the form.
877
- * This is required - a hidden field without a value serves no purpose.
878
- */
879
- value: TValue;
880
- }
881
-
882
- /**
883
- * Page field interface for creating top-level page layouts
884
- * This is a special field type that contains other field definitions
885
- * The page itself doesn't have a value - it's a layout container like row
886
- * Pages can only be used at the top level and cannot be nested
887
- * This is a programmatic field type only - users cannot customize this field type
888
- *
889
- * TypeScript cannot enforce field nesting rules due to circular dependency limitations.
890
- * For documentation: Pages should contain rows, groups, and leaf fields, but NOT other pages.
891
- * Runtime validation enforces these rules.
652
+ * TypeScript cannot enforce field nesting rules due to circular dependency limitations.
653
+ * For documentation: Pages should contain rows, groups, and leaf fields, but NOT other pages.
654
+ * Runtime validation enforces these rules.
892
655
  *
893
656
  * Note: Pages are container fields and do not support `meta` since they have no native form element.
894
657
  */
@@ -2335,6 +2098,8 @@ interface SchemaDefinition {
2335
2098
  subSchemas?: SchemaApplicationConfig[];
2336
2099
  }
2337
2100
 
2101
+ type DynamicText = string | Observable<string> | Signal<string>;
2102
+
2338
2103
  /**
2339
2104
  * Re-export Angular's ValidationError for consistency
2340
2105
  * This replaces our custom ValidationError interface
@@ -2420,7 +2185,6 @@ type SubmissionActionResult = Promise<TreeValidationResult> | Observable<TreeVal
2420
2185
  * @typeParam TValue - The form value type
2421
2186
  *
2422
2187
  * @public
2423
- * @experimental
2424
2188
  */
2425
2189
  interface SubmissionConfig<TValue = unknown> {
2426
2190
  /**
@@ -3433,6 +3197,58 @@ interface TextField extends FieldDef<TextProps> {
3433
3197
  readonly logic?: NonFieldLogicConfig[];
3434
3198
  }
3435
3199
 
3200
+ /**
3201
+ * Scalar types supported by hidden fields.
3202
+ * These are the primitive value types that can be stored.
3203
+ */
3204
+ type HiddenScalar = string | number | boolean;
3205
+ /**
3206
+ * All value types supported by hidden fields.
3207
+ * Supports both scalar values and arrays of scalars for storing
3208
+ * multiple IDs or similar data.
3209
+ */
3210
+ type HiddenValue = HiddenScalar | HiddenScalar[];
3211
+ /**
3212
+ * Hidden field definition for storing values without rendering UI.
3213
+ *
3214
+ * Hidden fields participate in the form schema and contribute to form values,
3215
+ * but do not render any visible component. They are useful for:
3216
+ * - Storing IDs when updating existing records
3217
+ * - Persisting metadata that shouldn't be user-editable
3218
+ * - Tracking computed values that need to be submitted
3219
+ *
3220
+ * Unlike the `hidden` property on other fields (which hides a rendered field),
3221
+ * this field type renders nothing at all - it's a componentless field.
3222
+ *
3223
+ * @example
3224
+ * ```typescript
3225
+ * // Store a record ID for updates
3226
+ * const idField: HiddenField<string> = {
3227
+ * type: 'hidden',
3228
+ * key: 'id',
3229
+ * value: '550e8400-e29b-41d4-a716-446655440000',
3230
+ * };
3231
+ *
3232
+ * // Store multiple tag IDs
3233
+ * const tagIdsField: HiddenField<number[]> = {
3234
+ * type: 'hidden',
3235
+ * key: 'tagIds',
3236
+ * value: [1, 2, 3],
3237
+ * };
3238
+ * ```
3239
+ *
3240
+ * @typeParam TValue - The type of value stored (must be HiddenValue compatible)
3241
+ */
3242
+ interface HiddenField<TValue extends HiddenValue = HiddenValue> extends FieldDef<never> {
3243
+ /** Discriminant for hidden field type */
3244
+ type: 'hidden';
3245
+ /**
3246
+ * The value to store in the form.
3247
+ * This is required - a hidden field without a value serves no purpose.
3248
+ */
3249
+ value: TValue;
3250
+ }
3251
+
3436
3252
  /**
3437
3253
  * Configuration for the built-in 'css' wrapper type.
3438
3254
  *
@@ -3472,6 +3288,118 @@ interface RowWrapper {
3472
3288
  readonly type: 'row';
3473
3289
  }
3474
3290
 
3291
+ /**
3292
+ * Resolves a wrapper type name to its registered config interface.
3293
+ *
3294
+ * When `TWrappers` is a specific registered key (e.g., `'css'`), resolves to
3295
+ * the full config type from `FieldRegistryWrappers` (e.g., `CssWrapper`),
3296
+ * providing type-safe access to wrapper-specific properties like `cssClasses`.
3297
+ *
3298
+ * When `TWrappers` is the full `RegisteredWrapperTypes` union, distributes
3299
+ * to produce a discriminated union of all registered wrapper configs.
3300
+ *
3301
+ * @example
3302
+ * ```typescript
3303
+ * // Resolves to CssWrapper — cssClasses is typed
3304
+ * type CssConfig = WrapperConfig<'css'>;
3305
+ *
3306
+ * // Union of all registered wrapper configs
3307
+ * type AnyConfig = WrapperConfig;
3308
+ * ```
3309
+ */
3310
+ type WrapperConfig<TWrappers extends RegisteredWrapperTypes = RegisteredWrapperTypes> = TWrappers extends keyof FieldRegistryWrappers ? FieldRegistryWrappers[TWrappers] : {
3311
+ readonly type: TWrappers;
3312
+ };
3313
+ /**
3314
+ * Signature of a lazy component loader — either a direct component class or
3315
+ * an ES module whose `default` export is the component. Shared by field and
3316
+ * wrapper registrations so the `loadComponent: () => import('./x.component')`
3317
+ * idiom types cleanly in both places.
3318
+ */
3319
+ type LazyComponentLoader<T = unknown> = () => Promise<Type<T> | {
3320
+ default: Type<T>;
3321
+ }>;
3322
+ /**
3323
+ * Configuration interface for registering wrapper types.
3324
+ *
3325
+ * Defines how a wrapper component is loaded and identified. Wrapper components
3326
+ * provide visual decoration around field content (sections, headers, styling)
3327
+ * without affecting the form data structure.
3328
+ *
3329
+ * @example
3330
+ * ```typescript
3331
+ * const SectionWrapper: WrapperTypeDefinition = {
3332
+ * name: 'section',
3333
+ * loadComponent: () => import('./section-wrapper.component').then(m => m.SectionWrapperComponent),
3334
+ * };
3335
+ * ```
3336
+ */
3337
+ interface WrapperTypeDefinition<T extends WrapperConfig = WrapperConfig> {
3338
+ /** Unique identifier for the wrapper type (also serves as discriminant from FieldTypeDefinition) */
3339
+ wrapperName: string;
3340
+ /** Wrapper definition type marker (internal use) */
3341
+ _wrapper?: T;
3342
+ /**
3343
+ * Function to load the wrapper component (supports lazy loading).
3344
+ * Returns a Promise that resolves to the component class or module with default export.
3345
+ */
3346
+ loadComponent: LazyComponentLoader;
3347
+ /**
3348
+ * Field types this wrapper should auto-apply to.
3349
+ *
3350
+ * When a field's `type` matches any entry, the wrapper is injected into that
3351
+ * field's effective wrapper chain at the lowest priority (can be overridden
3352
+ * by `FormConfig.defaultWrappers` or the field-level `wrappers` array, and
3353
+ * fully cleared with `wrappers: null`).
3354
+ */
3355
+ types?: readonly string[];
3356
+ }
3357
+ /**
3358
+ * Type guard for WrapperTypeDefinition.
3359
+ *
3360
+ * Discriminates via `wrapperName` — field types use `name`, wrapper types use `wrapperName`.
3361
+ */
3362
+ declare function isWrapperTypeDefinition(value: unknown): value is WrapperTypeDefinition;
3363
+ /**
3364
+ * Contract that wrapper components must satisfy.
3365
+ *
3366
+ * Each wrapper exposes a `#fieldComponent` ViewContainerRef where the inner
3367
+ * content (next wrapper, or the field) is rendered imperatively. Config
3368
+ * properties (minus `type`) are set on the component via `setInput`; a
3369
+ * wrapper opts into a key by declaring a matching `input()`, and unknown
3370
+ * keys are silently dropped. Wrappers may additionally declare a
3371
+ * `fieldInputs` input for the wrapped field's mapper outputs (see
3372
+ * `WrapperFieldInputs` for when that's undefined).
3373
+ *
3374
+ * @example
3375
+ * ```typescript
3376
+ * @Component({
3377
+ * template: `
3378
+ * <dbx-section [header]="header() ?? ''">
3379
+ * <ng-container #fieldComponent></ng-container>
3380
+ * </dbx-section>
3381
+ * `,
3382
+ * })
3383
+ * export class SectionWrapperComponent implements FieldWrapper {
3384
+ * readonly fieldComponent = viewChild.required('fieldComponent', { read: ViewContainerRef });
3385
+ * readonly header = input<string>();
3386
+ * readonly fieldInputs = input<WrapperFieldInputs>();
3387
+ * }
3388
+ * ```
3389
+ */
3390
+ interface FieldWrapper {
3391
+ /** ViewContainerRef slot where inner content is rendered */
3392
+ readonly fieldComponent: Signal<ViewContainerRef>;
3393
+ }
3394
+ /**
3395
+ * Injection token for the wrapper type registry.
3396
+ *
3397
+ * Provides access to the map of registered wrapper types. The registry is
3398
+ * populated via `provideDynamicForm()` and used by `ContainerFieldComponent` to
3399
+ * resolve wrapper types to their component implementations.
3400
+ */
3401
+ declare const WRAPPER_REGISTRY: InjectionToken<Map<string, WrapperTypeDefinition<RowWrapper | _ng_forge_dynamic_forms.CssWrapper>>>;
3402
+
3475
3403
  /**
3476
3404
  * Container field interface for wrapping child fields with UI chrome.
3477
3405
  *
@@ -3522,36 +3450,281 @@ interface RowWrapper {
3522
3450
  * };
3523
3451
  * ```
3524
3452
  */
3525
- interface ContainerField<TFields extends readonly ContainerAllowedChildren[] = readonly ContainerAllowedChildren[], TWrapperConfigs extends readonly WrapperConfig[] = readonly WrapperConfig[]> extends FieldDef<never> {
3526
- type: 'container';
3527
- /** Child definitions to render within this container */
3528
- readonly fields: TFields;
3453
+ interface ContainerField<TFields extends readonly ContainerAllowedChildren[] = readonly ContainerAllowedChildren[], TWrapperConfigs extends readonly WrapperConfig[] = readonly WrapperConfig[]> extends FieldDef<never> {
3454
+ type: 'container';
3455
+ /** Child definitions to render within this container */
3456
+ readonly fields: TFields;
3457
+ /**
3458
+ * Wrapper components to chain around the children.
3459
+ * Applied outermost-first: the first wrapper in the array is the outermost.
3460
+ * Each wrapper component receives the subsequent wrapper (or children) inside
3461
+ * its `#fieldComponent` ViewContainerRef slot.
3462
+ */
3463
+ readonly wrappers: TWrapperConfigs;
3464
+ /** Container fields do not have a label property */
3465
+ readonly label?: never;
3466
+ /** Containers do not support meta — they have no native form element */
3467
+ readonly meta?: never;
3468
+ /**
3469
+ * Logic configurations for conditional container visibility.
3470
+ * Only 'hidden' type logic is supported for containers.
3471
+ */
3472
+ readonly logic?: ContainerLogicConfig[];
3473
+ }
3474
+ /**
3475
+ * Type guard for ContainerField with proper type narrowing.
3476
+ *
3477
+ * `wrappers` is part of the type but optional in practice — many configs use
3478
+ * containers purely as flex/layout wrappers without any wrapper components.
3479
+ * Match on `type === 'container'` and the `fields` shape only, mirroring
3480
+ * `isPageField` / `isRowField`.
3481
+ */
3482
+ declare function isContainerTypedField(field: FieldDef<any>): field is ContainerField;
3483
+
3484
+ /**
3485
+ * Type constraints for field nesting rules
3486
+ * These ensure that container fields can only contain valid child field types
3487
+ *
3488
+ * Note: We explicitly list types instead of using Exclude to avoid circular dependencies
3489
+ */
3490
+ /**
3491
+ * Fields that are allowed as children of Page fields
3492
+ * Pages can contain: rows, groups, arrays, and leaf fields (but NOT other pages)
3493
+ */
3494
+ type PageAllowedChildren = LeafFieldTypes | RowField | GroupField | ArrayField | SimplifiedArrayField | ContainerField;
3495
+ /**
3496
+ * Fields that are allowed as children of Group fields
3497
+ * Groups can contain: rows and leaf fields (but NOT pages or other groups)
3498
+ */
3499
+ type GroupAllowedChildren = LeafFieldTypes | RowField | ContainerField;
3500
+ /**
3501
+ * Fields that are allowed as children of Array fields
3502
+ * Arrays can contain: rows, groups, and leaf fields (but NOT pages or other arrays)
3503
+ * Groups are used for creating object arrays where each array item is an object
3504
+ */
3505
+ type ArrayAllowedChildren = LeafFieldTypes | RowField | GroupField | ContainerField;
3506
+ /**
3507
+ * Fields that are allowed as children of Container fields.
3508
+ * Containers are pure layout primitives that flatten their children into the
3509
+ * parent form, so most registered field types may appear inside — including
3510
+ * hidden fields and other containers — but NOT pages.
3511
+ */
3512
+ type ContainerAllowedChildren = LeafFieldTypes | RowField | GroupField | ArrayField | SimplifiedArrayField | ContainerField;
3513
+ /**
3514
+ * Row is a synthetic field type that resolves to a Container at runtime, so
3515
+ * it accepts the same children as a Container.
3516
+ */
3517
+ type RowAllowedChildren = ContainerAllowedChildren;
3518
+
3519
+ /**
3520
+ * An array item template is an array of allowed children that defines one OBJECT array item's fields.
3521
+ * Used for object arrays where each item is `{ key1: value1, key2: value2, ... }`.
3522
+ */
3523
+ type ArrayItemTemplate = readonly ArrayAllowedChildren[];
3524
+ /**
3525
+ * An array item definition can be either:
3526
+ * - A single field (ArrayAllowedChildren) for PRIMITIVE array items - extracts field value directly
3527
+ * - An array of fields (ArrayItemTemplate) for OBJECT array items - merges fields into object
3528
+ *
3529
+ * This allows support for:
3530
+ * - Primitive arrays: `['tag1', 'tag2']`
3531
+ * - Object arrays: `[{ name: 'Alice', email: '...' }]`
3532
+ * - Heterogeneous arrays: `[{ value: 'x' }, 'y']` (mixed primitives and objects)
3533
+ */
3534
+ type ArrayItemDefinition = ArrayAllowedChildren | ArrayItemTemplate;
3535
+ /**
3536
+ * Array field interface for creating dynamic field collections that map to array values.
3537
+ *
3538
+ * Key concepts:
3539
+ * - The outer `fields` array defines INITIAL ITEMS (each element is one array item to render)
3540
+ * - Each element can be either:
3541
+ * - A single FieldDef (primitive item) - the field's value is extracted directly
3542
+ * - An array of FieldDefs (object item) - fields are merged into an object
3543
+ * - Items can have different field configurations (heterogeneous arrays supported)
3544
+ * - Empty `fields: []` means no initial items - user adds via buttons with explicit templates
3545
+ * - Initial values are declared via `value` property on each field definition
3546
+ *
3547
+ * @example
3548
+ * // Primitive array: ['angular', 'typescript']
3549
+ * {
3550
+ * key: 'tags',
3551
+ * type: 'array',
3552
+ * fields: [
3553
+ * { key: 'tag', type: 'input', value: 'angular' }, // Single field = primitive
3554
+ * { key: 'tag', type: 'input', value: 'typescript' },
3555
+ * ]
3556
+ * }
3557
+ *
3558
+ * @example
3559
+ * // Object array: [{ name: 'Alice', email: '...' }]
3560
+ * {
3561
+ * key: 'contacts',
3562
+ * type: 'array',
3563
+ * fields: [
3564
+ * [ // Array = object
3565
+ * { key: 'name', type: 'input', value: 'Alice' },
3566
+ * { key: 'email', type: 'input', value: 'alice@example.com' }
3567
+ * ],
3568
+ * ]
3569
+ * }
3570
+ *
3571
+ * @example
3572
+ * // Heterogeneous array: [{ label: 'Structured' }, 'Simple']
3573
+ * {
3574
+ * key: 'items',
3575
+ * type: 'array',
3576
+ * fields: [
3577
+ * [{ key: 'label', type: 'input', value: 'Structured' }], // Object item
3578
+ * { key: 'value', type: 'input', value: 'Simple' }, // Primitive item
3579
+ * ]
3580
+ * }
3581
+ *
3582
+ * @example
3583
+ * // Empty array (add items via buttons)
3584
+ * {
3585
+ * key: 'tags',
3586
+ * type: 'array',
3587
+ * fields: [] // No initial items - user adds via button with template
3588
+ * }
3589
+ *
3590
+ * Nesting constraints: Arrays can contain rows, leaf fields, or groups (for object arrays),
3591
+ * but NOT pages or other arrays. Runtime validation enforces these rules.
3592
+ *
3593
+ * Note: Arrays are container fields and do not support `meta` since they have no native form element.
3594
+ */
3595
+ interface ArrayField<TFields extends readonly ArrayItemDefinition[] = readonly ArrayItemDefinition[]> extends FieldDef<never> {
3596
+ type: 'array';
3597
+ /**
3598
+ * Array of item definitions. Each element defines one array item:
3599
+ * - Single FieldDef = primitive item (field's value is extracted directly)
3600
+ * - Array of FieldDefs = object item (fields are merged into an object)
3601
+ * - Empty array `[]` = no initial items (add via buttons with explicit templates)
3602
+ * - Items can have different configurations (heterogeneous arrays supported)
3603
+ * - Initial values are set via `value` property on each field definition
3604
+ */
3605
+ readonly fields: TFields;
3606
+ /** Array fields do not have a label property **/
3607
+ readonly label?: never;
3608
+ /** Arrays do not support meta - they have no native form element **/
3609
+ readonly meta?: never;
3610
+ /**
3611
+ * Logic configurations for conditional array visibility.
3612
+ * Only 'hidden' type logic is supported for arrays.
3613
+ */
3614
+ readonly logic?: ContainerLogicConfig[];
3615
+ /**
3616
+ * Minimum number of items required in the array.
3617
+ * Validation fails if the array has fewer items than this value.
3618
+ */
3619
+ readonly minLength?: number;
3620
+ /**
3621
+ * Maximum number of items allowed in the array.
3622
+ * Validation fails if the array has more items than this value.
3623
+ */
3624
+ readonly maxLength?: number;
3625
+ }
3626
+ /**
3627
+ * Type guard for ArrayField with proper type narrowing.
3628
+ * Validates that the field is an array type with a fields property that is an array.
3629
+ * Fields can contain either single FieldDefs (primitive items) or arrays of FieldDefs (object items).
3630
+ */
3631
+ declare function isArrayField(field: FieldDef<any>): field is ArrayField;
3632
+ /**
3633
+ * Configuration for auto-generated add/remove buttons in simplified array fields.
3634
+ */
3635
+ interface ArrayButtonConfig {
3636
+ /** Custom label for the button */
3637
+ readonly label?: string;
3638
+ /** Additional properties passed to the button component */
3639
+ readonly props?: Record<string, unknown>;
3640
+ }
3641
+ /**
3642
+ * Simplified array field interface for common use cases.
3643
+ *
3644
+ * Instead of manually specifying each item in `fields`, provide a `template` that defines
3645
+ * the structure of a single item, and a `value` array with initial data.
3646
+ * The library auto-generates add/remove buttons.
3647
+ *
3648
+ * Discriminant: `template` presence → simplified API; `Array.isArray(template)` → object vs primitive.
3649
+ *
3650
+ * @example
3651
+ * // Primitive array: ['angular', 'typescript']
3652
+ * {
3653
+ * key: 'tags',
3654
+ * type: 'array',
3655
+ * template: { key: 'value', type: 'input', label: 'Tag', required: true },
3656
+ * value: ['angular', 'typescript']
3657
+ * }
3658
+ *
3659
+ * @example
3660
+ * // Object array: [{ name: 'Jane', phone: '555' }]
3661
+ * {
3662
+ * key: 'contacts',
3663
+ * type: 'array',
3664
+ * template: [
3665
+ * { key: 'name', type: 'input', label: 'Contact Name', required: true },
3666
+ * { key: 'phone', type: 'input', label: 'Phone Number' },
3667
+ * ],
3668
+ * value: [{ name: 'Jane', phone: '555' }]
3669
+ * }
3670
+ *
3671
+ * @example
3672
+ * // Button customization / opt-out
3673
+ * {
3674
+ * key: 'tags',
3675
+ * type: 'array',
3676
+ * template: { key: 'value', type: 'input', label: 'Tag' },
3677
+ * addButton: { label: 'Add Tag', props: { color: 'primary' } },
3678
+ * removeButton: false
3679
+ * }
3680
+ */
3681
+ interface SimplifiedArrayField extends FieldDef<never> {
3682
+ type: 'array';
3529
3683
  /**
3530
- * Wrapper components to chain around the children.
3531
- * Applied outermost-first: the first wrapper in the array is the outermost.
3532
- * Each wrapper component receives the subsequent wrapper (or children) inside
3533
- * its `#fieldComponent` ViewContainerRef slot.
3684
+ * Template defining the structure of a single array item.
3685
+ * - Single field (ArrayAllowedChildren) → primitive array (each item is a single value)
3686
+ * - Array of fields (readonly ArrayAllowedChildren[]) → object array (each item is an object)
3534
3687
  */
3535
- readonly wrappers: TWrapperConfigs;
3536
- /** Container fields do not have a label property */
3688
+ readonly template: ArrayAllowedChildren | readonly ArrayAllowedChildren[];
3689
+ /** Initial values for the array. Each element creates one array item. */
3690
+ readonly value?: readonly unknown[];
3691
+ /**
3692
+ * Configuration for the auto-generated "Add" button, or `false` to disable it.
3693
+ * Defaults to a button with label "Add".
3694
+ */
3695
+ readonly addButton?: ArrayButtonConfig | false;
3696
+ /**
3697
+ * Configuration for the auto-generated "Remove" button on each item, or `false` to disable it.
3698
+ * Defaults to a button with label "Remove".
3699
+ */
3700
+ readonly removeButton?: ArrayButtonConfig | false;
3701
+ /** Simplified arrays do not support the label property */
3537
3702
  readonly label?: never;
3538
- /** Containers do not support meta — they have no native form element */
3703
+ /** Simplified arrays do not support meta */
3539
3704
  readonly meta?: never;
3540
3705
  /**
3541
- * Logic configurations for conditional container visibility.
3542
- * Only 'hidden' type logic is supported for containers.
3706
+ * Logic configurations for conditional array visibility.
3707
+ * Only 'hidden' type logic is supported for arrays.
3543
3708
  */
3544
3709
  readonly logic?: ContainerLogicConfig[];
3710
+ /**
3711
+ * Minimum number of items required in the array.
3712
+ * Validation fails if the array has fewer items than this value.
3713
+ */
3714
+ readonly minLength?: number;
3715
+ /**
3716
+ * Maximum number of items allowed in the array.
3717
+ * Validation fails if the array has more items than this value.
3718
+ */
3719
+ readonly maxLength?: number;
3720
+ /** Mutually exclusive with `template` — use `fields` for the full API instead */
3721
+ readonly fields?: never;
3545
3722
  }
3546
3723
  /**
3547
- * Type guard for ContainerField with proper type narrowing.
3548
- *
3549
- * `wrappers` is part of the type but optional in practice — many configs use
3550
- * containers purely as flex/layout wrappers without any wrapper components.
3551
- * Match on `type === 'container'` and the `fields` shape only, mirroring
3552
- * `isPageField` / `isRowField`.
3724
+ * Type guard for SimplifiedArrayField.
3725
+ * Checks for `type: 'array'` with a `template` property (discriminant from full ArrayField).
3553
3726
  */
3554
- declare function isContainerTypedField(field: FieldDef<any>): field is ContainerField;
3727
+ declare function isSimplifiedArrayField(field: FieldDef<any>): field is SimplifiedArrayField;
3555
3728
 
3556
3729
  /**
3557
3730
  * Container fields registry - augment this interface to add custom container fields
@@ -3701,180 +3874,6 @@ type NarrowField<T> = T extends {
3701
3874
  */
3702
3875
  type NarrowFields = readonly NarrowField<RegisteredFieldTypes>[];
3703
3876
 
3704
- /**
3705
- * Type constraints for field nesting rules
3706
- * These ensure that container fields can only contain valid child field types
3707
- *
3708
- * Note: We explicitly list types instead of using Exclude to avoid circular dependencies
3709
- */
3710
- /**
3711
- * Fields that are allowed as children of Page fields
3712
- * Pages can contain: rows, groups, arrays, and leaf fields (but NOT other pages)
3713
- */
3714
- type PageAllowedChildren = LeafFieldTypes | RowField | GroupField | ArrayField | SimplifiedArrayField | ContainerField;
3715
- /**
3716
- * Fields that are allowed as children of Group fields
3717
- * Groups can contain: rows and leaf fields (but NOT pages or other groups)
3718
- */
3719
- type GroupAllowedChildren = LeafFieldTypes | RowField | ContainerField;
3720
- /**
3721
- * Fields that are allowed as children of Array fields
3722
- * Arrays can contain: rows, groups, and leaf fields (but NOT pages or other arrays)
3723
- * Groups are used for creating object arrays where each array item is an object
3724
- */
3725
- type ArrayAllowedChildren = LeafFieldTypes | RowField | GroupField | ContainerField;
3726
- /**
3727
- * Fields that are allowed as children of Container fields.
3728
- * Containers are pure layout primitives that flatten their children into the
3729
- * parent form, so most registered field types may appear inside — including
3730
- * hidden fields and other containers — but NOT pages.
3731
- */
3732
- type ContainerAllowedChildren = LeafFieldTypes | RowField | GroupField | ArrayField | SimplifiedArrayField | ContainerField;
3733
- /**
3734
- * Row is a synthetic field type that resolves to a Container at runtime, so
3735
- * it accepts the same children as a Container.
3736
- */
3737
- type RowAllowedChildren = ContainerAllowedChildren;
3738
-
3739
- /**
3740
- * Row field interface for creating horizontal layouts.
3741
- * A row is a synthetic field type that resolves to a Container at runtime,
3742
- * with a synthesized `{ type: 'row' }` wrapper applied for layout. The row
3743
- * itself does not hold a value — its children flatten into the parent form.
3744
- *
3745
- * Note: Rows do not support `meta` since they have no native form element.
3746
- */
3747
- interface RowField<TFields extends readonly RowAllowedChildren[] = readonly RowAllowedChildren[]> extends FieldDef<never> {
3748
- type: 'row';
3749
- /** Child definitions to render within this row */
3750
- readonly fields: TFields;
3751
- /** Row fields do not have a label property **/
3752
- readonly label?: never;
3753
- /** Rows do not support meta - they have no native form element **/
3754
- readonly meta?: never;
3755
- /**
3756
- * Logic configurations for conditional row visibility.
3757
- * Only 'hidden' type logic is supported for rows.
3758
- */
3759
- readonly logic?: ContainerLogicConfig[];
3760
- }
3761
- /**
3762
- * Type guard for RowField with proper type narrowing
3763
- */
3764
- declare function isRowField(field: FieldDef<any>): field is RowField;
3765
-
3766
- /**
3767
- * Resolves a wrapper type name to its registered config interface.
3768
- *
3769
- * When `TWrappers` is a specific registered key (e.g., `'css'`), resolves to
3770
- * the full config type from `FieldRegistryWrappers` (e.g., `CssWrapper`),
3771
- * providing type-safe access to wrapper-specific properties like `cssClasses`.
3772
- *
3773
- * When `TWrappers` is the full `RegisteredWrapperTypes` union, distributes
3774
- * to produce a discriminated union of all registered wrapper configs.
3775
- *
3776
- * @example
3777
- * ```typescript
3778
- * // Resolves to CssWrapper — cssClasses is typed
3779
- * type CssConfig = WrapperConfig<'css'>;
3780
- *
3781
- * // Union of all registered wrapper configs
3782
- * type AnyConfig = WrapperConfig;
3783
- * ```
3784
- */
3785
- type WrapperConfig<TWrappers extends RegisteredWrapperTypes = RegisteredWrapperTypes> = TWrappers extends keyof FieldRegistryWrappers ? FieldRegistryWrappers[TWrappers] : {
3786
- readonly type: TWrappers;
3787
- };
3788
- /**
3789
- * Signature of a lazy component loader — either a direct component class or
3790
- * an ES module whose `default` export is the component. Shared by field and
3791
- * wrapper registrations so the `loadComponent: () => import('./x.component')`
3792
- * idiom types cleanly in both places.
3793
- */
3794
- type LazyComponentLoader<T = unknown> = () => Promise<Type<T> | {
3795
- default: Type<T>;
3796
- }>;
3797
- /**
3798
- * Configuration interface for registering wrapper types.
3799
- *
3800
- * Defines how a wrapper component is loaded and identified. Wrapper components
3801
- * provide visual decoration around field content (sections, headers, styling)
3802
- * without affecting the form data structure.
3803
- *
3804
- * @example
3805
- * ```typescript
3806
- * const SectionWrapper: WrapperTypeDefinition = {
3807
- * name: 'section',
3808
- * loadComponent: () => import('./section-wrapper.component').then(m => m.SectionWrapperComponent),
3809
- * };
3810
- * ```
3811
- */
3812
- interface WrapperTypeDefinition<T extends WrapperConfig = WrapperConfig> {
3813
- /** Unique identifier for the wrapper type (also serves as discriminant from FieldTypeDefinition) */
3814
- wrapperName: string;
3815
- /** Wrapper definition type marker (internal use) */
3816
- _wrapper?: T;
3817
- /**
3818
- * Function to load the wrapper component (supports lazy loading).
3819
- * Returns a Promise that resolves to the component class or module with default export.
3820
- */
3821
- loadComponent: LazyComponentLoader;
3822
- /**
3823
- * Field types this wrapper should auto-apply to.
3824
- *
3825
- * When a field's `type` matches any entry, the wrapper is injected into that
3826
- * field's effective wrapper chain at the lowest priority (can be overridden
3827
- * by `FormConfig.defaultWrappers` or the field-level `wrappers` array, and
3828
- * fully cleared with `wrappers: null`).
3829
- */
3830
- types?: readonly string[];
3831
- }
3832
- /**
3833
- * Type guard for WrapperTypeDefinition.
3834
- *
3835
- * Discriminates via `wrapperName` — field types use `name`, wrapper types use `wrapperName`.
3836
- */
3837
- declare function isWrapperTypeDefinition(value: unknown): value is WrapperTypeDefinition;
3838
- /**
3839
- * Contract that wrapper components must satisfy.
3840
- *
3841
- * Each wrapper exposes a `#fieldComponent` ViewContainerRef where the inner
3842
- * content (next wrapper, or the field) is rendered imperatively. Config
3843
- * properties (minus `type`) are set on the component via `setInput`; a
3844
- * wrapper opts into a key by declaring a matching `input()`, and unknown
3845
- * keys are silently dropped. Wrappers may additionally declare a
3846
- * `fieldInputs` input for the wrapped field's mapper outputs (see
3847
- * `WrapperFieldInputs` for when that's undefined).
3848
- *
3849
- * @example
3850
- * ```typescript
3851
- * @Component({
3852
- * template: `
3853
- * <dbx-section [header]="header() ?? ''">
3854
- * <ng-container #fieldComponent></ng-container>
3855
- * </dbx-section>
3856
- * `,
3857
- * })
3858
- * export class SectionWrapperComponent implements FieldWrapper {
3859
- * readonly fieldComponent = viewChild.required('fieldComponent', { read: ViewContainerRef });
3860
- * readonly header = input<string>();
3861
- * readonly fieldInputs = input<WrapperFieldInputs>();
3862
- * }
3863
- * ```
3864
- */
3865
- interface FieldWrapper {
3866
- /** ViewContainerRef slot where inner content is rendered */
3867
- readonly fieldComponent: Signal<ViewContainerRef>;
3868
- }
3869
- /**
3870
- * Injection token for the wrapper type registry.
3871
- *
3872
- * Provides access to the map of registered wrapper types. The registry is
3873
- * populated via `provideDynamicForm()` and used by `ContainerFieldComponent` to
3874
- * resolve wrapper types to their component implementations.
3875
- */
3876
- declare const WRAPPER_REGISTRY: InjectionToken<Map<string, WrapperTypeDefinition<RowWrapper | _ng_forge_dynamic_forms.CssWrapper>>>;
3877
-
3878
3877
  /**
3879
3878
  * Base interface for native HTML attributes that can be passed to form field elements.
3880
3879
  *
@@ -3974,18 +3973,26 @@ interface FieldDef<TProps, TMeta extends FieldMeta = FieldMeta> {
3974
3973
  /**
3975
3974
  * Field type identifier for component selection.
3976
3975
  *
3977
- * Determines which component will be rendered for this field.
3978
- * Must match a registered field type name in the field registry.
3976
+ * Determines which component will be rendered for this field. Names
3977
+ * registered through module augmentation of `DynamicFormFieldRegistry`
3978
+ * are surfaced as IDE autocomplete suggestions via `RegisteredFieldTypes`;
3979
+ * the `(string & {})` branch keeps arbitrary custom identifiers accepted
3980
+ * as an escape hatch for fields that haven't been augmented into the
3981
+ * registry.
3979
3982
  *
3980
3983
  * @example
3981
3984
  * ```typescript
3982
- * type: 'input' // Text input field
3983
- * type: 'select' // Dropdown selection
3984
- * type: 'checkbox' // Boolean checkbox
3985
- * type: 'group' // Field group container
3985
+ * type: 'input' // Text input field (registered)
3986
+ * type: 'select' // Dropdown selection (registered)
3987
+ * type: 'checkbox' // Boolean checkbox (registered)
3988
+ * type: 'group' // Field group container (registered)
3989
+ * type: 'my-custom' // Unregistered — still accepted, no autocomplete
3986
3990
  * ```
3991
+ *
3992
+ * Wrapper types are intentionally excluded — wrappers are configured through
3993
+ * `wrappers` / `withFormWrappers()` rather than via the field-type discriminant.
3987
3994
  */
3988
- type: string;
3995
+ type: RegisteredFieldTypes['type'] | (string & {});
3989
3996
  /**
3990
3997
  * Human-readable field label displayed to users.
3991
3998
  *
@@ -4374,7 +4381,7 @@ interface FieldTypeDefinition<T extends FieldDef<any> = any> {
4374
4381
  /** Semantic scope for tooling to discover interchangeable field alternatives */
4375
4382
  scope?: FieldScope | FieldScope[];
4376
4383
  /** Mapped component inputs that must exist before the renderer instantiates the component */
4377
- renderReadyWhen?: RenderReadyInput[];
4384
+ renderReadyWhen?: readonly RenderReadyInput[];
4378
4385
  }
4379
4386
  /**
4380
4387
  * Injection token for the global field type registry.
@@ -4403,6 +4410,15 @@ interface ResolvedField {
4403
4410
  injector: Injector;
4404
4411
  inputs: Signal<Record<string, unknown>>;
4405
4412
  renderReady: Signal<boolean>;
4413
+ /**
4414
+ * Whether the field is currently hidden. Sourced from the FieldTree's
4415
+ * `state.hidden()` for value-bearing fields (set by Angular Signal Forms in
4416
+ * response to `hidden(path, …)` calls), or from the mapper's explicit
4417
+ * `hidden` input for non-value fields (button, text, container, …). Consumers
4418
+ * must `@if (!field.hidden())` around `*dfFieldOutlet` so hidden fields are
4419
+ * removed from the DOM — Angular Signal Forms warns (NG01916) otherwise.
4420
+ */
4421
+ hidden: Signal<boolean>;
4406
4422
  }
4407
4423
 
4408
4424
  /**
@@ -6495,8 +6511,6 @@ declare function applyMetaToElement(element: Element, meta: FieldMeta | undefine
6495
6511
  * );
6496
6512
  * // user.value() keeps the old user data during loading transitions
6497
6513
  * ```
6498
- *
6499
- * @experimental Uses Angular's experimental resource composition APIs.
6500
6514
  */
6501
6515
  declare function withPreviousValue<T>(input: Resource<T>): Resource<T>;
6502
6516
 
@@ -6615,6 +6629,12 @@ interface ResolvedArrayItemField {
6615
6629
  inputs: Signal<Record<string, unknown>>;
6616
6630
  /** Whether required mapped inputs are available for safe component instantiation. */
6617
6631
  renderReady: Signal<boolean>;
6632
+ /**
6633
+ * Whether the array-item field is currently hidden — mirrors `ResolvedField.hidden`
6634
+ * so the same `@if (!field.hidden())` template gate works for top-level and
6635
+ * array-item fields.
6636
+ */
6637
+ hidden: Signal<boolean>;
6618
6638
  }
6619
6639
  /**
6620
6640
  * Resolved array item ready for declarative rendering with ngComponentOutlet.
@@ -6645,7 +6665,9 @@ declare class ArrayFieldComponent<TModel extends Record<string, unknown> = Recor
6645
6665
  protected readonly environmentInjector: EnvironmentInjector;
6646
6666
  private readonly eventBus;
6647
6667
  private readonly logger;
6648
- private readonly templateRegistry;
6668
+ private readonly arrayItemRegistry;
6669
+ private readonly slot;
6670
+ /** Bound id-generator reference threaded to `resolveArrayItem` so callsites stay terse. */
6649
6671
  private readonly generateItemId;
6650
6672
  field: _angular_core.InputSignal<ArrayField<readonly ArrayItemDefinition[]>>;
6651
6673
  key: _angular_core.InputSignal<string>;
@@ -6710,9 +6732,7 @@ declare class ArrayFieldComponent<TModel extends Record<string, unknown> = Recor
6710
6732
  private readonly itemTemplates;
6711
6733
  private readonly arrayFieldTrees;
6712
6734
  private readonly resolvedItemsSignal;
6713
- private readonly updateVersion;
6714
- private readonly pendingInitializationCycle;
6715
- private readonly settledInitializationCycle;
6735
+ private readonly fsm;
6716
6736
  /**
6717
6737
  * Map of item IDs to their current positions. O(1) lookup vs O(n) indexOf().
6718
6738
  * Used by child linkedSignals to reactively track their position in the array.