@smicolon/ai-kit 0.0.1 → 0.1.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 (163) hide show
  1. package/.claude-plugin/CLAUDE.md +7 -0
  2. package/.claude-plugin/marketplace.json +373 -0
  3. package/README.md +132 -0
  4. package/package.json +13 -3
  5. package/packs/architect/CHANGELOG.md +17 -0
  6. package/packs/architect/README.md +58 -0
  7. package/packs/architect/agents/system-architect.md +768 -0
  8. package/packs/architect/commands/diagram-create.md +300 -0
  9. package/packs/better-auth/.claude-plugin/plugin.json +14 -0
  10. package/packs/better-auth/.mcp.json +14 -0
  11. package/packs/better-auth/CHANGELOG.md +26 -0
  12. package/packs/better-auth/README.md +125 -0
  13. package/packs/better-auth/agents/auth-architect.md +278 -0
  14. package/packs/better-auth/commands/auth-provider-add.md +265 -0
  15. package/packs/better-auth/commands/auth-setup.md +298 -0
  16. package/packs/better-auth/skills/auth-security/SKILL.md +425 -0
  17. package/packs/better-auth/skills/better-auth-patterns/SKILL.md +455 -0
  18. package/packs/dev-loop/.claude-plugin/plugin.json +10 -0
  19. package/packs/dev-loop/CHANGELOG.md +69 -0
  20. package/packs/dev-loop/README.md +155 -0
  21. package/packs/dev-loop/commands/cancel-dev.md +21 -0
  22. package/packs/dev-loop/commands/dev-loop.md +72 -0
  23. package/packs/dev-loop/commands/dev-plan.md +351 -0
  24. package/packs/dev-loop/hooks/hooks.json +15 -0
  25. package/packs/dev-loop/hooks/stop-hook.sh +178 -0
  26. package/packs/dev-loop/scripts/setup-dev-loop.sh +194 -0
  27. package/packs/dev-loop/skills/tdd-planner/SKILL.md +249 -0
  28. package/packs/dev-loop/skills/tdd-planner/references/framework-patterns.md +874 -0
  29. package/packs/dev-loop/skills/tdd-planner/references/good-example.md +260 -0
  30. package/packs/dev-loop/skills/tdd-planner/references/plan-template.md +275 -0
  31. package/packs/django/CHANGELOG.md +39 -0
  32. package/packs/django/README.md +92 -0
  33. package/packs/django/agents/django-architect.md +182 -0
  34. package/packs/django/agents/django-builder.md +250 -0
  35. package/packs/django/agents/django-feature-based.md +420 -0
  36. package/packs/django/agents/django-reviewer.md +253 -0
  37. package/packs/django/agents/django-tester.md +230 -0
  38. package/packs/django/commands/api-endpoint.md +285 -0
  39. package/packs/django/commands/model-create.md +178 -0
  40. package/packs/django/commands/test-generate.md +325 -0
  41. package/packs/django/rules/migrations.md +138 -0
  42. package/packs/django/rules/models.md +167 -0
  43. package/packs/django/rules/serializers.md +126 -0
  44. package/packs/django/rules/services.md +131 -0
  45. package/packs/django/rules/tests.md +140 -0
  46. package/packs/django/rules/views.md +102 -0
  47. package/packs/django/skills/import-convention-enforcer/SKILL.md +226 -0
  48. package/packs/django/skills/import-convention-enforcer/patterns/django-imports.md +343 -0
  49. package/packs/django/skills/migration-safety-checker/SKILL.md +375 -0
  50. package/packs/django/skills/model-entity-validator/SKILL.md +298 -0
  51. package/packs/django/skills/performance-optimizer/SKILL.md +447 -0
  52. package/packs/django/skills/red-phase-verifier/SKILL.md +180 -0
  53. package/packs/django/skills/security-first-validator/SKILL.md +435 -0
  54. package/packs/django/skills/test-coverage-advisor/SKILL.md +394 -0
  55. package/packs/django/skills/test-validity-checker/SKILL.md +194 -0
  56. package/packs/failure-log/.claude-plugin/plugin.json +14 -0
  57. package/packs/failure-log/CHANGELOG.md +20 -0
  58. package/packs/failure-log/README.md +168 -0
  59. package/packs/failure-log/commands/failure-add.md +106 -0
  60. package/packs/failure-log/commands/failure-list.md +89 -0
  61. package/packs/failure-log/hooks/hooks.json +16 -0
  62. package/packs/failure-log/hooks/scripts/inject-failures.sh +64 -0
  63. package/packs/failure-log/skills/failure-log-manager/SKILL.md +164 -0
  64. package/packs/flutter/.claude-plugin/plugin.json +10 -0
  65. package/packs/flutter/CHANGELOG.md +19 -0
  66. package/packs/flutter/README.md +170 -0
  67. package/packs/flutter/agents/flutter-architect.md +166 -0
  68. package/packs/flutter/agents/flutter-builder.md +303 -0
  69. package/packs/flutter/agents/release-manager.md +355 -0
  70. package/packs/flutter/commands/fastlane-setup.md +188 -0
  71. package/packs/flutter/commands/flutter-build.md +90 -0
  72. package/packs/flutter/commands/flutter-deploy.md +133 -0
  73. package/packs/flutter/commands/flutter-test.md +117 -0
  74. package/packs/flutter/commands/signing-setup.md +209 -0
  75. package/packs/flutter/hooks/hooks.json +17 -0
  76. package/packs/flutter/skills/fastlane-knowledge/SKILL.md +193 -0
  77. package/packs/flutter/skills/flutter-architecture/SKILL.md +127 -0
  78. package/packs/flutter/skills/store-publishing/SKILL.md +163 -0
  79. package/packs/hono/.claude-plugin/plugin.json +19 -0
  80. package/packs/hono/CHANGELOG.md +19 -0
  81. package/packs/hono/README.md +143 -0
  82. package/packs/hono/agents/hono-architect.md +240 -0
  83. package/packs/hono/agents/hono-builder.md +285 -0
  84. package/packs/hono/agents/hono-reviewer.md +279 -0
  85. package/packs/hono/agents/hono-tester.md +346 -0
  86. package/packs/hono/commands/middleware-create.md +223 -0
  87. package/packs/hono/commands/project-init.md +306 -0
  88. package/packs/hono/commands/route-create.md +153 -0
  89. package/packs/hono/commands/rpc-client.md +263 -0
  90. package/packs/hono/hooks/hooks.json +4 -0
  91. package/packs/hono/skills/cloudflare-bindings/SKILL.md +408 -0
  92. package/packs/hono/skills/hono-patterns/SKILL.md +309 -0
  93. package/packs/hono/skills/rpc-typesafe/SKILL.md +388 -0
  94. package/packs/hono/skills/zod-validation/SKILL.md +332 -0
  95. package/packs/nestjs/CHANGELOG.md +29 -0
  96. package/packs/nestjs/README.md +75 -0
  97. package/packs/nestjs/agents/nestjs-architect.md +402 -0
  98. package/packs/nestjs/agents/nestjs-builder.md +301 -0
  99. package/packs/nestjs/agents/nestjs-tester.md +437 -0
  100. package/packs/nestjs/commands/module-create.md +369 -0
  101. package/packs/nestjs/rules/controllers.md +92 -0
  102. package/packs/nestjs/rules/dto.md +124 -0
  103. package/packs/nestjs/rules/entities.md +102 -0
  104. package/packs/nestjs/rules/services.md +106 -0
  105. package/packs/nestjs/skills/barrel-export-manager/SKILL.md +389 -0
  106. package/packs/nestjs/skills/import-convention-enforcer/SKILL.md +365 -0
  107. package/packs/nextjs/CHANGELOG.md +36 -0
  108. package/packs/nextjs/README.md +76 -0
  109. package/packs/nextjs/agents/frontend-tester.md +680 -0
  110. package/packs/nextjs/agents/frontend-visual.md +820 -0
  111. package/packs/nextjs/agents/nextjs-architect.md +331 -0
  112. package/packs/nextjs/agents/nextjs-modular.md +433 -0
  113. package/packs/nextjs/commands/component-create.md +398 -0
  114. package/packs/nextjs/rules/api-routes.md +129 -0
  115. package/packs/nextjs/rules/components.md +106 -0
  116. package/packs/nextjs/rules/hooks.md +132 -0
  117. package/packs/nextjs/skills/accessibility-validator/SKILL.md +445 -0
  118. package/packs/nextjs/skills/import-convention-enforcer/SKILL.md +399 -0
  119. package/packs/nextjs/skills/react-form-validator/SKILL.md +569 -0
  120. package/packs/nuxtjs/CHANGELOG.md +30 -0
  121. package/packs/nuxtjs/README.md +56 -0
  122. package/packs/nuxtjs/agents/frontend-tester.md +680 -0
  123. package/packs/nuxtjs/agents/frontend-visual.md +820 -0
  124. package/packs/nuxtjs/agents/nuxtjs-architect.md +537 -0
  125. package/packs/nuxtjs/commands/component-create.md +223 -0
  126. package/packs/nuxtjs/rules/components.md +101 -0
  127. package/packs/nuxtjs/rules/composables.md +118 -0
  128. package/packs/nuxtjs/rules/server-routes.md +127 -0
  129. package/packs/nuxtjs/skills/accessibility-validator/SKILL.md +183 -0
  130. package/packs/nuxtjs/skills/import-convention-enforcer/SKILL.md +196 -0
  131. package/packs/nuxtjs/skills/veevalidate-form-validator/SKILL.md +190 -0
  132. package/packs/onboard/CHANGELOG.md +22 -0
  133. package/packs/onboard/README.md +103 -0
  134. package/packs/onboard/agents/onboard-guide.md +118 -0
  135. package/packs/onboard/commands/onboard.md +313 -0
  136. package/packs/onboard/skills/onboard-context-provider/SKILL.md +98 -0
  137. package/packs/tanstack-router/.claude-plugin/plugin.json +14 -0
  138. package/packs/tanstack-router/CHANGELOG.md +30 -0
  139. package/packs/tanstack-router/README.md +113 -0
  140. package/packs/tanstack-router/agents/tanstack-architect.md +173 -0
  141. package/packs/tanstack-router/agents/tanstack-builder.md +360 -0
  142. package/packs/tanstack-router/agents/tanstack-tester.md +454 -0
  143. package/packs/tanstack-router/commands/form-create.md +313 -0
  144. package/packs/tanstack-router/commands/query-create.md +263 -0
  145. package/packs/tanstack-router/commands/route-create.md +190 -0
  146. package/packs/tanstack-router/commands/table-create.md +413 -0
  147. package/packs/tanstack-router/skills/ai-patterns/SKILL.md +370 -0
  148. package/packs/tanstack-router/skills/db-patterns/SKILL.md +346 -0
  149. package/packs/tanstack-router/skills/devtools-patterns/SKILL.md +415 -0
  150. package/packs/tanstack-router/skills/form-patterns/SKILL.md +425 -0
  151. package/packs/tanstack-router/skills/pacer-patterns/SKILL.md +341 -0
  152. package/packs/tanstack-router/skills/query-patterns/SKILL.md +359 -0
  153. package/packs/tanstack-router/skills/router-patterns/SKILL.md +285 -0
  154. package/packs/tanstack-router/skills/store-patterns/SKILL.md +351 -0
  155. package/packs/tanstack-router/skills/table-patterns/SKILL.md +531 -0
  156. package/packs/tanstack-router/skills/tanstack-conventions/SKILL.md +428 -0
  157. package/packs/tanstack-router/skills/virtual-patterns/SKILL.md +490 -0
  158. package/packs/worktree/.claude-plugin/plugin.json +19 -0
  159. package/packs/worktree/CHANGELOG.md +24 -0
  160. package/packs/worktree/README.md +110 -0
  161. package/packs/worktree/commands/wt.md +73 -0
  162. package/packs/worktree/scripts/wt.sh +396 -0
  163. package/packs/worktree/skills/worktree-manager/SKILL.md +68 -0
