@ng-forge/dynamic-forms 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/fesm2022/ng-forge-dynamic-forms-integration.mjs +138 -58
- package/fesm2022/ng-forge-dynamic-forms-integration.mjs.map +1 -1
- package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-DHxoGouT.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-BWFdMPyw.mjs} +3876 -354
- package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-BWFdMPyw.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-page-field.component-Bt6blv9I.mjs → ng-forge-dynamic-forms-page-field.component-RN1hmG69.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-page-field.component-Bt6blv9I.mjs.map → ng-forge-dynamic-forms-page-field.component-RN1hmG69.mjs.map} +1 -1
- package/fesm2022/ng-forge-dynamic-forms-schema.mjs +92 -0
- package/fesm2022/ng-forge-dynamic-forms-schema.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-text-field.component-DKCx7Z_U.mjs → ng-forge-dynamic-forms-text-field.component-DIVyioMX.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-text-field.component-DKCx7Z_U.mjs.map → ng-forge-dynamic-forms-text-field.component-DIVyioMX.mjs.map} +1 -1
- package/fesm2022/ng-forge-dynamic-forms.mjs +1 -1
- package/package.json +5 -4
- package/types/ng-forge-dynamic-forms-integration.d.ts +6 -14
- package/types/ng-forge-dynamic-forms-schema.d.ts +178 -0
- package/types/ng-forge-dynamic-forms.d.ts +1040 -45
- package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-DHxoGouT.mjs.map +0 -1
- package/fesm2022/ng-forge-dynamic-forms-testing-test-button.harness-C79EBW0o.mjs +0 -31
- package/fesm2022/ng-forge-dynamic-forms-testing-test-button.harness-C79EBW0o.mjs.map +0 -1
- package/fesm2022/ng-forge-dynamic-forms-testing.mjs +0 -973
- package/fesm2022/ng-forge-dynamic-forms-testing.mjs.map +0 -1
- package/types/ng-forge-dynamic-forms-testing.d.ts +0 -603
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as rxjs from 'rxjs';
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
|
-
import * as _angular_forms from '@angular/forms';
|
|
4
3
|
import * as _angular_forms_signals from '@angular/forms/signals';
|
|
5
|
-
import { FieldTree, FieldContext, ValidationError as ValidationError$1, TreeValidationResult,
|
|
4
|
+
import { FieldTree, FieldContext, ValidationError as ValidationError$1, TreeValidationResult, SchemaPath, SchemaPathTree } from '@angular/forms/signals';
|
|
5
|
+
import * as _angular_forms from '@angular/forms';
|
|
6
6
|
import * as _ng_forge_dynamic_forms from '@ng-forge/dynamic-forms';
|
|
7
7
|
import * as _angular_core from '@angular/core';
|
|
8
8
|
import { Signal, Injector, WritableSignal, InjectionToken, Type, ResourceRef, OnDestroy, InputSignal, Provider, EnvironmentProviders, PipeTransform } from '@angular/core';
|
|
9
|
+
import { FormSchema } from '@ng-forge/dynamic-forms/schema';
|
|
9
10
|
|
|
10
11
|
type WithInputSignals<T> = {
|
|
11
12
|
readonly [K in keyof T]-?: Signal<T[K]>;
|
|
@@ -752,7 +753,86 @@ type FormStateCondition =
|
|
|
752
753
|
/** True when fields on the current page are invalid (for paged forms) */
|
|
753
754
|
| 'pageInvalid';
|
|
754
755
|
/**
|
|
755
|
-
*
|
|
756
|
+
* Logic type for controlling field state (hidden, readonly, disabled, required).
|
|
757
|
+
*
|
|
758
|
+
* @public
|
|
759
|
+
*/
|
|
760
|
+
type StateLogicType = 'hidden' | 'readonly' | 'disabled' | 'required';
|
|
761
|
+
/**
|
|
762
|
+
* Base configuration for conditional field state logic.
|
|
763
|
+
*
|
|
764
|
+
* @internal
|
|
765
|
+
*/
|
|
766
|
+
interface BaseStateLogicConfig {
|
|
767
|
+
/**
|
|
768
|
+
* Logic type identifier for field state.
|
|
769
|
+
*
|
|
770
|
+
* - `hidden`: Hide the field from view (still participates in form state)
|
|
771
|
+
* - `readonly`: Make the field read-only
|
|
772
|
+
* - `disabled`: Disable user interaction
|
|
773
|
+
* - `required`: Make the field required
|
|
774
|
+
*/
|
|
775
|
+
type: StateLogicType;
|
|
776
|
+
/**
|
|
777
|
+
* Condition that determines when this logic applies.
|
|
778
|
+
*
|
|
779
|
+
* Can be:
|
|
780
|
+
* - `boolean`: Static value (always applies or never applies)
|
|
781
|
+
* - `ConditionalExpression`: Expression evaluated against field/form values
|
|
782
|
+
* - `FormStateCondition`: Special form/page state check (for buttons)
|
|
783
|
+
*
|
|
784
|
+
* @example
|
|
785
|
+
* ```typescript
|
|
786
|
+
* // Static condition
|
|
787
|
+
* condition: true
|
|
788
|
+
*
|
|
789
|
+
* // Field value condition
|
|
790
|
+
* condition: {
|
|
791
|
+
* type: 'fieldValue',
|
|
792
|
+
* fieldPath: 'status',
|
|
793
|
+
* operator: 'equals',
|
|
794
|
+
* value: 'locked'
|
|
795
|
+
* }
|
|
796
|
+
*
|
|
797
|
+
* // Form state condition (for buttons)
|
|
798
|
+
* condition: 'formSubmitting'
|
|
799
|
+
* ```
|
|
800
|
+
*/
|
|
801
|
+
condition: ConditionalExpression | boolean | FormStateCondition;
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* State logic that evaluates immediately on change (default).
|
|
805
|
+
*
|
|
806
|
+
* @internal
|
|
807
|
+
*/
|
|
808
|
+
interface ImmediateStateLogicConfig extends BaseStateLogicConfig {
|
|
809
|
+
/**
|
|
810
|
+
* Trigger for immediate evaluation.
|
|
811
|
+
* @default 'onChange'
|
|
812
|
+
*/
|
|
813
|
+
trigger?: 'onChange';
|
|
814
|
+
/** Not allowed for onChange trigger */
|
|
815
|
+
debounceMs?: never;
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* State logic that evaluates after a debounce period.
|
|
819
|
+
*
|
|
820
|
+
* @internal
|
|
821
|
+
*/
|
|
822
|
+
interface DebouncedStateLogicConfig extends BaseStateLogicConfig {
|
|
823
|
+
/**
|
|
824
|
+
* Trigger for debounced evaluation.
|
|
825
|
+
* Evaluates after the value has stabilized for the debounce duration.
|
|
826
|
+
*/
|
|
827
|
+
trigger: 'debounced';
|
|
828
|
+
/**
|
|
829
|
+
* Debounce duration in milliseconds.
|
|
830
|
+
* @default 500
|
|
831
|
+
*/
|
|
832
|
+
debounceMs?: number;
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Configuration for conditional field state logic.
|
|
756
836
|
*
|
|
757
837
|
* Defines how field behavior changes based on conditions.
|
|
758
838
|
* Supports hiding, disabling, making readonly, or requiring fields
|
|
@@ -776,47 +856,279 @@ type FormStateCondition =
|
|
|
776
856
|
* type: 'disabled',
|
|
777
857
|
* condition: 'formSubmitting'
|
|
778
858
|
* }
|
|
859
|
+
*
|
|
860
|
+
* // Debounced visibility (avoids flicker during rapid typing)
|
|
861
|
+
* {
|
|
862
|
+
* type: 'hidden',
|
|
863
|
+
* trigger: 'debounced',
|
|
864
|
+
* debounceMs: 300,
|
|
865
|
+
* condition: {
|
|
866
|
+
* type: 'fieldValue',
|
|
867
|
+
* fieldPath: 'search',
|
|
868
|
+
* operator: 'isEmpty'
|
|
869
|
+
* }
|
|
870
|
+
* }
|
|
779
871
|
* ```
|
|
780
872
|
*
|
|
781
873
|
* @public
|
|
782
874
|
*/
|
|
783
|
-
|
|
875
|
+
type StateLogicConfig = ImmediateStateLogicConfig | DebouncedStateLogicConfig;
|
|
876
|
+
/**
|
|
877
|
+
* Base configuration for value derivation logic.
|
|
878
|
+
*
|
|
879
|
+
* All derivations target the field they are defined on (self-targeting).
|
|
880
|
+
* This simplifies configuration by removing the need for `targetField` -
|
|
881
|
+
* derivation logic is placed on the field that should receive the computed value.
|
|
882
|
+
*
|
|
883
|
+
* @internal
|
|
884
|
+
*/
|
|
885
|
+
interface BaseDerivationLogicConfig {
|
|
784
886
|
/**
|
|
785
|
-
* Logic type identifier.
|
|
887
|
+
* Logic type identifier for value derivation.
|
|
888
|
+
*/
|
|
889
|
+
type: 'derivation';
|
|
890
|
+
/**
|
|
891
|
+
* Optional name for this derivation for debugging purposes.
|
|
786
892
|
*
|
|
787
|
-
*
|
|
788
|
-
*
|
|
789
|
-
*
|
|
790
|
-
*
|
|
893
|
+
* When provided, this name appears in derivation debug logs,
|
|
894
|
+
* making it easier to identify specific derivations in complex forms.
|
|
895
|
+
*
|
|
896
|
+
* @example
|
|
897
|
+
* ```typescript
|
|
898
|
+
* {
|
|
899
|
+
* key: 'lineTotal',
|
|
900
|
+
* type: 'input',
|
|
901
|
+
* logic: [{
|
|
902
|
+
* type: 'derivation',
|
|
903
|
+
* debugName: 'Calculate line total',
|
|
904
|
+
* expression: 'formValue.quantity * formValue.unitPrice'
|
|
905
|
+
* }]
|
|
906
|
+
* }
|
|
907
|
+
* ```
|
|
791
908
|
*/
|
|
792
|
-
|
|
909
|
+
debugName?: string;
|
|
793
910
|
/**
|
|
794
|
-
* Condition that determines when this
|
|
911
|
+
* Condition that determines when this derivation applies.
|
|
795
912
|
*
|
|
796
913
|
* Can be:
|
|
797
914
|
* - `boolean`: Static value (always applies or never applies)
|
|
798
915
|
* - `ConditionalExpression`: Expression evaluated against field/form values
|
|
799
|
-
*
|
|
916
|
+
*
|
|
917
|
+
* Defaults to `true` (always apply).
|
|
918
|
+
*
|
|
919
|
+
* Note: FormStateCondition is not supported for derivations.
|
|
800
920
|
*
|
|
801
921
|
* @example
|
|
802
922
|
* ```typescript
|
|
803
|
-
* //
|
|
923
|
+
* // Always compute (default)
|
|
804
924
|
* condition: true
|
|
805
925
|
*
|
|
806
|
-
* //
|
|
926
|
+
* // Conditional derivation
|
|
807
927
|
* condition: {
|
|
808
928
|
* type: 'fieldValue',
|
|
809
|
-
* fieldPath: '
|
|
929
|
+
* fieldPath: 'country',
|
|
810
930
|
* operator: 'equals',
|
|
811
|
-
* value: '
|
|
931
|
+
* value: 'USA'
|
|
812
932
|
* }
|
|
933
|
+
* ```
|
|
934
|
+
*/
|
|
935
|
+
condition?: ConditionalExpression | boolean;
|
|
936
|
+
/**
|
|
937
|
+
* Static value to set on this field.
|
|
813
938
|
*
|
|
814
|
-
*
|
|
815
|
-
*
|
|
939
|
+
* Use when the derived value is a constant.
|
|
940
|
+
* Mutually exclusive with `expression` and `functionName`.
|
|
941
|
+
*
|
|
942
|
+
* @example
|
|
943
|
+
* ```typescript
|
|
944
|
+
* value: '+1' // String
|
|
945
|
+
* value: 100 // Number
|
|
946
|
+
* value: true // Boolean
|
|
947
|
+
* value: { code: 'US' } // Object
|
|
816
948
|
* ```
|
|
817
949
|
*/
|
|
818
|
-
|
|
950
|
+
value?: unknown;
|
|
951
|
+
/**
|
|
952
|
+
* JavaScript expression to evaluate for the derived value.
|
|
953
|
+
*
|
|
954
|
+
* Has access to `formValue` object containing all form values.
|
|
955
|
+
* For array fields, `formValue` is scoped to the current array item.
|
|
956
|
+
* Uses the same secure AST-based parser as other expressions.
|
|
957
|
+
* Mutually exclusive with `value` and `functionName`.
|
|
958
|
+
*
|
|
959
|
+
* @example
|
|
960
|
+
* ```typescript
|
|
961
|
+
* expression: 'formValue.quantity * formValue.unitPrice'
|
|
962
|
+
* expression: 'formValue.firstName + " " + formValue.lastName'
|
|
963
|
+
* expression: 'formValue.price * (1 - formValue.discount / 100)'
|
|
964
|
+
* ```
|
|
965
|
+
*/
|
|
966
|
+
expression?: string;
|
|
967
|
+
/**
|
|
968
|
+
* Name of a registered custom derivation function.
|
|
969
|
+
*
|
|
970
|
+
* The function receives the evaluation context and returns the derived value.
|
|
971
|
+
* Register functions in `customFnConfig.derivations`.
|
|
972
|
+
* Mutually exclusive with `value` and `expression`.
|
|
973
|
+
*
|
|
974
|
+
* @example
|
|
975
|
+
* ```typescript
|
|
976
|
+
* functionName: 'getCurrencyForCountry'
|
|
977
|
+
* functionName: 'calculateTax'
|
|
978
|
+
* functionName: 'formatPhoneNumber'
|
|
979
|
+
* ```
|
|
980
|
+
*/
|
|
981
|
+
functionName?: string;
|
|
982
|
+
/**
|
|
983
|
+
* Explicit field dependencies for derivations.
|
|
984
|
+
*
|
|
985
|
+
* When using `functionName`, you can optionally specify which fields
|
|
986
|
+
* the function depends on. This enables more efficient re-evaluation
|
|
987
|
+
* by only triggering when specific dependencies change.
|
|
988
|
+
*
|
|
989
|
+
* If not provided with `functionName`, defaults to all fields ('*').
|
|
990
|
+
* For `expression`, dependencies are automatically extracted from the expression.
|
|
991
|
+
* For `value`, no dependencies are needed (static value).
|
|
992
|
+
*
|
|
993
|
+
* @example
|
|
994
|
+
* ```typescript
|
|
995
|
+
* // Only re-evaluate when country changes
|
|
996
|
+
* {
|
|
997
|
+
* key: 'currency',
|
|
998
|
+
* logic: [{
|
|
999
|
+
* type: 'derivation',
|
|
1000
|
+
* functionName: 'getCurrencyForCountry',
|
|
1001
|
+
* dependsOn: ['country']
|
|
1002
|
+
* }]
|
|
1003
|
+
* }
|
|
1004
|
+
*
|
|
1005
|
+
* // Override automatic detection for complex expressions
|
|
1006
|
+
* {
|
|
1007
|
+
* key: 'total',
|
|
1008
|
+
* logic: [{
|
|
1009
|
+
* type: 'derivation',
|
|
1010
|
+
* expression: 'calculateTotal(formValue)',
|
|
1011
|
+
* dependsOn: ['quantity', 'unitPrice', 'discount']
|
|
1012
|
+
* }]
|
|
1013
|
+
* }
|
|
1014
|
+
* ```
|
|
1015
|
+
*/
|
|
1016
|
+
dependsOn?: string[];
|
|
1017
|
+
}
|
|
1018
|
+
/**
|
|
1019
|
+
* Derivation logic that evaluates immediately on change (default).
|
|
1020
|
+
*
|
|
1021
|
+
* @internal
|
|
1022
|
+
*/
|
|
1023
|
+
interface OnChangeDerivationLogicConfig extends BaseDerivationLogicConfig {
|
|
1024
|
+
/**
|
|
1025
|
+
* Trigger for immediate evaluation.
|
|
1026
|
+
* @default 'onChange'
|
|
1027
|
+
*/
|
|
1028
|
+
trigger?: 'onChange';
|
|
1029
|
+
/** Not allowed for onChange trigger */
|
|
1030
|
+
debounceMs?: never;
|
|
819
1031
|
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Derivation logic that evaluates after a debounce period.
|
|
1034
|
+
*
|
|
1035
|
+
* Use this for self-transforms (lowercase, trim, format) to avoid
|
|
1036
|
+
* interrupting the user while they're actively typing.
|
|
1037
|
+
*
|
|
1038
|
+
* @internal
|
|
1039
|
+
*/
|
|
1040
|
+
interface DebouncedDerivationLogicConfig extends BaseDerivationLogicConfig {
|
|
1041
|
+
/**
|
|
1042
|
+
* Trigger for debounced evaluation.
|
|
1043
|
+
* Evaluates after the value has stabilized for the debounce duration.
|
|
1044
|
+
*/
|
|
1045
|
+
trigger: 'debounced';
|
|
1046
|
+
/**
|
|
1047
|
+
* Debounce duration in milliseconds.
|
|
1048
|
+
* @default 500
|
|
1049
|
+
*/
|
|
1050
|
+
debounceMs?: number;
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* Configuration for value derivation logic.
|
|
1054
|
+
*
|
|
1055
|
+
* Enables programmatic value derivation based on conditions.
|
|
1056
|
+
* Derivations are self-targeting: the logic is placed on the field
|
|
1057
|
+
* that should receive the computed value.
|
|
1058
|
+
*
|
|
1059
|
+
* @example
|
|
1060
|
+
* ```typescript
|
|
1061
|
+
* // Set phone prefix based on country selection
|
|
1062
|
+
* {
|
|
1063
|
+
* key: 'phonePrefix',
|
|
1064
|
+
* logic: [{
|
|
1065
|
+
* type: 'derivation',
|
|
1066
|
+
* value: '+1',
|
|
1067
|
+
* condition: {
|
|
1068
|
+
* type: 'fieldValue',
|
|
1069
|
+
* fieldPath: 'country',
|
|
1070
|
+
* operator: 'equals',
|
|
1071
|
+
* value: 'USA'
|
|
1072
|
+
* }
|
|
1073
|
+
* }]
|
|
1074
|
+
* }
|
|
1075
|
+
*
|
|
1076
|
+
* // Compute total from quantity and price
|
|
1077
|
+
* {
|
|
1078
|
+
* key: 'total',
|
|
1079
|
+
* derivation: 'formValue.quantity * formValue.unitPrice'
|
|
1080
|
+
* }
|
|
1081
|
+
*
|
|
1082
|
+
* // Use custom function for complex logic
|
|
1083
|
+
* {
|
|
1084
|
+
* key: 'currency',
|
|
1085
|
+
* logic: [{
|
|
1086
|
+
* type: 'derivation',
|
|
1087
|
+
* functionName: 'getCurrencyForCountry'
|
|
1088
|
+
* }]
|
|
1089
|
+
* }
|
|
1090
|
+
*
|
|
1091
|
+
* // Self-transform with debounced trigger
|
|
1092
|
+
* // (applies after user stops typing)
|
|
1093
|
+
* {
|
|
1094
|
+
* key: 'email',
|
|
1095
|
+
* logic: [{
|
|
1096
|
+
* type: 'derivation',
|
|
1097
|
+
* expression: 'formValue.email.toLowerCase()',
|
|
1098
|
+
* trigger: 'debounced',
|
|
1099
|
+
* debounceMs: 500
|
|
1100
|
+
* }]
|
|
1101
|
+
* }
|
|
1102
|
+
*
|
|
1103
|
+
* // Array item derivation (formValue is scoped to current item)
|
|
1104
|
+
* {
|
|
1105
|
+
* key: 'lineTotal', // Inside array field
|
|
1106
|
+
* derivation: 'formValue.quantity * formValue.unitPrice'
|
|
1107
|
+
* }
|
|
1108
|
+
* ```
|
|
1109
|
+
*
|
|
1110
|
+
* @public
|
|
1111
|
+
*/
|
|
1112
|
+
type DerivationLogicConfig = OnChangeDerivationLogicConfig | DebouncedDerivationLogicConfig;
|
|
1113
|
+
/**
|
|
1114
|
+
* Union type for all logic configurations.
|
|
1115
|
+
*
|
|
1116
|
+
* - `StateLogicConfig`: For field state changes (hidden, readonly, disabled, required)
|
|
1117
|
+
* - `DerivationLogicConfig`: For value derivation
|
|
1118
|
+
*
|
|
1119
|
+
* @public
|
|
1120
|
+
*/
|
|
1121
|
+
type LogicConfig = StateLogicConfig | DerivationLogicConfig;
|
|
1122
|
+
/**
|
|
1123
|
+
* Log level for derivation debug output.
|
|
1124
|
+
*
|
|
1125
|
+
* - 'none': No debug logging
|
|
1126
|
+
* - 'summary': Log cycle completion with counts (default in dev mode)
|
|
1127
|
+
* - 'verbose': Log individual derivation evaluations with details
|
|
1128
|
+
*
|
|
1129
|
+
* @public
|
|
1130
|
+
*/
|
|
1131
|
+
type DerivationLogLevel = 'none' | 'summary' | 'verbose';
|
|
820
1132
|
/**
|
|
821
1133
|
* Type guard to check if a condition is a FormStateCondition.
|
|
822
1134
|
*
|
|
@@ -825,7 +1137,7 @@ interface LogicConfig {
|
|
|
825
1137
|
*
|
|
826
1138
|
* @public
|
|
827
1139
|
*/
|
|
828
|
-
declare function isFormStateCondition(condition:
|
|
1140
|
+
declare function isFormStateCondition(condition: StateLogicConfig['condition'] | DerivationLogicConfig['condition']): condition is FormStateCondition;
|
|
829
1141
|
|
|
830
1142
|
/**
|
|
831
1143
|
* Text element type for rendering different HTML text elements
|
|
@@ -1004,8 +1316,13 @@ type InferValueType<T, V> = T extends {
|
|
|
1004
1316
|
type: 'number';
|
|
1005
1317
|
};
|
|
1006
1318
|
} ? number : Widen<V>;
|
|
1007
|
-
/**
|
|
1319
|
+
/**
|
|
1320
|
+
* Make type optional if field is not required.
|
|
1321
|
+
* Hidden fields are never optional since they require a value property.
|
|
1322
|
+
*/
|
|
1008
1323
|
type MaybeOptional<T, V> = T extends {
|
|
1324
|
+
type: 'hidden';
|
|
1325
|
+
} ? V : T extends {
|
|
1009
1326
|
required: true;
|
|
1010
1327
|
} ? V : V | undefined;
|
|
1011
1328
|
/**
|
|
@@ -1022,13 +1339,27 @@ type ProcessField<T, D extends number = 5> = [D] extends [never] ? Record<string
|
|
|
1022
1339
|
[P in K]: InferFormValueWithDepth<F, Depth[D]>;
|
|
1023
1340
|
} : {
|
|
1024
1341
|
[P in K]: Record<string, unknown>;
|
|
1342
|
+
} : never : T extends {
|
|
1343
|
+
type: 'array';
|
|
1344
|
+
key: infer K;
|
|
1345
|
+
fields: infer F;
|
|
1346
|
+
} ? K extends string ? F extends RegisteredFieldTypes[] ? {
|
|
1347
|
+
[P in K]: InferFormValueWithDepth<F, Depth[D]>[];
|
|
1348
|
+
} : {
|
|
1349
|
+
[P in K]: unknown[];
|
|
1025
1350
|
} : never : T extends {
|
|
1026
1351
|
type: 'text';
|
|
1352
|
+
} ? never : T extends {
|
|
1353
|
+
type: 'submit' | 'button' | 'next' | 'previous' | 'addArrayItem' | 'removeArrayItem';
|
|
1027
1354
|
} ? never : T extends {
|
|
1028
1355
|
key: infer K;
|
|
1029
1356
|
value: infer V;
|
|
1030
1357
|
} ? K extends string ? {
|
|
1031
1358
|
[P in K]: MaybeOptional<T, InferValueType<T, V>>;
|
|
1359
|
+
} : never : T extends {
|
|
1360
|
+
key: infer K;
|
|
1361
|
+
} ? K extends string ? {
|
|
1362
|
+
[P in K]: MaybeOptional<T, string>;
|
|
1032
1363
|
} : never : never;
|
|
1033
1364
|
/**
|
|
1034
1365
|
* Internal helper with depth tracking
|
|
@@ -1472,7 +1803,13 @@ interface Logger {
|
|
|
1472
1803
|
interface EvaluationContext<TValue = unknown> {
|
|
1473
1804
|
/** Current field value */
|
|
1474
1805
|
fieldValue: TValue;
|
|
1475
|
-
/**
|
|
1806
|
+
/**
|
|
1807
|
+
* Form value for the current evaluation scope.
|
|
1808
|
+
*
|
|
1809
|
+
* For regular (non-array) derivations, this contains the complete form value.
|
|
1810
|
+
* For array item derivations, this is scoped to the current array item.
|
|
1811
|
+
* Use `rootFormValue` to access the complete form when inside an array context.
|
|
1812
|
+
*/
|
|
1476
1813
|
formValue: Record<string, unknown>;
|
|
1477
1814
|
/** Field path for relative references */
|
|
1478
1815
|
fieldPath: string;
|
|
@@ -1480,6 +1817,60 @@ interface EvaluationContext<TValue = unknown> {
|
|
|
1480
1817
|
customFunctions?: Record<string, (context: EvaluationContext) => unknown>;
|
|
1481
1818
|
/** Logger for diagnostic output */
|
|
1482
1819
|
logger: Logger;
|
|
1820
|
+
/**
|
|
1821
|
+
* Root form value when inside an array context.
|
|
1822
|
+
*
|
|
1823
|
+
* This provides access to values outside the current array item.
|
|
1824
|
+
* When a derivation targets an array item field (e.g., `items.$.lineTotal`),
|
|
1825
|
+
* `formValue` is scoped to the current array item, while `rootFormValue`
|
|
1826
|
+
* provides access to the entire form value including fields outside the array.
|
|
1827
|
+
*
|
|
1828
|
+
* @example
|
|
1829
|
+
* ```typescript
|
|
1830
|
+
* // In an array item derivation (on the lineTotal field inside lineItems array):
|
|
1831
|
+
* {
|
|
1832
|
+
* key: 'lineTotal',
|
|
1833
|
+
* type: 'input',
|
|
1834
|
+
* // formValue = current array item { quantity: 2, unitPrice: 50 }
|
|
1835
|
+
* // rootFormValue = entire form { globalDiscount: 0.1, lineItems: [...] }
|
|
1836
|
+
* derivation: 'formValue.quantity * formValue.unitPrice * (1 - rootFormValue.globalDiscount)'
|
|
1837
|
+
* }
|
|
1838
|
+
* ```
|
|
1839
|
+
*
|
|
1840
|
+
* For non-array derivations, `rootFormValue` is not set and `formValue`
|
|
1841
|
+
* contains the entire form value.
|
|
1842
|
+
*/
|
|
1843
|
+
rootFormValue?: Record<string, unknown>;
|
|
1844
|
+
/**
|
|
1845
|
+
* Current array index when inside an array derivation.
|
|
1846
|
+
*/
|
|
1847
|
+
arrayIndex?: number;
|
|
1848
|
+
/**
|
|
1849
|
+
* Path to the array field when inside an array derivation.
|
|
1850
|
+
*/
|
|
1851
|
+
arrayPath?: string;
|
|
1852
|
+
/**
|
|
1853
|
+
* External data signals resolved to their current values.
|
|
1854
|
+
*
|
|
1855
|
+
* This allows forms to reference data from outside the form context
|
|
1856
|
+
* in conditional logic, derivations, and other expressions.
|
|
1857
|
+
*
|
|
1858
|
+
* @example
|
|
1859
|
+
* ```typescript
|
|
1860
|
+
* // In form config:
|
|
1861
|
+
* externalData: {
|
|
1862
|
+
* userRole: computed(() => this.userService.currentRole()),
|
|
1863
|
+
* permissions: computed(() => this.authService.permissions()),
|
|
1864
|
+
* }
|
|
1865
|
+
*
|
|
1866
|
+
* // In JavaScript expression:
|
|
1867
|
+
* condition: {
|
|
1868
|
+
* type: 'javascript',
|
|
1869
|
+
* expression: "externalData.userRole === 'admin'"
|
|
1870
|
+
* }
|
|
1871
|
+
* ```
|
|
1872
|
+
*/
|
|
1873
|
+
externalData?: Record<string, unknown>;
|
|
1483
1874
|
/** Allow additional properties for flexible expression evaluation */
|
|
1484
1875
|
[key: string]: unknown;
|
|
1485
1876
|
}
|
|
@@ -1697,7 +2088,7 @@ interface SubmissionConfig<TValue = unknown> {
|
|
|
1697
2088
|
*
|
|
1698
2089
|
* @public
|
|
1699
2090
|
*/
|
|
1700
|
-
interface FormConfig<TFields extends NarrowFields | RegisteredFieldTypes[] = RegisteredFieldTypes[], TValue = InferFormValue$1<TFields extends readonly RegisteredFieldTypes[] ? TFields : RegisteredFieldTypes[]>, TProps extends object = Record<string, unknown
|
|
2091
|
+
interface FormConfig<TFields extends NarrowFields | RegisteredFieldTypes[] = RegisteredFieldTypes[], TValue = InferFormValue$1<TFields extends readonly RegisteredFieldTypes[] ? TFields : RegisteredFieldTypes[]>, TProps extends object = Record<string, unknown>, TSchemaValue = unknown> {
|
|
1701
2092
|
/**
|
|
1702
2093
|
* Array of field definitions that define the form structure.
|
|
1703
2094
|
*
|
|
@@ -1716,19 +2107,32 @@ interface FormConfig<TFields extends NarrowFields | RegisteredFieldTypes[] = Reg
|
|
|
1716
2107
|
*/
|
|
1717
2108
|
fields: TFields;
|
|
1718
2109
|
/**
|
|
1719
|
-
* Optional form-level validation schema.
|
|
2110
|
+
* Optional form-level validation schema using Standard Schema spec.
|
|
1720
2111
|
*
|
|
1721
2112
|
* Provides additional validation beyond field-level validation.
|
|
2113
|
+
* Supports Zod, Valibot, ArkType, and other Standard Schema compliant libraries.
|
|
1722
2114
|
* Useful for cross-field validation rules.
|
|
1723
2115
|
*
|
|
1724
2116
|
* @example
|
|
1725
2117
|
* ```typescript
|
|
1726
|
-
*
|
|
1727
|
-
*
|
|
1728
|
-
*
|
|
2118
|
+
* import { z } from 'zod';
|
|
2119
|
+
* import { standardSchema } from '@ng-forge/dynamic-forms/schema';
|
|
2120
|
+
*
|
|
2121
|
+
* const PasswordSchema = z.object({
|
|
2122
|
+
* password: z.string().min(8),
|
|
2123
|
+
* confirmPassword: z.string(),
|
|
2124
|
+
* }).refine(
|
|
2125
|
+
* (data) => data.password === data.confirmPassword,
|
|
2126
|
+
* { message: 'Passwords must match', path: ['confirmPassword'] }
|
|
2127
|
+
* );
|
|
2128
|
+
*
|
|
2129
|
+
* const formConfig = {
|
|
2130
|
+
* fields: [...],
|
|
2131
|
+
* schema: standardSchema(PasswordSchema),
|
|
2132
|
+
* } as const satisfies FormConfig;
|
|
1729
2133
|
* ```
|
|
1730
2134
|
*/
|
|
1731
|
-
schema?:
|
|
2135
|
+
schema?: FormSchema<TSchemaValue>;
|
|
1732
2136
|
/**
|
|
1733
2137
|
* Global form configuration options.
|
|
1734
2138
|
*
|
|
@@ -1834,6 +2238,54 @@ interface FormConfig<TFields extends NarrowFields | RegisteredFieldTypes[] = Reg
|
|
|
1834
2238
|
* ```
|
|
1835
2239
|
*/
|
|
1836
2240
|
defaultProps?: TProps;
|
|
2241
|
+
/**
|
|
2242
|
+
* External data signals available to conditional logic and derivations.
|
|
2243
|
+
*
|
|
2244
|
+
* Provides a way to inject external application state into form expressions.
|
|
2245
|
+
* Each property is a Signal that will be unwrapped and made available in the
|
|
2246
|
+
* `EvaluationContext` under `externalData`.
|
|
2247
|
+
*
|
|
2248
|
+
* The signals are read reactively in logic functions (when/readonly/disabled)
|
|
2249
|
+
* so changes to the external data will trigger re-evaluation of conditions.
|
|
2250
|
+
*
|
|
2251
|
+
* @example
|
|
2252
|
+
* ```typescript
|
|
2253
|
+
* const config: FormConfig = {
|
|
2254
|
+
* externalData: {
|
|
2255
|
+
* userRole: computed(() => this.authService.currentRole()),
|
|
2256
|
+
* permissions: computed(() => this.authService.permissions()),
|
|
2257
|
+
* featureFlags: computed(() => this.featureFlagService.flags()),
|
|
2258
|
+
* },
|
|
2259
|
+
* fields: [
|
|
2260
|
+
* {
|
|
2261
|
+
* type: 'input',
|
|
2262
|
+
* key: 'adminField',
|
|
2263
|
+
* label: 'Admin Only Field',
|
|
2264
|
+
* logic: [{
|
|
2265
|
+
* effect: 'show',
|
|
2266
|
+
* condition: {
|
|
2267
|
+
* type: 'javascript',
|
|
2268
|
+
* expression: "externalData.userRole === 'admin'"
|
|
2269
|
+
* }
|
|
2270
|
+
* }]
|
|
2271
|
+
* },
|
|
2272
|
+
* {
|
|
2273
|
+
* type: 'select',
|
|
2274
|
+
* key: 'advancedOption',
|
|
2275
|
+
* label: 'Advanced Option',
|
|
2276
|
+
* logic: [{
|
|
2277
|
+
* effect: 'show',
|
|
2278
|
+
* condition: {
|
|
2279
|
+
* type: 'javascript',
|
|
2280
|
+
* expression: "externalData.featureFlags.advancedMode === true"
|
|
2281
|
+
* }
|
|
2282
|
+
* }]
|
|
2283
|
+
* }
|
|
2284
|
+
* ]
|
|
2285
|
+
* };
|
|
2286
|
+
* ```
|
|
2287
|
+
*/
|
|
2288
|
+
externalData?: Record<string, Signal<unknown>>;
|
|
1837
2289
|
}
|
|
1838
2290
|
/**
|
|
1839
2291
|
* Signal forms adapter configuration for advanced form behavior.
|
|
@@ -1851,6 +2303,14 @@ interface FormConfig<TFields extends NarrowFields | RegisteredFieldTypes[] = Reg
|
|
|
1851
2303
|
* currency: 'USD'
|
|
1852
2304
|
* }).format(context.value)
|
|
1853
2305
|
* },
|
|
2306
|
+
* derivations: {
|
|
2307
|
+
* getCurrencyForCountry: (context) => {
|
|
2308
|
+
* const countryToCurrency: Record<string, string> = {
|
|
2309
|
+
* 'USA': 'USD', 'Germany': 'EUR', 'UK': 'GBP'
|
|
2310
|
+
* };
|
|
2311
|
+
* return countryToCurrency[context.formValue.country as string] ?? 'USD';
|
|
2312
|
+
* }
|
|
2313
|
+
* },
|
|
1854
2314
|
* simpleValidators: {
|
|
1855
2315
|
* noSpaces: (value) => {
|
|
1856
2316
|
* return typeof value === 'string' && value.includes(' ')
|
|
@@ -1893,6 +2353,74 @@ interface CustomFnConfig {
|
|
|
1893
2353
|
* ```
|
|
1894
2354
|
*/
|
|
1895
2355
|
customFunctions?: Record<string, CustomFunction>;
|
|
2356
|
+
/**
|
|
2357
|
+
* Custom derivation functions for value derivation logic.
|
|
2358
|
+
*
|
|
2359
|
+
* These functions compute derived values and are called when a
|
|
2360
|
+
* `DerivationLogicConfig` references them by `functionName`.
|
|
2361
|
+
*
|
|
2362
|
+
* Derivation functions:
|
|
2363
|
+
* - Receive an `EvaluationContext` with access to `formValue`
|
|
2364
|
+
* - Return the value to set on the target field
|
|
2365
|
+
* - Are called reactively when dependencies change
|
|
2366
|
+
*
|
|
2367
|
+
* Use derivation functions for complex mappings or logic that
|
|
2368
|
+
* can't be easily expressed as a JavaScript expression.
|
|
2369
|
+
*
|
|
2370
|
+
* @example
|
|
2371
|
+
* ```typescript
|
|
2372
|
+
* derivations: {
|
|
2373
|
+
* // Country to currency mapping
|
|
2374
|
+
* getCurrencyForCountry: (context) => {
|
|
2375
|
+
* const countryToCurrency: Record<string, string> = {
|
|
2376
|
+
* 'USA': 'USD',
|
|
2377
|
+
* 'Germany': 'EUR',
|
|
2378
|
+
* 'France': 'EUR',
|
|
2379
|
+
* 'UK': 'GBP',
|
|
2380
|
+
* 'Japan': 'JPY'
|
|
2381
|
+
* };
|
|
2382
|
+
* return countryToCurrency[context.formValue.country as string] ?? 'USD';
|
|
2383
|
+
* },
|
|
2384
|
+
*
|
|
2385
|
+
* // Complex tax calculation
|
|
2386
|
+
* calculateTax: (context) => {
|
|
2387
|
+
* const subtotal = context.formValue.subtotal as number ?? 0;
|
|
2388
|
+
* const state = context.formValue.state as string;
|
|
2389
|
+
* const taxRates: Record<string, number> = {
|
|
2390
|
+
* 'CA': 0.0725, 'NY': 0.08, 'TX': 0.0625
|
|
2391
|
+
* };
|
|
2392
|
+
* return subtotal * (taxRates[state] ?? 0);
|
|
2393
|
+
* },
|
|
2394
|
+
*
|
|
2395
|
+
* // Format phone number
|
|
2396
|
+
* formatPhoneNumber: (context) => {
|
|
2397
|
+
* const phone = context.fieldValue as string ?? '';
|
|
2398
|
+
* const digits = phone.replace(/\D/g, '');
|
|
2399
|
+
* if (digits.length === 10) {
|
|
2400
|
+
* return `(${digits.slice(0,3)}) ${digits.slice(3,6)}-${digits.slice(6)}`;
|
|
2401
|
+
* }
|
|
2402
|
+
* return phone;
|
|
2403
|
+
* }
|
|
2404
|
+
* }
|
|
2405
|
+
* ```
|
|
2406
|
+
*
|
|
2407
|
+
* Field configuration using a derivation function:
|
|
2408
|
+
* ```typescript
|
|
2409
|
+
* // Derivation is defined on the target field (currency), not the source field (country)
|
|
2410
|
+
* {
|
|
2411
|
+
* key: 'currency',
|
|
2412
|
+
* type: 'select',
|
|
2413
|
+
* logic: [
|
|
2414
|
+
* {
|
|
2415
|
+
* type: 'derivation',
|
|
2416
|
+
* functionName: 'getCurrencyForCountry',
|
|
2417
|
+
* dependsOn: ['country']
|
|
2418
|
+
* }
|
|
2419
|
+
* ]
|
|
2420
|
+
* }
|
|
2421
|
+
* ```
|
|
2422
|
+
*/
|
|
2423
|
+
derivations?: Record<string, CustomFunction>;
|
|
1896
2424
|
/**
|
|
1897
2425
|
* Custom validators using Angular's public FieldContext API
|
|
1898
2426
|
*
|
|
@@ -2104,6 +2632,19 @@ interface FormOptions {
|
|
|
2104
2632
|
* @value false
|
|
2105
2633
|
*/
|
|
2106
2634
|
disabled?: boolean;
|
|
2635
|
+
/**
|
|
2636
|
+
* Maximum number of iterations for derivation chain processing.
|
|
2637
|
+
*
|
|
2638
|
+
* Derivations can trigger other derivations (e.g., A → B → C).
|
|
2639
|
+
* This limit prevents infinite loops in case of circular dependencies
|
|
2640
|
+
* that weren't caught at build time.
|
|
2641
|
+
*
|
|
2642
|
+
* Increase this value if you have legitimate deep derivation chains
|
|
2643
|
+
* (more than 10 levels deep).
|
|
2644
|
+
*
|
|
2645
|
+
* @default 10
|
|
2646
|
+
*/
|
|
2647
|
+
maxDerivationIterations?: number;
|
|
2107
2648
|
/**
|
|
2108
2649
|
* Default disabled behavior for submit buttons.
|
|
2109
2650
|
*
|
|
@@ -2138,6 +2679,35 @@ interface FormOptions {
|
|
|
2138
2679
|
* ```
|
|
2139
2680
|
*/
|
|
2140
2681
|
nextButton?: NextButtonOptions;
|
|
2682
|
+
/**
|
|
2683
|
+
* Whether to attach the current form value to all events dispatched through the EventBus.
|
|
2684
|
+
*
|
|
2685
|
+
* This per-form setting overrides the global `withEventFormValue()` feature:
|
|
2686
|
+
* - `true` - Enable form value emission for this form (even if globally disabled)
|
|
2687
|
+
* - `false` - Disable form value emission for this form (even if globally enabled)
|
|
2688
|
+
* - `undefined` - Use global setting (default)
|
|
2689
|
+
*
|
|
2690
|
+
* When enabled, events will include a `formValue` property with the current form state.
|
|
2691
|
+
* Use the `hasFormValue()` type guard to safely access this property.
|
|
2692
|
+
*
|
|
2693
|
+
* @example
|
|
2694
|
+
* ```typescript
|
|
2695
|
+
* // Enable for this form only (no global withEventFormValue() needed)
|
|
2696
|
+
* const config: FormConfig = {
|
|
2697
|
+
* fields: [...],
|
|
2698
|
+
* options: { emitFormValueOnEvents: true }
|
|
2699
|
+
* };
|
|
2700
|
+
*
|
|
2701
|
+
* // Disable for this form (when globally enabled)
|
|
2702
|
+
* const config: FormConfig = {
|
|
2703
|
+
* fields: [...],
|
|
2704
|
+
* options: { emitFormValueOnEvents: false }
|
|
2705
|
+
* };
|
|
2706
|
+
* ```
|
|
2707
|
+
*
|
|
2708
|
+
* @default undefined (uses global setting)
|
|
2709
|
+
*/
|
|
2710
|
+
emitFormValueOnEvents?: boolean;
|
|
2141
2711
|
}
|
|
2142
2712
|
/**
|
|
2143
2713
|
* Options for controlling submit button disabled behavior.
|
|
@@ -2238,6 +2808,107 @@ type FieldPathAccess<TValue> = {
|
|
|
2238
2808
|
[K in keyof TValue]: SchemaPath<TValue[K]> | SchemaPathTree<TValue[K]>;
|
|
2239
2809
|
};
|
|
2240
2810
|
|
|
2811
|
+
/**
|
|
2812
|
+
* Result of processing all pending derivations.
|
|
2813
|
+
*
|
|
2814
|
+
* @public
|
|
2815
|
+
*/
|
|
2816
|
+
interface DerivationProcessingResult {
|
|
2817
|
+
/** Number of derivations successfully applied */
|
|
2818
|
+
appliedCount: number;
|
|
2819
|
+
/** Number of derivations skipped (condition not met or value unchanged) */
|
|
2820
|
+
skippedCount: number;
|
|
2821
|
+
/** Number of derivations that failed with errors */
|
|
2822
|
+
errorCount: number;
|
|
2823
|
+
/**
|
|
2824
|
+
* Number of derivations that encountered warnings (e.g., missing target field).
|
|
2825
|
+
*
|
|
2826
|
+
* These are not counted as errors because they may be intentional (conditional fields)
|
|
2827
|
+
* but indicate potential configuration issues if unexpected.
|
|
2828
|
+
*/
|
|
2829
|
+
warnCount: number;
|
|
2830
|
+
/** Total iterations performed */
|
|
2831
|
+
iterations: number;
|
|
2832
|
+
/** Whether max iterations was reached (potential loop) */
|
|
2833
|
+
maxIterationsReached: boolean;
|
|
2834
|
+
}
|
|
2835
|
+
|
|
2836
|
+
/**
|
|
2837
|
+
* Information about a single derivation evaluation for logging.
|
|
2838
|
+
*
|
|
2839
|
+
* @public
|
|
2840
|
+
*/
|
|
2841
|
+
interface DerivationLogEntry {
|
|
2842
|
+
/** Debug name if provided in the derivation config */
|
|
2843
|
+
debugName?: string;
|
|
2844
|
+
/** Field key where the derivation is defined and targets */
|
|
2845
|
+
fieldKey: string;
|
|
2846
|
+
/** Result of the derivation evaluation */
|
|
2847
|
+
result: 'applied' | 'skipped' | 'error';
|
|
2848
|
+
/** Reason for skipping (if result is 'skipped') */
|
|
2849
|
+
skipReason?: 'condition-false' | 'value-unchanged' | 'already-applied' | 'target-not-found';
|
|
2850
|
+
/** The new value that was set (if result is 'applied') */
|
|
2851
|
+
newValue?: unknown;
|
|
2852
|
+
/** The previous value before the derivation (if result is 'applied') */
|
|
2853
|
+
previousValue?: unknown;
|
|
2854
|
+
/** Error message (if result is 'error') */
|
|
2855
|
+
error?: string;
|
|
2856
|
+
/** Duration in milliseconds (optional, for performance tracking) */
|
|
2857
|
+
durationMs?: number;
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2860
|
+
/**
|
|
2861
|
+
* Service interface for derivation logging.
|
|
2862
|
+
*
|
|
2863
|
+
* Provides methods to log derivation processing events at different verbosity levels.
|
|
2864
|
+
* Use `DERIVATION_LOGGER` injection token to get an instance.
|
|
2865
|
+
*
|
|
2866
|
+
* @public
|
|
2867
|
+
*/
|
|
2868
|
+
interface DerivationLogger {
|
|
2869
|
+
/**
|
|
2870
|
+
* Logs the start of a derivation processing cycle.
|
|
2871
|
+
* Only logs when config level is 'verbose'.
|
|
2872
|
+
*/
|
|
2873
|
+
cycleStart(trigger: 'onChange' | 'debounced', entryCount: number): void;
|
|
2874
|
+
/**
|
|
2875
|
+
* Logs the start of a derivation iteration within a cycle.
|
|
2876
|
+
* Only logs when config level is 'verbose'.
|
|
2877
|
+
*/
|
|
2878
|
+
iteration(iterationNumber: number): void;
|
|
2879
|
+
/**
|
|
2880
|
+
* Logs a single derivation evaluation result.
|
|
2881
|
+
* Only logs when config level is 'verbose'.
|
|
2882
|
+
*/
|
|
2883
|
+
evaluation(entry: DerivationLogEntry): void;
|
|
2884
|
+
/**
|
|
2885
|
+
* Logs a summary of derivation processing results.
|
|
2886
|
+
* Logs when config level is 'summary' or 'verbose' and something interesting happened.
|
|
2887
|
+
*/
|
|
2888
|
+
summary(result: DerivationProcessingResult, trigger: 'onChange' | 'debounced'): void;
|
|
2889
|
+
/**
|
|
2890
|
+
* Logs when max iterations are reached (always logged as warning).
|
|
2891
|
+
*/
|
|
2892
|
+
maxIterationsReached(result: DerivationProcessingResult, trigger: 'onChange' | 'debounced'): void;
|
|
2893
|
+
}
|
|
2894
|
+
|
|
2895
|
+
/**
|
|
2896
|
+
* Minimal configuration for creating a DerivationOrchestrator.
|
|
2897
|
+
* Only includes form-specific signals that cannot be injected.
|
|
2898
|
+
*
|
|
2899
|
+
* @internal
|
|
2900
|
+
*/
|
|
2901
|
+
interface DerivationOrchestratorConfig {
|
|
2902
|
+
/** Signal containing the flattened schema fields */
|
|
2903
|
+
schemaFields: Signal<FieldDef<unknown>[] | undefined>;
|
|
2904
|
+
/** Signal containing the current form value */
|
|
2905
|
+
formValue: Signal<Record<string, unknown>>;
|
|
2906
|
+
/** Signal containing the form accessor */
|
|
2907
|
+
form: Signal<FieldTree<unknown>>;
|
|
2908
|
+
/** Signal containing the derivation logger */
|
|
2909
|
+
derivationLogger: Signal<DerivationLogger>;
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2241
2912
|
/**
|
|
2242
2913
|
* Base interface for all form events in the dynamic form system.
|
|
2243
2914
|
*
|
|
@@ -2260,7 +2931,38 @@ type FieldPathAccess<TValue> = {
|
|
|
2260
2931
|
interface FormEvent {
|
|
2261
2932
|
/** Unique identifier for the event type used for filtering and subscriptions */
|
|
2262
2933
|
readonly type: string;
|
|
2934
|
+
/**
|
|
2935
|
+
* Optional form value attached to the event when `withEventFormValue()` is enabled
|
|
2936
|
+
* or `options.emitFormValueOnEvents` is set to `true` in the form config.
|
|
2937
|
+
*
|
|
2938
|
+
* Use the `hasFormValue()` type guard to check if this property is present.
|
|
2939
|
+
*/
|
|
2940
|
+
readonly formValue?: unknown;
|
|
2263
2941
|
}
|
|
2942
|
+
/**
|
|
2943
|
+
* Type guard to check if a form event has a form value attached.
|
|
2944
|
+
*
|
|
2945
|
+
* Use this to safely access the `formValue` property on events when
|
|
2946
|
+
* `withEventFormValue()` is enabled globally or `options.emitFormValueOnEvents`
|
|
2947
|
+
* is set to `true` in the form config.
|
|
2948
|
+
*
|
|
2949
|
+
* @example
|
|
2950
|
+
* ```typescript
|
|
2951
|
+
* eventBus.on<SubmitEvent>('submit').subscribe(event => {
|
|
2952
|
+
* if (hasFormValue(event)) {
|
|
2953
|
+
* console.log('Form value:', event.formValue);
|
|
2954
|
+
* }
|
|
2955
|
+
* });
|
|
2956
|
+
* ```
|
|
2957
|
+
*
|
|
2958
|
+
* @param event - The form event to check
|
|
2959
|
+
* @returns `true` if the event has a form value attached, narrowing the type
|
|
2960
|
+
*
|
|
2961
|
+
* @public
|
|
2962
|
+
*/
|
|
2963
|
+
declare function hasFormValue<T extends FormEvent>(event: T): event is T & {
|
|
2964
|
+
formValue: unknown;
|
|
2965
|
+
};
|
|
2264
2966
|
/**
|
|
2265
2967
|
* Constructor type for form event classes.
|
|
2266
2968
|
*
|
|
@@ -2397,6 +3099,7 @@ declare class DynamicForm<TFields extends RegisteredFieldTypes[] = RegisteredFie
|
|
|
2397
3099
|
private readonly functionRegistry;
|
|
2398
3100
|
private readonly schemaRegistry;
|
|
2399
3101
|
private readonly logger;
|
|
3102
|
+
private readonly derivationLogConfig;
|
|
2400
3103
|
/** Form configuration defining the structure, validation, and behavior. */
|
|
2401
3104
|
config: InputSignal<FormConfig<TFields>>;
|
|
2402
3105
|
/** Runtime form options that override config options when provided. */
|
|
@@ -2413,9 +3116,18 @@ declare class DynamicForm<TFields extends RegisteredFieldTypes[] = RegisteredFie
|
|
|
2413
3116
|
readonly pageFieldDefinitions: Signal<PageField<_ng_forge_dynamic_forms.PageAllowedChildren[]>[]>;
|
|
2414
3117
|
readonly effectiveFormOptions: Signal<{
|
|
2415
3118
|
disabled?: boolean;
|
|
3119
|
+
maxDerivationIterations?: number;
|
|
2416
3120
|
submitButton?: _ng_forge_dynamic_forms.SubmitButtonOptions;
|
|
2417
3121
|
nextButton?: _ng_forge_dynamic_forms.NextButtonOptions;
|
|
3122
|
+
emitFormValueOnEvents?: boolean;
|
|
2418
3123
|
}>;
|
|
3124
|
+
/**
|
|
3125
|
+
* Computed derivation logger based on injected config.
|
|
3126
|
+
*
|
|
3127
|
+
* Uses factory pattern to return no-op logger when logging is disabled,
|
|
3128
|
+
* avoiding any logging overhead in production.
|
|
3129
|
+
*/
|
|
3130
|
+
private readonly derivationLogger;
|
|
2419
3131
|
readonly fieldSignalContext: Signal<FieldSignalContext<TModel>>;
|
|
2420
3132
|
/**
|
|
2421
3133
|
* Injector for field components with FIELD_SIGNAL_CONTEXT.
|
|
@@ -2424,7 +3136,7 @@ declare class DynamicForm<TFields extends RegisteredFieldTypes[] = RegisteredFie
|
|
|
2424
3136
|
private readonly fieldInjector;
|
|
2425
3137
|
readonly defaultValues: _angular_core.WritableSignal<TModel>;
|
|
2426
3138
|
private readonly entity;
|
|
2427
|
-
readonly form: Signal<
|
|
3139
|
+
readonly form: Signal<FieldTree<TModel, string | number>>;
|
|
2428
3140
|
private readonly componentId;
|
|
2429
3141
|
private readonly totalComponentsCount;
|
|
2430
3142
|
private readonly fieldsSource;
|
|
@@ -2450,16 +3162,28 @@ declare class DynamicForm<TFields extends RegisteredFieldTypes[] = RegisteredFie
|
|
|
2450
3162
|
readonly disabled: Signal<boolean>;
|
|
2451
3163
|
/** Whether the form is currently submitting. */
|
|
2452
3164
|
readonly submitting: Signal<boolean>;
|
|
3165
|
+
/**
|
|
3166
|
+
* Configuration for the derivation orchestrator.
|
|
3167
|
+
* Bundles the form-specific signals needed by the orchestrator.
|
|
3168
|
+
*
|
|
3169
|
+
* @internal Used by DERIVATION_ORCHESTRATOR provider.
|
|
3170
|
+
*/
|
|
3171
|
+
readonly derivationOrchestratorConfig: DerivationOrchestratorConfig;
|
|
2453
3172
|
readonly initialized$: rxjs.Observable<boolean>;
|
|
2454
3173
|
/** Emits when form validity changes. */
|
|
2455
3174
|
readonly validityChange: _angular_core.OutputRef<boolean>;
|
|
2456
3175
|
/** Emits when form dirty state changes. */
|
|
2457
3176
|
readonly dirtyChange: _angular_core.OutputRef<boolean>;
|
|
2458
3177
|
/**
|
|
2459
|
-
* Emits form values when submitted (via SubmitEvent).
|
|
3178
|
+
* Emits form values when submitted (via SubmitEvent) and form is valid.
|
|
3179
|
+
*
|
|
3180
|
+
* **Important:** This output only emits when the form is valid. If you need to
|
|
3181
|
+
* handle submit events regardless of validity, use the `(events)` output and
|
|
3182
|
+
* filter for `'submit'` events.
|
|
3183
|
+
*
|
|
2460
3184
|
* Note: Does not emit when `submission.action` is configured - use one or the other.
|
|
2461
3185
|
*/
|
|
2462
|
-
readonly submitted: _angular_core.OutputRef<
|
|
3186
|
+
readonly submitted: _angular_core.OutputRef<TModel>;
|
|
2463
3187
|
/** Emits when form is reset to default values. */
|
|
2464
3188
|
readonly reset: _angular_core.OutputRef<FormResetEvent>;
|
|
2465
3189
|
/** Emits when form is cleared to empty state. */
|
|
@@ -2524,13 +3248,9 @@ type ExtractFieldDef<T> = T extends FieldTypeDefinition<infer F> ? F : never;
|
|
|
2524
3248
|
*/
|
|
2525
3249
|
type FieldDefUnion<T extends FieldTypeDefinition[]> = ExtractFieldDef<T[number]>;
|
|
2526
3250
|
/**
|
|
2527
|
-
* Infer form value type from field definitions
|
|
2528
|
-
* Note: Full value type inference requires complex recursive type mapping.
|
|
2529
|
-
* Using unknown as placeholder until full inference is implemented.
|
|
3251
|
+
* Infer form value type from field definitions using the real inference type.
|
|
2530
3252
|
*/
|
|
2531
|
-
type InferFormValue<TFieldDefs extends FieldDef<unknown>[]> =
|
|
2532
|
-
[K in TFieldDefs[number]['key']]: unknown;
|
|
2533
|
-
};
|
|
3253
|
+
type InferFormValue<TFieldDefs extends FieldDef<unknown>[]> = InferFormValue$1<TFieldDefs>;
|
|
2534
3254
|
/**
|
|
2535
3255
|
* Provider result with type inference
|
|
2536
3256
|
*/
|
|
@@ -2650,20 +3370,55 @@ type ExtractFormValue<T> = T extends {
|
|
|
2650
3370
|
*/
|
|
2651
3371
|
declare const BUILT_IN_FIELDS: FieldTypeDefinition[];
|
|
2652
3372
|
|
|
3373
|
+
/**
|
|
3374
|
+
* Configuration options for the logger feature.
|
|
3375
|
+
*
|
|
3376
|
+
* @public
|
|
3377
|
+
*/
|
|
3378
|
+
interface LoggerConfigOptions {
|
|
3379
|
+
/**
|
|
3380
|
+
* Whether general logging is enabled.
|
|
3381
|
+
*
|
|
3382
|
+
* @default true
|
|
3383
|
+
*/
|
|
3384
|
+
enabled?: boolean;
|
|
3385
|
+
/**
|
|
3386
|
+
* Derivation logging level.
|
|
3387
|
+
*
|
|
3388
|
+
* - `'none'`: No derivation debug logging (default)
|
|
3389
|
+
* - `'summary'`: Log cycle completion with counts
|
|
3390
|
+
* - `'verbose'`: Log individual derivation evaluations with details
|
|
3391
|
+
*
|
|
3392
|
+
* @default 'none'
|
|
3393
|
+
*/
|
|
3394
|
+
derivations?: DerivationLogLevel;
|
|
3395
|
+
}
|
|
2653
3396
|
/**
|
|
2654
3397
|
* Configure logging for dynamic forms.
|
|
2655
3398
|
*
|
|
2656
|
-
* By default, logging is enabled (ConsoleLogger)
|
|
2657
|
-
*
|
|
3399
|
+
* By default, general logging is enabled (ConsoleLogger) and derivation
|
|
3400
|
+
* logging is disabled ('none'). Use this feature to enable derivation debugging.
|
|
2658
3401
|
*
|
|
2659
3402
|
* @example
|
|
2660
3403
|
* ```typescript
|
|
2661
|
-
* // Disable logging
|
|
3404
|
+
* // Disable all logging
|
|
2662
3405
|
* provideDynamicForm(
|
|
2663
3406
|
* ...withMaterialFields(),
|
|
2664
3407
|
* withLoggerConfig(false)
|
|
2665
3408
|
* )
|
|
2666
3409
|
*
|
|
3410
|
+
* // Enable verbose derivation logging
|
|
3411
|
+
* provideDynamicForm(
|
|
3412
|
+
* ...withMaterialFields(),
|
|
3413
|
+
* withLoggerConfig({ derivations: 'verbose' })
|
|
3414
|
+
* )
|
|
3415
|
+
*
|
|
3416
|
+
* // Disable derivation logging but keep general logging
|
|
3417
|
+
* provideDynamicForm(
|
|
3418
|
+
* ...withMaterialFields(),
|
|
3419
|
+
* withLoggerConfig({ derivations: 'none' })
|
|
3420
|
+
* )
|
|
3421
|
+
*
|
|
2667
3422
|
* // Conditional logging (e.g., only in dev mode)
|
|
2668
3423
|
* provideDynamicForm(
|
|
2669
3424
|
* ...withMaterialFields(),
|
|
@@ -2671,10 +3426,12 @@ declare const BUILT_IN_FIELDS: FieldTypeDefinition[];
|
|
|
2671
3426
|
* )
|
|
2672
3427
|
* ```
|
|
2673
3428
|
*
|
|
2674
|
-
* @param
|
|
3429
|
+
* @param config - Boolean to enable/disable logging, a function returning boolean, or a config object
|
|
2675
3430
|
* @returns A DynamicFormFeature that configures logging
|
|
3431
|
+
*
|
|
3432
|
+
* @public
|
|
2676
3433
|
*/
|
|
2677
|
-
declare function withLoggerConfig(
|
|
3434
|
+
declare function withLoggerConfig(config?: boolean | (() => boolean) | LoggerConfigOptions): DynamicFormFeature<'logger'>;
|
|
2678
3435
|
|
|
2679
3436
|
/**
|
|
2680
3437
|
* Injection token for the dynamic forms logger.
|
|
@@ -2706,6 +3463,52 @@ declare class NoopLogger implements Logger {
|
|
|
2706
3463
|
error(): void;
|
|
2707
3464
|
}
|
|
2708
3465
|
|
|
3466
|
+
/**
|
|
3467
|
+
* Enables automatic form value attachment to all events dispatched through the EventBus.
|
|
3468
|
+
*
|
|
3469
|
+
* When this feature is enabled, events dispatched via `eventBus.dispatch()` will include
|
|
3470
|
+
* the current form value in the `formValue` property. This is useful for event handlers
|
|
3471
|
+
* that need access to the complete form state at the time of the event.
|
|
3472
|
+
*
|
|
3473
|
+
* @example Global opt-in
|
|
3474
|
+
* ```typescript
|
|
3475
|
+
* provideDynamicForm(
|
|
3476
|
+
* ...withMaterialFields(),
|
|
3477
|
+
* withEventFormValue()
|
|
3478
|
+
* )
|
|
3479
|
+
* ```
|
|
3480
|
+
*
|
|
3481
|
+
* @example Consumer usage
|
|
3482
|
+
* ```typescript
|
|
3483
|
+
* eventBus.on<SubmitEvent>('submit').subscribe(event => {
|
|
3484
|
+
* if (hasFormValue(event)) {
|
|
3485
|
+
* console.log('Form value:', event.formValue);
|
|
3486
|
+
* }
|
|
3487
|
+
* });
|
|
3488
|
+
* ```
|
|
3489
|
+
*
|
|
3490
|
+
* @example Per-form disable (when globally enabled)
|
|
3491
|
+
* ```typescript
|
|
3492
|
+
* const config: FormConfig = {
|
|
3493
|
+
* fields: [...],
|
|
3494
|
+
* options: { emitFormValueOnEvents: false }
|
|
3495
|
+
* };
|
|
3496
|
+
* ```
|
|
3497
|
+
*
|
|
3498
|
+
* @remarks
|
|
3499
|
+
* **Precedence rules:**
|
|
3500
|
+
* 1. Per-form `false` - Disables for this form, regardless of global setting
|
|
3501
|
+
* 2. Per-form `true` - Enables for this form, regardless of global setting
|
|
3502
|
+
* 3. Per-form `undefined` - Uses global setting
|
|
3503
|
+
* 4. Global `withEventFormValue()` - Enables globally
|
|
3504
|
+
* 5. No global feature - Disabled globally (default)
|
|
3505
|
+
*
|
|
3506
|
+
* @returns A DynamicFormFeature that enables form value attachment to events
|
|
3507
|
+
*
|
|
3508
|
+
* @public
|
|
3509
|
+
*/
|
|
3510
|
+
declare function withEventFormValue(): DynamicFormFeature<'event-form-value'>;
|
|
3511
|
+
|
|
2709
3512
|
interface FieldOption<T = unknown> {
|
|
2710
3513
|
label: DynamicText;
|
|
2711
3514
|
value: T;
|
|
@@ -2925,6 +3728,43 @@ interface FieldWithValidation {
|
|
|
2925
3728
|
readonly validators?: ValidatorConfig[];
|
|
2926
3729
|
readonly validationMessages?: ValidationMessages;
|
|
2927
3730
|
readonly logic?: LogicConfig[];
|
|
3731
|
+
/**
|
|
3732
|
+
* Shorthand for simple computed/derived fields.
|
|
3733
|
+
*
|
|
3734
|
+
* The expression is evaluated whenever its dependencies change,
|
|
3735
|
+
* and the result is set as this field's value.
|
|
3736
|
+
*
|
|
3737
|
+
* Has access to `formValue` object containing all form values.
|
|
3738
|
+
* Uses the same secure AST-based parser as other expressions.
|
|
3739
|
+
*
|
|
3740
|
+
* For conditional derivations or derivations targeting other fields,
|
|
3741
|
+
* use the full `logic` array with `{ type: 'derivation', ... }`.
|
|
3742
|
+
*
|
|
3743
|
+
* @example
|
|
3744
|
+
* ```typescript
|
|
3745
|
+
* // Compute total from quantity and price
|
|
3746
|
+
* {
|
|
3747
|
+
* key: 'total',
|
|
3748
|
+
* type: 'number',
|
|
3749
|
+
* derivation: 'formValue.quantity * formValue.unitPrice'
|
|
3750
|
+
* }
|
|
3751
|
+
*
|
|
3752
|
+
* // Concatenate names
|
|
3753
|
+
* {
|
|
3754
|
+
* key: 'fullName',
|
|
3755
|
+
* type: 'input',
|
|
3756
|
+
* derivation: 'formValue.firstName + " " + formValue.lastName'
|
|
3757
|
+
* }
|
|
3758
|
+
*
|
|
3759
|
+
* // Calculate discounted price
|
|
3760
|
+
* {
|
|
3761
|
+
* key: 'discountedPrice',
|
|
3762
|
+
* type: 'number',
|
|
3763
|
+
* derivation: 'formValue.price * (1 - formValue.discountPercent / 100)'
|
|
3764
|
+
* }
|
|
3765
|
+
* ```
|
|
3766
|
+
*/
|
|
3767
|
+
readonly derivation?: string;
|
|
2928
3768
|
readonly schemas?: SchemaApplicationConfig[];
|
|
2929
3769
|
}
|
|
2930
3770
|
|
|
@@ -2943,7 +3783,7 @@ interface BaseValueField<TProps, TValue, TMeta extends FieldMeta = FieldMeta> ex
|
|
|
2943
3783
|
required?: boolean;
|
|
2944
3784
|
}
|
|
2945
3785
|
declare function isValueField<TProps, TMeta extends FieldMeta = FieldMeta>(field: FieldDef<TProps, TMeta>): field is BaseValueField<TProps, ValueType, TMeta>;
|
|
2946
|
-
type ExcludedKeys$1 = 'type' | 'conditionals' | 'value' | 'valueType' | 'disabled' | 'readonly' | 'hidden' | 'col' | 'minValue' | 'maxValue' | 'step' | 'required' | 'email' | 'min' | 'max' | 'minLength' | 'maxLength' | 'pattern' | 'validators' | 'logic' | 'schemas';
|
|
3786
|
+
type ExcludedKeys$1 = 'type' | 'conditionals' | 'value' | 'valueType' | 'disabled' | 'readonly' | 'hidden' | 'col' | 'minValue' | 'maxValue' | 'step' | 'required' | 'email' | 'min' | 'max' | 'minLength' | 'maxLength' | 'pattern' | 'validators' | 'logic' | 'derivation' | 'schemas';
|
|
2947
3787
|
type ValueFieldComponent<T extends BaseValueField<Record<string, unknown> | unknown, unknown>> = Prettify<WithInputSignals<Omit<T, ExcludedKeys$1>>>;
|
|
2948
3788
|
|
|
2949
3789
|
interface BaseCheckedField<TProps, TMeta extends FieldMeta = FieldMeta> extends FieldDef<TProps, TMeta>, FieldWithValidation {
|
|
@@ -3079,7 +3919,10 @@ declare class RemoveArrayItemEvent implements FormEvent {
|
|
|
3079
3919
|
* ```
|
|
3080
3920
|
*/
|
|
3081
3921
|
declare class EventBus {
|
|
3082
|
-
private pipeline$;
|
|
3922
|
+
private readonly pipeline$;
|
|
3923
|
+
private readonly globalEmitFormValue;
|
|
3924
|
+
private readonly rootFormRegistry;
|
|
3925
|
+
private readonly formOptions;
|
|
3083
3926
|
events$: Observable<FormEvent>;
|
|
3084
3927
|
/**
|
|
3085
3928
|
* Dispatches an event to all subscribers.
|
|
@@ -3087,6 +3930,10 @@ declare class EventBus {
|
|
|
3087
3930
|
* Creates an instance of the provided event constructor and broadcasts it
|
|
3088
3931
|
* through the event pipeline to all active subscribers.
|
|
3089
3932
|
*
|
|
3933
|
+
* If `withEventFormValue()` is enabled globally or `options.emitFormValueOnEvents`
|
|
3934
|
+
* is set to `true` in the form config, the current form value will be attached
|
|
3935
|
+
* to the event's `formValue` property.
|
|
3936
|
+
*
|
|
3090
3937
|
* @param eventConstructor - Constructor function for the event to dispatch
|
|
3091
3938
|
*
|
|
3092
3939
|
* @example
|
|
@@ -3099,6 +3946,14 @@ declare class EventBus {
|
|
|
3099
3946
|
* ```
|
|
3100
3947
|
*/
|
|
3101
3948
|
dispatch<T extends FormEventConstructor>(eventConstructor: T, ...args: ConstructorParameters<T>): void;
|
|
3949
|
+
/**
|
|
3950
|
+
* Determines whether form value should be attached to events.
|
|
3951
|
+
*
|
|
3952
|
+
* Precedence rules:
|
|
3953
|
+
* 1. Per-form setting (if defined) takes precedence
|
|
3954
|
+
* 2. Falls back to global setting
|
|
3955
|
+
*/
|
|
3956
|
+
private shouldEmitFormValue;
|
|
3102
3957
|
/**
|
|
3103
3958
|
* Subscribes to events of a specific type.
|
|
3104
3959
|
*
|
|
@@ -3168,6 +4023,120 @@ interface ArrayItemContext {
|
|
|
3168
4023
|
formValue?: unknown;
|
|
3169
4024
|
}
|
|
3170
4025
|
|
|
4026
|
+
/**
|
|
4027
|
+
* Type-safe form config builder that ensures schema matches field structure.
|
|
4028
|
+
*
|
|
4029
|
+
* This helper function provides type safety when using form-level schemas by
|
|
4030
|
+
* automatically inferring the form value type from fields and constraining
|
|
4031
|
+
* the schema type parameter accordingly.
|
|
4032
|
+
*
|
|
4033
|
+
* **When to use:**
|
|
4034
|
+
* - When you have a form-level `schema` and want type safety between fields and schema
|
|
4035
|
+
* - When you prefer function syntax over `as const satisfies FormConfig`
|
|
4036
|
+
*
|
|
4037
|
+
* **Note:** This is optional. Users who don't need schema type safety can
|
|
4038
|
+
* continue using `as const satisfies FormConfig` directly.
|
|
4039
|
+
*
|
|
4040
|
+
* @typeParam TFields - The field definitions array (narrowed via `as const`)
|
|
4041
|
+
* @typeParam TProps - Optional form-level default props type
|
|
4042
|
+
*
|
|
4043
|
+
* @param config - The form configuration object
|
|
4044
|
+
* @returns The same configuration with proper type inference
|
|
4045
|
+
*
|
|
4046
|
+
* @example Basic usage with Zod schema
|
|
4047
|
+
* ```typescript
|
|
4048
|
+
* import { z } from 'zod';
|
|
4049
|
+
* import { formConfig } from '@ng-forge/dynamic-forms';
|
|
4050
|
+
* import { standardSchema } from '@ng-forge/dynamic-forms/schema';
|
|
4051
|
+
*
|
|
4052
|
+
* const passwordSchema = z.object({
|
|
4053
|
+
* password: z.string().min(8),
|
|
4054
|
+
* confirmPassword: z.string(),
|
|
4055
|
+
* }).refine(
|
|
4056
|
+
* (data) => data.password === data.confirmPassword,
|
|
4057
|
+
* { message: 'Passwords must match', path: ['confirmPassword'] }
|
|
4058
|
+
* );
|
|
4059
|
+
*
|
|
4060
|
+
* const config = formConfig({
|
|
4061
|
+
* schema: standardSchema(passwordSchema),
|
|
4062
|
+
* fields: [
|
|
4063
|
+
* { key: 'password', type: 'input', label: 'Password', required: true, props: { type: 'password' } },
|
|
4064
|
+
* { key: 'confirmPassword', type: 'input', label: 'Confirm', required: true, props: { type: 'password' } },
|
|
4065
|
+
* { key: 'submit', type: 'submit', label: 'Register' },
|
|
4066
|
+
* ] as const,
|
|
4067
|
+
* });
|
|
4068
|
+
* ```
|
|
4069
|
+
*
|
|
4070
|
+
* @example Equivalent without helper
|
|
4071
|
+
* ```typescript
|
|
4072
|
+
* const config = {
|
|
4073
|
+
* schema: standardSchema(passwordSchema),
|
|
4074
|
+
* fields: [...],
|
|
4075
|
+
* } as const satisfies FormConfig;
|
|
4076
|
+
* ```
|
|
4077
|
+
*/
|
|
4078
|
+
declare function formConfig<const TFields extends NarrowFields, TProps extends object = Record<string, unknown>>(config: Omit<FormConfig<TFields, InferFormValue$1<TFields>, TProps>, 'schema'> & {
|
|
4079
|
+
schema?: FormSchema<InferFormValue$1<TFields>>;
|
|
4080
|
+
}): FormConfig<TFields, InferFormValue$1<TFields>, TProps>;
|
|
4081
|
+
|
|
4082
|
+
/**
|
|
4083
|
+
* Creates a typed field configuration with helpful error messages for common mistakes.
|
|
4084
|
+
*
|
|
4085
|
+
* This helper function provides early validation and clear error messages
|
|
4086
|
+
* for common configuration pitfalls that would otherwise cause runtime errors.
|
|
4087
|
+
*
|
|
4088
|
+
* @example
|
|
4089
|
+
* ```typescript
|
|
4090
|
+
* // Basic usage
|
|
4091
|
+
* const nameField = createField('input', {
|
|
4092
|
+
* key: 'name',
|
|
4093
|
+
* label: 'Name',
|
|
4094
|
+
* value: ''
|
|
4095
|
+
* });
|
|
4096
|
+
*
|
|
4097
|
+
* // With validation
|
|
4098
|
+
* const emailField = createField('input', {
|
|
4099
|
+
* key: 'email',
|
|
4100
|
+
* label: 'Email',
|
|
4101
|
+
* required: true,
|
|
4102
|
+
* email: true,
|
|
4103
|
+
* props: { type: 'email' }
|
|
4104
|
+
* });
|
|
4105
|
+
*
|
|
4106
|
+
* // Select with options (at field level)
|
|
4107
|
+
* const countryField = createField('select', {
|
|
4108
|
+
* key: 'country',
|
|
4109
|
+
* label: 'Country',
|
|
4110
|
+
* options: [{ label: 'USA', value: 'us' }]
|
|
4111
|
+
* });
|
|
4112
|
+
*
|
|
4113
|
+
* // Slider with minValue/maxValue (at field level)
|
|
4114
|
+
* const ratingField = createField('slider', {
|
|
4115
|
+
* key: 'rating',
|
|
4116
|
+
* label: 'Rating',
|
|
4117
|
+
* minValue: 1,
|
|
4118
|
+
* maxValue: 10,
|
|
4119
|
+
* step: 1,
|
|
4120
|
+
* value: 5
|
|
4121
|
+
* });
|
|
4122
|
+
* ```
|
|
4123
|
+
*
|
|
4124
|
+
* @param type - The field type (e.g., 'input', 'select', 'group')
|
|
4125
|
+
* @param config - The field configuration (excluding the 'type' property)
|
|
4126
|
+
* @returns A properly typed field configuration
|
|
4127
|
+
* @throws DynamicFormError if the configuration contains common mistakes
|
|
4128
|
+
*/
|
|
4129
|
+
declare function createField<T extends AvailableFieldTypes>(type: T, config: Omit<ExtractField<T>, 'type'>): ExtractField<T>;
|
|
4130
|
+
/**
|
|
4131
|
+
* Shorthand alias for createField
|
|
4132
|
+
*
|
|
4133
|
+
* @example
|
|
4134
|
+
* ```typescript
|
|
4135
|
+
* const nameField = field('input', { key: 'name', label: 'Name', value: '' });
|
|
4136
|
+
* ```
|
|
4137
|
+
*/
|
|
4138
|
+
declare const field: typeof createField;
|
|
4139
|
+
|
|
3171
4140
|
/**
|
|
3172
4141
|
* Base error class for all Dynamic Forms errors.
|
|
3173
4142
|
*
|
|
@@ -3476,6 +4445,32 @@ declare function getArrayLength<T>(arrayFieldTree: ArrayFieldTree<T>): number;
|
|
|
3476
4445
|
* Native JavaScript utility functions to replace lodash-es
|
|
3477
4446
|
* These are simple implementations for common object manipulation patterns
|
|
3478
4447
|
*/
|
|
4448
|
+
/**
|
|
4449
|
+
* Performs a deep equality comparison between two values.
|
|
4450
|
+
*
|
|
4451
|
+
* Handles:
|
|
4452
|
+
* - Primitives (including NaN via Object.is)
|
|
4453
|
+
* - Dates (by timestamp)
|
|
4454
|
+
* - Arrays (deep element comparison)
|
|
4455
|
+
* - Plain objects (deep property comparison)
|
|
4456
|
+
* - RegExp (by source and flags)
|
|
4457
|
+
* - Map and Set (by entries)
|
|
4458
|
+
* - Circular references (via WeakMap tracking)
|
|
4459
|
+
*
|
|
4460
|
+
* @param a - First value
|
|
4461
|
+
* @param b - Second value
|
|
4462
|
+
* @returns true if values are deeply equal
|
|
4463
|
+
*
|
|
4464
|
+
* @example
|
|
4465
|
+
* ```typescript
|
|
4466
|
+
* isEqual({ a: 1 }, { a: 1 }); // true
|
|
4467
|
+
* isEqual([1, 2], [1, 2]); // true
|
|
4468
|
+
* isEqual({ a: 1 }, { a: 2 }); // false
|
|
4469
|
+
* isEqual(new Date('2024-01-01'), new Date('2024-01-01')); // true
|
|
4470
|
+
* isEqual(/abc/gi, /abc/gi); // true
|
|
4471
|
+
* ```
|
|
4472
|
+
*/
|
|
4473
|
+
declare function isEqual(a: unknown, b: unknown): boolean;
|
|
3479
4474
|
/**
|
|
3480
4475
|
* Creates a new object without the specified keys
|
|
3481
4476
|
* Native replacement for lodash omit()
|
|
@@ -3598,5 +4593,5 @@ declare class RootFormRegistryService {
|
|
|
3598
4593
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<RootFormRegistryService>;
|
|
3599
4594
|
}
|
|
3600
4595
|
|
|
3601
|
-
export { ARRAY_CONTEXT, AddArrayItemEvent, ArrayFieldComponent, BUILT_IN_FIELDS, ConsoleLogger, DEFAULT_PROPS, DEFAULT_VALIDATION_MESSAGES, DynamicForm, DynamicFormError, DynamicFormLogger, DynamicTextPipe, EventBus, FIELD_REGISTRY, FIELD_SIGNAL_CONTEXT, FORM_OPTIONS, FormClearEvent, FormResetEvent, GroupFieldComponent, NextPageEvent, NoopLogger, PageChangeEvent, PreviousPageEvent, RemoveArrayItemEvent, RootFormRegistryService, RowFieldComponent, SubmitEvent, applyMetaToElement, applyValidator, applyValidators, arrayFieldMapper, baseFieldMapper, buildBaseInputs, dynamicTextToObservable, getArrayLength, groupFieldMapper, interpolateParams, isArrayField, isCheckedField, isContainerField, isDisplayOnlyField, isFormStateCondition, isGroupField, isLeafField, isPageField, isRowField, isValueBearingField, isValueField, omit, pageFieldMapper, provideDynamicForm, resolveNextButtonDisabled, resolveSubmitButtonDisabled, resolveTokens, rowFieldMapper, textFieldMapper, withLoggerConfig };
|
|
4596
|
+
export { ARRAY_CONTEXT, AddArrayItemEvent, ArrayFieldComponent, BUILT_IN_FIELDS, ConsoleLogger, DEFAULT_PROPS, DEFAULT_VALIDATION_MESSAGES, DynamicForm, DynamicFormError, DynamicFormLogger, DynamicTextPipe, EventBus, FIELD_REGISTRY, FIELD_SIGNAL_CONTEXT, FORM_OPTIONS, FormClearEvent, FormResetEvent, GroupFieldComponent, NextPageEvent, NoopLogger, PageChangeEvent, PreviousPageEvent, RemoveArrayItemEvent, RootFormRegistryService, RowFieldComponent, SubmitEvent, applyMetaToElement, applyValidator, applyValidators, arrayFieldMapper, baseFieldMapper, buildBaseInputs, createField, dynamicTextToObservable, field, formConfig, getArrayLength, groupFieldMapper, hasFormValue, interpolateParams, isArrayField, isCheckedField, isContainerField, isDisplayOnlyField, isEqual, isFormStateCondition, isGroupField, isLeafField, isPageField, isRowField, isValueBearingField, isValueField, omit, pageFieldMapper, provideDynamicForm, resolveNextButtonDisabled, resolveSubmitButtonDisabled, resolveTokens, rowFieldMapper, textFieldMapper, withEventFormValue, withLoggerConfig };
|
|
3602
4597
|
export type { ArrayAllowedChildren, ArrayContext, ArrayField, ArrayFieldTree, ArrayItemContext, AsyncCustomValidator, AsyncValidatorConfig, AvailableFieldTypes, BaseCheckedField, BaseValidatorConfig, BaseValueField, BuiltInValidatorConfig, ButtonLogicContext, CheckedFieldComponent, ConditionalExpression, ContainerFieldTypes, CustomFnConfig, CustomValidator, CustomValidatorConfig, DynamicFormFieldRegistry, DynamicText, EvaluationContext, ExtractField, ExtractFieldDefs, ExtractFormValue, FieldComponent, FieldDef, FieldMeta, FieldOption, FieldPathAccess, FieldRegistryContainers, FieldRegistryLeaves, FieldSignalContext, FieldTypeDefinition, FieldWithValidation, FormConfig, FormEvent, FormEventConstructor, FormMode, FormModeDetectionResult, FormOptions, FormStateCondition, GroupAllowedChildren, GroupField, HttpCustomValidator, HttpResourceRequest, HttpValidatorConfig, InferFormValue$1 as InferFormValue, LeafFieldTypes, Logger, LogicConfig, MapperFn, NarrowField, NarrowFields, NextButtonOptions, PageAllowedChildren, PageField, Prettify, RegisteredFieldTypes, RowAllowedChildren, RowField, SchemaApplicationConfig, SchemaDefinition, SubmissionActionResult, SubmissionConfig, SubmitButtonOptions, TextElementType, TextField, TextProps, TokenContext, ValidationError, ValidationMessages, ValidatorConfig, ValueFieldComponent, ValueHandlingMode, ValueType, WithInputSignals };
|