@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
@@ -1,5 +1,6 @@
1
- import { FormEvent, FieldDef, FormEventConstructor, BaseCheckedField, BaseValueField, DynamicText, FieldOption, ValidationMessages } from '@ng-forge/dynamic-forms';
2
- import { Signal, Injector } from '@angular/core';
1
+ import { FormEvent, FieldDef, FormEventConstructor, BaseCheckedField, BaseValueField, DynamicText, FieldMeta, FieldOption, ValidationMessages } from '@ng-forge/dynamic-forms';
2
+ import * as i0 from '@angular/core';
3
+ import { Signal, Injector, ElementRef, PipeTransform } from '@angular/core';
3
4
  import { FieldTree } from '@angular/forms/signals';
4
5
 
5
6
  /**
@@ -42,6 +43,94 @@ interface DatepickerField<TProps> extends BaseValueField<TProps, Date | string>
42
43
  startAt?: Date | null;
43
44
  }
44
45
 
46
+ /**
47
+ * Autocomplete values for HTML input elements.
48
+ * Based on the WHATWG HTML specification for autofill.
49
+ *
50
+ * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill
51
+ */
52
+ type AutocompleteValue = 'off' | 'on' | 'name' | 'honorific-prefix' | 'given-name' | 'additional-name' | 'family-name' | 'honorific-suffix' | 'nickname' | 'email' | 'username' | 'new-password' | 'current-password' | 'one-time-code' | 'organization-title' | 'organization' | 'street-address' | 'address-line1' | 'address-line2' | 'address-line3' | 'address-level4' | 'address-level3' | 'address-level2' | 'address-level1' | 'country' | 'country-name' | 'postal-code' | 'cc-name' | 'cc-given-name' | 'cc-additional-name' | 'cc-family-name' | 'cc-number' | 'cc-exp' | 'cc-exp-month' | 'cc-exp-year' | 'cc-csc' | 'cc-type' | 'transaction-currency' | 'transaction-amount' | 'language' | 'bday' | 'bday-day' | 'bday-month' | 'bday-year' | 'sex' | 'tel' | 'tel-country-code' | 'tel-national' | 'tel-area-code' | 'tel-local' | 'tel-extension' | 'impp' | 'url' | 'photo';
53
+ /**
54
+ * Input mode hints for virtual keyboards on mobile devices.
55
+ *
56
+ * @see https://html.spec.whatwg.org/multipage/interaction.html#input-modalities:-the-inputmode-attribute
57
+ */
58
+ type InputMode = 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url';
59
+ /**
60
+ * Enter key hints for virtual keyboards.
61
+ *
62
+ * @see https://html.spec.whatwg.org/multipage/interaction.html#input-modalities:-the-enterkeyhint-attribute
63
+ */
64
+ type EnterKeyHint = 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send';
65
+ /**
66
+ * Autocapitalization hints for virtual keyboards.
67
+ *
68
+ * @see https://html.spec.whatwg.org/multipage/interaction.html#attr-autocapitalize
69
+ */
70
+ type Autocapitalize = 'off' | 'none' | 'on' | 'sentences' | 'words' | 'characters';
71
+ /**
72
+ * Meta attributes specific to HTML input elements.
73
+ *
74
+ * Extends FieldMeta with input-specific native attributes that can be passed through
75
+ * to the underlying input element.
76
+ *
77
+ * @example
78
+ * ```typescript
79
+ * // Input field with meta attributes
80
+ * {
81
+ * type: 'input',
82
+ * key: 'email',
83
+ * meta: {
84
+ * autocomplete: 'email',
85
+ * inputmode: 'email',
86
+ * enterkeyhint: 'next',
87
+ * spellcheck: false,
88
+ * 'data-testid': 'email-input'
89
+ * }
90
+ * }
91
+ * ```
92
+ *
93
+ * @public
94
+ */
95
+ interface InputMeta extends FieldMeta {
96
+ /**
97
+ * Hint for form autofill behavior.
98
+ */
99
+ autocomplete?: AutocompleteValue;
100
+ /**
101
+ * Hint for virtual keyboard type on mobile devices.
102
+ */
103
+ inputmode?: InputMode;
104
+ /**
105
+ * Hint for the enter key label on virtual keyboards.
106
+ */
107
+ enterkeyhint?: EnterKeyHint;
108
+ /**
109
+ * Whether to enable spellchecking for the input.
110
+ */
111
+ spellcheck?: boolean;
112
+ /**
113
+ * Hint for autocapitalization behavior on virtual keyboards.
114
+ */
115
+ autocapitalize?: Autocapitalize;
116
+ /**
117
+ * Pattern for client-side validation (regex).
118
+ */
119
+ pattern?: string;
120
+ /**
121
+ * Size hint for the input element (character count).
122
+ */
123
+ size?: number;
124
+ /**
125
+ * Maximum number of characters allowed.
126
+ */
127
+ maxlength?: number;
128
+ /**
129
+ * Minimum number of characters required.
130
+ */
131
+ minlength?: number;
132
+ }
133
+
45
134
  /**
46
135
  * HTML input types supported by input fields
47
136
  */
