@ng-forge/dynamic-forms 0.5.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.
@@ -876,6 +876,10 @@ type StateLogicConfig = ImmediateStateLogicConfig | DebouncedStateLogicConfig;
876
876
  /**
877
877
  * Base configuration for value derivation logic.
878
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
+ *
879
883
  * @internal
880
884
  */
881
885
  interface BaseDerivationLogicConfig {
@@ -892,29 +896,17 @@ interface BaseDerivationLogicConfig {
892
896
  * @example
893
897
  * ```typescript
894
898
  * {
895
- * type: 'derivation',
896
- * debugName: 'Calculate line total',
897
- * targetField: '$.lineTotal',
898
- * expression: 'formValue.quantity * formValue.unitPrice'
899
+ * key: 'lineTotal',
900
+ * type: 'input',
901
+ * logic: [{
902
+ * type: 'derivation',
903
+ * debugName: 'Calculate line total',
904
+ * expression: 'formValue.quantity * formValue.unitPrice'
905
+ * }]
899
906
  * }
900
907
  * ```
901
908
  */
902
909
  debugName?: string;
903
- /**
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
910
  /**
919
911
  * Condition that determines when this derivation applies.
920
912
  *
@@ -942,7 +934,7 @@ interface BaseDerivationLogicConfig {
942
934
  */
943
935
  condition?: ConditionalExpression | boolean;
944
936
  /**
945
- * Static value to set on the target field.
937
+ * Static value to set on this field.
946
938
  *
947
939
  * Use when the derived value is a constant.
948
940
  * Mutually exclusive with `expression` and `functionName`.
@@ -960,6 +952,7 @@ interface BaseDerivationLogicConfig {
960
952
  * JavaScript expression to evaluate for the derived value.
961
953
  *
962
954
  * Has access to `formValue` object containing all form values.
955
+ * For array fields, `formValue` is scoped to the current array item.
963
956
  * Uses the same secure AST-based parser as other expressions.
964
957
  * Mutually exclusive with `value` and `functionName`.
965
958
  *
@@ -1001,18 +994,22 @@ interface BaseDerivationLogicConfig {
1001
994
  * ```typescript
1002
995
  * // Only re-evaluate when country changes
1003
996
  * {
1004
- * type: 'derivation',
1005
- * targetField: 'currency',
1006
- * functionName: 'getCurrencyForCountry',
1007
- * dependsOn: ['country']
997
+ * key: 'currency',
998
+ * logic: [{
999
+ * type: 'derivation',
1000
+ * functionName: 'getCurrencyForCountry',
1001
+ * dependsOn: ['country']
1002
+ * }]
1008
1003
  * }
1009
1004
  *
1010
1005
  * // Override automatic detection for complex expressions
1011
1006
  * {
1012
- * type: 'derivation',
1013
- * targetField: 'total',
1014
- * expression: 'calculateTotal(formValue)',
1015
- * dependsOn: ['quantity', 'unitPrice', 'discount']
1007
+ * key: 'total',
1008
+ * logic: [{
1009
+ * type: 'derivation',
1010
+ * expression: 'calculateTotal(formValue)',
1011
+ * dependsOn: ['quantity', 'unitPrice', 'discount']
1012
+ * }]
1016
1013
  * }
1017
1014
  * ```
1018
1015
  */
@@ -1056,53 +1053,57 @@ interface DebouncedDerivationLogicConfig extends BaseDerivationLogicConfig {
1056
1053
  * Configuration for value derivation logic.
1057
1054
  *
1058
1055
  * 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.
1056
+ * Derivations are self-targeting: the logic is placed on the field
1057
+ * that should receive the computed value.
1061
1058
  *
1062
1059
  * @example
1063
1060
  * ```typescript
1064
1061
  * // Set phone prefix based on country selection
1065
1062
  * {
1066
- * type: 'derivation',
1067
- * targetField: 'phonePrefix',
1068
- * value: '+1',
1069
- * condition: {
1070
- * type: 'fieldValue',
1071
- * fieldPath: 'country',
1072
- * operator: 'equals',
1073
- * value: 'USA'
1074
- * }
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
+ * }]
1075
1074
  * }
1076
1075
  *
1077
1076
  * // Compute total from quantity and price
1078
1077
  * {
1079
- * type: 'derivation',
1080
- * targetField: 'total',
1081
- * expression: 'formValue.quantity * formValue.unitPrice'
1078
+ * key: 'total',
1079
+ * derivation: 'formValue.quantity * formValue.unitPrice'
1082
1080
  * }
1083
1081
  *
1084
1082
  * // Use custom function for complex logic
1085
1083
  * {
1086
- * type: 'derivation',
1087
- * targetField: 'currency',
1088
- * functionName: 'getCurrencyForCountry'
1084
+ * key: 'currency',
1085
+ * logic: [{
1086
+ * type: 'derivation',
1087
+ * functionName: 'getCurrencyForCountry'
1088
+ * }]
1089
1089
  * }
1090
1090
  *
1091
1091
  * // Self-transform with debounced trigger
1092
1092
  * // (applies after user stops typing)
1093
1093
  * {
1094
- * type: 'derivation',
1095
- * targetField: 'email',
1096
- * expression: 'formValue.email.toLowerCase()',
1097
- * trigger: 'debounced',
1098
- * debounceMs: 500
1094
+ * key: 'email',
1095
+ * logic: [{
1096
+ * type: 'derivation',
1097
+ * expression: 'formValue.email.toLowerCase()',
1098
+ * trigger: 'debounced',
1099
+ * debounceMs: 500
1100
+ * }]
1099
1101
  * }
1100
1102
  *
1101
- * // Relative path for array items
1103
+ * // Array item derivation (formValue is scoped to current item)
1102
1104
  * {
1103
- * type: 'derivation',
1104
- * targetField: '$.lineTotal', // Same array index as source field
1105
- * expression: 'formValue.quantity * formValue.unitPrice'
1105
+ * key: 'lineTotal', // Inside array field
1106
+ * derivation: 'formValue.quantity * formValue.unitPrice'
1106
1107
  * }
1107
1108
  * ```
1108
1109
  *
@@ -1315,8 +1316,13 @@ type InferValueType<T, V> = T extends {
1315
1316
  type: 'number';
1316
1317
  };
1317
1318
  } ? number : Widen<V>;
1318
- /** Make type optional if field is not required */
1319
+ /**
1320
+ * Make type optional if field is not required.
1321
+ * Hidden fields are never optional since they require a value property.
1322
+ */
1319
1323
  type MaybeOptional<T, V> = T extends {
1324
+ type: 'hidden';
1325
+ } ? V : T extends {
1320
1326
  required: true;
1321
1327
  } ? V : V | undefined;
1322
1328
  /**
@@ -1333,10 +1339,18 @@ type ProcessField<T, D extends number = 5> = [D] extends [never] ? Record<string
1333
1339
  [P in K]: InferFormValueWithDepth<F, Depth[D]>;
1334
1340
  } : {
1335
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[];
1336
1350
  } : never : T extends {
1337
1351
  type: 'text';
1338
1352
  } ? never : T extends {
1339
- type: 'submit' | 'button';
1353
+ type: 'submit' | 'button' | 'next' | 'previous' | 'addArrayItem' | 'removeArrayItem';
1340
1354
  } ? never : T extends {
1341
1355
  key: infer K;
1342
1356
  value: infer V;
@@ -1813,13 +1827,13 @@ interface EvaluationContext<TValue = unknown> {
1813
1827
  *
1814
1828
  * @example
1815
1829
  * ```typescript
1816
- * // In an array item derivation (e.g., lineItems.$.lineTotal):
1830
+ * // In an array item derivation (on the lineTotal field inside lineItems array):
1817
1831
  * {
1818
- * type: 'derivation',
1819
- * targetField: '$.lineTotal',
1832
+ * key: 'lineTotal',
1833
+ * type: 'input',
1820
1834
  * // formValue = current array item { quantity: 2, unitPrice: 50 }
1821
1835
  * // rootFormValue = entire form { globalDiscount: 0.1, lineItems: [...] }
1822
- * expression: 'formValue.quantity * formValue.unitPrice * (1 - rootFormValue.globalDiscount)'
1836
+ * derivation: 'formValue.quantity * formValue.unitPrice * (1 - rootFormValue.globalDiscount)'
1823
1837
  * }
1824
1838
  * ```
1825
1839
  *
@@ -1835,6 +1849,28 @@ interface EvaluationContext<TValue = unknown> {
1835
1849
  * Path to the array field when inside an array derivation.
1836
1850
  */
1837
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>;
1838
1874
  /** Allow additional properties for flexible expression evaluation */
1839
1875
  [key: string]: unknown;
1840
1876
  }
@@ -2202,6 +2238,54 @@ interface FormConfig<TFields extends NarrowFields | RegisteredFieldTypes[] = Reg
2202
2238
  * ```
2203
2239
  */
2204
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>>;
2205
2289
  }
2206
2290
  /**
2207
2291
  * Signal forms adapter configuration for advanced form behavior.
@@ -2322,14 +2406,15 @@ interface CustomFnConfig {
2322
2406
  *
2323
2407
  * Field configuration using a derivation function:
2324
2408
  * ```typescript
2409
+ * // Derivation is defined on the target field (currency), not the source field (country)
2325
2410
  * {
2326
- * key: 'country',
2411
+ * key: 'currency',
2327
2412
  * type: 'select',
2328
2413
  * logic: [
2329
2414
  * {
2330
2415
  * type: 'derivation',
2331
- * targetField: 'currency',
2332
- * functionName: 'getCurrencyForCountry'
2416
+ * functionName: 'getCurrencyForCountry',
2417
+ * dependsOn: ['country']
2333
2418
  * }
2334
2419
  * ]
2335
2420
  * }
@@ -2594,6 +2679,35 @@ interface FormOptions {
2594
2679
  * ```
2595
2680
  */
2596
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;
2597
2711
  }
2598
2712
  /**
2599
2713
  * Options for controlling submit button disabled behavior.
@@ -2727,10 +2841,8 @@ interface DerivationProcessingResult {
2727
2841
  interface DerivationLogEntry {
2728
2842
  /** Debug name if provided in the derivation config */
2729
2843
  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;
2844
+ /** Field key where the derivation is defined and targets */
2845
+ fieldKey: string;
2734
2846
  /** Result of the derivation evaluation */
2735
2847
  result: 'applied' | 'skipped' | 'error';
2736
2848
  /** Reason for skipping (if result is 'skipped') */
@@ -2819,7 +2931,38 @@ interface DerivationOrchestratorConfig {
2819
2931
  interface FormEvent {
2820
2932
  /** Unique identifier for the event type used for filtering and subscriptions */
2821
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;
2822
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
+ };
2823
2966
  /**
2824
2967
  * Constructor type for form event classes.
2825
2968
  *
@@ -2976,6 +3119,7 @@ declare class DynamicForm<TFields extends RegisteredFieldTypes[] = RegisteredFie
2976
3119
  maxDerivationIterations?: number;
2977
3120
  submitButton?: _ng_forge_dynamic_forms.SubmitButtonOptions;
2978
3121
  nextButton?: _ng_forge_dynamic_forms.NextButtonOptions;
3122
+ emitFormValueOnEvents?: boolean;
2979
3123
  }>;
2980
3124
  /**
2981
3125
  * Computed derivation logger based on injected config.
@@ -3031,10 +3175,15 @@ declare class DynamicForm<TFields extends RegisteredFieldTypes[] = RegisteredFie
3031
3175
  /** Emits when form dirty state changes. */
3032
3176
  readonly dirtyChange: _angular_core.OutputRef<boolean>;
3033
3177
  /**
3034
- * 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
+ *
3035
3184
  * Note: Does not emit when `submission.action` is configured - use one or the other.
3036
3185
  */
3037
- readonly submitted: _angular_core.OutputRef<Partial<TModel> | undefined>;
3186
+ readonly submitted: _angular_core.OutputRef<TModel>;
3038
3187
  /** Emits when form is reset to default values. */
3039
3188
  readonly reset: _angular_core.OutputRef<FormResetEvent>;
3040
3189
  /** Emits when form is cleared to empty state. */
@@ -3099,13 +3248,9 @@ type ExtractFieldDef<T> = T extends FieldTypeDefinition<infer F> ? F : never;
3099
3248
  */
3100
3249
  type FieldDefUnion<T extends FieldTypeDefinition[]> = ExtractFieldDef<T[number]>;
3101
3250
  /**
3102
- * Infer form value type from field definitions
3103
- * Note: Full value type inference requires complex recursive type mapping.
3104
- * Using unknown as placeholder until full inference is implemented.
3251
+ * Infer form value type from field definitions using the real inference type.
3105
3252
  */
3106
- type InferFormValue<TFieldDefs extends FieldDef<unknown>[]> = {
3107
- [K in TFieldDefs[number]['key']]: unknown;
3108
- };
3253
+ type InferFormValue<TFieldDefs extends FieldDef<unknown>[]> = InferFormValue$1<TFieldDefs>;
3109
3254
  /**
3110
3255
  * Provider result with type inference
3111
3256
  */
@@ -3318,6 +3463,52 @@ declare class NoopLogger implements Logger {
3318
3463
  error(): void;
3319
3464
  }
3320
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
+
3321
3512
  interface FieldOption<T = unknown> {
3322
3513
  label: DynamicText;
3323
3514
  value: T;
@@ -3728,7 +3919,10 @@ declare class RemoveArrayItemEvent implements FormEvent {
3728
3919
  * ```
3729
3920
  */
3730
3921
  declare class EventBus {
3731
- private pipeline$;
3922
+ private readonly pipeline$;
3923
+ private readonly globalEmitFormValue;
3924
+ private readonly rootFormRegistry;
3925
+ private readonly formOptions;
3732
3926
  events$: Observable<FormEvent>;
3733
3927
  /**
3734
3928
  * Dispatches an event to all subscribers.
@@ -3736,6 +3930,10 @@ declare class EventBus {
3736
3930
  * Creates an instance of the provided event constructor and broadcasts it
3737
3931
  * through the event pipeline to all active subscribers.
3738
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
+ *
3739
3937
  * @param eventConstructor - Constructor function for the event to dispatch
3740
3938
  *
3741
3939
  * @example
@@ -3748,6 +3946,14 @@ declare class EventBus {
3748
3946
  * ```
3749
3947
  */
3750
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;
3751
3957
  /**
3752
3958
  * Subscribes to events of a specific type.
3753
3959
  *
@@ -3873,6 +4079,64 @@ declare function formConfig<const TFields extends NarrowFields, TProps extends o
3873
4079
  schema?: FormSchema<InferFormValue$1<TFields>>;
3874
4080
  }): FormConfig<TFields, InferFormValue$1<TFields>, TProps>;
3875
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
+
3876
4140
  /**
3877
4141
  * Base error class for all Dynamic Forms errors.
3878
4142
  *
@@ -4329,5 +4593,5 @@ declare class RootFormRegistryService {
4329
4593
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<RootFormRegistryService>;
4330
4594
  }
4331
4595
 
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 };
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 };
4333
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 };