@ng-forge/dynamic-forms 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/fesm2022/ng-forge-dynamic-forms-integration.mjs +18 -52
- 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-WGww2nXx.mjs} +3401 -294
- package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-WGww2nXx.mjs.map +1 -0
- package/fesm2022/{ng-forge-dynamic-forms-page-field.component-Bt6blv9I.mjs → ng-forge-dynamic-forms-page-field.component-CrO9WTDw.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-page-field.component-Bt6blv9I.mjs.map → ng-forge-dynamic-forms-page-field.component-CrO9WTDw.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-BcFx_kOz.mjs} +2 -2
- package/fesm2022/{ng-forge-dynamic-forms-text-field.component-DKCx7Z_U.mjs.map → ng-forge-dynamic-forms-text-field.component-BcFx_kOz.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 +3 -14
- package/types/ng-forge-dynamic-forms-schema.d.ts +178 -0
- package/types/ng-forge-dynamic-forms.d.ts +766 -35
- 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,278 @@ 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
|
+
* @internal
|
|
880
|
+
*/
|
|
881
|
+
interface BaseDerivationLogicConfig {
|
|
882
|
+
/**
|
|
883
|
+
* Logic type identifier for value derivation.
|
|
884
|
+
*/
|
|
885
|
+
type: 'derivation';
|
|
784
886
|
/**
|
|
785
|
-
*
|
|
887
|
+
* Optional name for this derivation for debugging purposes.
|
|
786
888
|
*
|
|
787
|
-
*
|
|
788
|
-
*
|
|
789
|
-
*
|
|
790
|
-
*
|
|
889
|
+
* When provided, this name appears in derivation debug logs,
|
|
890
|
+
* making it easier to identify specific derivations in complex forms.
|
|
891
|
+
*
|
|
892
|
+
* @example
|
|
893
|
+
* ```typescript
|
|
894
|
+
* {
|
|
895
|
+
* type: 'derivation',
|
|
896
|
+
* debugName: 'Calculate line total',
|
|
897
|
+
* targetField: '$.lineTotal',
|
|
898
|
+
* expression: 'formValue.quantity * formValue.unitPrice'
|
|
899
|
+
* }
|
|
900
|
+
* ```
|
|
791
901
|
*/
|
|
792
|
-
|
|
902
|
+
debugName?: string;
|
|
793
903
|
/**
|
|
794
|
-
*
|
|
904
|
+
* The field whose value will be modified.
|
|
905
|
+
*
|
|
906
|
+
* Can be:
|
|
907
|
+
* - Absolute path: 'fieldName' or 'nested.field.path'
|
|
908
|
+
* - Relative path for arrays: '$.siblingField' (same index as source)
|
|
909
|
+
*
|
|
910
|
+
* @example
|
|
911
|
+
* ```typescript
|
|
912
|
+
* targetField: 'phonePrefix' // Absolute path
|
|
913
|
+
* targetField: 'address.country' // Nested path
|
|
914
|
+
* targetField: '$.lineTotal' // Relative path (array sibling)
|
|
915
|
+
* ```
|
|
916
|
+
*/
|
|
917
|
+
targetField: string;
|
|
918
|
+
/**
|
|
919
|
+
* Condition that determines when this derivation applies.
|
|
795
920
|
*
|
|
796
921
|
* Can be:
|
|
797
922
|
* - `boolean`: Static value (always applies or never applies)
|
|
798
923
|
* - `ConditionalExpression`: Expression evaluated against field/form values
|
|
799
|
-
*
|
|
924
|
+
*
|
|
925
|
+
* Defaults to `true` (always apply).
|
|
926
|
+
*
|
|
927
|
+
* Note: FormStateCondition is not supported for derivations.
|
|
800
928
|
*
|
|
801
929
|
* @example
|
|
802
930
|
* ```typescript
|
|
803
|
-
* //
|
|
931
|
+
* // Always compute (default)
|
|
804
932
|
* condition: true
|
|
805
933
|
*
|
|
806
|
-
* //
|
|
934
|
+
* // Conditional derivation
|
|
807
935
|
* condition: {
|
|
808
936
|
* type: 'fieldValue',
|
|
809
|
-
* fieldPath: '
|
|
937
|
+
* fieldPath: 'country',
|
|
810
938
|
* operator: 'equals',
|
|
811
|
-
* value: '
|
|
939
|
+
* value: 'USA'
|
|
812
940
|
* }
|
|
941
|
+
* ```
|
|
942
|
+
*/
|
|
943
|
+
condition?: ConditionalExpression | boolean;
|
|
944
|
+
/**
|
|
945
|
+
* Static value to set on the target field.
|
|
813
946
|
*
|
|
814
|
-
*
|
|
815
|
-
*
|
|
947
|
+
* Use when the derived value is a constant.
|
|
948
|
+
* Mutually exclusive with `expression` and `functionName`.
|
|
949
|
+
*
|
|
950
|
+
* @example
|
|
951
|
+
* ```typescript
|
|
952
|
+
* value: '+1' // String
|
|
953
|
+
* value: 100 // Number
|
|
954
|
+
* value: true // Boolean
|
|
955
|
+
* value: { code: 'US' } // Object
|
|
816
956
|
* ```
|
|
817
957
|
*/
|
|
818
|
-
|
|
958
|
+
value?: unknown;
|
|
959
|
+
/**
|
|
960
|
+
* JavaScript expression to evaluate for the derived value.
|
|
961
|
+
*
|
|
962
|
+
* Has access to `formValue` object containing all form values.
|
|
963
|
+
* Uses the same secure AST-based parser as other expressions.
|
|
964
|
+
* Mutually exclusive with `value` and `functionName`.
|
|
965
|
+
*
|
|
966
|
+
* @example
|
|
967
|
+
* ```typescript
|
|
968
|
+
* expression: 'formValue.quantity * formValue.unitPrice'
|
|
969
|
+
* expression: 'formValue.firstName + " " + formValue.lastName'
|
|
970
|
+
* expression: 'formValue.price * (1 - formValue.discount / 100)'
|
|
971
|
+
* ```
|
|
972
|
+
*/
|
|
973
|
+
expression?: string;
|
|
974
|
+
/**
|
|
975
|
+
* Name of a registered custom derivation function.
|
|
976
|
+
*
|
|
977
|
+
* The function receives the evaluation context and returns the derived value.
|
|
978
|
+
* Register functions in `customFnConfig.derivations`.
|
|
979
|
+
* Mutually exclusive with `value` and `expression`.
|
|
980
|
+
*
|
|
981
|
+
* @example
|
|
982
|
+
* ```typescript
|
|
983
|
+
* functionName: 'getCurrencyForCountry'
|
|
984
|
+
* functionName: 'calculateTax'
|
|
985
|
+
* functionName: 'formatPhoneNumber'
|
|
986
|
+
* ```
|
|
987
|
+
*/
|
|
988
|
+
functionName?: string;
|
|
989
|
+
/**
|
|
990
|
+
* Explicit field dependencies for derivations.
|
|
991
|
+
*
|
|
992
|
+
* When using `functionName`, you can optionally specify which fields
|
|
993
|
+
* the function depends on. This enables more efficient re-evaluation
|
|
994
|
+
* by only triggering when specific dependencies change.
|
|
995
|
+
*
|
|
996
|
+
* If not provided with `functionName`, defaults to all fields ('*').
|
|
997
|
+
* For `expression`, dependencies are automatically extracted from the expression.
|
|
998
|
+
* For `value`, no dependencies are needed (static value).
|
|
999
|
+
*
|
|
1000
|
+
* @example
|
|
1001
|
+
* ```typescript
|
|
1002
|
+
* // Only re-evaluate when country changes
|
|
1003
|
+
* {
|
|
1004
|
+
* type: 'derivation',
|
|
1005
|
+
* targetField: 'currency',
|
|
1006
|
+
* functionName: 'getCurrencyForCountry',
|
|
1007
|
+
* dependsOn: ['country']
|
|
1008
|
+
* }
|
|
1009
|
+
*
|
|
1010
|
+
* // Override automatic detection for complex expressions
|
|
1011
|
+
* {
|
|
1012
|
+
* type: 'derivation',
|
|
1013
|
+
* targetField: 'total',
|
|
1014
|
+
* expression: 'calculateTotal(formValue)',
|
|
1015
|
+
* dependsOn: ['quantity', 'unitPrice', 'discount']
|
|
1016
|
+
* }
|
|
1017
|
+
* ```
|
|
1018
|
+
*/
|
|
1019
|
+
dependsOn?: string[];
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Derivation logic that evaluates immediately on change (default).
|
|
1023
|
+
*
|
|
1024
|
+
* @internal
|
|
1025
|
+
*/
|
|
1026
|
+
interface OnChangeDerivationLogicConfig extends BaseDerivationLogicConfig {
|
|
1027
|
+
/**
|
|
1028
|
+
* Trigger for immediate evaluation.
|
|
1029
|
+
* @default 'onChange'
|
|
1030
|
+
*/
|
|
1031
|
+
trigger?: 'onChange';
|
|
1032
|
+
/** Not allowed for onChange trigger */
|
|
1033
|
+
debounceMs?: never;
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Derivation logic that evaluates after a debounce period.
|
|
1037
|
+
*
|
|
1038
|
+
* Use this for self-transforms (lowercase, trim, format) to avoid
|
|
1039
|
+
* interrupting the user while they're actively typing.
|
|
1040
|
+
*
|
|
1041
|
+
* @internal
|
|
1042
|
+
*/
|
|
1043
|
+
interface DebouncedDerivationLogicConfig extends BaseDerivationLogicConfig {
|
|
1044
|
+
/**
|
|
1045
|
+
* Trigger for debounced evaluation.
|
|
1046
|
+
* Evaluates after the value has stabilized for the debounce duration.
|
|
1047
|
+
*/
|
|
1048
|
+
trigger: 'debounced';
|
|
1049
|
+
/**
|
|
1050
|
+
* Debounce duration in milliseconds.
|
|
1051
|
+
* @default 500
|
|
1052
|
+
*/
|
|
1053
|
+
debounceMs?: number;
|
|
819
1054
|
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Configuration for value derivation logic.
|
|
1057
|
+
*
|
|
1058
|
+
* Enables programmatic value derivation based on conditions.
|
|
1059
|
+
* When the condition is met, the target field's value is set
|
|
1060
|
+
* using a static value, expression, or custom function.
|
|
1061
|
+
*
|
|
1062
|
+
* @example
|
|
1063
|
+
* ```typescript
|
|
1064
|
+
* // Set phone prefix based on country selection
|
|
1065
|
+
* {
|
|
1066
|
+
* type: 'derivation',
|
|
1067
|
+
* targetField: 'phonePrefix',
|
|
1068
|
+
* value: '+1',
|
|
1069
|
+
* condition: {
|
|
1070
|
+
* type: 'fieldValue',
|
|
1071
|
+
* fieldPath: 'country',
|
|
1072
|
+
* operator: 'equals',
|
|
1073
|
+
* value: 'USA'
|
|
1074
|
+
* }
|
|
1075
|
+
* }
|
|
1076
|
+
*
|
|
1077
|
+
* // Compute total from quantity and price
|
|
1078
|
+
* {
|
|
1079
|
+
* type: 'derivation',
|
|
1080
|
+
* targetField: 'total',
|
|
1081
|
+
* expression: 'formValue.quantity * formValue.unitPrice'
|
|
1082
|
+
* }
|
|
1083
|
+
*
|
|
1084
|
+
* // Use custom function for complex logic
|
|
1085
|
+
* {
|
|
1086
|
+
* type: 'derivation',
|
|
1087
|
+
* targetField: 'currency',
|
|
1088
|
+
* functionName: 'getCurrencyForCountry'
|
|
1089
|
+
* }
|
|
1090
|
+
*
|
|
1091
|
+
* // Self-transform with debounced trigger
|
|
1092
|
+
* // (applies after user stops typing)
|
|
1093
|
+
* {
|
|
1094
|
+
* type: 'derivation',
|
|
1095
|
+
* targetField: 'email',
|
|
1096
|
+
* expression: 'formValue.email.toLowerCase()',
|
|
1097
|
+
* trigger: 'debounced',
|
|
1098
|
+
* debounceMs: 500
|
|
1099
|
+
* }
|
|
1100
|
+
*
|
|
1101
|
+
* // Relative path for array items
|
|
1102
|
+
* {
|
|
1103
|
+
* type: 'derivation',
|
|
1104
|
+
* targetField: '$.lineTotal', // Same array index as source field
|
|
1105
|
+
* expression: 'formValue.quantity * formValue.unitPrice'
|
|
1106
|
+
* }
|
|
1107
|
+
* ```
|
|
1108
|
+
*
|
|
1109
|
+
* @public
|
|
1110
|
+
*/
|
|
1111
|
+
type DerivationLogicConfig = OnChangeDerivationLogicConfig | DebouncedDerivationLogicConfig;
|
|
1112
|
+
/**
|
|
1113
|
+
* Union type for all logic configurations.
|
|
1114
|
+
*
|
|
1115
|
+
* - `StateLogicConfig`: For field state changes (hidden, readonly, disabled, required)
|
|
1116
|
+
* - `DerivationLogicConfig`: For value derivation
|
|
1117
|
+
*
|
|
1118
|
+
* @public
|
|
1119
|
+
*/
|
|
1120
|
+
type LogicConfig = StateLogicConfig | DerivationLogicConfig;
|
|
1121
|
+
/**
|
|
1122
|
+
* Log level for derivation debug output.
|
|
1123
|
+
*
|
|
1124
|
+
* - 'none': No debug logging
|
|
1125
|
+
* - 'summary': Log cycle completion with counts (default in dev mode)
|
|
1126
|
+
* - 'verbose': Log individual derivation evaluations with details
|
|
1127
|
+
*
|
|
1128
|
+
* @public
|
|
1129
|
+
*/
|
|
1130
|
+
type DerivationLogLevel = 'none' | 'summary' | 'verbose';
|
|
820
1131
|
/**
|
|
821
1132
|
* Type guard to check if a condition is a FormStateCondition.
|
|
822
1133
|
*
|
|
@@ -825,7 +1136,7 @@ interface LogicConfig {
|
|
|
825
1136
|
*
|
|
826
1137
|
* @public
|
|
827
1138
|
*/
|
|
828
|
-
declare function isFormStateCondition(condition:
|
|
1139
|
+
declare function isFormStateCondition(condition: StateLogicConfig['condition'] | DerivationLogicConfig['condition']): condition is FormStateCondition;
|
|
829
1140
|
|
|
830
1141
|
/**
|
|
831
1142
|
* Text element type for rendering different HTML text elements
|
|
@@ -1024,11 +1335,17 @@ type ProcessField<T, D extends number = 5> = [D] extends [never] ? Record<string
|
|
|
1024
1335
|
[P in K]: Record<string, unknown>;
|
|
1025
1336
|
} : never : T extends {
|
|
1026
1337
|
type: 'text';
|
|
1338
|
+
} ? never : T extends {
|
|
1339
|
+
type: 'submit' | 'button';
|
|
1027
1340
|
} ? never : T extends {
|
|
1028
1341
|
key: infer K;
|
|
1029
1342
|
value: infer V;
|
|
1030
1343
|
} ? K extends string ? {
|
|
1031
1344
|
[P in K]: MaybeOptional<T, InferValueType<T, V>>;
|
|
1345
|
+
} : never : T extends {
|
|
1346
|
+
key: infer K;
|
|
1347
|
+
} ? K extends string ? {
|
|
1348
|
+
[P in K]: MaybeOptional<T, string>;
|
|
1032
1349
|
} : never : never;
|
|
1033
1350
|
/**
|
|
1034
1351
|
* Internal helper with depth tracking
|
|
@@ -1472,7 +1789,13 @@ interface Logger {
|
|
|
1472
1789
|
interface EvaluationContext<TValue = unknown> {
|
|
1473
1790
|
/** Current field value */
|
|
1474
1791
|
fieldValue: TValue;
|
|
1475
|
-
/**
|
|
1792
|
+
/**
|
|
1793
|
+
* Form value for the current evaluation scope.
|
|
1794
|
+
*
|
|
1795
|
+
* For regular (non-array) derivations, this contains the complete form value.
|
|
1796
|
+
* For array item derivations, this is scoped to the current array item.
|
|
1797
|
+
* Use `rootFormValue` to access the complete form when inside an array context.
|
|
1798
|
+
*/
|
|
1476
1799
|
formValue: Record<string, unknown>;
|
|
1477
1800
|
/** Field path for relative references */
|
|
1478
1801
|
fieldPath: string;
|
|
@@ -1480,6 +1803,38 @@ interface EvaluationContext<TValue = unknown> {
|
|
|
1480
1803
|
customFunctions?: Record<string, (context: EvaluationContext) => unknown>;
|
|
1481
1804
|
/** Logger for diagnostic output */
|
|
1482
1805
|
logger: Logger;
|
|
1806
|
+
/**
|
|
1807
|
+
* Root form value when inside an array context.
|
|
1808
|
+
*
|
|
1809
|
+
* This provides access to values outside the current array item.
|
|
1810
|
+
* When a derivation targets an array item field (e.g., `items.$.lineTotal`),
|
|
1811
|
+
* `formValue` is scoped to the current array item, while `rootFormValue`
|
|
1812
|
+
* provides access to the entire form value including fields outside the array.
|
|
1813
|
+
*
|
|
1814
|
+
* @example
|
|
1815
|
+
* ```typescript
|
|
1816
|
+
* // In an array item derivation (e.g., lineItems.$.lineTotal):
|
|
1817
|
+
* {
|
|
1818
|
+
* type: 'derivation',
|
|
1819
|
+
* targetField: '$.lineTotal',
|
|
1820
|
+
* // formValue = current array item { quantity: 2, unitPrice: 50 }
|
|
1821
|
+
* // rootFormValue = entire form { globalDiscount: 0.1, lineItems: [...] }
|
|
1822
|
+
* expression: 'formValue.quantity * formValue.unitPrice * (1 - rootFormValue.globalDiscount)'
|
|
1823
|
+
* }
|
|
1824
|
+
* ```
|
|
1825
|
+
*
|
|
1826
|
+
* For non-array derivations, `rootFormValue` is not set and `formValue`
|
|
1827
|
+
* contains the entire form value.
|
|
1828
|
+
*/
|
|
1829
|
+
rootFormValue?: Record<string, unknown>;
|
|
1830
|
+
/**
|
|
1831
|
+
* Current array index when inside an array derivation.
|
|
1832
|
+
*/
|
|
1833
|
+
arrayIndex?: number;
|
|
1834
|
+
/**
|
|
1835
|
+
* Path to the array field when inside an array derivation.
|
|
1836
|
+
*/
|
|
1837
|
+
arrayPath?: string;
|
|
1483
1838
|
/** Allow additional properties for flexible expression evaluation */
|
|
1484
1839
|
[key: string]: unknown;
|
|
1485
1840
|
}
|
|
@@ -1697,7 +2052,7 @@ interface SubmissionConfig<TValue = unknown> {
|
|
|
1697
2052
|
*
|
|
1698
2053
|
* @public
|
|
1699
2054
|
*/
|
|
1700
|
-
interface FormConfig<TFields extends NarrowFields | RegisteredFieldTypes[] = RegisteredFieldTypes[], TValue = InferFormValue$1<TFields extends readonly RegisteredFieldTypes[] ? TFields : RegisteredFieldTypes[]>, TProps extends object = Record<string, unknown
|
|
2055
|
+
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
2056
|
/**
|
|
1702
2057
|
* Array of field definitions that define the form structure.
|
|
1703
2058
|
*
|
|
@@ -1716,19 +2071,32 @@ interface FormConfig<TFields extends NarrowFields | RegisteredFieldTypes[] = Reg
|
|
|
1716
2071
|
*/
|
|
1717
2072
|
fields: TFields;
|
|
1718
2073
|
/**
|
|
1719
|
-
* Optional form-level validation schema.
|
|
2074
|
+
* Optional form-level validation schema using Standard Schema spec.
|
|
1720
2075
|
*
|
|
1721
2076
|
* Provides additional validation beyond field-level validation.
|
|
2077
|
+
* Supports Zod, Valibot, ArkType, and other Standard Schema compliant libraries.
|
|
1722
2078
|
* Useful for cross-field validation rules.
|
|
1723
2079
|
*
|
|
1724
2080
|
* @example
|
|
1725
2081
|
* ```typescript
|
|
1726
|
-
*
|
|
1727
|
-
*
|
|
1728
|
-
*
|
|
2082
|
+
* import { z } from 'zod';
|
|
2083
|
+
* import { standardSchema } from '@ng-forge/dynamic-forms/schema';
|
|
2084
|
+
*
|
|
2085
|
+
* const PasswordSchema = z.object({
|
|
2086
|
+
* password: z.string().min(8),
|
|
2087
|
+
* confirmPassword: z.string(),
|
|
2088
|
+
* }).refine(
|
|
2089
|
+
* (data) => data.password === data.confirmPassword,
|
|
2090
|
+
* { message: 'Passwords must match', path: ['confirmPassword'] }
|
|
2091
|
+
* );
|
|
2092
|
+
*
|
|
2093
|
+
* const formConfig = {
|
|
2094
|
+
* fields: [...],
|
|
2095
|
+
* schema: standardSchema(PasswordSchema),
|
|
2096
|
+
* } as const satisfies FormConfig;
|
|
1729
2097
|
* ```
|
|
1730
2098
|
*/
|
|
1731
|
-
schema?:
|
|
2099
|
+
schema?: FormSchema<TSchemaValue>;
|
|
1732
2100
|
/**
|
|
1733
2101
|
* Global form configuration options.
|
|
1734
2102
|
*
|
|
@@ -1851,6 +2219,14 @@ interface FormConfig<TFields extends NarrowFields | RegisteredFieldTypes[] = Reg
|
|
|
1851
2219
|
* currency: 'USD'
|
|
1852
2220
|
* }).format(context.value)
|
|
1853
2221
|
* },
|
|
2222
|
+
* derivations: {
|
|
2223
|
+
* getCurrencyForCountry: (context) => {
|
|
2224
|
+
* const countryToCurrency: Record<string, string> = {
|
|
2225
|
+
* 'USA': 'USD', 'Germany': 'EUR', 'UK': 'GBP'
|
|
2226
|
+
* };
|
|
2227
|
+
* return countryToCurrency[context.formValue.country as string] ?? 'USD';
|
|
2228
|
+
* }
|
|
2229
|
+
* },
|
|
1854
2230
|
* simpleValidators: {
|
|
1855
2231
|
* noSpaces: (value) => {
|
|
1856
2232
|
* return typeof value === 'string' && value.includes(' ')
|
|
@@ -1893,6 +2269,73 @@ interface CustomFnConfig {
|
|
|
1893
2269
|
* ```
|
|
1894
2270
|
*/
|
|
1895
2271
|
customFunctions?: Record<string, CustomFunction>;
|
|
2272
|
+
/**
|
|
2273
|
+
* Custom derivation functions for value derivation logic.
|
|
2274
|
+
*
|
|
2275
|
+
* These functions compute derived values and are called when a
|
|
2276
|
+
* `DerivationLogicConfig` references them by `functionName`.
|
|
2277
|
+
*
|
|
2278
|
+
* Derivation functions:
|
|
2279
|
+
* - Receive an `EvaluationContext` with access to `formValue`
|
|
2280
|
+
* - Return the value to set on the target field
|
|
2281
|
+
* - Are called reactively when dependencies change
|
|
2282
|
+
*
|
|
2283
|
+
* Use derivation functions for complex mappings or logic that
|
|
2284
|
+
* can't be easily expressed as a JavaScript expression.
|
|
2285
|
+
*
|
|
2286
|
+
* @example
|
|
2287
|
+
* ```typescript
|
|
2288
|
+
* derivations: {
|
|
2289
|
+
* // Country to currency mapping
|
|
2290
|
+
* getCurrencyForCountry: (context) => {
|
|
2291
|
+
* const countryToCurrency: Record<string, string> = {
|
|
2292
|
+
* 'USA': 'USD',
|
|
2293
|
+
* 'Germany': 'EUR',
|
|
2294
|
+
* 'France': 'EUR',
|
|
2295
|
+
* 'UK': 'GBP',
|
|
2296
|
+
* 'Japan': 'JPY'
|
|
2297
|
+
* };
|
|
2298
|
+
* return countryToCurrency[context.formValue.country as string] ?? 'USD';
|
|
2299
|
+
* },
|
|
2300
|
+
*
|
|
2301
|
+
* // Complex tax calculation
|
|
2302
|
+
* calculateTax: (context) => {
|
|
2303
|
+
* const subtotal = context.formValue.subtotal as number ?? 0;
|
|
2304
|
+
* const state = context.formValue.state as string;
|
|
2305
|
+
* const taxRates: Record<string, number> = {
|
|
2306
|
+
* 'CA': 0.0725, 'NY': 0.08, 'TX': 0.0625
|
|
2307
|
+
* };
|
|
2308
|
+
* return subtotal * (taxRates[state] ?? 0);
|
|
2309
|
+
* },
|
|
2310
|
+
*
|
|
2311
|
+
* // Format phone number
|
|
2312
|
+
* formatPhoneNumber: (context) => {
|
|
2313
|
+
* const phone = context.fieldValue as string ?? '';
|
|
2314
|
+
* const digits = phone.replace(/\D/g, '');
|
|
2315
|
+
* if (digits.length === 10) {
|
|
2316
|
+
* return `(${digits.slice(0,3)}) ${digits.slice(3,6)}-${digits.slice(6)}`;
|
|
2317
|
+
* }
|
|
2318
|
+
* return phone;
|
|
2319
|
+
* }
|
|
2320
|
+
* }
|
|
2321
|
+
* ```
|
|
2322
|
+
*
|
|
2323
|
+
* Field configuration using a derivation function:
|
|
2324
|
+
* ```typescript
|
|
2325
|
+
* {
|
|
2326
|
+
* key: 'country',
|
|
2327
|
+
* type: 'select',
|
|
2328
|
+
* logic: [
|
|
2329
|
+
* {
|
|
2330
|
+
* type: 'derivation',
|
|
2331
|
+
* targetField: 'currency',
|
|
2332
|
+
* functionName: 'getCurrencyForCountry'
|
|
2333
|
+
* }
|
|
2334
|
+
* ]
|
|
2335
|
+
* }
|
|
2336
|
+
* ```
|
|
2337
|
+
*/
|
|
2338
|
+
derivations?: Record<string, CustomFunction>;
|
|
1896
2339
|
/**
|
|
1897
2340
|
* Custom validators using Angular's public FieldContext API
|
|
1898
2341
|
*
|
|
@@ -2104,6 +2547,19 @@ interface FormOptions {
|
|
|
2104
2547
|
* @value false
|
|
2105
2548
|
*/
|
|
2106
2549
|
disabled?: boolean;
|
|
2550
|
+
/**
|
|
2551
|
+
* Maximum number of iterations for derivation chain processing.
|
|
2552
|
+
*
|
|
2553
|
+
* Derivations can trigger other derivations (e.g., A → B → C).
|
|
2554
|
+
* This limit prevents infinite loops in case of circular dependencies
|
|
2555
|
+
* that weren't caught at build time.
|
|
2556
|
+
*
|
|
2557
|
+
* Increase this value if you have legitimate deep derivation chains
|
|
2558
|
+
* (more than 10 levels deep).
|
|
2559
|
+
*
|
|
2560
|
+
* @default 10
|
|
2561
|
+
*/
|
|
2562
|
+
maxDerivationIterations?: number;
|
|
2107
2563
|
/**
|
|
2108
2564
|
* Default disabled behavior for submit buttons.
|
|
2109
2565
|
*
|
|
@@ -2238,6 +2694,109 @@ type FieldPathAccess<TValue> = {
|
|
|
2238
2694
|
[K in keyof TValue]: SchemaPath<TValue[K]> | SchemaPathTree<TValue[K]>;
|
|
2239
2695
|
};
|
|
2240
2696
|
|
|
2697
|
+
/**
|
|
2698
|
+
* Result of processing all pending derivations.
|
|
2699
|
+
*
|
|
2700
|
+
* @public
|
|
2701
|
+
*/
|
|
2702
|
+
interface DerivationProcessingResult {
|
|
2703
|
+
/** Number of derivations successfully applied */
|
|
2704
|
+
appliedCount: number;
|
|
2705
|
+
/** Number of derivations skipped (condition not met or value unchanged) */
|
|
2706
|
+
skippedCount: number;
|
|
2707
|
+
/** Number of derivations that failed with errors */
|
|
2708
|
+
errorCount: number;
|
|
2709
|
+
/**
|
|
2710
|
+
* Number of derivations that encountered warnings (e.g., missing target field).
|
|
2711
|
+
*
|
|
2712
|
+
* These are not counted as errors because they may be intentional (conditional fields)
|
|
2713
|
+
* but indicate potential configuration issues if unexpected.
|
|
2714
|
+
*/
|
|
2715
|
+
warnCount: number;
|
|
2716
|
+
/** Total iterations performed */
|
|
2717
|
+
iterations: number;
|
|
2718
|
+
/** Whether max iterations was reached (potential loop) */
|
|
2719
|
+
maxIterationsReached: boolean;
|
|
2720
|
+
}
|
|
2721
|
+
|
|
2722
|
+
/**
|
|
2723
|
+
* Information about a single derivation evaluation for logging.
|
|
2724
|
+
*
|
|
2725
|
+
* @public
|
|
2726
|
+
*/
|
|
2727
|
+
interface DerivationLogEntry {
|
|
2728
|
+
/** Debug name if provided in the derivation config */
|
|
2729
|
+
debugName?: string;
|
|
2730
|
+
/** Source field key where the derivation is defined */
|
|
2731
|
+
sourceFieldKey: string;
|
|
2732
|
+
/** Target field key that will be modified */
|
|
2733
|
+
targetFieldKey: string;
|
|
2734
|
+
/** Result of the derivation evaluation */
|
|
2735
|
+
result: 'applied' | 'skipped' | 'error';
|
|
2736
|
+
/** Reason for skipping (if result is 'skipped') */
|
|
2737
|
+
skipReason?: 'condition-false' | 'value-unchanged' | 'already-applied' | 'target-not-found';
|
|
2738
|
+
/** The new value that was set (if result is 'applied') */
|
|
2739
|
+
newValue?: unknown;
|
|
2740
|
+
/** The previous value before the derivation (if result is 'applied') */
|
|
2741
|
+
previousValue?: unknown;
|
|
2742
|
+
/** Error message (if result is 'error') */
|
|
2743
|
+
error?: string;
|
|
2744
|
+
/** Duration in milliseconds (optional, for performance tracking) */
|
|
2745
|
+
durationMs?: number;
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
/**
|
|
2749
|
+
* Service interface for derivation logging.
|
|
2750
|
+
*
|
|
2751
|
+
* Provides methods to log derivation processing events at different verbosity levels.
|
|
2752
|
+
* Use `DERIVATION_LOGGER` injection token to get an instance.
|
|
2753
|
+
*
|
|
2754
|
+
* @public
|
|
2755
|
+
*/
|
|
2756
|
+
interface DerivationLogger {
|
|
2757
|
+
/**
|
|
2758
|
+
* Logs the start of a derivation processing cycle.
|
|
2759
|
+
* Only logs when config level is 'verbose'.
|
|
2760
|
+
*/
|
|
2761
|
+
cycleStart(trigger: 'onChange' | 'debounced', entryCount: number): void;
|
|
2762
|
+
/**
|
|
2763
|
+
* Logs the start of a derivation iteration within a cycle.
|
|
2764
|
+
* Only logs when config level is 'verbose'.
|
|
2765
|
+
*/
|
|
2766
|
+
iteration(iterationNumber: number): void;
|
|
2767
|
+
/**
|
|
2768
|
+
* Logs a single derivation evaluation result.
|
|
2769
|
+
* Only logs when config level is 'verbose'.
|
|
2770
|
+
*/
|
|
2771
|
+
evaluation(entry: DerivationLogEntry): void;
|
|
2772
|
+
/**
|
|
2773
|
+
* Logs a summary of derivation processing results.
|
|
2774
|
+
* Logs when config level is 'summary' or 'verbose' and something interesting happened.
|
|
2775
|
+
*/
|
|
2776
|
+
summary(result: DerivationProcessingResult, trigger: 'onChange' | 'debounced'): void;
|
|
2777
|
+
/**
|
|
2778
|
+
* Logs when max iterations are reached (always logged as warning).
|
|
2779
|
+
*/
|
|
2780
|
+
maxIterationsReached(result: DerivationProcessingResult, trigger: 'onChange' | 'debounced'): void;
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
/**
|
|
2784
|
+
* Minimal configuration for creating a DerivationOrchestrator.
|
|
2785
|
+
* Only includes form-specific signals that cannot be injected.
|
|
2786
|
+
*
|
|
2787
|
+
* @internal
|
|
2788
|
+
*/
|
|
2789
|
+
interface DerivationOrchestratorConfig {
|
|
2790
|
+
/** Signal containing the flattened schema fields */
|
|
2791
|
+
schemaFields: Signal<FieldDef<unknown>[] | undefined>;
|
|
2792
|
+
/** Signal containing the current form value */
|
|
2793
|
+
formValue: Signal<Record<string, unknown>>;
|
|
2794
|
+
/** Signal containing the form accessor */
|
|
2795
|
+
form: Signal<FieldTree<unknown>>;
|
|
2796
|
+
/** Signal containing the derivation logger */
|
|
2797
|
+
derivationLogger: Signal<DerivationLogger>;
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2241
2800
|
/**
|
|
2242
2801
|
* Base interface for all form events in the dynamic form system.
|
|
2243
2802
|
*
|
|
@@ -2397,6 +2956,7 @@ declare class DynamicForm<TFields extends RegisteredFieldTypes[] = RegisteredFie
|
|
|
2397
2956
|
private readonly functionRegistry;
|
|
2398
2957
|
private readonly schemaRegistry;
|
|
2399
2958
|
private readonly logger;
|
|
2959
|
+
private readonly derivationLogConfig;
|
|
2400
2960
|
/** Form configuration defining the structure, validation, and behavior. */
|
|
2401
2961
|
config: InputSignal<FormConfig<TFields>>;
|
|
2402
2962
|
/** Runtime form options that override config options when provided. */
|
|
@@ -2413,9 +2973,17 @@ declare class DynamicForm<TFields extends RegisteredFieldTypes[] = RegisteredFie
|
|
|
2413
2973
|
readonly pageFieldDefinitions: Signal<PageField<_ng_forge_dynamic_forms.PageAllowedChildren[]>[]>;
|
|
2414
2974
|
readonly effectiveFormOptions: Signal<{
|
|
2415
2975
|
disabled?: boolean;
|
|
2976
|
+
maxDerivationIterations?: number;
|
|
2416
2977
|
submitButton?: _ng_forge_dynamic_forms.SubmitButtonOptions;
|
|
2417
2978
|
nextButton?: _ng_forge_dynamic_forms.NextButtonOptions;
|
|
2418
2979
|
}>;
|
|
2980
|
+
/**
|
|
2981
|
+
* Computed derivation logger based on injected config.
|
|
2982
|
+
*
|
|
2983
|
+
* Uses factory pattern to return no-op logger when logging is disabled,
|
|
2984
|
+
* avoiding any logging overhead in production.
|
|
2985
|
+
*/
|
|
2986
|
+
private readonly derivationLogger;
|
|
2419
2987
|
readonly fieldSignalContext: Signal<FieldSignalContext<TModel>>;
|
|
2420
2988
|
/**
|
|
2421
2989
|
* Injector for field components with FIELD_SIGNAL_CONTEXT.
|
|
@@ -2424,7 +2992,7 @@ declare class DynamicForm<TFields extends RegisteredFieldTypes[] = RegisteredFie
|
|
|
2424
2992
|
private readonly fieldInjector;
|
|
2425
2993
|
readonly defaultValues: _angular_core.WritableSignal<TModel>;
|
|
2426
2994
|
private readonly entity;
|
|
2427
|
-
readonly form: Signal<
|
|
2995
|
+
readonly form: Signal<FieldTree<TModel, string | number>>;
|
|
2428
2996
|
private readonly componentId;
|
|
2429
2997
|
private readonly totalComponentsCount;
|
|
2430
2998
|
private readonly fieldsSource;
|
|
@@ -2450,6 +3018,13 @@ declare class DynamicForm<TFields extends RegisteredFieldTypes[] = RegisteredFie
|
|
|
2450
3018
|
readonly disabled: Signal<boolean>;
|
|
2451
3019
|
/** Whether the form is currently submitting. */
|
|
2452
3020
|
readonly submitting: Signal<boolean>;
|
|
3021
|
+
/**
|
|
3022
|
+
* Configuration for the derivation orchestrator.
|
|
3023
|
+
* Bundles the form-specific signals needed by the orchestrator.
|
|
3024
|
+
*
|
|
3025
|
+
* @internal Used by DERIVATION_ORCHESTRATOR provider.
|
|
3026
|
+
*/
|
|
3027
|
+
readonly derivationOrchestratorConfig: DerivationOrchestratorConfig;
|
|
2453
3028
|
readonly initialized$: rxjs.Observable<boolean>;
|
|
2454
3029
|
/** Emits when form validity changes. */
|
|
2455
3030
|
readonly validityChange: _angular_core.OutputRef<boolean>;
|
|
@@ -2650,20 +3225,55 @@ type ExtractFormValue<T> = T extends {
|
|
|
2650
3225
|
*/
|
|
2651
3226
|
declare const BUILT_IN_FIELDS: FieldTypeDefinition[];
|
|
2652
3227
|
|
|
3228
|
+
/**
|
|
3229
|
+
* Configuration options for the logger feature.
|
|
3230
|
+
*
|
|
3231
|
+
* @public
|
|
3232
|
+
*/
|
|
3233
|
+
interface LoggerConfigOptions {
|
|
3234
|
+
/**
|
|
3235
|
+
* Whether general logging is enabled.
|
|
3236
|
+
*
|
|
3237
|
+
* @default true
|
|
3238
|
+
*/
|
|
3239
|
+
enabled?: boolean;
|
|
3240
|
+
/**
|
|
3241
|
+
* Derivation logging level.
|
|
3242
|
+
*
|
|
3243
|
+
* - `'none'`: No derivation debug logging (default)
|
|
3244
|
+
* - `'summary'`: Log cycle completion with counts
|
|
3245
|
+
* - `'verbose'`: Log individual derivation evaluations with details
|
|
3246
|
+
*
|
|
3247
|
+
* @default 'none'
|
|
3248
|
+
*/
|
|
3249
|
+
derivations?: DerivationLogLevel;
|
|
3250
|
+
}
|
|
2653
3251
|
/**
|
|
2654
3252
|
* Configure logging for dynamic forms.
|
|
2655
3253
|
*
|
|
2656
|
-
* By default, logging is enabled (ConsoleLogger)
|
|
2657
|
-
*
|
|
3254
|
+
* By default, general logging is enabled (ConsoleLogger) and derivation
|
|
3255
|
+
* logging is disabled ('none'). Use this feature to enable derivation debugging.
|
|
2658
3256
|
*
|
|
2659
3257
|
* @example
|
|
2660
3258
|
* ```typescript
|
|
2661
|
-
* // Disable logging
|
|
3259
|
+
* // Disable all logging
|
|
2662
3260
|
* provideDynamicForm(
|
|
2663
3261
|
* ...withMaterialFields(),
|
|
2664
3262
|
* withLoggerConfig(false)
|
|
2665
3263
|
* )
|
|
2666
3264
|
*
|
|
3265
|
+
* // Enable verbose derivation logging
|
|
3266
|
+
* provideDynamicForm(
|
|
3267
|
+
* ...withMaterialFields(),
|
|
3268
|
+
* withLoggerConfig({ derivations: 'verbose' })
|
|
3269
|
+
* )
|
|
3270
|
+
*
|
|
3271
|
+
* // Disable derivation logging but keep general logging
|
|
3272
|
+
* provideDynamicForm(
|
|
3273
|
+
* ...withMaterialFields(),
|
|
3274
|
+
* withLoggerConfig({ derivations: 'none' })
|
|
3275
|
+
* )
|
|
3276
|
+
*
|
|
2667
3277
|
* // Conditional logging (e.g., only in dev mode)
|
|
2668
3278
|
* provideDynamicForm(
|
|
2669
3279
|
* ...withMaterialFields(),
|
|
@@ -2671,10 +3281,12 @@ declare const BUILT_IN_FIELDS: FieldTypeDefinition[];
|
|
|
2671
3281
|
* )
|
|
2672
3282
|
* ```
|
|
2673
3283
|
*
|
|
2674
|
-
* @param
|
|
3284
|
+
* @param config - Boolean to enable/disable logging, a function returning boolean, or a config object
|
|
2675
3285
|
* @returns A DynamicFormFeature that configures logging
|
|
3286
|
+
*
|
|
3287
|
+
* @public
|
|
2676
3288
|
*/
|
|
2677
|
-
declare function withLoggerConfig(
|
|
3289
|
+
declare function withLoggerConfig(config?: boolean | (() => boolean) | LoggerConfigOptions): DynamicFormFeature<'logger'>;
|
|
2678
3290
|
|
|
2679
3291
|
/**
|
|
2680
3292
|
* Injection token for the dynamic forms logger.
|
|
@@ -2925,6 +3537,43 @@ interface FieldWithValidation {
|
|
|
2925
3537
|
readonly validators?: ValidatorConfig[];
|
|
2926
3538
|
readonly validationMessages?: ValidationMessages;
|
|
2927
3539
|
readonly logic?: LogicConfig[];
|
|
3540
|
+
/**
|
|
3541
|
+
* Shorthand for simple computed/derived fields.
|
|
3542
|
+
*
|
|
3543
|
+
* The expression is evaluated whenever its dependencies change,
|
|
3544
|
+
* and the result is set as this field's value.
|
|
3545
|
+
*
|
|
3546
|
+
* Has access to `formValue` object containing all form values.
|
|
3547
|
+
* Uses the same secure AST-based parser as other expressions.
|
|
3548
|
+
*
|
|
3549
|
+
* For conditional derivations or derivations targeting other fields,
|
|
3550
|
+
* use the full `logic` array with `{ type: 'derivation', ... }`.
|
|
3551
|
+
*
|
|
3552
|
+
* @example
|
|
3553
|
+
* ```typescript
|
|
3554
|
+
* // Compute total from quantity and price
|
|
3555
|
+
* {
|
|
3556
|
+
* key: 'total',
|
|
3557
|
+
* type: 'number',
|
|
3558
|
+
* derivation: 'formValue.quantity * formValue.unitPrice'
|
|
3559
|
+
* }
|
|
3560
|
+
*
|
|
3561
|
+
* // Concatenate names
|
|
3562
|
+
* {
|
|
3563
|
+
* key: 'fullName',
|
|
3564
|
+
* type: 'input',
|
|
3565
|
+
* derivation: 'formValue.firstName + " " + formValue.lastName'
|
|
3566
|
+
* }
|
|
3567
|
+
*
|
|
3568
|
+
* // Calculate discounted price
|
|
3569
|
+
* {
|
|
3570
|
+
* key: 'discountedPrice',
|
|
3571
|
+
* type: 'number',
|
|
3572
|
+
* derivation: 'formValue.price * (1 - formValue.discountPercent / 100)'
|
|
3573
|
+
* }
|
|
3574
|
+
* ```
|
|
3575
|
+
*/
|
|
3576
|
+
readonly derivation?: string;
|
|
2928
3577
|
readonly schemas?: SchemaApplicationConfig[];
|
|
2929
3578
|
}
|
|
2930
3579
|
|
|
@@ -2943,7 +3592,7 @@ interface BaseValueField<TProps, TValue, TMeta extends FieldMeta = FieldMeta> ex
|
|
|
2943
3592
|
required?: boolean;
|
|
2944
3593
|
}
|
|
2945
3594
|
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';
|
|
3595
|
+
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
3596
|
type ValueFieldComponent<T extends BaseValueField<Record<string, unknown> | unknown, unknown>> = Prettify<WithInputSignals<Omit<T, ExcludedKeys$1>>>;
|
|
2948
3597
|
|
|
2949
3598
|
interface BaseCheckedField<TProps, TMeta extends FieldMeta = FieldMeta> extends FieldDef<TProps, TMeta>, FieldWithValidation {
|
|
@@ -3168,6 +3817,62 @@ interface ArrayItemContext {
|
|
|
3168
3817
|
formValue?: unknown;
|
|
3169
3818
|
}
|
|
3170
3819
|
|
|
3820
|
+
/**
|
|
3821
|
+
* Type-safe form config builder that ensures schema matches field structure.
|
|
3822
|
+
*
|
|
3823
|
+
* This helper function provides type safety when using form-level schemas by
|
|
3824
|
+
* automatically inferring the form value type from fields and constraining
|
|
3825
|
+
* the schema type parameter accordingly.
|
|
3826
|
+
*
|
|
3827
|
+
* **When to use:**
|
|
3828
|
+
* - When you have a form-level `schema` and want type safety between fields and schema
|
|
3829
|
+
* - When you prefer function syntax over `as const satisfies FormConfig`
|
|
3830
|
+
*
|
|
3831
|
+
* **Note:** This is optional. Users who don't need schema type safety can
|
|
3832
|
+
* continue using `as const satisfies FormConfig` directly.
|
|
3833
|
+
*
|
|
3834
|
+
* @typeParam TFields - The field definitions array (narrowed via `as const`)
|
|
3835
|
+
* @typeParam TProps - Optional form-level default props type
|
|
3836
|
+
*
|
|
3837
|
+
* @param config - The form configuration object
|
|
3838
|
+
* @returns The same configuration with proper type inference
|
|
3839
|
+
*
|
|
3840
|
+
* @example Basic usage with Zod schema
|
|
3841
|
+
* ```typescript
|
|
3842
|
+
* import { z } from 'zod';
|
|
3843
|
+
* import { formConfig } from '@ng-forge/dynamic-forms';
|
|
3844
|
+
* import { standardSchema } from '@ng-forge/dynamic-forms/schema';
|
|
3845
|
+
*
|
|
3846
|
+
* const passwordSchema = z.object({
|
|
3847
|
+
* password: z.string().min(8),
|
|
3848
|
+
* confirmPassword: z.string(),
|
|
3849
|
+
* }).refine(
|
|
3850
|
+
* (data) => data.password === data.confirmPassword,
|
|
3851
|
+
* { message: 'Passwords must match', path: ['confirmPassword'] }
|
|
3852
|
+
* );
|
|
3853
|
+
*
|
|
3854
|
+
* const config = formConfig({
|
|
3855
|
+
* schema: standardSchema(passwordSchema),
|
|
3856
|
+
* fields: [
|
|
3857
|
+
* { key: 'password', type: 'input', label: 'Password', required: true, props: { type: 'password' } },
|
|
3858
|
+
* { key: 'confirmPassword', type: 'input', label: 'Confirm', required: true, props: { type: 'password' } },
|
|
3859
|
+
* { key: 'submit', type: 'submit', label: 'Register' },
|
|
3860
|
+
* ] as const,
|
|
3861
|
+
* });
|
|
3862
|
+
* ```
|
|
3863
|
+
*
|
|
3864
|
+
* @example Equivalent without helper
|
|
3865
|
+
* ```typescript
|
|
3866
|
+
* const config = {
|
|
3867
|
+
* schema: standardSchema(passwordSchema),
|
|
3868
|
+
* fields: [...],
|
|
3869
|
+
* } as const satisfies FormConfig;
|
|
3870
|
+
* ```
|
|
3871
|
+
*/
|
|
3872
|
+
declare function formConfig<const TFields extends NarrowFields, TProps extends object = Record<string, unknown>>(config: Omit<FormConfig<TFields, InferFormValue$1<TFields>, TProps>, 'schema'> & {
|
|
3873
|
+
schema?: FormSchema<InferFormValue$1<TFields>>;
|
|
3874
|
+
}): FormConfig<TFields, InferFormValue$1<TFields>, TProps>;
|
|
3875
|
+
|
|
3171
3876
|
/**
|
|
3172
3877
|
* Base error class for all Dynamic Forms errors.
|
|
3173
3878
|
*
|
|
@@ -3476,6 +4181,32 @@ declare function getArrayLength<T>(arrayFieldTree: ArrayFieldTree<T>): number;
|
|
|
3476
4181
|
* Native JavaScript utility functions to replace lodash-es
|
|
3477
4182
|
* These are simple implementations for common object manipulation patterns
|
|
3478
4183
|
*/
|
|
4184
|
+
/**
|
|
4185
|
+
* Performs a deep equality comparison between two values.
|
|
4186
|
+
*
|
|
4187
|
+
* Handles:
|
|
4188
|
+
* - Primitives (including NaN via Object.is)
|
|
4189
|
+
* - Dates (by timestamp)
|
|
4190
|
+
* - Arrays (deep element comparison)
|
|
4191
|
+
* - Plain objects (deep property comparison)
|
|
4192
|
+
* - RegExp (by source and flags)
|
|
4193
|
+
* - Map and Set (by entries)
|
|
4194
|
+
* - Circular references (via WeakMap tracking)
|
|
4195
|
+
*
|
|
4196
|
+
* @param a - First value
|
|
4197
|
+
* @param b - Second value
|
|
4198
|
+
* @returns true if values are deeply equal
|
|
4199
|
+
*
|
|
4200
|
+
* @example
|
|
4201
|
+
* ```typescript
|
|
4202
|
+
* isEqual({ a: 1 }, { a: 1 }); // true
|
|
4203
|
+
* isEqual([1, 2], [1, 2]); // true
|
|
4204
|
+
* isEqual({ a: 1 }, { a: 2 }); // false
|
|
4205
|
+
* isEqual(new Date('2024-01-01'), new Date('2024-01-01')); // true
|
|
4206
|
+
* isEqual(/abc/gi, /abc/gi); // true
|
|
4207
|
+
* ```
|
|
4208
|
+
*/
|
|
4209
|
+
declare function isEqual(a: unknown, b: unknown): boolean;
|
|
3479
4210
|
/**
|
|
3480
4211
|
* Creates a new object without the specified keys
|
|
3481
4212
|
* Native replacement for lodash omit()
|
|
@@ -3598,5 +4329,5 @@ declare class RootFormRegistryService {
|
|
|
3598
4329
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<RootFormRegistryService>;
|
|
3599
4330
|
}
|
|
3600
4331
|
|
|
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 };
|
|
4332
|
+
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, formConfig, getArrayLength, groupFieldMapper, interpolateParams, isArrayField, isCheckedField, isContainerField, isDisplayOnlyField, isEqual, isFormStateCondition, isGroupField, isLeafField, isPageField, isRowField, isValueBearingField, isValueField, omit, pageFieldMapper, provideDynamicForm, resolveNextButtonDisabled, resolveSubmitButtonDisabled, resolveTokens, rowFieldMapper, textFieldMapper, withLoggerConfig };
|
|
3602
4333
|
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 };
|