@@ -76,7 +165,7 @@ interface NumberInputField<TProps extends {
76
165
  type?: string;
77
166
  } = InputProps> extends BaseValueField<TProps & {
78
167
  type: 'number';
79
- }, number> {
168
+ }, number, InputMeta> {
80
169
  type: 'input';
81
170
  props: TProps & {
82
171
  type: 'number';
@@ -91,7 +180,7 @@ interface StringInputField<TProps extends {
91
180
  type?: string;
92
181
  } = InputProps> extends BaseValueField<TProps & {
93
182
  type?: StringInputType;
94
- }, string> {
183
+ }, string, InputMeta> {
95
184
  type: 'input';
96
185
  props?: TProps & {
97
186
  type?: StringInputType;
@@ -155,12 +244,12 @@ type InputField<TProps extends {
155
244
  */
156
245
  interface MultiCheckboxField<TValue, TProps = object> extends BaseValueField<TProps, TValue[]> {
157
246
  type: 'multi-checkbox';
158
- options: FieldOption<TValue>[];
247
+ readonly options: readonly FieldOption<TValue>[];
159
248
  }
160
249
 
161
250
  interface RadioField<T, TProps> extends BaseValueField<TProps, T> {
162
251
  type: 'radio';
163
- options: FieldOption<T>[];
252
+ readonly options: readonly FieldOption<T>[];
164
253
  }
165
254
 
166
255
  interface SelectProps {
@@ -178,12 +267,75 @@ interface SliderField<TProps> extends BaseValueField<TProps, number> {
178
267
  step?: number;
179
268
  }
180
269
 
270
+ /**
271
+ * Text wrapping behavior for textarea elements.
272
+ *
273
+ * @see https://html.spec.whatwg.org/multipage/form-elements.html#attr-textarea-wrap
274
+ */
275
+ type TextareaWrap = 'hard' | 'soft' | 'off';
276
+ /**
277
+ * Meta attributes specific to HTML textarea elements.
278
+ *
279
+ * Extends FieldMeta with textarea-specific native attributes that can be passed through
280
+ * to the underlying textarea element.
281
+ *
282
+ * @example
283
+ * ```typescript
284
+ * // Textarea field with meta attributes
285
+ * {
286
+ * type: 'textarea',
287
+ * key: 'description',
288
+ * meta: {
289
+ * wrap: 'soft',
290
+ * spellcheck: true,
291
+ * autocomplete: 'off',
292
+ * 'data-testid': 'description-textarea'
293
+ * }
294
+ * }
295
+ * ```
296
+ *
297
+ * @public
298
+ */
299
+ interface TextareaMeta extends FieldMeta {
300
+ /**
301
+ * How text should wrap when submitted.
302
+ * - 'hard': Line breaks are inserted to wrap text at cols width
303
+ * - 'soft': Text is wrapped for display but not in submitted value
304
+ * - 'off': No wrapping, horizontal scrolling if needed
305
+ */
306
+ wrap?: TextareaWrap;
307
+ /**
308
+ * Whether to enable spellchecking for the textarea.
309
+ */
310
+ spellcheck?: boolean;
311
+ /**
312
+ * Hint for form autofill behavior.
313
+ */
314
+ autocomplete?: AutocompleteValue;
315
+ /**
316
+ * Hint for autocapitalization behavior on virtual keyboards.
317
+ */
318
+ autocapitalize?: Autocapitalize;
319
+ /**
320
+ * Hint for the enter key label on virtual keyboards.
321
+ */
322
+ enterkeyhint?: EnterKeyHint;
323
+ /**
324
+ * Maximum number of characters allowed.
325
+ */
326
+ maxlength?: number;
327
+ /**
328
+ * Minimum number of characters required.
329
+ */
330
+ minlength?: number;
331
+ }
332
+
181
333
  interface TextareaProps {
182
334
  placeholder?: DynamicText;
183
335
  rows?: number;
184
336
  cols?: number | undefined;
185
337
  }
186
- interface TextareaField<TProps = TextareaProps> extends BaseValueField<TProps, string> {
338
+ interface TextareaField<TProps = TextareaProps> extends BaseValueField<TProps, string, TextareaMeta> {
187
339
  type: 'textarea';
188
340
  maxLength?: number | undefined;
189
341
  }
@@ -311,5 +463,81 @@ declare function createResolvedErrorsSignal<T>(field: Signal<FieldTree<T>>, vali
311
463
  */
312
464
  declare function shouldShowErrors<T>(field: Signal<FieldTree<T>>): Signal<boolean>;
313
465
 
314
- export { buildValueFieldInputs, checkboxFieldMapper, createResolvedErrorsSignal, datepickerFieldMapper, optionsFieldMapper, resolveValueFieldContext, shouldShowErrors, valueFieldMapper };
315
- export type { ButtonField, CheckboxField, DatepickerField, DatepickerProps, EventArgs, FieldWithOptions, InputField, InputProps, InputType, InputTypeToValueType, MultiCheckboxField, RadioField, ResolvedError, SelectField, SelectProps, SliderField, StringInputType, TextareaField, TextareaProps, ToggleField, ValueFieldContext };
466
+ /**
467
+ * Performs a deep equality comparison between two values
468
+ */
469
+ declare function isEqual(a: unknown, b: unknown): boolean;
470
+
471
+ /**
472
+ * Configuration options for setupMetaTracking.
473
+ */
474
+ interface MetaTrackingOptions {
475
+ /**
476
+ * CSS selector for target elements within the host.
477
+ * If not provided, meta attributes are applied directly to the host element.
478
+ *
479
+ * @example
480
+ * // Apply to internal radio inputs
481
+ * selector: 'input[type="radio"]'
482
+ *
483
+ * // Apply to host element (for Shadow DOM components)
484
+ * selector: undefined
485
+ */
486
+ selector?: string;
487
+ /**
488
+ * Additional signals to track that should trigger re-application of meta.
489
+ * Useful for components where DOM elements are dynamically created (e.g., radio options).
490
+ *
491
+ * @example
492
+ * // Re-apply when options change
493
+ * dependents: [this.options]
494
+ */
495
+ dependents?: Signal<unknown>[];
496
+ }
497
+ /**
498
+ * Sets up automatic meta attribute tracking and application for wrapped components.
499
+ *
500
+ * This utility creates an `afterRenderEffect` that applies meta attributes to DOM elements
501
+ * after Angular's render cycle. It efficiently tracks signal dependencies and only re-applies
502
+ * when the meta signal or any dependent signals change.
503
+ *
504
+ * Use this instead of MutationObserver for better performance and integration with Angular's
505
+ * change detection.
506
+ *
507
+ * @param elementRef - Reference to the host element
508
+ * @param meta - Signal containing meta attributes to apply
509
+ * @param options - Configuration options
510
+ *
511
+ * @example
512
+ * ```typescript
513
+ * // For a radio group with dynamic options
514
+ * constructor() {
515
+ * setupMetaTracking(inject(ElementRef), this.meta, {
516
+ * selector: 'input[type="radio"]',
517
+ * dependents: [this.options]
518
+ * });
519
+ * }
520
+ *
521
+ * // For a simple checkbox
522
+ * constructor() {
523
+ * setupMetaTracking(inject(ElementRef), this.meta, {
524
+ * selector: 'input[type="checkbox"]'
525
+ * });
526
+ * }
527
+ *
528
+ * // For Shadow DOM components (apply to host)
529
+ * constructor() {
530
+ * setupMetaTracking(inject(ElementRef), this.meta);
531
+ * }
532
+ * ```
533
+ */
534
+ declare function setupMetaTracking(elementRef: ElementRef<HTMLElement>, meta: Signal<FieldMeta | undefined>, options?: MetaTrackingOptions): void;
535
+
536
+ declare class ValueInArrayPipe implements PipeTransform {
537
+ transform<T>(element: T, array: T[] | undefined): boolean;
538
+ static ɵfac: i0.ɵɵFactoryDeclaration<ValueInArrayPipe, never>;
539
+ static ɵpipe: i0.ɵɵPipeDeclaration<ValueInArrayPipe, "inArray", true>;
540
+ }
541
+
542
+ export { ValueInArrayPipe, buildValueFieldInputs, checkboxFieldMapper, createResolvedErrorsSignal, datepickerFieldMapper, isEqual, optionsFieldMapper, resolveValueFieldContext, setupMetaTracking, shouldShowErrors, valueFieldMapper };
543
+ export type { Autocapitalize, AutocompleteValue, ButtonField, CheckboxField, DatepickerField, DatepickerProps, EnterKeyHint, EventArgs, FieldWithOptions, InputField, InputMeta, InputMode, InputProps, InputType, InputTypeToValueType, MetaTrackingOptions, MultiCheckboxField, RadioField, ResolvedError, SelectField, SelectProps, SliderField, StringInputType, TextareaField, TextareaMeta, TextareaProps, TextareaWrap, ToggleField, ValueFieldContext };
@@ -1,9 +1,9 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { Provider, Injector, WritableSignal, Type } from '@angular/core';
1
3
  import { Mock } from 'vitest';
2
- import { DynamicFormLogger, FieldDef, FormConfig, DynamicForm, ValidationMessages, FieldSignalContext } from '@ng-forge/dynamic-forms';
4
+ import { Logger, FieldDef, FormConfig, DynamicForm, ValidationMessages, FieldSignalContext, RegisteredFieldTypes } from '@ng-forge/dynamic-forms';
3
5
  import { ComponentFixture } from '@angular/core/testing';
4
6
  import { ValidationError, form, FieldTree } from '@angular/forms/signals';
5
- import * as _angular_core from '@angular/core';
6
- import { Injector, WritableSignal, Type } from '@angular/core';
7
7
  import { Observable } from 'rxjs';
8
8
 
9
9
  /**
@@ -31,7 +31,7 @@ declare function delay(ms?: number): Promise<void>;
31
31
  /**
32
32
  * Mock logger with vitest spies for testing.
33
33
  */
34
- interface MockLogger extends DynamicFormLogger {
34
+ interface MockLogger extends Logger {
35
35
  debug: Mock;
36
36
  info: Mock;
37
37
  warn: Mock;
@@ -43,10 +43,10 @@ interface MockLogger extends DynamicFormLogger {
43
43
  */
44
44
  declare function createMockLogger(): MockLogger;
45
45
  /**
46
- * Creates a silent logger that doesn't output anything.
47
- * Useful for tests where logging output is not relevant.
46
+ * Provider for a console logger in tests.
47
+ * Add this to TestBed.configureTestingModule providers when not using provideDynamicForm().
48
48
  */
49
- declare function createSilentLogger(): DynamicFormLogger;
49
+ declare function provideTestLogger(): Provider;
50
50
 
51
51
  /**
52
52
  * Configuration for creating a dynamic form test
@@ -68,7 +68,7 @@ interface DynamicFormTestResult {
68
68
  */
69
69
  declare class FormConfigBuilder {
70
70
  private fields;
71
- field(field: FieldDef<any>): FormConfigBuilder;
71
+ field(field: FieldDef<unknown>): FormConfigBuilder;
72
72
  inputField(key: string, props?: Record<string, unknown>): FormConfigBuilder;
73
73
  requiredInputField(key: string, props?: Record<string, unknown>): FormConfigBuilder;
74
74
  selectField(key: string, options: Array<{
@@ -76,10 +76,10 @@ declare class FormConfigBuilder {
76
76
  label: string;
77
77
  }>, props?: Record<string, unknown>): FormConfigBuilder;
78
78
  checkboxField(key: string, props?: Record<string, unknown>): FormConfigBuilder;
79
- rowField(key: string, fields: FieldDef<any>[]): FormConfigBuilder;
80
- groupField(key: string, fields: FieldDef<any>[]): FormConfigBuilder;
79
+ rowField(key: string, fields: FieldDef<unknown>[]): FormConfigBuilder;
80
+ groupField(key: string, fields: FieldDef<unknown>[]): FormConfigBuilder;
81
81
  buttonField(key: string, props?: Record<string, unknown>): FormConfigBuilder;
82
- pageField(key: string, fields: FieldDef<any>[], title?: string): FormConfigBuilder;
82
+ pageField(key: string, fields: FieldDef<unknown>[], title?: string): FormConfigBuilder;
83
83
  build(): FormConfig;
84
84
  }
85
85
  /**
@@ -257,7 +257,7 @@ declare function createTestFieldContext<TModel extends Record<string, unknown> =
257
257
  * Simple form configuration interface for testing
258
258
  */
259
259
  interface TestFormConfig$1 {
260
- fields: FieldDef<any>[];
260
+ fields: FieldDef<unknown>[];
261
261
  }
262
262
  /**
263
263
  * Configuration for creating a dynamic form test
@@ -267,18 +267,19 @@ interface SimpleTestConfig<T = Record<string, unknown>> {
267
267
  initialValue?: T;
268
268
  }
269
269
  /**
270
- * Result of creating a dynamic form test
270
+ * Result of creating a dynamic form test.
271
+ * Uses the base DynamicForm type without generic constraints for flexibility in tests.
271
272
  */
272
273
  interface SimpleTestResult {
273
- component: any;
274
- fixture: any;
274
+ component: DynamicForm<RegisteredFieldTypes[]>;
275
+ fixture: ComponentFixture<DynamicForm<RegisteredFieldTypes[]>>;
275
276
  }
276
277
  /**
277
278
  * Fluent API for building form configurations using existing field structure
278
279
  */
279
280
  declare class TestFormConfigBuilder<T = Record<string, unknown>> {
280
281
  private fields;
281
- field(field: FieldDef<any>): TestFormConfigBuilder<T>;
282
+ field(field: FieldDef<unknown>): TestFormConfigBuilder<T>;
282
283
  inputField(key: string, props?: Record<string, unknown>): TestFormConfigBuilder<T>;
283
284
  requiredInputField(key: string, props?: Record<string, unknown>): TestFormConfigBuilder<T>;
284
285
  checkboxField(key: string, props?: Record<string, unknown>): TestFormConfigBuilder<T>;
@@ -299,58 +300,58 @@ declare class SimpleTestUtils {
299
300
  /**
300
301
  * Waits for the dynamic form to initialize
301
302
  */
302
- static waitForInit(fixture: any): Promise<void>;
303
+ static waitForInit(fixture: ComponentFixture<DynamicForm>): Promise<void>;
303
304
  /**
304
305
  * Simulates user input on a field element
305
306
  */
306
- static simulateInput(fixture: any, selector: string, value: string): Promise<void>;
307
+ static simulateInput(fixture: ComponentFixture<DynamicForm>, selector: string, value: string): Promise<void>;
307
308
  /**
308
309
  * Simulates checkbox toggle
309
310
  */
310
- static simulateCheckbox(fixture: any, selector: string, checked: boolean): Promise<void>;
311
+ static simulateCheckbox(fixture: ComponentFixture<DynamicForm>, selector: string, checked: boolean): Promise<void>;
311
312
  /**
312
313
  * Gets the current form value from the component
313
314
  */
314
- static getFormValue(component: any): Record<string, unknown> | undefined;
315
+ static getFormValue(component: DynamicForm): Record<string, unknown> | undefined;
315
316
  /**
316
317
  * Checks if the form is valid
317
318
  */
318
- static isFormValid(component: any): boolean;
319
+ static isFormValid(component: DynamicForm): boolean;
319
320
  /**
320
321
  * Asserts that the form has a specific value
321
322
  */
322
- static assertFormValue(component: any, expectedValue: Record<string, unknown>): void;
323
+ static assertFormValue(component: DynamicForm, expectedValue: Record<string, unknown>): void;
323
324
  }
324
325
  declare class TestFieldComponent {
325
- value: _angular_core.WritableSignal<string>;
326
+ field: _angular_core.InputSignal<unknown>;
326
327
  key: _angular_core.InputSignal<string>;
327
328
  label: _angular_core.InputSignal<string>;
328
329
  className: _angular_core.InputSignal<string>;
329
330
  tabIndex: _angular_core.InputSignal<number | undefined>;
330
331
  props: _angular_core.InputSignal<Record<string, unknown> | undefined>;
331
332
  placeholder: _angular_core.InputSignal<string>;
332
- fields: _angular_core.InputSignal<unknown[]>;
333
333
  arrayContext: _angular_core.InputSignal<unknown>;
334
+ fields: _angular_core.InputSignal<unknown[]>;
334
335
  validationMessages: _angular_core.InputSignal<Record<string, string> | undefined>;
335
336
  defaultValidationMessages: _angular_core.InputSignal<Record<string, string> | undefined>;
336
- field: _angular_core.InputSignal<unknown>;
337
+ value: _angular_core.WritableSignal<string>;
337
338
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<TestFieldComponent, never>;
338
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<TestFieldComponent, "df-test-field", never, { "key": { "alias": "key"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "className": { "alias": "className"; "required": false; "isSignal": true; }; "tabIndex": { "alias": "tabIndex"; "required": false; "isSignal": true; }; "props": { "alias": "props"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "fields": { "alias": "fields"; "required": false; "isSignal": true; }; "arrayContext": { "alias": "arrayContext"; "required": false; "isSignal": true; }; "validationMessages": { "alias": "validationMessages"; "required": false; "isSignal": true; }; "defaultValidationMessages": { "alias": "defaultValidationMessages"; "required": false; "isSignal": true; }; "field": { "alias": "field"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
339
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TestFieldComponent, "df-test-field", never, { "field": { "alias": "field"; "required": false; "isSignal": true; }; "key": { "alias": "key"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "className": { "alias": "className"; "required": false; "isSignal": true; }; "tabIndex": { "alias": "tabIndex"; "required": false; "isSignal": true; }; "props": { "alias": "props"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "arrayContext": { "alias": "arrayContext"; "required": false; "isSignal": true; }; "fields": { "alias": "fields"; "required": false; "isSignal": true; }; "validationMessages": { "alias": "validationMessages"; "required": false; "isSignal": true; }; "defaultValidationMessages": { "alias": "defaultValidationMessages"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
339
340
  }
340
341
  /**
341
342
  * Configuration for setting up a simple component test
342
343
  */
343
- interface SimpleComponentTestConfig<T = any> {
344
- field: FieldDef<any>;
344
+ interface SimpleComponentTestConfig<T = unknown> {
345
+ field: FieldDef<unknown>;
345
346
  value?: T;
346
347
  pageIndex?: number;
347
348
  isVisible?: boolean;
348
- [key: string]: any;
349
+ [key: string]: unknown;
349
350
  }
350
351
  /**
351
352
  * Result of setting up a simple component test
352
353
  */
353
- interface SimpleComponentTestResult<T = any> {
354
+ interface SimpleComponentTestResult<T = unknown> {
354
355
  component: T;
355
356
  fixture: ComponentFixture<T>;
356
357
  }
@@ -361,13 +362,13 @@ declare function setupSimpleTest<T>(componentType: Type<T>, config: SimpleCompon
361
362
  /**
362
363
  * Creates a simple test field definition
363
364
  */
364
- declare function createSimpleTestField(key: string, label: string): FieldDef<any>;
365
+ declare function createSimpleTestField(key: string, label: string): FieldDef<unknown>;
365
366
 
366
367
  /**
367
368
  * Simple form configuration interface for testing
368
369
  */
369
370
  interface TestFormConfig {
370
- fields: FieldDef<any>[];
371
+ fields: FieldDef<unknown>[];
371
372
  }
372
373
  /**
373
374
  * Unified configuration for creating dynamic form tests
@@ -390,7 +391,7 @@ interface TestResult<T = unknown> {
390
391
  * Configuration for setting up individual field component tests
391
392
  */
392
393
  interface ComponentTestConfig<T = unknown> {
393
- field: FieldDef<any>;
394
+ field: FieldDef<unknown>;
394
395
  value?: T;
395
396
  }
396
397
  /**
@@ -401,6 +402,37 @@ interface ComponentTestResult<T = unknown> {
401
402
  fixture: ComponentFixture<T>;
402
403
  }
403
404
 
405
+ /**
406
+ * Type utilities for exhaustive whitelist type testing.
407
+ *
408
+ * These utilities help ensure that type definitions remain stable by detecting
409
+ * when properties are added, removed, or changed.
410
+ */
411
+ /**
412
+ * Extracts only the required keys from a type.
413
+ *
414
+ * @example
415
+ * ```typescript
416
+ * interface Example { a: string; b?: number; }
417
+ * type Required = RequiredKeys<Example>; // 'a'
418
+ * ```
419
+ */
420
+ type RequiredKeys<T> = {
421
+ [K in keyof T]-?: object extends Pick<T, K> ? never : K;
422
+ }[keyof T];
423
+ /**
424
+ * Extracts only the optional keys from a type.
425
+ *
426
+ * @example
427
+ * ```typescript
428
+ * interface Example { a: string; b?: number; }
429
+ * type Optional = OptionalKeys<Example>; // 'b'
430
+ * ```
431
+ */
432
+ type OptionalKeys<T> = {
433
+ [K in keyof T]-?: object extends Pick<T, K> ? K : never;
434
+ }[keyof T];
435
+
404
436
  declare class TestInputHarness {
405
437
  readonly field: _angular_core.InputSignal<FieldTree<string>>;
406
438
  readonly key: _angular_core.InputSignal<string>;
@@ -561,5 +593,5 @@ declare const SPANISH_TEST_TRANSLATIONS: {
561
593
  */
562
594
  declare function createTestTranslationService(initialTranslations?: Record<string, string>): FakeTranslationService;
563
595
 
564
- export { DEFAULT_TEST_TRANSLATIONS, DynamicFormTestUtils, FakeTranslationService, FormConfigBuilder, SPANISH_TEST_TRANSLATIONS, TestFormConfigBuilder as SimpleFormConfigBuilder, SimpleTestUtils, TestCheckboxHarness as TestCheckboxHarnessComponent, TestFieldComponent, TestInputHarness as TestInputHarnessComponent, TestSelectHarness as TestSelectHarnessComponent, createMockLogger, createSilentLogger, createSimpleTestField, createTestFieldContext, createTestFormInjector, createTestTranslationService, delay, setupSimpleTest, testMapper };
565
- export type { ComponentTestConfig, ComponentTestResult, DynamicFormTestConfig, DynamicFormTestResult, MockLogger, SimpleComponentTestConfig, SimpleComponentTestResult, SimpleTestConfig, SimpleTestResult, TestConfig, TestFieldContextConfig, TestFormConfig, TestResult };
596
+ export { DEFAULT_TEST_TRANSLATIONS, DynamicFormTestUtils, FakeTranslationService, FormConfigBuilder, SPANISH_TEST_TRANSLATIONS, TestFormConfigBuilder as SimpleFormConfigBuilder, SimpleTestUtils, TestCheckboxHarness as TestCheckboxHarnessComponent, TestFieldComponent, TestInputHarness as TestInputHarnessComponent, TestSelectHarness as TestSelectHarnessComponent, createMockLogger, createSimpleTestField, createTestFieldContext, createTestFormInjector, createTestTranslationService, delay, provideTestLogger, setupSimpleTest, testMapper };
597
+ export type { ComponentTestConfig, ComponentTestResult, DynamicFormTestConfig, DynamicFormTestResult, MockLogger, OptionalKeys, RequiredKeys, SimpleComponentTestConfig, SimpleComponentTestResult, SimpleTestConfig, SimpleTestResult, TestConfig, TestFieldContextConfig, TestFormConfig, TestResult };