@ng-forge/dynamic-forms 0.1.3 → 0.3.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.
Files changed (21) hide show
  1. package/README.md +6 -4
  2. package/fesm2022/ng-forge-dynamic-forms-integration.mjs +121 -4
  3. package/fesm2022/ng-forge-dynamic-forms-integration.mjs.map +1 -1
  4. package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-B_676NHl.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-CMSmISSp.mjs} +561 -331
  5. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-CMSmISSp.mjs.map +1 -0
  6. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-YHFQcpCS.mjs → ng-forge-dynamic-forms-page-field.component-rdGD8A9d.mjs} +6 -6
  7. package/fesm2022/ng-forge-dynamic-forms-page-field.component-rdGD8A9d.mjs.map +1 -0
  8. package/fesm2022/{ng-forge-dynamic-forms-testing-test-button.harness-BenmCFcM.mjs → ng-forge-dynamic-forms-testing-test-button.harness-0iXHLraC.mjs} +7 -7
  9. package/fesm2022/ng-forge-dynamic-forms-testing-test-button.harness-0iXHLraC.mjs.map +1 -0
  10. package/fesm2022/ng-forge-dynamic-forms-testing.mjs +41 -38
  11. package/fesm2022/ng-forge-dynamic-forms-testing.mjs.map +1 -1
  12. package/fesm2022/{ng-forge-dynamic-forms-text-field.component-CiYq73aF.mjs → ng-forge-dynamic-forms-text-field.component-CDxka2KD.mjs} +5 -5
  13. package/fesm2022/{ng-forge-dynamic-forms-text-field.component-CiYq73aF.mjs.map → ng-forge-dynamic-forms-text-field.component-CDxka2KD.mjs.map} +1 -1
  14. package/fesm2022/ng-forge-dynamic-forms.mjs +1 -1
  15. package/package.json +4 -4
  16. package/types/ng-forge-dynamic-forms-integration.d.ts +237 -9
  17. package/types/ng-forge-dynamic-forms-testing.d.ts +67 -35
  18. package/types/ng-forge-dynamic-forms.d.ts +263 -99
  19. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-B_676NHl.mjs.map +0 -1
  20. package/fesm2022/ng-forge-dynamic-forms-page-field.component-YHFQcpCS.mjs.map +0 -1
  21. package/fesm2022/ng-forge-dynamic-forms-testing-test-button.harness-BenmCFcM.mjs.map +0 -1
