@ng-modular-forms/core 0.7.0 → 0.7.2

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 (2) hide show
  1. package/README.md +28 -113
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -6,11 +6,7 @@ Core primitives, behaviors, and input components for orchestrating complex Angul
6
6
 
7
7
  ```bash
8
8
  npm install @ng-modular-forms/core
9
- ```
10
-
11
- There is also an optional package which supports Angular Material UI components:
12
-
13
- ```bash
9
+ # Optional Material UI bindings:
14
10
  npm install @ng-modular-forms/material
15
11
  ```
16
12
 
@@ -29,45 +25,27 @@ export class ExampleComponent extends FormOrchestrator {
29
25
  override readonly serializer: FormSerializer,
30
26
  ) {
31
27
  super(hydrator, serializer);
32
-
33
- const sectionAHandler = inject(SectionAHandler);
34
-
35
- form = new FormGroup({});
36
- handlers = [sectionAHandler]
37
-
38
- this.initialize({ form, handlers });
28
+ this.initialize({
29
+ form: new FormGroup({}),
30
+ handlerRegistry: [inject(SectionAHandler)]
31
+ });
39
32
  }
40
33
  }
41
34
  ```
42
35
 
43
36
  ### FormHandlerBase
44
37
 
45
- Encapsulates reactive logic.
38
+ Encapsulates reactive logic (e.g., if Field A changes, disable Field B). Keeps UI logic out of the component.
46
39
 
47
40
  ```ts
48
- const CONTROL_NAMES = ["fieldA", "dependentField"] as const;
49
-
50
- type ControlNames = (typeof CONTROL_NAMES)[number];
51
-
52
41
  @Injectable()
