@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.
- package/fesm2022/{ng-forge-dynamic-forms-array-field.component-DJ-LiLm_.mjs → ng-forge-dynamic-forms-array-field.component-BgCrTME1.mjs} +154 -69
- package/fesm2022/ng-forge-dynamic-forms-array-field.component-BgCrTME1.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-container-field.component-Pcxg5PQu.mjs → ng-forge-dynamic-forms-container-field.component-VHaBk_1l.mjs} +9 -5
- package/fesm2022/ng-forge-dynamic-forms-container-field.component-VHaBk_1l.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-container-utils-a4RstR2Z.mjs → ng-forge-dynamic-forms-container-utils-CGJiiKBY.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-container-utils-a4RstR2Z.mjs.map → ng-forge-dynamic-forms-container-utils-CGJiiKBY.mjs.map} +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-css-wrapper.component-CJACCIEK.mjs → ng-forge-dynamic-forms-css-wrapper.component-BOdw40ZF.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-css-wrapper.component-CJACCIEK.mjs.map → ng-forge-dynamic-forms-css-wrapper.component-BOdw40ZF.mjs.map} +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-emit-initialization-Bjf_I0D_.mjs → ng-forge-dynamic-forms-emit-initialization-D72mQxlX.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-emit-initialization-Bjf_I0D_.mjs.map → ng-forge-dynamic-forms-emit-initialization-D72mQxlX.mjs.map} +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-group-field.component-fzKwPrQr.mjs → ng-forge-dynamic-forms-group-field.component-BvTQwoLg.mjs} +9 -5
- package/fesm2022/ng-forge-dynamic-forms-group-field.component-BvTQwoLg.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-o3rJX4vG.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-BAPGCjUs.mjs} +396 -248
- package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-BAPGCjUs.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-page-field.component-BX4R9GGa.mjs → ng-forge-dynamic-forms-page-field.component-DDzmhJNn.mjs} +9 -5
- package/fesm2022/ng-forge-dynamic-forms-page-field.component-DDzmhJNn.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-text-field.component-B9SK8Vun.mjs → ng-forge-dynamic-forms-text-field.component-Bo4zNJXY.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-text-field.component-B9SK8Vun.mjs.map → ng-forge-dynamic-forms-text-field.component-Bo4zNJXY.mjs.map} +1 -1
- package/fesm2022/ng-forge-dynamic-forms.mjs +1 -1
- package/package.json +1 -1
- package/types/ng-forge-dynamic-forms.d.ts +488 -468
- package/fesm2022/ng-forge-dynamic-forms-array-field.component-DJ-LiLm_.mjs.map +0 -1
- package/fesm2022/ng-forge-dynamic-forms-container-field.component-Pcxg5PQu.mjs.map +0 -1
- package/fesm2022/ng-forge-dynamic-forms-group-field.component-fzKwPrQr.mjs.map +0 -1
- package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-o3rJX4vG.mjs.map +0 -1
- 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
|
-
*
|
|
593
|
-
*
|
|
594
|
-
|
|
595
|
-
|
|
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:
|
|
595
|
+
* Note: Rows do not support `meta` since they have no native form element.
|
|
666
596
|
*/
|
|
667
|
-
interface
|
|
668
|
-
type: '
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
603
|
+
/** Rows do not support meta - they have no native form element **/
|
|
776
604
|
readonly meta?: never;
|
|
777
605
|
/**
|
|
778
|
-
* Logic configurations for conditional
|
|
779
|
-
* Only 'hidden' type logic is supported for
|
|
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
|
|
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
|
|
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
|
-
*
|
|
832
|
-
*
|
|
833
|
-
|
|
834
|
-
|
|
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
|
-
*
|
|
854
|
-
*
|
|
855
|
-
*
|
|
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
|
-
*
|
|
3531
|
-
*
|
|
3532
|
-
*
|
|
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
|
|
3536
|
-
/**
|
|
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
|
-
/**
|
|
3703
|
+
/** Simplified arrays do not support meta */
|
|
3539
3704
|
readonly meta?: never;
|
|
3540
3705
|
/**
|
|
3541
|
-
* Logic configurations for conditional
|
|
3542
|
-
* Only 'hidden' type logic is supported for
|
|
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
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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.
|