@@ -17,6 +17,39 @@ type Prettify<T> = {
17
17
 
18
18
  type DynamicText = string | Observable<string> | Signal<string>;
19
19
 
20
+ /**
21
+ * Base interface for native HTML attributes that can be passed to form field elements.
22
+ *
23
+ * This interface serves as the base type for all meta attributes. Specific field types
24
+ * (like input, textarea) extend this with their own specialized meta types.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * // Using FieldMeta for custom attributes
29
+ * meta: {
30
+ * 'data-testid': 'email-input',
31
+ * 'aria-describedby': 'email-help',
32
+ * 'x-custom': 'value'
33
+ * }
34
+ * ```
35
+ *
36
+ * @public
37
+ */
38
+ interface FieldMeta {
39
+ /**
40
+ * Allows any data-* attribute
41
+ */
42
+ [key: `data-${string}`]: string | undefined;
43
+ /**
44
+ * Allows any aria-* attribute
45
+ */
46
+ [key: `aria-${string}`]: string | boolean | undefined;
47
+ /**
48
+ * Allows additional custom attributes as escape hatch
49
+ */
50
+ [key: string]: string | number | boolean | undefined;
51
+ }
52
+
20
53
  /**
21
54
  * Base interface for all dynamic form field definitions.
22
55
  *
@@ -56,10 +89,11 @@ type DynamicText = string | Observable<string> | Signal<string>;
56
89
  * ```
57
90
  *
58
91
  * @typeParam TProps - Field-specific properties interface
92
+ * @typeParam TMeta - Native HTML attributes interface (extends FieldMeta)
59
93
  *
60
94
  * @public
61
95
  */
62
- interface FieldDef<TProps> {
96
+ interface FieldDef<TProps, TMeta extends FieldMeta = FieldMeta> {
63
97
  /**
64
98
  * Unique field identifier used for form binding and value tracking.
65
99
  *
@@ -136,6 +170,32 @@ interface FieldDef<TProps> {
136
170
  * ```
137
171
  */
138
172
  props?: TProps;
173
+ /**
174
+ * Native HTML attributes to pass through to the underlying element.
175
+ *
176
+ * Contains attributes that are applied directly to the native input/element.
177
+ * Useful for accessibility, autocomplete hints, and custom attributes.
178
+ * The shape is defined by the TMeta generic parameter, which extends FieldMeta.
179
+ *
180
+ * @example
181
+ * ```typescript
182
+ * // Input field meta
183
+ * meta: {
184
+ * autocomplete: 'email',
185
+ * inputmode: 'email',
186
+ * 'aria-describedby': 'email-help',
187
+ * 'data-testid': 'email-input'
188
+ * }
189
+ *
190
+ * // Textarea meta
191
+ * meta: {
192
+ * wrap: 'soft',
193
+ * spellcheck: true,
194
+ * 'aria-label': 'Description field'
195
+ * }
196
+ * ```
197
+ */
198
+ meta?: TMeta;
139
199
  /**
140
200
  * Additional CSS classes for custom styling.
141
201
  *
@@ -236,7 +296,7 @@ type IncludedKeys = 'label' | 'className' | 'hidden' | 'tabIndex';
236
296
  *
237
297
  * @public
238
298
  */
239
- type FieldComponent<T extends FieldDef<any>> = Prettify<WithInputSignals<Pick<T, IncludedKeys>>>;
299
+ type FieldComponent<T extends FieldDef<unknown, FieldMeta>> = Prettify<WithInputSignals<Pick<T, IncludedKeys>>>;
240
300
 
241
301
  /**
242
302
  * Re-export Angular's ValidationError for consistency
@@ -261,8 +321,10 @@ interface ValidationMessages {
261
321
  * This is a programmatic field type only - users cannot customize this field type
262
322
  *
263
323
  * TypeScript cannot enforce field nesting rules due to circular dependency limitations.
264
- * For documentation: Rows should contain groups and leaf fields, but NOT pages or other rows.
324
+ * For documentation: Rows should contain groups and leaf fields, but NOT pages, other rows, or hidden fields.
265
325
  * Runtime validation enforces these rules.
326
+ *
327
+ * Note: Rows are container fields and do not support `meta` since they have no native form element.
266
328
  */
267
329
  interface RowField<TFields extends readonly RowAllowedChildren[] = readonly RowAllowedChildren[]> extends FieldDef<never> {
268
330
  type: 'row';
@@ -270,6 +332,8 @@ interface RowField<TFields extends readonly RowAllowedChildren[] = readonly RowA
270
332
  readonly fields: TFields;
271
333
  /** Row fields do not have a label property **/
272
334
  readonly label?: never;
335
+ /** Rows do not support meta - they have no native form element **/
336
+ readonly meta?: never;
273
337
  }
274
338
  /**
275
339
  * Type guard for RowField with proper type narrowing
@@ -284,18 +348,74 @@ declare function isRowField(field: FieldDef<any>): field is RowField;
284
348
  * TypeScript cannot enforce field nesting rules due to circular dependency limitations.
285
349
  * For documentation: Groups should contain rows and leaf fields, but NOT pages or other groups.
286
350
  * Runtime validation enforces these rules.
351
+ *
352
+ * Note: Groups are container fields and do not support `meta` since they have no native form element.
287
353
  */
288
354
  interface GroupField<TFields extends readonly GroupAllowedChildren[] = readonly GroupAllowedChildren[]> extends FieldDef<never> {
289
355
  type: 'group';
290
356
  readonly fields: TFields;
291
357
  /** Groups do not have a label property - they are logical containers only **/
292
358
  readonly label?: never;
359
+ /** Groups do not support meta - they have no native form element **/
360
+ readonly meta?: never;
293
361
  }
294
362
  /**
295
363
  * Type guard for GroupField with proper type narrowing
296
364
  */
297
365
  declare function isGroupField(field: FieldDef<any>): field is GroupField;
298
366
 
367
+ /**
368
+ * Scalar types supported by hidden fields.
369
+ * These are the primitive value types that can be stored.
370
+ */
371
+ type HiddenScalar = string | number | boolean;
372
+ /**
373
+ * All value types supported by hidden fields.
374
+ * Supports both scalar values and arrays of scalars for storing
375
+ * multiple IDs or similar data.
376
+ */
377
+ type HiddenValue = HiddenScalar | HiddenScalar[];
378
+ /**
379
+ * Hidden field definition for storing values without rendering UI.
380
+ *
381
+ * Hidden fields participate in the form schema and contribute to form values,
382
+ * but do not render any visible component. They are useful for:
383
+ * - Storing IDs when updating existing records
384
+ * - Persisting metadata that shouldn't be user-editable
385
+ * - Tracking computed values that need to be submitted
386
+ *
387
+ * Unlike the `hidden` property on other fields (which hides a rendered field),
388
+ * this field type renders nothing at all - it's a componentless field.
389
+ *
390
+ * @example
391
+ * ```typescript
392
+ * // Store a record ID for updates
393
+ * const idField: HiddenField<string> = {
394
+ * type: 'hidden',
395
+ * key: 'id',
396
+ * value: '550e8400-e29b-41d4-a716-446655440000',
397
+ * };
398
+ *
399
+ * // Store multiple tag IDs
400
+ * const tagIdsField: HiddenField<number[]> = {
401
+ * type: 'hidden',
402
+ * key: 'tagIds',
403
+ * value: [1, 2, 3],
404
+ * };
405
+ * ```
406
+ *
407
+ * @typeParam TValue - The type of value stored (must be HiddenValue compatible)
408
+ */
409
+ interface HiddenField<TValue extends HiddenValue = HiddenValue> extends FieldDef<never> {
410
+ /** Discriminant for hidden field type */
411
+ type: 'hidden';
412
+ /**
413
+ * The value to store in the form.
414
+ * This is required - a hidden field without a value serves no purpose.
415
+ */
416
+ value: TValue;
417
+ }
418
+
299
419
  /**
300
420
  * Type constraints for field nesting rules
301
421
  * These ensure that container fields can only contain valid child field types
@@ -309,9 +429,10 @@ declare function isGroupField(field: FieldDef<any>): field is GroupField;
309
429
  type PageAllowedChildren = LeafFieldTypes | RowField | GroupField | ArrayField;
310
430
  /**
311
431
  * Fields that are allowed as children of Row fields
312
- * Rows can contain: groups, arrays, and leaf fields (but NOT pages or other rows)
432
+ * Rows can contain: groups, arrays, and leaf fields (but NOT pages, other rows, or hidden fields)
433
+ * Hidden fields are excluded because rows are for horizontal layouts and hidden fields don't render
313
434
  */
314
- type RowAllowedChildren = LeafFieldTypes | GroupField | ArrayField;
435
+ type RowAllowedChildren = Exclude<LeafFieldTypes, HiddenField> | GroupField | ArrayField;
315
436
  /**
316
437
  * Fields that are allowed as children of Group fields
317
438
  * Groups can contain: rows and leaf fields (but NOT pages or other groups)
@@ -359,6 +480,8 @@ type ArrayAllowedChildren = LeafFieldTypes | RowField | GroupField;
359
480
  *
360
481
  * Nesting constraints: Arrays can contain rows, leaf fields, or groups (for object arrays),
361
482
  * but NOT pages or other arrays. Runtime validation enforces these rules.
483
+ *
484
+ * Note: Arrays are container fields and do not support `meta` since they have no native form element.
362
485
  */
363
486
  interface ArrayField<TFields extends readonly ArrayAllowedChildren[] = readonly ArrayAllowedChildren[]> extends FieldDef<never> {
364
487
  type: 'array';
@@ -371,6 +494,8 @@ interface ArrayField<TFields extends readonly ArrayAllowedChildren[] = readonly
371
494
  readonly fields: TFields;
372
495
  /** Array fields do not have a label property **/
373
496
  readonly label?: never;
497
+ /** Arrays do not support meta - they have no native form element **/
498
+ readonly meta?: never;
374
499
  }
375
500
  /**
376
501
  * Type guard for ArrayField with proper type narrowing
@@ -416,6 +541,8 @@ interface PageLogicConfig {
416
541
  * TypeScript cannot enforce field nesting rules due to circular dependency limitations.
417
542
  * For documentation: Pages should contain rows, groups, and leaf fields, but NOT other pages.
418
543
  * Runtime validation enforces these rules.
544
+ *
545
+ * Note: Pages are container fields and do not support `meta` since they have no native form element.
419
546
  */
420
547
  interface PageField<TFields extends readonly PageAllowedChildren[] = PageAllowedChildren[]> extends FieldDef<never> {
421
548
  type: 'page';
@@ -423,6 +550,8 @@ interface PageField<TFields extends readonly PageAllowedChildren[] = PageAllowed
423
550
  readonly fields: TFields;
424
551
  /** Page fields do not have a label property **/
425
552
  readonly label?: never;
553
+ /** Pages do not support meta - they have no native form element **/
554
+ readonly meta?: never;
426
555
  /**
427
556
  * Logic configurations for conditional page visibility.
428
557
  * Only 'hidden' type logic is supported for pages.
@@ -618,6 +747,7 @@ interface FieldRegistryContainers {
618
747
  */
619
748
  interface FieldRegistryLeaves {
620
749
  text: TextField;
750
+ hidden: HiddenField;
621
751
  }
622
752
  /**
623
753
  * Global interface for dynamic form field definitions with categorization
@@ -707,10 +837,10 @@ type NarrowField<T> = T extends {
707
837
  type NarrowFields = readonly NarrowField<RegisteredFieldTypes>[];
708
838
 
709
839
  /**
710
- * Helper type to convert union to intersection
711
- * Note: `any` is necessary for distributive conditional types
840
+ * Helper type to convert union to intersection.
841
+ * Uses `U extends U` to trigger distributive conditional type behavior.
712
842
  */
713
- type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
843
+ type UnionToIntersection<U> = (U extends U ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
714
844
  /**
715
845
  * Depth counter for recursion limiting (prevents infinite type instantiation)
716
846
  */
@@ -928,8 +1058,8 @@ interface SchemaDefinition {
928
1058
  * - Field state: `ctx.state` (errors, touched, dirty, etc.)
929
1059
  * - Other field values: `ctx.valueOf(path)` where path is a FieldPath
930
1060
  * - Other field states: `ctx.stateOf(path)`
931
- * - Other fields: `ctx.fieldOf(path)`
932
- * - Current field tree: `ctx.field`
1061
+ * - Other fields: `ctx.fieldTreeOf(path)`
1062
+ * - Current field tree: `ctx.fieldTree`
933
1063
  *
934
1064
  * **Return Types:**
935
1065
  * - Single error: `{ kind: 'errorKind' }` for field-level validation
@@ -1184,7 +1314,7 @@ interface HttpCustomValidator<TValue = unknown, TResult = unknown> {
1184
1314
  * Interface for dynamic forms logger implementations.
1185
1315
  * Allows custom logging integrations (Sentry, DataDog, etc.)
1186
1316
  */
1187
- interface DynamicFormLogger {
1317
+ interface Logger {
1188
1318
  /**
1189
1319
  * Log a debug message.
1190
1320
  * Use for detailed diagnostic information during development.
@@ -1217,7 +1347,7 @@ interface EvaluationContext<TValue = unknown> {
1217
1347
  /** Custom evaluation functions */
1218
1348
  customFunctions?: Record<string, (context: EvaluationContext) => unknown>;
1219
1349
  /** Logger for diagnostic output */
1220
- logger: DynamicFormLogger;
1350
+ logger: Logger;
1221
1351
  /** Allow additional properties for flexible expression evaluation */
1222
1352
  [key: string]: unknown;
1223
1353
  }
@@ -1956,12 +2086,45 @@ interface FieldTypeDefinition<T extends FieldDef<any> = any> {
1956
2086
  name: string;
1957
2087
  /** Field definition type marker (internal use) */
1958
2088
  _fieldDef?: T;
1959
- /** Function to load the component (supports lazy loading) */
2089
+ /**
2090
+ * Function to load the component (supports lazy loading).
2091
+ * Returns a Promise that resolves to the component class or module with default export.
2092
+ *
2093
+ * Optional - omit for componentless fields (e.g., hidden fields) that only
2094
+ * contribute to form values without rendering any UI.
2095
+ */
1960
2096
  loadComponent?: () => Promise<any>;
1961
- /** Mapper function that converts field definition to component bindings */
1962
- mapper: MapperFn<T>;
2097
+ /**
2098
+ * Mapper function that converts field definition to component bindings.
2099
+ *
2100
+ * Optional - omit for componentless fields (like hidden fields) that don't need
2101
+ * input mapping. When omitted for componentless fields (no loadComponent), an empty
2102
+ * signal is returned. When omitted for regular fields with a component, falls back
2103
+ * to baseFieldMapper.
2104
+ */
2105
+ mapper?: MapperFn<T>;
1963
2106
  /** How this field type handles form values and data collection (defaults to 'include') */
1964
2107
  valueHandling?: ValueHandlingMode;
2108
+ /**
2109
+ * List of prop keys to forward to the meta object.
2110
+ *
2111
+ * Some props (like `type` for inputs, `rows`/`cols` for textareas) are actually
2112
+ * native HTML attributes. Specifying them here causes them to be merged into
2113
+ * the meta object before being passed to the component, ensuring they're applied
2114
+ * via the meta tracking mechanism.
2115
+ *
2116
+ * Note: Meta values always take precedence over forwarded props.
2117
+ *
2118
+ * @example
2119
+ * ```typescript
2120
+ * {
2121
+ * name: 'input',
2122
+ * propsToMeta: ['type'],
2123
+ * // ...
2124
+ * }
2125
+ * ```
2126
+ */
2127
+ propsToMeta?: string[];
1965
2128
  }
1966
2129
  /**
1967
2130
  * Injection token for the global field type registry.
@@ -2330,9 +2493,11 @@ type ExtractFieldDef<T> = T extends FieldTypeDefinition<infer F> ? F : never;
2330
2493
  type FieldDefUnion<T extends FieldTypeDefinition[]> = ExtractFieldDef<T[number]>;
2331
2494
  /**
2332
2495
  * Infer form value type from field definitions
2496
+ * Note: Full value type inference requires complex recursive type mapping.
2497
+ * Using unknown as placeholder until full inference is implemented.
2333
2498
  */
2334
- type InferFormValue<TFieldDefs extends FieldDef<any>[]> = {
2335
- [K in TFieldDefs[number]['key']]: any;
2499
+ type InferFormValue<TFieldDefs extends FieldDef<unknown>[]> = {
2500
+ [K in TFieldDefs[number]['key']]: unknown;
2336
2501
  };
2337
2502
  /**
2338
2503
  * Provider result with type inference
@@ -2357,7 +2522,7 @@ type ExtractFieldTypes<T extends FieldTypeOrFeature[]> = {
2357
2522
  * This function creates environment providers that can be used at application or route level
2358
2523
  * to register field types. It provides type-safe field registration with automatic type inference.
2359
2524
  *
2360
- * @param items - Field type definitions and/or features (like withLogger)
2525
+ * @param items - Field type definitions and/or features (like withLoggerConfig)
2361
2526
  * @returns Environment providers for dependency injection with type inference
2362
2527
  *
2363
2528
  * @example
@@ -2372,12 +2537,12 @@ type ExtractFieldTypes<T extends FieldTypeOrFeature[]> = {
2372
2537
  *
2373
2538
  * @example
2374
2539
  * ```typescript
2375
- * // With logging configuration
2540
+ * // Disable logging
2376
2541
  * bootstrapApplication(AppComponent, {
2377
2542
  * providers: [
2378
2543
  * provideDynamicForm(
2379
2544
  * ...withMaterialFields(),
2380
- * withLogger({ level: LogLevel.Debug })
2545
+ * withLoggerConfig(false)
2381
2546
  * )
2382
2547
  * ]
2383
2548
  * });
@@ -2385,18 +2550,6 @@ type ExtractFieldTypes<T extends FieldTypeOrFeature[]> = {
2385
2550
  *
2386
2551
  * @example
2387
2552
  * ```typescript
2388
- * // Route-level setup
2389
- * const routes: Routes = [
2390
- * {
2391
- * path: 'form',
2392
- * component: FormComponent,
2393
- * providers: [provideDynamicForm(...withMaterialFields())]
2394
- * }
2395
- * ];
2396
- * ```
2397
- *
2398
- * @example
2399
- * ```typescript
2400
2553
  * // Custom field types with type inference
2401
2554
  * import { CustomFieldType, AnotherFieldType } from './custom-fields';
2402
2555
  *
@@ -2456,93 +2609,65 @@ type ExtractFormValue<T> = T extends {
2456
2609
  * { type: 'page', key: 'step1', fields: [...] }
2457
2610
  * ```
2458
2611
  */
2459
- declare const BUILT_IN_FIELDS: FieldTypeDefinition[];
2460
-
2461
2612
  /**
2462
- * Log levels for the dynamic forms logger.
2463
- * Each level includes all levels above it (more severe).
2613
+ * Built-in field types provided by the dynamic form library.
2464
2614
  *
2465
- * - Off: No logging
2466
- * - Error: Only errors
2467
- * - Warn: Errors + warnings
2468
- * - Info: Errors + warnings + info
2469
- * - Debug: All messages including debug
2615
+ * Each field type is validated at compile time using satisfies, ensuring
2616
+ * type safety of the mapper function while allowing the array to be typed
2617
+ * as FieldTypeDefinition[] for consumer flexibility.
2470
2618
  */
2471
- declare enum LogLevel {
2472
- /** Disable all logging */
2473
- Off = 0,
2474
- /** Only log errors */
2475
- Error = 1,
2476
- /** Log errors and warnings */
2477
- Warn = 2,
2478
- /** Log errors, warnings, and info messages */
2479
- Info = 3,
2480
- /** Log all messages including debug */
2481
- Debug = 4
2482
- }
2619
+ declare const BUILT_IN_FIELDS: FieldTypeDefinition[];
2483
2620
 
2484
- /**
2485
- * Configuration options for the logger feature
2486
- */
2487
- interface LoggerFeatureOptions {
2488
- /**
2489
- * Log level to use. Messages below this level will be filtered.
2490
- * @default LogLevel.Warn in dev, LogLevel.Off in prod
2491
- */
2492
- level?: LogLevel;
2493
- /**
2494
- * Custom logger implementation.
2495
- * Use this to integrate with external logging services (Sentry, DataDog, etc.)
2496
- * If provided, `level` is ignored - your implementation controls filtering.
2497
- */
2498
- logger?: DynamicFormLogger;
2499
- }
2500
2621
  /**
2501
2622
  * Configure logging for dynamic forms.
2502
2623
  *
2624
+ * By default, logging is enabled (ConsoleLogger). Use this feature to disable logging
2625
+ * or configure it conditionally.
2626
+ *
2503
2627
  * @example
2504
2628
  * ```typescript
2505
- * // Set log level
2629
+ * // Disable logging
2506
2630
  * provideDynamicForm(
2507
2631
  * ...withMaterialFields(),
2508
- * withLogger({ level: LogLevel.Debug })
2632
+ * withLoggerConfig(false)
2509
2633
  * )
2510
2634
  *
2511
- * // Disable logging entirely
2635
+ * // Conditional logging (e.g., only in dev mode)
2512
2636
  * provideDynamicForm(
2513
2637
  * ...withMaterialFields(),
2514
- * withLogger({ level: LogLevel.Off })
2515
- * )
2516
- *
2517
- * // Custom logger implementation
2518
- * provideDynamicForm(
2519
- * ...withMaterialFields(),
2520
- * withLogger({ logger: mySentryLogger })
2638
+ * withLoggerConfig(() => isDevMode())
2521
2639
  * )
2522
2640
  * ```
2523
2641
  *
2524
- * @param options - Logger configuration options
2642
+ * @param enabled - Whether logging is enabled. Can be a boolean or a function that returns a boolean. Defaults to true.
2525
2643
  * @returns A DynamicFormFeature that configures logging
2526
2644
  */
2527
- declare function withLogger(options?: LoggerFeatureOptions): DynamicFormFeature<'logger'>;
2645
+ declare function withLoggerConfig(enabled?: boolean | (() => boolean)): DynamicFormFeature<'logger'>;
2528
2646
 
2529
2647
  /**
2530
2648
  * Injection token for the dynamic forms logger.
2531
2649
  *
2532
- * Default behavior:
2533
- * - Development mode: ConsoleLogger with LogLevel.Warn
2534
- * - Production mode: NoopLogger (silent)
2535
- *
2536
- * Override by providing a custom logger via withLogger() feature
2537
- * or by providing directly to this token.
2650
+ * Provided by provideDynamicForm() with ConsoleLogger as default.
2651
+ * Override with withLoggerConfig(false) to disable logging.
2538
2652
  */
2539
- declare const DYNAMIC_FORM_LOGGER: InjectionToken<DynamicFormLogger>;
2653
+ declare const DynamicFormLogger: InjectionToken<Logger>;
2654
+
2655
+ /**
2656
+ * Console-based logger implementation.
2657
+ */
2658
+ declare class ConsoleLogger implements Logger {
2659
+ private readonly prefix;
2660
+ debug(message: string, ...args: unknown[]): void;
2661
+ info(message: string, ...args: unknown[]): void;
2662
+ warn(message: string, ...args: unknown[]): void;
2663
+ error(message: string, ...args: unknown[]): void;
2664
+ }
2540
2665
 
2541
2666
  /**
2542
2667
  * No-operation logger implementation.
2543
2668
  * All methods are no-ops - used in production by default.
2544
2669
  */
2545
- declare class NoopLogger implements DynamicFormLogger {
2670
+ declare class NoopLogger implements Logger {
2546
2671
  debug(): void;
2547
2672
  info(): void;
2548
2673
  warn(): void;
@@ -2626,7 +2751,7 @@ interface ButtonLogicContext {
2626
2751
  /** Current form value for evaluating conditional expressions */
2627
2752
  formValue?: unknown;
2628
2753
  /** Optional logger for diagnostic output. Falls back to no-op logger if not provided. */
2629
- logger?: DynamicFormLogger;
2754
+ logger?: Logger;
2630
2755
  }
2631
2756
  /**
2632
2757
  * Resolves the disabled state for a submit button.
@@ -2700,7 +2825,7 @@ interface FieldWithValidation {
2700
2825
  * This type represents all possible value types that can be used in form fields.
2701
2826
  */
2702
2827
  type ValueType = string | number | boolean | Date | object | unknown[];
2703
- interface BaseValueField<TProps, TValue> extends FieldDef<TProps>, FieldWithValidation {
2828
+ interface BaseValueField<TProps, TValue, TMeta extends FieldMeta = FieldMeta> extends FieldDef<TProps, TMeta>, FieldWithValidation {
2704
2829
  value?: TValue;
2705
2830
  /**
2706
2831
  * Placeholder text displayed when the field is empty.
@@ -2709,11 +2834,11 @@ interface BaseValueField<TProps, TValue> extends FieldDef<TProps>, FieldWithVali
2709
2834
  placeholder?: DynamicText;
2710
2835
  required?: boolean;
2711
2836
  }
2712
- declare function isValueField<TProps>(field: FieldDef<TProps>): field is BaseValueField<TProps, ValueType>;
2837
+ declare function isValueField<TProps, TMeta extends FieldMeta = FieldMeta>(field: FieldDef<TProps, TMeta>): field is BaseValueField<TProps, ValueType, TMeta>;
2713
2838
  type ExcludedKeys$1 = 'type' | 'conditionals' | 'value' | 'valueType' | 'disabled' | 'readonly' | 'hidden' | 'col' | 'minValue' | 'maxValue' | 'step' | 'required' | 'email' | 'min' | 'max' | 'minLength' | 'maxLength' | 'pattern' | 'validators' | 'logic' | 'schemas';
2714
- type ValueFieldComponent<T extends BaseValueField<any, unknown>> = Prettify<WithInputSignals<Omit<T, ExcludedKeys$1>>>;
2839
+ type ValueFieldComponent<T extends BaseValueField<Record<string, unknown> | unknown, unknown>> = Prettify<WithInputSignals<Omit<T, ExcludedKeys$1>>>;
2715
2840
 
2716
- interface BaseCheckedField<TProps> extends FieldDef<TProps>, FieldWithValidation {
2841
+ interface BaseCheckedField<TProps, TMeta extends FieldMeta = FieldMeta> extends FieldDef<TProps, TMeta>, FieldWithValidation {
2717
2842
  value?: boolean;
2718
2843
  /**
2719
2844
  * Placeholder text displayed when the field is empty.
@@ -2722,9 +2847,9 @@ interface BaseCheckedField<TProps> extends FieldDef<TProps>, FieldWithValidation
2722
2847
  placeholder?: DynamicText;
2723
2848
  required?: boolean;
2724
2849
  }
2725
- declare function isCheckedField<TProps>(field: FieldDef<TProps>): field is BaseCheckedField<TProps>;
2850
+ declare function isCheckedField<TProps, TMeta extends FieldMeta = FieldMeta>(field: FieldDef<TProps, TMeta>): field is BaseCheckedField<TProps, TMeta>;
2726
2851
  type ExcludedKeys = 'type' | 'conditionals' | 'value' | 'disabled' | 'readonly' | 'hidden' | 'col' | keyof FieldWithValidation;
2727
- type CheckedFieldComponent<T extends BaseCheckedField<any>> = Prettify<WithInputSignals<Omit<T, ExcludedKeys>>>;
2852
+ type CheckedFieldComponent<T extends BaseCheckedField<Record<string, unknown> | unknown>> = Prettify<WithInputSignals<Omit<T, ExcludedKeys>>>;
2728
2853
 
2729
2854
  declare function applyValidator(config: ValidatorConfig, fieldPath: SchemaPath<any> | SchemaPathTree<any>): void;
2730
2855
  declare function applyValidators(configs: ValidatorConfig[], fieldPath: SchemaPath<any> | SchemaPathTree<any>): void;
@@ -2865,7 +2990,7 @@ declare class EventBus {
2865
2990
  * eventBus.dispatch(CustomFormEvent);
2866
2991
  * ```
2867
2992
  */
2868
- dispatch<T extends FormEventConstructor>(eventConstructor: T, ...args: any[]): void;
2993
+ dispatch<T extends FormEventConstructor>(eventConstructor: T, ...args: ConstructorParameters<T>): void;
2869
2994
  /**
2870
2995
  * Subscribes to events of a specific type.
2871
2996
  *
@@ -2935,6 +3060,18 @@ interface ArrayItemContext {
2935
3060
  formValue?: unknown;
2936
3061
  }
2937
3062
 
3063
+ /**
3064
+ * Base error class for all Dynamic Forms errors.
3065
+ *
3066
+ * This class centralizes the `[Dynamic Forms]` prefix, ensuring consistent
3067
+ * error messaging across the library without requiring each error site to
3068
+ * manually include the prefix.
3069
+ */
3070
+ declare class DynamicFormError extends Error {
3071
+ private static readonly PREFIX;
3072
+ constructor(message: string);
3073
+ }
3074
+
2938
3075
  /**
2939
3076
  * Builds base input properties from a field definition.
2940
3077
  *
@@ -3024,6 +3161,33 @@ declare function textFieldMapper(fieldDef: TextField): Signal<Record<string, unk
3024
3161
  */
3025
3162
  declare function dynamicTextToObservable(value: DynamicText | undefined, injector?: Injector): Observable<string>;
3026
3163
 
3164
+ /**
3165
+ * Applies meta attributes to a DOM element and tracks which attributes were applied.
3166
+ *
3167
+ * This utility handles:
3168
+ * - Removing previously applied attributes that are no longer in meta
3169
+ * - Setting new attributes from meta
3170
+ * - Converting all values to strings via String()
3171
+ *
3172
+ * @param element - The DOM element to apply attributes to
3173
+ * @param meta - The meta object containing attributes to apply
3174
+ * @param previouslyApplied - Set of attribute names that were previously applied
3175
+ * @returns A new Set containing the attribute names that were applied
3176
+ *
3177
+ * @example
3178
+ * ```typescript
3179
+ * private appliedAttrs = new Set<string>();
3180
+ *
3181
+ * explicitEffect([this.meta], ([meta]) => {
3182
+ * const input = this.el.nativeElement.querySelector('input');
3183
+ * if (input) {
3184
+ * this.appliedAttrs = applyMetaToElement(input, meta, this.appliedAttrs);
3185
+ * }
3186
+ * });
3187
+ * ```
3188
+ */
3189
+ declare function applyMetaToElement(element: Element, meta: FieldMeta | undefined, previouslyApplied: Set<string>): Set<string>;
3190
+
3027
3191
  /**
3028
3192
  * Pipe that handles dynamic text resolution with support for static strings,
3029
3193
  * Observables, and Signals.
@@ -3226,5 +3390,5 @@ declare function omit<T extends object, K extends keyof T>(obj: T, keys: K[]): O
3226
3390
  */
3227
3391
  declare function interpolateParams(message: string, error: ValidationError): string;
3228
3392
 
3229
- export { ARRAY_CONTEXT, AddArrayItemEvent, ArrayFieldComponent, BUILT_IN_FIELDS, DYNAMIC_FORM_LOGGER, DynamicForm, DynamicTextPipe, EventBus, FIELD_REGISTRY, FIELD_SIGNAL_CONTEXT, FormClearEvent, FormResetEvent, GroupFieldComponent, LogLevel, NextPageEvent, NoopLogger, PageChangeEvent, PreviousPageEvent, RemoveArrayItemEvent, RowFieldComponent, SubmitEvent, 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, withLogger };
3230
- export type { ArrayAllowedChildren, ArrayContext, ArrayField, ArrayFieldTree, ArrayItemContext, AsyncCustomValidator, AsyncValidatorConfig, AvailableFieldTypes, BaseCheckedField, BaseValidatorConfig, BaseValueField, BuiltInValidatorConfig, ButtonLogicContext, CheckedFieldComponent, ConditionalExpression, ContainerFieldTypes, CustomFnConfig, CustomValidator, CustomValidatorConfig, DynamicFormFieldRegistry, DynamicFormLogger, DynamicText, EvaluationContext, ExtractField, ExtractFieldDefs, ExtractFormValue, FieldComponent, FieldDef, FieldOption, FieldPathAccess, FieldRegistryContainers, FieldRegistryLeaves, FieldSignalContext, FieldTypeDefinition, FieldWithValidation, FormConfig, FormEvent, FormEventConstructor, FormMode, FormModeDetectionResult, FormOptions, FormStateCondition, GroupAllowedChildren, GroupField, HttpCustomValidator, HttpResourceRequest, HttpValidatorConfig, InferFormValue$1 as InferFormValue, LeafFieldTypes, LoggerFeatureOptions, 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 };
3393
+ export { ARRAY_CONTEXT, AddArrayItemEvent, ArrayFieldComponent, BUILT_IN_FIELDS, ConsoleLogger, DynamicForm, DynamicFormError, DynamicFormLogger, DynamicTextPipe, EventBus, FIELD_REGISTRY, FIELD_SIGNAL_CONTEXT, FormClearEvent, FormResetEvent, GroupFieldComponent, NextPageEvent, NoopLogger, PageChangeEvent, PreviousPageEvent, RemoveArrayItemEvent, 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 };
3394
+ 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 };