@@ -0,0 +1,425 @@
1
+ ---
2
+ name: TanStack Form Patterns
3
+ description: >-
4
+ Auto-enforce TanStack Form best practices with Zod validation. Activates when
5
+ creating forms, handling form state, implementing validation, or building
6
+ input components in React applications.
7
+ version: 1.0.0
8
+ ---
9
+
10
+ # TanStack Form Patterns
11
+
12
+ This skill enforces TanStack Form best practices for type-safe forms with Zod validation.
13
+
14
+ ## Basic Form Setup
15
+
16
+ ```typescript
17
+ import { useForm } from '@tanstack/react-form'
18
+ import { zodValidator } from '@tanstack/zod-form-adapter'
19
+ import { z } from 'zod'
20
+
21
+ const postSchema = z.object({
22
+ title: z.string().min(3, 'Title must be at least 3 characters'),
23
+ content: z.string().min(10, 'Content must be at least 10 characters'),
24
+ published: z.boolean().default(false),
25
+ tags: z.array(z.string()).min(1, 'At least one tag required'),
26
+ })
27
+
28
+ type PostFormData = z.infer<typeof postSchema>
29
+
30
+ export function PostForm({ onSubmit }: { onSubmit: (data: PostFormData) => void }) {
31
+ const form = useForm({
32
+ defaultValues: {
33
+ title: '',
34
+ content: '',
35
+ published: false,
36
+ tags: [],
37
+ } satisfies PostFormData,
38
+ onSubmit: async ({ value }) => {
39
+ onSubmit(value)
40
+ },
41
+ validatorAdapter: zodValidator(),
42
+ validators: {
43
+ onChange: postSchema,
44
+ },
45
+ })
46
+
47
+ return (
48
+ <form
49
+ onSubmit={(e) => {
50
+ e.preventDefault()
51
+ form.handleSubmit()
52
+ }}
53
+ >
54
+ {/* Form fields */}
55
+ </form>
56
+ )
57
+ }
58
+ ```
59
+
60
+ ## Field Components
61
+
62
+ ### Text Input Field
63
+ ```typescript
64
+ <form.Field
65
+ name="title"
66
+ children={(field) => (
67
+ <div className="field">
68
+ <label htmlFor={field.name}>Title</label>
69
+ <input
70
+ id={field.name}
71
+ name={field.name}
72
+ value={field.state.value}
73
+ onChange={(e) => field.handleChange(e.target.value)}
74
+ onBlur={field.handleBlur}
75
+ aria-invalid={field.state.meta.errors.length > 0}
76
+ aria-describedby={`${field.name}-error`}
77
+ />
78
+ {field.state.meta.isTouched && field.state.meta.errors.length > 0 && (
79
+ <span id={`${field.name}-error`} className="error">
80
+ {field.state.meta.errors[0]}
81
+ </span>
82
+ )}
83
+ </div>
84
+ )}
85
+ />
86
+ ```
87
+
88
+ ### Textarea Field
89
+ ```typescript
90
+ <form.Field
91
+ name="content"
92
+ children={(field) => (
93
+ <div className="field">
94
+ <label htmlFor={field.name}>Content</label>
95
+ <textarea
96
+ id={field.name}
97
+ name={field.name}
98
+ value={field.state.value}
99
+ onChange={(e) => field.handleChange(e.target.value)}
100
+ onBlur={field.handleBlur}
101
+ rows={5}
102
+ />
103
+ {field.state.meta.isTouched && field.state.meta.errors.length > 0 && (
104
+ <span className="error">{field.state.meta.errors[0]}</span>
105
+ )}
106
+ </div>
107
+ )}
108
+ />
109
+ ```
110
+
111
+ ### Checkbox Field
112
+ ```typescript
113
+ <form.Field
114
+ name="published"
115
+ children={(field) => (
116
+ <div className="field-checkbox">
117
+ <input
118
+ id={field.name}
119
+ type="checkbox"
120
+ checked={field.state.value}
121
+ onChange={(e) => field.handleChange(e.target.checked)}
122
+ />
123
+ <label htmlFor={field.name}>Published</label>
124
+ </div>
125
+ )}
126
+ />
127
+ ```
128
+
129
+ ### Select Field
130
+ ```typescript
131
+ <form.Field
132
+ name="category"
133
+ children={(field) => (
134
+ <div className="field">
135
+ <label htmlFor={field.name}>Category</label>
136
+ <select
137
+ id={field.name}
138
+ value={field.state.value}
139
+ onChange={(e) => field.handleChange(e.target.value)}
140
+ onBlur={field.handleBlur}
141
+ >
142
+ <option value="">Select category...</option>
143
+ <option value="tech">Technology</option>
144
+ <option value="business">Business</option>
145
+ <option value="lifestyle">Lifestyle</option>
146
+ </select>
147
+ </div>
148
+ )}
149
+ />
150
+ ```
151
+
152
+ ## Array Fields
153
+
154
+ ```typescript
155
+ const tagsSchema = z.array(z.string().min(1)).min(1, 'At least one tag')
156
+
157
+ <form.Field
158
+ name="tags"
159
+ mode="array"
160
+ children={(field) => (
161
+ <div className="field">
162
+ <label>Tags</label>
163
+ {field.state.value.map((_, index) => (
164
+ <div key={index} className="tag-input">
165
+ <form.Field
166
+ name={`tags[${index}]`}
167
+ children={(tagField) => (
168
+ <input
169
+ value={tagField.state.value}
170
+ onChange={(e) => tagField.handleChange(e.target.value)}
171
+ />
172
+ )}
173
+ />
174
+ <button
175
+ type="button"
176
+ onClick={() => field.removeValue(index)}
177
+ >
178
+ Remove
179
+ </button>
180
+ </div>
181
+ ))}
182
+ <button
183
+ type="button"
184
+ onClick={() => field.pushValue('')}
185
+ >
186
+ Add Tag
187
+ </button>
188
+ {field.state.meta.errors.length > 0 && (
189
+ <span className="error">{field.state.meta.errors[0]}</span>
190
+ )}
191
+ </div>
192
+ )}
193
+ />
194
+ ```
195
+
196
+ ## Async Validation
197
+
198
+ ```typescript
199
+ const usernameSchema = z.string().min(3)
200
+
201
+ <form.Field
202
+ name="username"
203
+ validators={{
204
+ onChange: usernameSchema,
205
+ onChangeAsyncDebounceMs: 500,
206
+ onChangeAsync: async ({ value }) => {
207
+ const exists = await checkUsernameExists(value)
208
+ if (exists) {
209
+ return 'Username already taken'
210
+ }
211
+ return undefined
212
+ },
213
+ }}
214
+ children={(field) => (
215
+ <div className="field">
216
+ <label htmlFor={field.name}>Username</label>
217
+ <input
218
+ id={field.name}
219
+ value={field.state.value}
220
+ onChange={(e) => field.handleChange(e.target.value)}
221
+ onBlur={field.handleBlur}
222
+ />
223
+ {field.state.meta.isValidating && <span>Checking...</span>}
224
+ {field.state.meta.errors.length > 0 && (
225
+ <span className="error">{field.state.meta.errors[0]}</span>
226
+ )}
227
+ </div>
228
+ )}
229
+ />
230
+ ```
231
+
232
+ ## Form with Mutation
233
+
234
+ ```typescript
235
+ import { useCreatePost } from '@/features/posts/hooks'
236
+
237
+ export function CreatePostForm() {
238
+ const createPost = useCreatePost()
239
+
240
+ const form = useForm({
241
+ defaultValues: { title: '', content: '', published: false },
242
+ onSubmit: async ({ value }) => {
243
+ await createPost.mutateAsync(value)
244
+ },
245
+ validatorAdapter: zodValidator(),
246
+ validators: {
247
+ onChange: postSchema,
248
+ },
249
+ })
250
+
251
+ return (
252
+ <form onSubmit={(e) => { e.preventDefault(); form.handleSubmit() }}>
253
+ {/* Fields */}
254
+ <form.Subscribe
255
+ selector={(state) => [state.canSubmit, state.isSubmitting]}
256
+ children={([canSubmit, isSubmitting]) => (
257
+ <button type="submit" disabled={!canSubmit || isSubmitting}>
258
+ {isSubmitting ? 'Creating...' : 'Create Post'}
259
+ </button>
260
+ )}
261
+ />
262
+ {createPost.isError && (
263
+ <div className="error">{createPost.error.message}</div>
264
+ )}
265
+ </form>
266
+ )
267
+ }
268
+ ```
269
+
270
+ ## Edit Form with Initial Data
271
+
272
+ ```typescript
273
+ interface EditPostFormProps {
274
+ post: Post
275
+ onSuccess: () => void
276
+ }
277
+
278
+ export function EditPostForm({ post, onSuccess }: EditPostFormProps) {
279
+ const updatePost = useUpdatePost()
280
+
281
+ const form = useForm({
282
+ defaultValues: {
283
+ title: post.title,
284
+ content: post.content,
285
+ published: post.published,
286
+ },
287
+ onSubmit: async ({ value }) => {
288
+ await updatePost.mutateAsync({ id: post.id, ...value })
289
+ onSuccess()
290
+ },
291
+ validatorAdapter: zodValidator(),
292
+ validators: {
293
+ onChange: postSchema,
294
+ },
295
+ })
296
+
297
+ return (
298
+ <form onSubmit={(e) => { e.preventDefault(); form.handleSubmit() }}>
299
+ {/* Fields */}
300
+ </form>
301
+ )
302
+ }
303
+ ```
304
+
305
+ ## Reusable Field Component
306
+
307
+ ```typescript
308
+ // components/ui/FormField.tsx
309
+ import type { FieldApi } from '@tanstack/react-form'
310
+
311
+ interface FormFieldProps<T> {
312
+ field: FieldApi<any, any, any, any, T>
313
+ label: string
314
+ type?: 'text' | 'email' | 'password' | 'textarea'
315
+ }
316
+
317
+ export function FormField<T extends string>({
318
+ field,
319
+ label,
320
+ type = 'text',
321
+ }: FormFieldProps<T>) {
322
+ const hasError = field.state.meta.isTouched && field.state.meta.errors.length > 0
323
+
324
+ const inputProps = {
325
+ id: field.name,
326
+ name: field.name,
327
+ value: field.state.value,
328
+ onChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) =>
329
+ field.handleChange(e.target.value as T),
330
+ onBlur: field.handleBlur,
331
+ 'aria-invalid': hasError,
332
+ 'aria-describedby': hasError ? `${field.name}-error` : undefined,
333
+ }
334
+
335
+ return (
336
+ <div className="form-field">
337
+ <label htmlFor={field.name}>{label}</label>
338
+ {type === 'textarea' ? (
339
+ <textarea {...inputProps} />
340
+ ) : (
341
+ <input type={type} {...inputProps} />
342
+ )}
343
+ {hasError && (
344
+ <span id={`${field.name}-error`} className="error" role="alert">
345
+ {field.state.meta.errors[0]}
346
+ </span>
347
+ )}
348
+ </div>
349
+ )
350
+ }
351
+ ```
352
+
353
+ ## Form State Subscription
354
+
355
+ ```typescript
356
+ // Subscribe to specific form state
357
+ <form.Subscribe
358
+ selector={(state) => ({
359
+ canSubmit: state.canSubmit,
360
+ isSubmitting: state.isSubmitting,
361
+ isDirty: state.isDirty,
362
+ errors: state.errors,
363
+ })}
364
+ children={({ canSubmit, isSubmitting, isDirty, errors }) => (
365
+ <div>
366
+ {isDirty && <span>Unsaved changes</span>}
367
+ {errors.length > 0 && <span>Form has errors</span>}
368
+ <button type="submit" disabled={!canSubmit || isSubmitting}>
369
+ {isSubmitting ? 'Saving...' : 'Save'}
370
+ </button>
371
+ </div>
372
+ )}
373
+ />
374
+ ```
375
+
376
+ ## Conventions to Enforce
377
+
378
+ 1. **Zod for validation** - Always use `zodValidator()` adapter
379
+ 2. **Type inference** - Use `z.infer<typeof schema>` for form types
380
+ 3. **Accessible forms** - Include labels, aria attributes, error associations
381
+ 4. **Touch-based errors** - Show errors only after field interaction
382
+ 5. **Submit handling** - Prevent default, use `form.handleSubmit()`
383
+ 6. **Mutation integration** - Connect forms to TanStack Query mutations
384
+ 7. **Default values** - Always provide with `satisfies` type check
385
+
386
+ ## Anti-Patterns to Block
387
+
388
+ ```typescript
389
+ // ❌ WRONG: No validation
390
+ const form = useForm({
391
+ defaultValues: { title: '' },
392
+ onSubmit: ({ value }) => save(value),
393
+ })
394
+
395
+ // ✅ CORRECT: Zod validation
396
+ const form = useForm({
397
+ defaultValues: { title: '' },
398
+ validatorAdapter: zodValidator(),
399
+ validators: { onChange: schema },
400
+ onSubmit: ({ value }) => save(value),
401
+ })
402
+
403
+ // ❌ WRONG: Missing error display
404
+ <input value={field.state.value} onChange={(e) => field.handleChange(e.target.value)} />
405
+
406
+ // ✅ CORRECT: Error handling
407
+ <input
408
+ value={field.state.value}
409
+ onChange={(e) => field.handleChange(e.target.value)}
410
+ aria-invalid={field.state.meta.errors.length > 0}
411
+ />
412
+ {field.state.meta.errors[0] && <span className="error">{field.state.meta.errors[0]}</span>}
413
+
414
+ // ❌ WRONG: No accessibility
415
+ <div>
416
+ <span>Email</span>
417
+ <input />
418
+ </div>
419
+
420
+ // ✅ CORRECT: Proper labeling
421
+ <div>
422
+ <label htmlFor="email">Email</label>
423
+ <input id="email" aria-describedby="email-error" />
424
+ </div>
425
+ ```