@signaltree/ng-forms 4.1.2 → 4.1.4

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 (3) hide show
  1. package/README.md +136 -24
  2. package/package.json +3 -3
  3. package/LICENSE +0 -54
package/README.md CHANGED
@@ -1,16 +1,89 @@
1
1
  # @signaltree/ng-forms
2
2
 
3
- Angular 20 signal forms meet SignalTree. `@signaltree/ng-forms` keeps your form state, validation, persistence, and wizard flows in sync with the rest of your application signals—no manual plumbing.
3
+ **Tree-structured signal forms for Angular 21+**. When Angular's native signal forms aren't enough—add persistence, wizards, history tracking, and nested state management.
4
4
 
5
5
  **Bundle size: 3.38KB gzipped**
6
6
 
7
+ ## Why ng-forms?
8
+
9
+ Angular 21 introduced native signal forms with `FormField<T>`, which work great for simple, flat forms. **ng-forms is for complex forms** that need:
10
+
11
+ ### **🌲 Tree-Structured State**
12
+ ```typescript
13
+ // Angular 21: Flat fields, no relationships
14
+ const name = formField('');
15
+ const email = formField('');
16
+
17
+ // ng-forms: Hierarchical structure that mirrors your data model
18
+ const form = createFormTree({
19
+ user: { name: '', email: '' },
20
+ address: { street: '', city: '', zip: '' }
21
+ });
22
+ // Access nested: form.$.user.name()
23
+ // Validate paths: 'address.zip'
24
+ ```
25
+
26
+ ### **💾 Auto-Persistence**
27
+ ```typescript
28
+ // Angular 21: No persistence, build it yourself
29
+ // ng-forms: Built-in with debouncing
30
+ const form = createFormTree(initialState, {
31
+ persistKey: 'checkout-draft',
32
+ storage: localStorage,
33
+ persistDebounceMs: 500
34
+ });
35
+ // Auto-saves changes, restores on init
36
+ ```
37
+
38
+ ### **🧙 Wizard & Multi-Step Forms**
39
+ ```typescript
40
+ // Angular 21: Build from scratch
41
+ // ng-forms: First-class wizard support
42
+ const wizard = createWizardForm([
43
+ { fields: ['profile.name', 'profile.email'] },
44
+ { fields: ['address.street', 'address.city'] }
45
+ ], initialValues);
46
+ wizard.nextStep(); // Automatic field visibility management
47
+ ```
48
+
49
+ ### **↩️ History / Undo-Redo**
50
+ ```typescript
51
+ // Angular 21: Not available
52
+ // ng-forms: Built-in
53
+ const form = withFormHistory(createFormTree(initialState));
54
+ form.undo();
55
+ form.redo();
56
+ ```
57
+
58
+ ### **🔗 Reactive Forms Bridge**
59
+ ```typescript
60
+ // Angular 21: New API, migration required
61
+ // ng-forms: Works with existing FormGroup/FormControl
62
+ <form [formGroup]="profile.form" (ngSubmit)="save()">
63
+ <input formControlName="name" />
64
+ </form>
65
+ // Signals AND reactive forms, incremental migration
66
+ ```
67
+
68
+ ### **⚙️ Declarative Configuration**
69
+ ```typescript
70
+ // Angular 21: Per-field imperative setup
71
+ // ng-forms: Centralized, glob-pattern configs
72
+ fieldConfigs: {
73
+ 'email': { validators: [validators.email()], debounceMs: 300 },
74
+ 'payment.card.*': { validators: validators.required() }
75
+ }
76
+ ```
77
+
78
+ **Use Angular 21 signal forms for simple forms. Use ng-forms for enterprise apps with complex state, persistence, and workflow requirements.**
79
+
7
80
  ## Installation
8
81
 
9
82
  ```bash
10
83
  pnpm add @signaltree/core @signaltree/ng-forms
11
84
  ```
12
85
 
13
- > This package supports Angular 17+ with TypeScript 5.5+. Angular 17-19 support uses a legacy bridge that will be deprecated when Angular 21 is released. For the best experience, upgrade to Angular 20.3+ to use native Signal Forms.
86
+ > **Compatibility**: Angular 17+ with TypeScript 5.5+. Angular 21+ recommended for best experience. Works alongside Angular's native signal forms—use both where appropriate.
14
87
 
15
88
  ## Quick start
16
89
 
@@ -97,30 +170,58 @@ The returned `FormTree` exposes:
97
170
  - **Signal ↔ Observable bridge**: Convert signals to RxJS streams for interoperability
