@smicolon/ai-kit 0.3.1 → 0.4.0
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.
- package/README.md +73 -40
- package/dist/index.js +260 -126
- package/package.json +5 -5
- package/.claude-plugin/marketplace.json +0 -373
- package/packs/architect/CHANGELOG.md +0 -17
- package/packs/architect/README.md +0 -58
- package/packs/architect/agents/system-architect.md +0 -768
- package/packs/architect/commands/diagram-create.md +0 -300
- package/packs/better-auth/.mcp.json +0 -14
- package/packs/better-auth/CHANGELOG.md +0 -26
- package/packs/better-auth/README.md +0 -125
- package/packs/better-auth/agents/auth-architect.md +0 -278
- package/packs/better-auth/commands/auth-provider-add.md +0 -265
- package/packs/better-auth/commands/auth-setup.md +0 -298
- package/packs/better-auth/skills/auth-security/SKILL.md +0 -425
- package/packs/better-auth/skills/better-auth-patterns/SKILL.md +0 -455
- package/packs/dev-loop/CHANGELOG.md +0 -69
- package/packs/dev-loop/README.md +0 -155
- package/packs/dev-loop/commands/cancel-dev.md +0 -21
- package/packs/dev-loop/commands/dev-loop.md +0 -72
- package/packs/dev-loop/commands/dev-plan.md +0 -351
- package/packs/dev-loop/hooks/hooks.json +0 -15
- package/packs/dev-loop/hooks/stop-hook.sh +0 -178
- package/packs/dev-loop/scripts/setup-dev-loop.sh +0 -194
- package/packs/dev-loop/skills/tdd-planner/SKILL.md +0 -249
- package/packs/dev-loop/skills/tdd-planner/references/framework-patterns.md +0 -874
- package/packs/dev-loop/skills/tdd-planner/references/good-example.md +0 -260
- package/packs/dev-loop/skills/tdd-planner/references/plan-template.md +0 -275
- package/packs/django/CHANGELOG.md +0 -39
- package/packs/django/README.md +0 -92
- package/packs/django/agents/django-architect.md +0 -182
- package/packs/django/agents/django-builder.md +0 -250
- package/packs/django/agents/django-feature-based.md +0 -420
- package/packs/django/agents/django-reviewer.md +0 -253
- package/packs/django/agents/django-tester.md +0 -230
- package/packs/django/commands/api-endpoint.md +0 -285
- package/packs/django/commands/model-create.md +0 -178
- package/packs/django/commands/test-generate.md +0 -325
- package/packs/django/rules/migrations.md +0 -138
- package/packs/django/rules/models.md +0 -167
- package/packs/django/rules/serializers.md +0 -126
- package/packs/django/rules/services.md +0 -131
- package/packs/django/rules/tests.md +0 -140
- package/packs/django/rules/views.md +0 -102
- package/packs/django/skills/import-convention-enforcer/SKILL.md +0 -226
- package/packs/django/skills/import-convention-enforcer/patterns/django-imports.md +0 -343
- package/packs/django/skills/migration-safety-checker/SKILL.md +0 -375
- package/packs/django/skills/model-entity-validator/SKILL.md +0 -298
- package/packs/django/skills/performance-optimizer/SKILL.md +0 -447
- package/packs/django/skills/red-phase-verifier/SKILL.md +0 -180
- package/packs/django/skills/security-first-validator/SKILL.md +0 -435
- package/packs/django/skills/test-coverage-advisor/SKILL.md +0 -394
- package/packs/django/skills/test-validity-checker/SKILL.md +0 -194
- package/packs/failure-log/CHANGELOG.md +0 -20
- package/packs/failure-log/README.md +0 -168
- package/packs/failure-log/commands/failure-add.md +0 -106
- package/packs/failure-log/commands/failure-list.md +0 -89
- package/packs/failure-log/hooks/hooks.json +0 -16
- package/packs/failure-log/hooks/scripts/inject-failures.sh +0 -64
- package/packs/failure-log/skills/failure-log-manager/SKILL.md +0 -164
- package/packs/flutter/CHANGELOG.md +0 -19
- package/packs/flutter/README.md +0 -170
- package/packs/flutter/agents/flutter-architect.md +0 -166
- package/packs/flutter/agents/flutter-builder.md +0 -303
- package/packs/flutter/agents/release-manager.md +0 -355
- package/packs/flutter/commands/fastlane-setup.md +0 -188
- package/packs/flutter/commands/flutter-build.md +0 -90
- package/packs/flutter/commands/flutter-deploy.md +0 -133
- package/packs/flutter/commands/flutter-test.md +0 -117
- package/packs/flutter/commands/signing-setup.md +0 -209
- package/packs/flutter/hooks/hooks.json +0 -17
- package/packs/flutter/skills/fastlane-knowledge/SKILL.md +0 -193
- package/packs/flutter/skills/flutter-architecture/SKILL.md +0 -127
- package/packs/flutter/skills/store-publishing/SKILL.md +0 -163
- package/packs/hono/CHANGELOG.md +0 -19
- package/packs/hono/README.md +0 -143
- package/packs/hono/agents/hono-architect.md +0 -240
- package/packs/hono/agents/hono-builder.md +0 -285
- package/packs/hono/agents/hono-reviewer.md +0 -279
- package/packs/hono/agents/hono-tester.md +0 -346
- package/packs/hono/commands/middleware-create.md +0 -223
- package/packs/hono/commands/project-init.md +0 -306
- package/packs/hono/commands/route-create.md +0 -153
- package/packs/hono/commands/rpc-client.md +0 -263
- package/packs/hono/hooks/hooks.json +0 -4
- package/packs/hono/skills/cloudflare-bindings/SKILL.md +0 -408
- package/packs/hono/skills/hono-patterns/SKILL.md +0 -309
- package/packs/hono/skills/rpc-typesafe/SKILL.md +0 -388
- package/packs/hono/skills/zod-validation/SKILL.md +0 -332
- package/packs/nestjs/CHANGELOG.md +0 -29
- package/packs/nestjs/README.md +0 -75
- package/packs/nestjs/agents/nestjs-architect.md +0 -402
- package/packs/nestjs/agents/nestjs-builder.md +0 -301
- package/packs/nestjs/agents/nestjs-tester.md +0 -437
- package/packs/nestjs/commands/module-create.md +0 -369
- package/packs/nestjs/rules/controllers.md +0 -92
- package/packs/nestjs/rules/dto.md +0 -124
- package/packs/nestjs/rules/entities.md +0 -102
- package/packs/nestjs/rules/services.md +0 -106
- package/packs/nestjs/skills/barrel-export-manager/SKILL.md +0 -389
- package/packs/nestjs/skills/import-convention-enforcer/SKILL.md +0 -365
- package/packs/nextjs/CHANGELOG.md +0 -36
- package/packs/nextjs/README.md +0 -76
- package/packs/nextjs/agents/frontend-tester.md +0 -680
- package/packs/nextjs/agents/frontend-visual.md +0 -820
- package/packs/nextjs/agents/nextjs-architect.md +0 -331
- package/packs/nextjs/agents/nextjs-modular.md +0 -433
- package/packs/nextjs/commands/component-create.md +0 -398
- package/packs/nextjs/rules/api-routes.md +0 -129
- package/packs/nextjs/rules/components.md +0 -106
- package/packs/nextjs/rules/hooks.md +0 -132
- package/packs/nextjs/skills/accessibility-validator/SKILL.md +0 -445
- package/packs/nextjs/skills/import-convention-enforcer/SKILL.md +0 -399
- package/packs/nextjs/skills/react-form-validator/SKILL.md +0 -569
- package/packs/nuxtjs/CHANGELOG.md +0 -30
- package/packs/nuxtjs/README.md +0 -56
- package/packs/nuxtjs/agents/frontend-tester.md +0 -680
- package/packs/nuxtjs/agents/frontend-visual.md +0 -820
- package/packs/nuxtjs/agents/nuxtjs-architect.md +0 -537
- package/packs/nuxtjs/commands/component-create.md +0 -223
- package/packs/nuxtjs/rules/components.md +0 -101
- package/packs/nuxtjs/rules/composables.md +0 -118
- package/packs/nuxtjs/rules/server-routes.md +0 -127
- package/packs/nuxtjs/skills/accessibility-validator/SKILL.md +0 -183
- package/packs/nuxtjs/skills/import-convention-enforcer/SKILL.md +0 -196
- package/packs/nuxtjs/skills/veevalidate-form-validator/SKILL.md +0 -190
- package/packs/onboard/CHANGELOG.md +0 -22
- package/packs/onboard/README.md +0 -103
- package/packs/onboard/agents/onboard-guide.md +0 -118
- package/packs/onboard/commands/onboard.md +0 -313
- package/packs/onboard/skills/onboard-context-provider/SKILL.md +0 -98
- package/packs/tanstack-router/CHANGELOG.md +0 -30
- package/packs/tanstack-router/README.md +0 -113
- package/packs/tanstack-router/agents/tanstack-architect.md +0 -173
- package/packs/tanstack-router/agents/tanstack-builder.md +0 -360
- package/packs/tanstack-router/agents/tanstack-tester.md +0 -454
- package/packs/tanstack-router/commands/form-create.md +0 -313
- package/packs/tanstack-router/commands/query-create.md +0 -263
- package/packs/tanstack-router/commands/route-create.md +0 -190
- package/packs/tanstack-router/commands/table-create.md +0 -413
- package/packs/tanstack-router/skills/ai-patterns/SKILL.md +0 -370
- package/packs/tanstack-router/skills/db-patterns/SKILL.md +0 -346
- package/packs/tanstack-router/skills/devtools-patterns/SKILL.md +0 -415
- package/packs/tanstack-router/skills/form-patterns/SKILL.md +0 -425
- package/packs/tanstack-router/skills/pacer-patterns/SKILL.md +0 -341
- package/packs/tanstack-router/skills/query-patterns/SKILL.md +0 -359
- package/packs/tanstack-router/skills/router-patterns/SKILL.md +0 -285
- package/packs/tanstack-router/skills/store-patterns/SKILL.md +0 -351
- package/packs/tanstack-router/skills/table-patterns/SKILL.md +0 -531
- package/packs/tanstack-router/skills/tanstack-conventions/SKILL.md +0 -428
- package/packs/tanstack-router/skills/virtual-patterns/SKILL.md +0 -490
- package/packs/worktree/CHANGELOG.md +0 -45
- package/packs/worktree/README.md +0 -219
- package/packs/worktree/commands/wt.md +0 -93
- package/packs/worktree/scripts/wt.sh +0 -957
- package/packs/worktree/skills/worktree-manager/SKILL.md +0 -113
|
@@ -1,569 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: react-form-validator
|
|
3
|
-
description: This skill should be used when the user asks to "create a form", "add validation", "handle form submission", "use React Hook Form", or when creating login, signup, or data entry forms. Enforces React Hook Form + Zod pattern.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# React Form Validator
|
|
7
|
-
|
|
8
|
-
Auto-enforces React Hook Form + Zod validation pattern for ALL forms in Next.js/React applications.
|
|
9
|
-
|
|
10
|
-
## Activation Triggers
|
|
11
|
-
|
|
12
|
-
This skill activates when:
|
|
13
|
-
- Creating form components
|
|
14
|
-
- Using `<form>`, `<input>`, form elements
|
|
15
|
-
- Mentioning "form", "validation", "submit", "input"
|
|
16
|
-
- Handling form state or submission
|
|
17
|
-
- Creating login, signup, or data entry forms
|
|
18
|
-
|
|
19
|
-
## Required Form Pattern (MANDATORY)
|
|
20
|
-
|
|
21
|
-
ALL forms MUST use:
|
|
22
|
-
- ✅ **React Hook Form** for form state management
|
|
23
|
-
- ✅ **Zod** for schema validation
|
|
24
|
-
- ✅ **TypeScript** types inferred from Zod schema
|
|
25
|
-
- ✅ **Error handling** with accessible error messages
|
|
26
|
-
- ✅ **Loading states** during submission
|
|
27
|
-
|
|
28
|
-
## Auto-Validation Process
|
|
29
|
-
|
|
30
|
-
### Step 1: Detect Form Without Pattern
|
|
31
|
-
|
|
32
|
-
When detecting a form being created:
|
|
33
|
-
|
|
34
|
-
```tsx
|
|
35
|
-
// ❌ WRONG - Uncontrolled form, no validation
|
|
36
|
-
function LoginForm() {
|
|
37
|
-
const handleSubmit = (e) => {
|
|
38
|
-
e.preventDefault()
|
|
39
|
-
const email = e.target.email.value // No validation!
|
|
40
|
-
const password = e.target.password.value
|
|
41
|
-
// Submit...
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return (
|
|
45
|
-
<form onSubmit={handleSubmit}>
|
|
46
|
-
<input name="email" type="email" />
|
|
47
|
-
<input name="password" type="password" />
|
|
48
|
-
<button>Login</button>
|
|
49
|
-
</form>
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### Step 2: Identify Missing Requirements
|
|
55
|
-
|
|
56
|
-
Detect:
|
|
57
|
-
- ❌ No React Hook Form
|
|
58
|
-
- ❌ No Zod validation
|
|
59
|
-
- ❌ No TypeScript types
|
|
60
|
-
- ❌ No error display
|
|
61
|
-
- ❌ No loading state
|
|
62
|
-
|
|
63
|
-
### Step 3: Auto-Fix to Correct Pattern
|
|
64
|
-
|
|
65
|
-
**After (Correct Pattern):**
|
|
66
|
-
```tsx
|
|
67
|
-
'use client'
|
|
68
|
-
import { useForm } from 'react-hook-form'
|
|
69
|
-
import { zodResolver } from '@hookform/resolvers/zod'
|
|
70
|
-
import * as z from 'zod'
|
|
71
|
-
|
|
72
|
-
// 1. Define Zod schema
|
|
73
|
-
const loginSchema = z.object({
|
|
74
|
-
email: z.string().email('Invalid email address'),
|
|
75
|
-
password: z.string().min(8, 'Password must be at least 8 characters'),
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
// 2. Infer TypeScript type from schema
|
|
79
|
-
type LoginFormData = z.infer<typeof loginSchema>
|
|
80
|
-
|
|
81
|
-
function LoginForm() {
|
|
82
|
-
// 3. Set up React Hook Form with Zod resolver
|
|
83
|
-
const {
|
|
84
|
-
register,
|
|
85
|
-
handleSubmit,
|
|
86
|
-
formState: { errors, isSubmitting },
|
|
87
|
-
} = useForm<LoginFormData>({
|
|
88
|
-
resolver: zodResolver(loginSchema),
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
// 4. Type-safe submit handler
|
|
92
|
-
const onSubmit = async (data: LoginFormData) => {
|
|
93
|
-
try {
|
|
94
|
-
await loginUser(data)
|
|
95
|
-
// Handle success
|
|
96
|
-
} catch (error) {
|
|
97
|
-
// Handle error
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return (
|
|
102
|
-
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
|
103
|
-
{/* Email field */}
|
|
104
|
-
<div>
|
|
105
|
-
<label htmlFor="email" className="block text-sm font-medium">
|
|
106
|
-
Email
|
|
107
|
-
</label>
|
|
108
|
-
<input
|
|
109
|
-
{...register('email')}
|
|
110
|
-
id="email"
|
|
111
|
-
type="email"
|
|
112
|
-
className="mt-1 block w-full rounded-md border-gray-300"
|
|
113
|
-
aria-invalid={!!errors.email}
|
|
114
|
-
aria-describedby={errors.email ? 'email-error' : undefined}
|
|
115
|
-
/>
|
|
116
|
-
{errors.email && (
|
|
117
|
-
<p id="email-error" className="mt-1 text-sm text-red-600" role="alert">
|
|
118
|
-
{errors.email.message}
|
|
119
|
-
</p>
|
|
120
|
-
)}
|
|
121
|
-
</div>
|
|
122
|
-
|
|
123
|
-
{/* Password field */}
|
|
124
|
-
<div>
|
|
125
|
-
<label htmlFor="password" className="block text-sm font-medium">
|
|
126
|
-
Password
|
|
127
|
-
</label>
|
|
128
|
-
<input
|
|
129
|
-
{...register('password')}
|
|
130
|
-
id="password"
|
|
131
|
-
type="password"
|
|
132
|
-
className="mt-1 block w-full rounded-md border-gray-300"
|
|
133
|
-
aria-invalid={!!errors.password}
|
|
134
|
-
aria-describedby={errors.password ? 'password-error' : undefined}
|
|
135
|
-
/>
|
|
136
|
-
{errors.password && (
|
|
137
|
-
<p id="password-error" className="mt-1 text-sm text-red-600" role="alert">
|
|
138
|
-
{errors.password.message}
|
|
139
|
-
</p>
|
|
140
|
-
)}
|
|
141
|
-
</div>
|
|
142
|
-
|
|
143
|
-
{/* Submit button with loading state */}
|
|
144
|
-
<button
|
|
145
|
-
type="submit"
|
|
146
|
-
disabled={isSubmitting}
|
|
147
|
-
className="w-full py-2 px-4 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50"
|
|
148
|
-
>
|
|
149
|
-
{isSubmitting ? 'Logging in...' : 'Login'}
|
|
150
|
-
</button>
|
|
151
|
-
</form>
|
|
152
|
-
)
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
### Step 4: Explain Pattern
|
|
157
|
-
|
|
158
|
-
> **Form Pattern Applied**
|
|
159
|
-
>
|
|
160
|
-
> **Added:**
|
|
161
|
-
> 1. ✅ Zod schema for validation
|
|
162
|
-
> 2. ✅ TypeScript types inferred from schema
|
|
163
|
-
> 3. ✅ React Hook Form for state management
|
|
164
|
-
> 4. ✅ zodResolver connects Zod to React Hook Form
|
|
165
|
-
> 5. ✅ Error messages displayed accessibly
|
|
166
|
-
> 6. ✅ Loading state during submission
|
|
167
|
-
>
|
|
168
|
-
> **Why:**
|
|
169
|
-
> - Zod provides runtime type validation
|
|
170
|
-
> - React Hook Form handles form state efficiently
|
|
171
|
-
> - Type safety prevents bugs
|
|
172
|
-
> - Accessible error messages help all users
|
|
173
|
-
|
|
174
|
-
## Complete Form Patterns
|
|
175
|
-
|
|
176
|
-
### Pattern 1: Simple Contact Form
|
|
177
|
-
|
|
178
|
-
```tsx
|
|
179
|
-
import { useForm } from 'react-hook-form'
|
|
180
|
-
import { zodResolver } from '@hookform/resolvers/zod'
|
|
181
|
-
import * as z from 'zod'
|
|
182
|
-
|
|
183
|
-
const contactSchema = z.object({
|
|
184
|
-
name: z.string().min(2, 'Name must be at least 2 characters'),
|
|
185
|
-
email: z.string().email('Invalid email address'),
|
|
186
|
-
message: z.string().min(10, 'Message must be at least 10 characters'),
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
type ContactFormData = z.infer<typeof contactSchema>
|
|
190
|
-
|
|
191
|
-
export function ContactForm() {
|
|
192
|
-
const {
|
|
193
|
-
register,
|
|
194
|
-
handleSubmit,
|
|
195
|
-
reset,
|
|
196
|
-
formState: { errors, isSubmitting, isSubmitSuccessful },
|
|
197
|
-
} = useForm<ContactFormData>({
|
|
198
|
-
resolver: zodResolver(contactSchema),
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
const onSubmit = async (data: ContactFormData) => {
|
|
202
|
-
await sendContactMessage(data)
|
|
203
|
-
reset() // Clear form after success
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return (
|
|
207
|
-
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
|
208
|
-
<div>
|
|
209
|
-
<label htmlFor="name">Name</label>
|
|
210
|
-
<input {...register('name')} id="name" type="text" />
|
|
211
|
-
{errors.name && <p role="alert">{errors.name.message}</p>}
|
|
212
|
-
</div>
|
|
213
|
-
|
|
214
|
-
<div>
|
|
215
|
-
<label htmlFor="email">Email</label>
|
|
216
|
-
<input {...register('email')} id="email" type="email" />
|
|
217
|
-
{errors.email && <p role="alert">{errors.email.message}</p>}
|
|
218
|
-
</div>
|
|
219
|
-
|
|
220
|
-
<div>
|
|
221
|
-
<label htmlFor="message">Message</label>
|
|
222
|
-
<textarea {...register('message')} id="message" rows={4} />
|
|
223
|
-
{errors.message && <p role="alert">{errors.message.message}</p>}
|
|
224
|
-
</div>
|
|
225
|
-
|
|
226
|
-
<button type="submit" disabled={isSubmitting}>
|
|
227
|
-
{isSubmitting ? 'Sending...' : 'Send Message'}
|
|
228
|
-
</button>
|
|
229
|
-
|
|
230
|
-
{isSubmitSuccessful && (
|
|
231
|
-
<p className="text-green-600">Message sent successfully!</p>
|
|
232
|
-
)}
|
|
233
|
-
</form>
|
|
234
|
-
)
|
|
235
|
-
}
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### Pattern 2: Complex Registration Form
|
|
239
|
-
|
|
240
|
-
```tsx
|
|
241
|
-
const registerSchema = z.object({
|
|
242
|
-
email: z.string().email(),
|
|
243
|
-
password: z.string().min(8).regex(/[A-Z]/, 'Must contain uppercase letter'),
|
|
244
|
-
confirmPassword: z.string(),
|
|
245
|
-
firstName: z.string().min(2),
|
|
246
|
-
lastName: z.string().min(2),
|
|
247
|
-
terms: z.boolean().refine((val) => val === true, {
|
|
248
|
-
message: 'You must accept the terms and conditions',
|
|
249
|
-
}),
|
|
250
|
-
}).refine((data) => data.password === data.confirmPassword, {
|
|
251
|
-
message: "Passwords don't match",
|
|
252
|
-
path: ['confirmPassword'],
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
type RegisterFormData = z.infer<typeof registerSchema>
|
|
256
|
-
|
|
257
|
-
export function RegisterForm() {
|
|
258
|
-
const {
|
|
259
|
-
register,
|
|
260
|
-
handleSubmit,
|
|
261
|
-
formState: { errors, isSubmitting },
|
|
262
|
-
} = useForm<RegisterFormData>({
|
|
263
|
-
resolver: zodResolver(registerSchema),
|
|
264
|
-
})
|
|
265
|
-
|
|
266
|
-
const onSubmit = async (data: RegisterFormData) => {
|
|
267
|
-
await createUser(data)
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
return (
|
|
271
|
-
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
|
272
|
-
{/* Email */}
|
|
273
|
-
<div>
|
|
274
|
-
<label htmlFor="email">Email</label>
|
|
275
|
-
<input {...register('email')} id="email" type="email" />
|
|
276
|
-
{errors.email && <p role="alert">{errors.email.message}</p>}
|
|
277
|
-
</div>
|
|
278
|
-
|
|
279
|
-
{/* Password */}
|
|
280
|
-
<div>
|
|
281
|
-
<label htmlFor="password">Password</label>
|
|
282
|
-
<input {...register('password')} id="password" type="password" />
|
|
283
|
-
{errors.password && <p role="alert">{errors.password.message}</p>}
|
|
284
|
-
</div>
|
|
285
|
-
|
|
286
|
-
{/* Confirm Password */}
|
|
287
|
-
<div>
|
|
288
|
-
<label htmlFor="confirmPassword">Confirm Password</label>
|
|
289
|
-
<input {...register('confirmPassword')} id="confirmPassword" type="password" />
|
|
290
|
-
{errors.confirmPassword && <p role="alert">{errors.confirmPassword.message}</p>}
|
|
291
|
-
</div>
|
|
292
|
-
|
|
293
|
-
{/* First Name */}
|
|
294
|
-
<div>
|
|
295
|
-
<label htmlFor="firstName">First Name</label>
|
|
296
|
-
<input {...register('firstName')} id="firstName" type="text" />
|
|
297
|
-
{errors.firstName && <p role="alert">{errors.firstName.message}</p>}
|
|
298
|
-
</div>
|
|
299
|
-
|
|
300
|
-
{/* Last Name */}
|
|
301
|
-
<div>
|
|
302
|
-
<label htmlFor="lastName">Last Name</label>
|
|
303
|
-
<input {...register('lastName')} id="lastName" type="text" />
|
|
304
|
-
{errors.lastName && <p role="alert">{errors.lastName.message}</p>}
|
|
305
|
-
</div>
|
|
306
|
-
|
|
307
|
-
{/* Terms checkbox */}
|
|
308
|
-
<div>
|
|
309
|
-
<label className="flex items-center">
|
|
310
|
-
<input {...register('terms')} type="checkbox" className="mr-2" />
|
|
311
|
-
I accept the terms and conditions
|
|
312
|
-
</label>
|
|
313
|
-
{errors.terms && <p role="alert">{errors.terms.message}</p>}
|
|
314
|
-
</div>
|
|
315
|
-
|
|
316
|
-
<button type="submit" disabled={isSubmitting}>
|
|
317
|
-
{isSubmitting ? 'Creating account...' : 'Sign Up'}
|
|
318
|
-
</button>
|
|
319
|
-
</form>
|
|
320
|
-
)
|
|
321
|
-
}
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
### Pattern 3: Multi-Step Form
|
|
325
|
-
|
|
326
|
-
```tsx
|
|
327
|
-
const step1Schema = z.object({
|
|
328
|
-
email: z.string().email(),
|
|
329
|
-
password: z.string().min(8),
|
|
330
|
-
})
|
|
331
|
-
|
|
332
|
-
const step2Schema = z.object({
|
|
333
|
-
firstName: z.string().min(2),
|
|
334
|
-
lastName: z.string().min(2),
|
|
335
|
-
phone: z.string().optional(),
|
|
336
|
-
})
|
|
337
|
-
|
|
338
|
-
type Step1Data = z.infer<typeof step1Schema>
|
|
339
|
-
type Step2Data = z.infer<typeof step2Schema>
|
|
340
|
-
|
|
341
|
-
export function MultiStepForm() {
|
|
342
|
-
const [step, setStep] = useState(1)
|
|
343
|
-
const [formData, setFormData] = useState<Partial<Step1Data & Step2Data>>({})
|
|
344
|
-
|
|
345
|
-
const step1Form = useForm<Step1Data>({
|
|
346
|
-
resolver: zodResolver(step1Schema),
|
|
347
|
-
})
|
|
348
|
-
|
|
349
|
-
const step2Form = useForm<Step2Data>({
|
|
350
|
-
resolver: zodResolver(step2Schema),
|
|
351
|
-
})
|
|
352
|
-
|
|
353
|
-
const handleStep1 = (data: Step1Data) => {
|
|
354
|
-
setFormData({ ...formData, ...data })
|
|
355
|
-
setStep(2)
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
const handleStep2 = async (data: Step2Data) => {
|
|
359
|
-
const finalData = { ...formData, ...data }
|
|
360
|
-
await submitRegistration(finalData)
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
return (
|
|
364
|
-
<div>
|
|
365
|
-
{step === 1 && (
|
|
366
|
-
<form onSubmit={step1Form.handleSubmit(handleStep1)}>
|
|
367
|
-
{/* Step 1 fields */}
|
|
368
|
-
<button type="submit">Next</button>
|
|
369
|
-
</form>
|
|
370
|
-
)}
|
|
371
|
-
|
|
372
|
-
{step === 2 && (
|
|
373
|
-
<form onSubmit={step2Form.handleSubmit(handleStep2)}>
|
|
374
|
-
{/* Step 2 fields */}
|
|
375
|
-
<button type="button" onClick={() => setStep(1)}>
|
|
376
|
-
Back
|
|
377
|
-
</button>
|
|
378
|
-
<button type="submit">Submit</button>
|
|
379
|
-
</form>
|
|
380
|
-
)}
|
|
381
|
-
</div>
|
|
382
|
-
)
|
|
383
|
-
}
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
## Advanced Zod Patterns
|
|
387
|
-
|
|
388
|
-
### Custom Validation
|
|
389
|
-
|
|
390
|
-
```tsx
|
|
391
|
-
const userSchema = z.object({
|
|
392
|
-
username: z.string()
|
|
393
|
-
.min(3)
|
|
394
|
-
.max(20)
|
|
395
|
-
.regex(/^[a-zA-Z0-9_]+$/, 'Only letters, numbers, and underscores allowed'),
|
|
396
|
-
age: z.number()
|
|
397
|
-
.int()
|
|
398
|
-
.min(18, 'Must be 18 or older')
|
|
399
|
-
.max(120),
|
|
400
|
-
website: z.string().url().optional(),
|
|
401
|
-
})
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
### Async Validation
|
|
405
|
-
|
|
406
|
-
```tsx
|
|
407
|
-
const emailSchema = z.string().email().refine(
|
|
408
|
-
async (email) => {
|
|
409
|
-
const available = await checkEmailAvailability(email)
|
|
410
|
-
return available
|
|
411
|
-
},
|
|
412
|
-
{ message: 'Email already in use' }
|
|
413
|
-
)
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
### Conditional Fields
|
|
417
|
-
|
|
418
|
-
```tsx
|
|
419
|
-
const shippingSchema = z.object({
|
|
420
|
-
sameAsBilling: z.boolean(),
|
|
421
|
-
address: z.string().optional(),
|
|
422
|
-
city: z.string().optional(),
|
|
423
|
-
zip: z.string().optional(),
|
|
424
|
-
}).refine(
|
|
425
|
-
(data) => {
|
|
426
|
-
if (!data.sameAsBilling) {
|
|
427
|
-
return !!data.address && !!data.city && !!data.zip
|
|
428
|
-
}
|
|
429
|
-
return true
|
|
430
|
-
},
|
|
431
|
-
{
|
|
432
|
-
message: 'Shipping address is required',
|
|
433
|
-
path: ['address'],
|
|
434
|
-
}
|
|
435
|
-
)
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
## Form Component Reusability
|
|
439
|
-
|
|
440
|
-
```tsx
|
|
441
|
-
// Reusable FormField component
|
|
442
|
-
interface FormFieldProps {
|
|
443
|
-
label: string
|
|
444
|
-
name: string
|
|
445
|
-
type?: string
|
|
446
|
-
register: UseFormRegister<any>
|
|
447
|
-
error?: FieldError
|
|
448
|
-
required?: boolean
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
function FormField({ label, name, type = 'text', register, error, required }: FormFieldProps) {
|
|
452
|
-
const id = `field-${name}`
|
|
453
|
-
|
|
454
|
-
return (
|
|
455
|
-
<div>
|
|
456
|
-
<label htmlFor={id} className="block text-sm font-medium">
|
|
457
|
-
{label} {required && <span className="text-red-600">*</span>}
|
|
458
|
-
</label>
|
|
459
|
-
<input
|
|
460
|
-
{...register(name)}
|
|
461
|
-
id={id}
|
|
462
|
-
type={type}
|
|
463
|
-
className="mt-1 block w-full rounded-md border-gray-300"
|
|
464
|
-
aria-invalid={!!error}
|
|
465
|
-
aria-describedby={error ? `${id}-error` : undefined}
|
|
466
|
-
aria-required={required}
|
|
467
|
-
/>
|
|
468
|
-
{error && (
|
|
469
|
-
<p id={`${id}-error`} className="mt-1 text-sm text-red-600" role="alert">
|
|
470
|
-
{error.message}
|
|
471
|
-
</p>
|
|
472
|
-
)}
|
|
473
|
-
</div>
|
|
474
|
-
)
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
// Usage
|
|
478
|
-
function LoginForm() {
|
|
479
|
-
const { register, handleSubmit, formState: { errors } } = useForm<LoginFormData>({
|
|
480
|
-
resolver: zodResolver(loginSchema),
|
|
481
|
-
})
|
|
482
|
-
|
|
483
|
-
return (
|
|
484
|
-
<form onSubmit={handleSubmit(onSubmit)}>
|
|
485
|
-
<FormField
|
|
486
|
-
label="Email"
|
|
487
|
-
name="email"
|
|
488
|
-
type="email"
|
|
489
|
-
register={register}
|
|
490
|
-
error={errors.email}
|
|
491
|
-
required
|
|
492
|
-
/>
|
|
493
|
-
<FormField
|
|
494
|
-
label="Password"
|
|
495
|
-
name="password"
|
|
496
|
-
type="password"
|
|
497
|
-
register={register}
|
|
498
|
-
error={errors.password}
|
|
499
|
-
required
|
|
500
|
-
/>
|
|
501
|
-
<button type="submit">Login</button>
|
|
502
|
-
</form>
|
|
503
|
-
)
|
|
504
|
-
}
|
|
505
|
-
```
|
|
506
|
-
|
|
507
|
-
## Server Actions Integration (Next.js 14+)
|
|
508
|
-
|
|
509
|
-
```tsx
|
|
510
|
-
'use server'
|
|
511
|
-
import { z } from 'zod'
|
|
512
|
-
|
|
513
|
-
const contactSchema = z.object({
|
|
514
|
-
name: z.string().min(2),
|
|
515
|
-
email: z.string().email(),
|
|
516
|
-
message: z.string().min(10),
|
|
517
|
-
})
|
|
518
|
-
|
|
519
|
-
export async function submitContact(formData: FormData) {
|
|
520
|
-
const data = {
|
|
521
|
-
name: formData.get('name'),
|
|
522
|
-
email: formData.get('email'),
|
|
523
|
-
message: formData.get('message'),
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
const result = contactSchema.safeParse(data)
|
|
527
|
-
|
|
528
|
-
if (!result.success) {
|
|
529
|
-
return { success: false, errors: result.error.flatten() }
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// Process valid data
|
|
533
|
-
await saveContact(result.data)
|
|
534
|
-
return { success: true }
|
|
535
|
-
}
|
|
536
|
-
```
|
|
537
|
-
|
|
538
|
-
## Success Criteria
|
|
539
|
-
|
|
540
|
-
✅ ALL forms use React Hook Form
|
|
541
|
-
✅ ALL forms use Zod validation
|
|
542
|
-
✅ TypeScript types inferred from schemas
|
|
543
|
-
✅ Error messages displayed accessibly
|
|
544
|
-
✅ Loading states during submission
|
|
545
|
-
✅ Forms are keyboard accessible
|
|
546
|
-
✅ ARIA attributes for errors
|
|
547
|
-
|
|
548
|
-
## Behavior
|
|
549
|
-
|
|
550
|
-
**Proactive enforcement:**
|
|
551
|
-
- Detect forms without being asked
|
|
552
|
-
- Add React Hook Form + Zod automatically
|
|
553
|
-
- Generate complete form code
|
|
554
|
-
- Explain benefits of the pattern
|
|
555
|
-
- Ensure accessibility
|
|
556
|
-
|
|
557
|
-
**Never:**
|
|
558
|
-
- Allow unvalidated forms
|
|
559
|
-
- Accept useState for form state
|
|
560
|
-
- Allow inline validation logic
|
|
561
|
-
- Skip TypeScript types
|
|
562
|
-
|
|
563
|
-
**Block completion if:**
|
|
564
|
-
- Form lacks validation
|
|
565
|
-
- No error handling
|
|
566
|
-
- Missing loading states
|
|
567
|
-
- Not using React Hook Form + Zod
|
|
568
|
-
|
|
569
|
-
This ensures all forms are type-safe, validated, and accessible from day one.
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to the smi-nuxtjs plugin will be documented in this file.
|
|
4
|
-
|
|
5
|
-
## [Unreleased]
|
|
6
|
-
|
|
7
|
-
### Changed
|
|
8
|
-
- Renamed from `smi-nuxtjs` to `nuxtjs` as part of ai-kit migration
|
|
9
|
-
- Moved from `plugins/smi-nuxtjs/` to `packs/nuxtjs/`
|
|
10
|
-
|
|
11
|
-
## [2.1.0] - 2025-01-02
|
|
12
|
-
|
|
13
|
-
### Added
|
|
14
|
-
- 3 auto-enforcing skills
|
|
15
|
-
- `accessibility-validator` - WCAG 2.1 AA compliance
|
|
16
|
-
- `veevalidate-form-validator` - VeeValidate + Zod
|
|
17
|
-
- `import-convention-enforcer` - ~/ path alias
|
|
18
|
-
|
|
19
|
-
## [2.0.0] - 2024-12-01
|
|
20
|
-
|
|
21
|
-
### Changed
|
|
22
|
-
- BREAKING: Migrated to Vue 3 Composition API
|
|
23
|
-
- Updated to Nuxt 3 patterns
|
|
24
|
-
|
|
25
|
-
## [1.0.0] - 2024-10-01
|
|
26
|
-
|
|
27
|
-
### Added
|
|
28
|
-
- Initial stable release
|
|
29
|
-
- 3 agents: architect, visual, tester
|
|
30
|
-
- 1 command: component-create
|
package/packs/nuxtjs/README.md
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# Nuxt.js Development Standards Plugin
|
|
2
|
-
|
|
3
|
-
Smicolon company standards for Nuxt.js/Vue 3 projects.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
# Add Smicolon marketplace
|
|
9
|
-
/plugin marketplace add https://github.com/smicolon/ai-kit
|
|
10
|
-
|
|
11
|
-
# Install Nuxt.js plugin
|
|
12
|
-
/plugin install nuxtjs
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## What's Included
|
|
16
|
-
|
|
17
|
-
### 3 Specialized Agents
|
|
18
|
-
|
|
19
|
-
- `@nuxtjs-architect` - Nuxt.js/Vue 3 architecture design
|
|
20
|
-
- `@frontend-visual` - Visual QA with Playwright + Figma MCP integration
|
|
21
|
-
- `@frontend-tester` - Frontend testing (unit, integration, E2E, accessibility)
|
|
22
|
-
|
|
23
|
-
### Automatic Convention Enforcement
|
|
24
|
-
|
|
25
|
-
**Required Standards:**
|
|
26
|
-
- TypeScript strict mode
|
|
27
|
-
- Vue 3 Composition API (`<script setup lang="ts">`)
|
|
28
|
-
- VeeValidate + Zod for forms
|
|
29
|
-
- Nuxt composables (useFetch, useAsyncData)
|
|
30
|
-
- Pinia for state management
|
|
31
|
-
- WCAG 2.1 AA accessibility
|
|
32
|
-
|
|
33
|
-
### Visual QA Integration
|
|
34
|
-
|
|
35
|
-
The `@frontend-visual` agent integrates with:
|
|
36
|
-
- **Playwright MCP** for automated browser testing
|
|
37
|
-
- **Figma MCP** for design comparison
|
|
38
|
-
|
|
39
|
-
See [MCP_SETUP.md](../../MCP_SETUP.md) for configuration.
|
|
40
|
-
|
|
41
|
-
## Usage
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
# Design architecture
|
|
45
|
-
@nuxtjs-architect "Design authentication flow with social login"
|
|
46
|
-
|
|
47
|
-
# Write comprehensive tests
|
|
48
|
-
@frontend-tester "Write tests for authentication module"
|
|
49
|
-
|
|
50
|
-
# Visual QA (requires Playwright + Figma MCP)
|
|
51
|
-
@frontend-visual "Verify login page matches Figma: https://figma.com/file/..."
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## Documentation
|
|
55
|
-
|
|
56
|
-
See the main [Smicolon Claude Infra repository](https://github.com/smicolon/ai-kit) for complete documentation.
|