@ng-forge/dynamic-forms 0.2.0 → 0.3.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.
Files changed (21) hide show
  1. package/README.md +7 -5
  2. package/fesm2022/ng-forge-dynamic-forms-integration.mjs +79 -6
  3. package/fesm2022/ng-forge-dynamic-forms-integration.mjs.map +1 -1
  4. package/fesm2022/{ng-forge-dynamic-forms-ng-forge-dynamic-forms-CZBdtTAU.mjs → ng-forge-dynamic-forms-ng-forge-dynamic-forms-D58rojQc.mjs} +375 -78
  5. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-D58rojQc.mjs.map +1 -0
  6. package/fesm2022/{ng-forge-dynamic-forms-page-field.component-BM32StxL.mjs → ng-forge-dynamic-forms-page-field.component-m35XgkkL.mjs} +13 -7
  7. package/fesm2022/ng-forge-dynamic-forms-page-field.component-m35XgkkL.mjs.map +1 -0
  8. package/fesm2022/{ng-forge-dynamic-forms-testing-test-button.harness-CbctXjtc.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 +25 -25
  11. package/fesm2022/ng-forge-dynamic-forms-testing.mjs.map +1 -1
  12. package/fesm2022/{ng-forge-dynamic-forms-text-field.component-C0I8jf9T.mjs → ng-forge-dynamic-forms-text-field.component-CfDZFTyf.mjs} +5 -5
  13. package/fesm2022/{ng-forge-dynamic-forms-text-field.component-C0I8jf9T.mjs.map → ng-forge-dynamic-forms-text-field.component-CfDZFTyf.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 +225 -9
  17. package/types/ng-forge-dynamic-forms-testing.d.ts +32 -1
  18. package/types/ng-forge-dynamic-forms.d.ts +211 -18
  19. package/fesm2022/ng-forge-dynamic-forms-ng-forge-dynamic-forms-CZBdtTAU.mjs.map +0 -1
  20. package/fesm2022/ng-forge-dynamic-forms-page-field.component-BM32StxL.mjs.map +0 -1
  21. package/fesm2022/ng-forge-dynamic-forms-testing-test-button.harness-CbctXjtc.mjs.map +0 -1
@@ -1,6 +1,6 @@
1
- import { FormEvent, FieldDef, FormEventConstructor, BaseCheckedField, BaseValueField, DynamicText, FieldOption, ValidationMessages } from '@ng-forge/dynamic-forms';
1
+ import { FormEvent, FieldDef, FormEventConstructor, BaseCheckedField, BaseValueField, DynamicText, FieldMeta, FieldOption, ValidationMessages } from '@ng-forge/dynamic-forms';
2
2
  import * as i0 from '@angular/core';
3
- import { Signal, Injector, PipeTransform } from '@angular/core';
3
+ import { Signal, Injector, ElementRef, PipeTransform } from '@angular/core';
4
4
  import { FieldTree } from '@angular/forms/signals';
5
5
 
6
6
  /**
@@ -43,6 +43,94 @@ interface DatepickerField<TProps> extends BaseValueField<TProps, Date | string>
43
43
  startAt?: Date | null;
44
44
  }
45
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
+
46
134
  /**
47
135
  * HTML input types supported by input fields
48
136
  */
@@ -77,7 +165,7 @@ interface NumberInputField<TProps extends {
77
165
  type?: string;
78
166
  } = InputProps> extends BaseValueField<TProps & {
79
167
  type: 'number';
80
- }, number> {
168
+ }, number, InputMeta> {
81
169
  type: 'input';
82
170
  props: TProps & {
83
171
  type: 'number';
@@ -92,7 +180,7 @@ interface StringInputField<TProps extends {
92
180
  type?: string;
93
181
  } = InputProps> extends BaseValueField<TProps & {
94
182
  type?: StringInputType;
95
- }, string> {
183
+ }, string, InputMeta> {
96
184
  type: 'input';
97
185
  props?: TProps & {
98
186
  type?: StringInputType;
@@ -156,12 +244,12 @@ type InputField<TProps extends {
156
244
  */
157
245
  interface MultiCheckboxField<TValue, TProps = object> extends BaseValueField<TProps, TValue[]> {
158
246
  type: 'multi-checkbox';
159
- options: FieldOption<TValue>[];
247
+ readonly options: readonly FieldOption<TValue>[];
160
248
  }
161
249
 
162
250
  interface RadioField<T, TProps> extends BaseValueField<TProps, T> {
163
251
  type: 'radio';
164
- options: FieldOption<T>[];
252
+ readonly options: readonly FieldOption<T>[];
165
253
  }
166
254
 
167
255
  interface SelectProps {
@@ -179,12 +267,75 @@ interface SliderField<TProps> extends BaseValueField<TProps, number> {
179
267
  step?: number;
180
268
  }
181
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
+
182
333
  interface TextareaProps {
183
334
  placeholder?: DynamicText;
184
335
  rows?: number;
185
336
  cols?: number | undefined;
186
337
  }
187
- interface TextareaField<TProps = TextareaProps> extends BaseValueField<TProps, string> {
338
+ interface TextareaField<TProps = TextareaProps> extends BaseValueField<TProps, string, TextareaMeta> {
188
339
  type: 'textarea';
189
340
  maxLength?: number | undefined;
190
341
  }
@@ -317,11 +468,76 @@ declare function shouldShowErrors<T>(field: Signal<FieldTree<T>>): Signal<boolea
317
468
  */
318
469
  declare function isEqual(a: unknown, b: unknown): boolean;
319
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
+
320
536
  declare class ValueInArrayPipe implements PipeTransform {
321
537
  transform<T>(element: T, array: T[] | undefined): boolean;
322
538
  static ɵfac: i0.ɵɵFactoryDeclaration<ValueInArrayPipe, never>;
323
539
  static ɵpipe: i0.ɵɵPipeDeclaration<ValueInArrayPipe, "inArray", true>;
324
540
  }
325
541
 
326
- export { ValueInArrayPipe, buildValueFieldInputs, checkboxFieldMapper, createResolvedErrorsSignal, datepickerFieldMapper, isEqual, optionsFieldMapper, resolveValueFieldContext, shouldShowErrors, valueFieldMapper };
327
- export type { ButtonField, CheckboxField, DatepickerField, DatepickerProps, EventArgs, FieldWithOptions, InputField, InputProps, InputType, InputTypeToValueType, MultiCheckboxField, RadioField, ResolvedError, SelectField, SelectProps, SliderField, StringInputType, TextareaField, TextareaProps, ToggleField, ValueFieldContext };
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 };
@@ -402,6 +402,37 @@ interface ComponentTestResult<T = unknown> {
402
402
  fixture: ComponentFixture<T>;
403
403
  }
404
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
+
405
436
  declare class TestInputHarness {
406
437
  readonly field: _angular_core.InputSignal<FieldTree<string>>;
407
438
  readonly key: _angular_core.InputSignal<string>;
@@ -563,4 +594,4 @@ declare const SPANISH_TEST_TRANSLATIONS: {
563
594
  declare function createTestTranslationService(initialTranslations?: Record<string, string>): FakeTranslationService;
564
595
 
565
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 };
566
- export type { ComponentTestConfig, ComponentTestResult, DynamicFormTestConfig, DynamicFormTestResult, MockLogger, SimpleComponentTestConfig, SimpleComponentTestResult, SimpleTestConfig, SimpleTestResult, TestConfig, TestFieldContextConfig, TestFormConfig, TestResult };
597
+ export type { ComponentTestConfig, ComponentTestResult, DynamicFormTestConfig, DynamicFormTestResult, MockLogger, OptionalKeys, RequiredKeys, SimpleComponentTestConfig, SimpleComponentTestResult, SimpleTestConfig, SimpleTestResult, TestConfig, TestFieldContextConfig, TestFormConfig, TestResult };