53
- export class SectionAHandler extends FormHandlerBase<ControlNames> {
42
+ export class SectionAHandler extends FormHandlerBase<'fieldA' | 'fieldB'> {
54
43
  override getReactiveLogic(form?: FormGroup): Subscription {
55
- this.registerControls(form, [...CONTROL_NAMES]);
56
-
57
- const sub = new Subscription();
58
-
59
- sub.add(this.reactiveMethod());
60
-
61
- return sub;
62
- }
44
+ this.registerControls(form, ["fieldA", "fieldB"]);
63
45
 
64
- private reactiveMethod() {
65
- return this.valueChangesOf("fieldA").subscribe((value) => {
66
- if (value) {
67
- this.controls.dependentField.enable();
68
- } else {
69
- this.controls.dependentField.disable();
70
- }
46
+ return this.valueChangesOf("fieldA").subscribe(val => {
47
+ const fieldB = getControl("fieldB", form);
48
+ val ? fieldB.enable() : fieldB.disable();
71
49
  });
72
50
  }
73
51
  }
@@ -75,106 +53,43 @@ export class SectionAHandler extends FormHandlerBase<ControlNames> {
75
53
 
76
54
  ### FormMapperBase
77
55
 
78
- Handles transformations between API and form. Optional: `FormHydrator` and `FormSerializer` will automatically map correlated values.
56
+ Handles transformations between API and form. `FormHydrator` and `FormSerializer` will call these automatically.
79
57
 
80
58
  ```ts
81
59
  export class ExampleMapper extends FormMapperBase<ApiModel, RequestModel, FormModel> {
82
60
  toRequest(form: FormGroup): RequestModel {
83
- const fieldA = form.value.fieldA ?? null;
84
- return {
85
- fieldA: fieldA?.replace(/_/g, " "),
86
- fieldB: form.value.fieldB,
87
- };
61
+ return { fieldA: form.value.fieldA?.trim() };
88
62
  }
89
63
 
90
64
  fromModel(model: ApiModel): FormModel {
91
- return {
92
- fieldA: model.fieldA,
93
- fieldB: model.fieldB,
94
- };
65
+ return { fieldA: model.fieldA };
95
66
  }
96
67
  }
97
68
  ```
98
69
 
99
70
  ### FormControlBase
100
71
 
101
- Provides the ControlValueAccessor implementation as well as common component inputs such as label, placeholder, etc.
102
-
103
- ```ts
104
- @Component({
105
- template: `
106
- <input
107
- [value]="displayValue()"
108
- [disabled]="disabled()"
109
- [required]="isRequired()"
110
- (blur)="onTouched()"
111
- (input)="onInput($event)" />
112
- `,
113
- })
114
- export class CustomInput extends FormControlBase<string | null> {
115
- displayValue = signal<string | null>(null);
116
-
117
- override writeValue(value: number | null): void {
118
- super.writeValue(value);
119
- this.displayValue.set(value != null ? formatNumber(value) : null);
120
- }
121
-
122
- onInput(event: Event) {
123
- if (this._disabled()) return;
124
-
125
- const rawValue: string | null = (event.target as HTMLInputElement).value ?? null;
126
- const value: number = parseNumber(rawValue);
127
-
128
- this.displayValue.set(value != null ? formatNumber(value) : null);
129
-
130
- this.onChange(value);
131
- }
132
- }
133
- ```
134
-
135
- ### Reusable Input Behaviors
136
-
137
- Behaviors are just plain JavaScript objects:
138
-
139
- ```ts
140
- export class CurrencyBehavior {
141
- blockNonDigitKey(event: KeyboardEvent) {
142
- const input = event.target as HTMLInputElement;
143
- const value = input.value;
144
-
145
- if (event.ctrlKey || event.metaKey) {
146
- return;
147
- }
148
-
149
- // Custom logic...
150
-
151
- event.preventDefault();
152
- }
153
- }
154
- ```
72
+ Provides ControlValueAccessor boilerplate and common UI inputs (labels, hints, error states) for custom components.
155
73
 
156
74
  ## Available Input Components
157
75
 
158
- All inputs share a consistent API and can be swapped between native and Material implementations without changing form logic.
76
+ All components share a consistent API and are interchangeable between Native and Material implementations without changing form logic.
159
77
 
160
- | Input Type | Native Selector | Material Selector | Description |
161
- |-----------------|--------------------------------|------------------------------------|----------------------------------------------------------------------------------|
162
- | Text / Password | `nmf-text` | `nmf-mat-text` | Supports multiple input types including password with visibility toggle |
163
- | Number | `nmf-number` | `nmf-mat-number` | Numeric input with type-safe value handling |
164
- | Currency | `nmf-currency` | `nmf-mat-currency` | Formatted currency input with parsing and display formatting |
165
- | Date | `nmf-datepicker` | `nmf-mat-datepicker` | Date selection with native or Angular Material datepicker UI |
166
- | Time | `nmf-timepicker` | `nmf-mat-timepicker` | Time input with structured formatting |
167
- | Select | `nmf-select` | `nmf-mat-select` | Dropdown/select with support for disabled options |
168
- | Textarea | `nmf-textarea` | `nmf-mat-textarea` | Multi-line text input with configurable rows |
78
+ | Input Type | Native Selector | Material Selector |
79
+ |-----------------|----------------------|-----------------------|
80
+ | Text / Password | `nmf-text` | `nmf-mat-text` |
81
+ | Number | `nmf-number` | `nmf-mat-number` |
82
+ | Currency | `nmf-currency` | `nmf-mat-currency` |
83
+ | Date | `nmf-datepicker` | `nmf-mat-datepicker` |
84
+ | Time | `nmf-timepicker` | `nmf-mat-timepicker` |
85
+ | Select | `nmf-select` | `nmf-mat-select` |
86
+ | Textarea | `nmf-textarea` | `nmf-mat-textarea` |
169
87
 
170
88
  ### Shared Features
171
89
 
172
- - Implements `ControlValueAccessor`
173
- - Fully compatible with Angular Reactive Forms
174
- - Consistent API across all inputs
175
- - Built-in validation state + error messaging
176
- - Label, required indicator, and loading state support
177
- - Behavior-driven input handling (formatting, parsing, restrictions)
90
+ - **CVA Compatible:** Works with formControlName.
91
+ - **Behavior-Driven:** Reusable logic for masking, parsing, and restrictions.
92
+ - **Validation:** Integrated error messaging and state handling.
178
93
 
179
94
  ## License
180
95
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ng-modular-forms/core",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "Core primitives, behaviors, and input components for orchestrating complex Angular reactive forms.",
5
5
  "keywords": [
6
6
  "angular",
@@ -15,7 +15,7 @@
15
15
  "input-components",
16
16
  "ng-modular-forms"
17
17
  ],
18
- "homepage": "https://github.com/ronbodnar/ng-modular-forms",
18
+ "homepage": "https://ngmf.ronbodnar.com",
19
19
  "repository": {
20
20
  "type": "git",
21
21
  "url": "https://github.com/ronbodnar/ng-modular-forms.git"