98
171
  - **Template-driven adapter**: `SignalValueDirective` bridges standalone signals with `ngModel`
99
172
 
100
- ## Signal Forms (Angular 20+)
173
+ ## Angular 21 Interoperability
101
174
 
102
- `@signaltree/ng-forms` now prefers Angular's experimental Signal Forms `connect()` API when available.
175
+ **ng-forms complements Angular 21's native signal forms**—use both in the same app:
103
176
 
104
- - Leaves in a SignalTree are native `WritableSignal<T>` and can be connected directly
105
- - For object slices, convert to a `WritableSignal<T>` via `toWritableSignal()` from `@signaltree/core`
177
+ ### Use Angular 21 `FormField<T>` for:
178
+ - Simple, flat forms (login, search)
179
+ - ✅ Single-field validation
180
+ - ✅ Maximum type safety
106
181
 
107
- ```ts
108
- import { toWritableSignal } from '@signaltree/core';
182
+ ### Use ng-forms `createFormTree()` for:
183
+ - Nested object structures (user + address + payment)
184
+ - ✅ Forms with persistence/auto-save
185
+ - ✅ Wizard/multi-step flows
186
+ - ✅ History/undo requirements
187
+ - ✅ Complex conditional logic
188
+ - ✅ Migration from reactive forms
109
189
 
110
- const values = createFormTree({
111
- user: { name: '', email: '' },
112
- });
113
-
114
- // Connect leaves directly
115
- nameControl.connect(values.$.user.name);
116
- emailControl.connect(values.$.user.email);
190
+ ### Hybrid Example: Simple Fields + Complex Tree
191
+ ```typescript
192
+ import { formField } from '@angular/forms';
193
+ import { createFormTree } from '@signaltree/ng-forms';
194
+
195
+ @Component({...})
196
+ class CheckoutComponent {
197
+ // Simple field: Use Angular 21 native
198
+ promoCode = formField('');
199
+
200
+ // Complex nested state: Use ng-forms
201
+ checkout = createFormTree({
202
+ shipping: { name: '', address: '', city: '', zip: '' },
203
+ payment: { card: '', cvv: '', expiry: '' },
204
+ items: [] as CartItem[]
205
+ }, {
206
+ persistKey: 'checkout-draft',
207
+ fieldConfigs: {
208
+ 'shipping.zip': { validators: validators.zipCode() },
209
+ 'payment.card': { validators: validators.creditCard(), debounceMs: 300 }
210
+ }
211
+ });
117
212
 
118
- // Or connect a whole slice
119
- const userSignal = toWritableSignal(values.values.$.user);
120
- userGroupControl.connect(userSignal);
213
+ // Both work together seamlessly
214
+ }
121
215
  ```
122
216
 
123
- Angular 20.3+ is preferred for native Signal Forms `connect()`. Angular 17-19 is supported via a legacy bridge that will be deprecated when Angular 21 is released.
217
+ ### Connecting to Reactive Forms
218
+ ```ts
219
+ import { toWritableSignal } from '@signaltree/core';
220
+
221
+ // Convert ng-forms signals to work with Angular's .connect()
222
+ const nameSignal = toWritableSignal(formTree.$.user.name);
223
+ reactiveControl.connect(nameSignal);
224
+ ```
124
225
 
125
226
  ## Form tree configuration
126
227
 
@@ -222,16 +323,27 @@ History tracking works at the FormGroup level so it plays nicely with external u
222
323
 
223
324
  Use `SignalValueDirective` to keep standalone signals and `ngModel` fields aligned in legacy sections while new pages migrate to forms-first APIs.
224
325
 
225
- ## When to reach for ng-forms
326
+ ## When to use ng-forms vs Angular 21 signal forms
327
+
328
+ | Scenario | Recommendation |
329
+ |----------|---------------|
330
+ | Login form (2-3 fields) | ✅ Angular 21 `FormField` |
331
+ | Search bar with filters | ✅ Angular 21 `FormField` |
332
+ | User profile with nested address | ✅ **ng-forms** (tree structure) |
333
+ | Checkout flow (shipping + payment + items) | ✅ **ng-forms** (persistence + wizard) |
334
+ | Multi-step onboarding (5+ steps) | ✅ **ng-forms** (wizard API) |
335
+ | Form with auto-save drafts | ✅ **ng-forms** (built-in persistence) |
336
+ | Complex editor with undo/redo | ✅ **ng-forms** (history tracking) |
337
+ | Migrating from reactive forms | ✅ **ng-forms** (FormGroup bridge) |
338
+ | Dynamic form with conditional fields | ✅ **ng-forms** (conditionals config) |
339
+ | Form synced with global app state | ✅ **ng-forms** (SignalTree integration) |
226
340
 
227
- - Complex Angular forms that need to remain in sync with SignalTree application state
228
- - Workflows that require persistence, auto-save, or offline drafts
229
- - Multi-step wizards or surveys with dynamic branching
230
- - Applications that benefit from first-class signal APIs around Angular forms
341
+ **Rule of thumb**: If your form data is a nested object or needs workflow features (persistence/wizards/history), use ng-forms. For simple flat forms, Angular 21's native signal forms are perfect.
231
342
 
232
343
  ## Links
233
344
 
234
345
  - [SignalTree Documentation](https://signaltree.io)
346
+ - [Angular 21 Migration Guide](./ANGULAR21-MIGRATION.md)
235
347
  - [Core Package](https://www.npmjs.com/package/@signaltree/core)
236
348
  - [GitHub Repository](https://github.com/JBorgia/signaltree)
237
349
  - [Demo Application](https://signaltree.io/examples)
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@signaltree/ng-forms",
3
- "version": "4.1.2",
3
+ "version": "4.1.4",
4
4
  "description": "Complete Angular forms integration for SignalTree. FormTree creation, custom directives, validators, form state tracking, and RxJS bridge.",
5
5
  "peerDependencies": {
6
6
  "@angular/core": "^20.3.0",
7
7
  "@angular/forms": "^20.3.0",
8
- "@signaltree/core": "4.1.2",
8
+ "@signaltree/core": "4.1.4",
9
9
  "rxjs": "^7.0.0"
10
10
  },
11
11
  "sideEffects": false,
@@ -43,4 +43,4 @@
43
43
  "dependencies": {
44
44
  "tslib": "^2.3.0"
45
45
  }
46
- }
46
+ }
package/LICENSE DELETED
@@ -1,54 +0,0 @@
1
- BUSINESS SOURCE LICENSE 1.1
2
-
3
- Copyright (c) 2025 Jonathan D Borgia
4
-
5
- This Business Source License 1.1 ("License") governs the use of the software and associated documentation files (the "Software"). You are granted a limited license to use the Software under the terms of this License.
6
-
7
- 1. Definitions
8
-
9
- "Change Date" means the date on which the Change License set out in section 6 will apply to the Software. The Change Date for this release is 2028-09-05.
10
-
11
- "Change License" means the open source license that will apply to the Software on and after the Change Date. The Change License for this release is the MIT License.
12
-
13
- "Licensor" means the copyright owner granting rights under this License (Jonathan D Borgia).
14
-
15
- "You" ("Licensee") means an individual or legal entity exercising rights under this License who has not violated the terms of this License or had their rights terminated.
16
-
17
- 2. License Grant
18
-
19
- Subject to the terms and conditions of this License, Licensor hereby grants You a non-exclusive, non-transferable, worldwide license to use, reproduce, display, perform, and distribute the Software, and to make modifications and derivative works for internal use, until the Change Date.
20
-
21
- 3. Commercial Use
22
-
23
- You may use the Software in commercial applications, including for providing services, selling products that include the Software, or otherwise exploiting the Software commercially, subject to the other terms of this License.
24
-
25
- 4. Limitations and Conditions
26
-
27
- a. You may not remove or alter this License, the copyright notice, or notices of the Change Date.
28
-
29
- b. You may not publicly offer a modified version of the Software that would directly compete with Licensor's public offering of the Software if doing so would circumvent the intent of this License.
30
-
31
- c. Except as expressly provided in this License, no rights are granted to You under any patent or trademark of Licensor.
32
-
33
- 5. Disclaimer and Limitation of Liability
34
-
35
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. TO THE FULLEST EXTENT PERMITTED BY LAW, LICENSOR WILL NOT BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM OR RELATING TO THE SOFTWARE.
36
-
37
- 6. Change License
38
-
39
- On and after the Change Date specified above, the Software will be licensed under the Change License (MIT License) on the same terms and conditions as set forth by that Change License.
40
-
41
- 7. Governing Law
42
-
43
- This License will be governed by and construed in accordance with the laws of the State of New York, USA, without regard to conflict of law principles.
44
-
45
- 8. Accepting this License
46
-
47
- You accept this License by copying, modifying, or distributing the Software or any portion thereof.
48
-
49
- ---
50
-
51
- LICENSE NOTE
52
-
53
- - Original license file replaced on 2025-09-05 to Business Source License 1.1. Change Date: 2028-09-05. Change License: MIT.
54
- or standard modifications for your own applications.