create-claude-workspace 1.1.69 → 1.1.70

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.
@@ -148,6 +148,53 @@ export class ProjectDetail {
148
148
  - WebSocket/SSE streams — use dedicated services
149
149
  - Non-HTTP async — use `resource()` instead
150
150
 
151
+ ## Forms — Signal Forms API
152
+
153
+ Use the **signal-based forms API** (`@angular/forms/signals`) for all form handling when available in the project's Angular version (stable or experimental). NEVER use legacy `FormControl`/`FormGroup`/`FormBuilder`/`ReactiveFormsModule`.
154
+
155
+ **Signal forms pattern:**
156
+ ```typescript
157
+ import { Component, signal } from '@angular/core';
158
+ import { form, FormField, required, email, minLength } from '@angular/forms/signals';
159
+
160
+ @Component({
161
+ imports: [FormField],
162
+ template: `
163
+ <input type="email" [formField]="loginForm.email" />
164
+ <input type="password" [formField]="loginForm.password" />
165
+ <button [disabled]="loginForm.invalid()">Submit</button>
166
+ `,
167
+ })
168
+ export class LoginForm {
169
+ readonly loginModel = signal({ email: '', password: '' });
170
+ readonly loginForm = form(this.loginModel, (schema) => {
171
+ required(schema.email);
172
+ email(schema.email);
173
+ required(schema.password);
174
+ minLength(schema.password, 8);
175
+ });
176
+
177
+ // Field state is signal-based:
178
+ // this.loginForm.email().value() — current value (signal)
179
+ // this.loginForm.email().dirty() — boolean signal
180
+ // this.loginForm.email().invalid() — boolean signal
181
+ // this.loginForm.email().value.set('new@email.com') — update programmatically
182
+ }
183
+ ```
184
+
185
+ **Key rules:**
186
+ - `form()` function with a signal model — form structure derived from model shape
187
+ - Validators from `@angular/forms/signals`: `required()`, `email()`, `minLength()`, `maxLength()`, `min()`, `max()`, `pattern()`
188
+ - Template binding via `[formField]` directive (import `FormField`)
189
+ - All field state (value, dirty, invalid, disabled) is signal-based — bind directly in templates
190
+ - No `.valueChanges` subscriptions — state is already reactive
191
+
192
+ **NEVER:**
193
+ - `new FormControl()` / `new FormGroup()` / `new FormArray()` / `FormBuilder` — use `form()` with signal model
194
+ - `ReactiveFormsModule` / `FormsModule` — use `FormField` directive from `@angular/forms/signals`
195
+ - `.valueChanges.subscribe()` — field state is already reactive via signals
196
+ - Wrapping validators in arrow functions (`control => Validators.required(control)`)
197
+
151
198
  ## Templates — MINIMAL Logic
152
199
 
153
200
  - ZERO method calls in templates — wrap in `computed()`, bind the signal
@@ -343,6 +390,7 @@ describe('CardBadge', () => {
343
390
 
344
391
  When reviewing Angular code, check:
345
392
  - Signal usage: signal/computed/input/output/model correctly used
393
+ - Forms: SignalFormBuilder used (no legacy FormControl/FormGroup/FormBuilder)
346
394
  - ZERO method calls in templates — all derived state in computed()
347
395
  - Feature vs dumb separation — no inject() in ui/ components
348
396
  - Content projection (composite pattern) over deep @Input trees
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-claude-workspace",
3
- "version": "1.1.69",
3
+ "version": "1.1.70",
4
4
  "description": "Scaffold a project with Claude Code agents for autonomous AI-driven development",
5
5
  "type": "module",
6
6
  "bin": {