design-protocol 1.0.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/LICENSE +21 -0
- package/README.md +225 -0
- package/agents/dp-researcher.md +239 -0
- package/agents/dp-verifier.md +207 -0
- package/bin/install.js +464 -0
- package/commands/dp-back.md +221 -0
- package/commands/dp-discuss.md +257 -0
- package/commands/dp-execute.md +513 -0
- package/commands/dp-journey.md +85 -0
- package/commands/dp-progress.md +178 -0
- package/commands/dp-roadmap.md +83 -0
- package/commands/dp-skip.md +186 -0
- package/commands/dp-start.md +510 -0
- package/commands/dp-storytell.md +94 -0
- package/commands/dp-verify.md +207 -0
- package/package.json +59 -0
- package/skills/dp-color/SKILL.md +214 -0
- package/skills/dp-color/export_tokens.py +297 -0
- package/skills/dp-color/references/apca-contrast.md +87 -0
- package/skills/dp-color/references/hue-emotions.md +109 -0
- package/skills/dp-color/references/oklch-gamut.md +79 -0
- package/skills/dp-color/references/pitfalls.md +171 -0
- package/skills/dp-color/references/scale-patterns.md +206 -0
- package/skills/dp-color/references/tool-workflows.md +200 -0
- package/skills/dp-discovery/SKILL.md +480 -0
- package/skills/dp-eng_review/SKILL.md +471 -0
- package/skills/dp-eng_review/references/code-review-checklist.md +385 -0
- package/skills/dp-eng_review/references/react-patterns.md +512 -0
- package/skills/dp-eng_review/references/shadcn-patterns.md +510 -0
- package/skills/dp-eng_review/references/tailwind-conventions.md +351 -0
- package/skills/dp-journey/SKILL.md +682 -0
- package/skills/dp-journey/references/journey-types.md +97 -0
- package/skills/dp-journey/references/map-structures.md +177 -0
- package/skills/dp-journey/references/omnichannel-patterns.md +208 -0
- package/skills/dp-journey/references/research-methods.md +125 -0
- package/skills/dp-prd/SKILL.md +201 -0
- package/skills/dp-prd/references/claude-code-spec.md +107 -0
- package/skills/dp-prd/references/interview-questions.md +158 -0
- package/skills/dp-prd/references/section-templates.md +231 -0
- package/skills/dp-research/SKILL.md +540 -0
- package/skills/dp-research/references/facilitation-guide.md +291 -0
- package/skills/dp-research/references/interview-guide-template.md +190 -0
- package/skills/dp-research/references/method-selection.md +195 -0
- package/skills/dp-research/references/question-writing.md +244 -0
- package/skills/dp-research/references/research-report-template.md +363 -0
- package/skills/dp-research/references/synthesis-methods.md +289 -0
- package/skills/dp-research/references/usability-test-template.md +260 -0
- package/skills/dp-roadmap/SKILL.md +648 -0
- package/skills/dp-roadmap/references/prioritization-frameworks.md +312 -0
- package/skills/dp-roadmap/references/roadmap-structures.md +179 -0
- package/skills/dp-roadmap/references/roadmap-workshops.md +264 -0
- package/skills/dp-roadmap/references/theme-development.md +168 -0
- package/skills/dp-storytell/SKILL.md +645 -0
- package/skills/dp-storytell/references/audience-playbooks.md +260 -0
- package/skills/dp-storytell/references/content-type-templates.md +310 -0
- package/skills/dp-storytell/references/delivery-tactics.md +228 -0
- package/skills/dp-storytell/references/narrative-frameworks.md +259 -0
- package/skills/dp-ui/SKILL.md +503 -0
- package/skills/dp-ui/references/b2b-enterprise-patterns.md +319 -0
- package/skills/dp-ui/references/data-visualization.md +304 -0
- package/skills/dp-ui/references/visual-design-principles.md +237 -0
- package/skills/dp-ux/SKILL.md +414 -0
- package/skills/dp-ux/references/accessibility-checklist.md +128 -0
- package/skills/dp-ux/references/product-excellence.md +149 -0
- package/skills/dp-ux/references/usability-principles.md +140 -0
- package/skills/dp-ux/references/ux-patterns.md +221 -0
- package/templates/config.json +55 -0
- package/templates/context.md +96 -0
- package/templates/project.md +83 -0
- package/templates/requirements.md +137 -0
- package/templates/roadmap.md +168 -0
- package/templates/state.md +107 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
# Code Review Checklist
|
|
2
|
+
|
|
3
|
+
Complete audit criteria for design engineer reviews. Use this as your reference when reviewing components.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Accessibility Audit (WCAG 2.1 AA)
|
|
8
|
+
|
|
9
|
+
### Critical Issues — Always Flag
|
|
10
|
+
|
|
11
|
+
#### 1. Missing Alternative Text (WCAG 1.1.1)
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
// BAD: No alt text
|
|
15
|
+
<Image src="/logo.png" width={100} height={50} />
|
|
16
|
+
<img src="/icon.svg" />
|
|
17
|
+
|
|
18
|
+
// GOOD: Descriptive alt
|
|
19
|
+
<Image src="/logo.png" width={100} height={50} alt="Shiplex logo" />
|
|
20
|
+
<img src="/icon.svg" alt="" /> {/* Empty alt for decorative images */}
|
|
21
|
+
|
|
22
|
+
// GOOD: Decorative images hidden from AT
|
|
23
|
+
<Image src="/decorative.png" alt="" aria-hidden="true" />
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
#### 2. Icon-Only Buttons (WCAG 4.1.2)
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
// BAD: No accessible name
|
|
30
|
+
<Button size="icon">
|
|
31
|
+
<Trash2 className="h-4 w-4" />
|
|
32
|
+
</Button>
|
|
33
|
+
|
|
34
|
+
// GOOD: aria-label
|
|
35
|
+
<Button size="icon" aria-label="Delete item">
|
|
36
|
+
<Trash2 className="h-4 w-4" />
|
|
37
|
+
</Button>
|
|
38
|
+
|
|
39
|
+
// GOOD: sr-only text
|
|
40
|
+
<Button size="icon">
|
|
41
|
+
<Trash2 className="h-4 w-4" />
|
|
42
|
+
<span className="sr-only">Delete item</span>
|
|
43
|
+
</Button>
|
|
44
|
+
|
|
45
|
+
// GOOD: Tooltip with accessible name
|
|
46
|
+
<TooltipProvider>
|
|
47
|
+
<Tooltip>
|
|
48
|
+
<TooltipTrigger asChild>
|
|
49
|
+
<Button size="icon" aria-label="Delete item">
|
|
50
|
+
<Trash2 className="h-4 w-4" />
|
|
51
|
+
</Button>
|
|
52
|
+
</TooltipTrigger>
|
|
53
|
+
<TooltipContent>Delete item</TooltipContent>
|
|
54
|
+
</Tooltip>
|
|
55
|
+
</TooltipProvider>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### 3. Form Inputs Without Labels (WCAG 1.3.1)
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
// BAD: Placeholder is not a label
|
|
62
|
+
<Input placeholder="Enter email" />
|
|
63
|
+
|
|
64
|
+
// BAD: Label not associated
|
|
65
|
+
<p>Email</p>
|
|
66
|
+
<Input />
|
|
67
|
+
|
|
68
|
+
// GOOD: Proper label association
|
|
69
|
+
<div className="space-y-2">
|
|
70
|
+
<Label htmlFor="email">Email</Label>
|
|
71
|
+
<Input id="email" type="email" />
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
// GOOD: aria-label for icon inputs
|
|
75
|
+
<Input aria-label="Search vessels" type="search" />
|
|
76
|
+
|
|
77
|
+
// GOOD: Visually hidden label
|
|
78
|
+
<Label htmlFor="search" className="sr-only">Search</Label>
|
|
79
|
+
<Input id="search" type="search" placeholder="Search..." />
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### 4. Non-Semantic Click Handlers (WCAG 2.1.1)
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
// BAD: div as button
|
|
86
|
+
<div onClick={handleClick}>Click me</div>
|
|
87
|
+
|
|
88
|
+
// BAD: span as link
|
|
89
|
+
<span onClick={() => navigate('/home')}>Go home</span>
|
|
90
|
+
|
|
91
|
+
// GOOD: Use proper elements
|
|
92
|
+
<button onClick={handleClick}>Click me</button>
|
|
93
|
+
<Button onClick={handleClick}>Click me</Button>
|
|
94
|
+
|
|
95
|
+
// GOOD: If you must use div, add full semantics
|
|
96
|
+
<div
|
|
97
|
+
role="button"
|
|
98
|
+
tabIndex={0}
|
|
99
|
+
onClick={handleClick}
|
|
100
|
+
onKeyDown={(e) => e.key === 'Enter' && handleClick()}
|
|
101
|
+
>
|
|
102
|
+
Click me
|
|
103
|
+
</div>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### 5. Missing Keyboard Support (WCAG 2.1.1)
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
// BAD: Mouse-only interaction
|
|
110
|
+
<div onClick={selectItem}>Item</div>
|
|
111
|
+
|
|
112
|
+
// GOOD: Full keyboard support
|
|
113
|
+
<div
|
|
114
|
+
role="option"
|
|
115
|
+
tabIndex={0}
|
|
116
|
+
onClick={selectItem}
|
|
117
|
+
onKeyDown={(e) => {
|
|
118
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
119
|
+
e.preventDefault()
|
|
120
|
+
selectItem()
|
|
121
|
+
}
|
|
122
|
+
}}
|
|
123
|
+
aria-selected={isSelected}
|
|
124
|
+
>
|
|
125
|
+
Item
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
// BEST: Use existing accessible components
|
|
129
|
+
<CommandItem onSelect={selectItem}>Item</CommandItem>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
### Serious Issues — Flag for Quality
|
|
135
|
+
|
|
136
|
+
#### 6. Focus Outline Removed (WCAG 2.4.7)
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
// BAD: Focus removed with no replacement
|
|
140
|
+
<button className="outline-none">Click</button>
|
|
141
|
+
<input className="focus:outline-none" />
|
|
142
|
+
|
|
143
|
+
// GOOD: Custom focus indicator
|
|
144
|
+
<button className="outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2">
|
|
145
|
+
Click
|
|
146
|
+
</button>
|
|
147
|
+
|
|
148
|
+
// GOOD: shadcn default (already has focus styles)
|
|
149
|
+
<Button>Click</Button>
|
|
150
|
+
<Input /> {/* Has built-in focus ring */}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### 7. Color-Only Information (WCAG 1.4.1)
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
// BAD: Status only indicated by color
|
|
157
|
+
<span className={status === 'error' ? 'text-red-500' : 'text-green-500'}>
|
|
158
|
+
{status}
|
|
159
|
+
</span>
|
|
160
|
+
|
|
161
|
+
// GOOD: Color + icon
|
|
162
|
+
<span className={status === 'error' ? 'text-red-500' : 'text-green-500'}>
|
|
163
|
+
{status === 'error' ? <AlertCircle className="inline mr-1" /> : <CheckCircle className="inline mr-1" />}
|
|
164
|
+
{status}
|
|
165
|
+
</span>
|
|
166
|
+
|
|
167
|
+
// GOOD: Color + text explanation
|
|
168
|
+
<Badge variant={status === 'error' ? 'destructive' : 'success'}>
|
|
169
|
+
{status === 'error' ? 'Failed' : 'Completed'}
|
|
170
|
+
</Badge>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### 8. Small Touch Targets (WCAG 2.5.5)
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
// BAD: Too small (< 44x44px)
|
|
177
|
+
<button className="p-1 h-6 w-6">
|
|
178
|
+
<X className="h-4 w-4" />
|
|
179
|
+
</button>
|
|
180
|
+
|
|
181
|
+
// GOOD: Adequate touch target
|
|
182
|
+
<button className="p-2 h-11 w-11 min-h-[44px] min-w-[44px]">
|
|
183
|
+
<X className="h-4 w-4" />
|
|
184
|
+
</button>
|
|
185
|
+
|
|
186
|
+
// GOOD: Use size="icon" which is properly sized
|
|
187
|
+
<Button size="icon"> {/* 40x40px by default */}
|
|
188
|
+
<X className="h-4 w-4" />
|
|
189
|
+
</Button>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
#### 9. Missing Error Association (WCAG 1.3.1)
|
|
193
|
+
|
|
194
|
+
```tsx
|
|
195
|
+
// BAD: Error not linked to input
|
|
196
|
+
<Input id="email" />
|
|
197
|
+
{error && <p className="text-red-500">{error}</p>}
|
|
198
|
+
|
|
199
|
+
// GOOD: Error linked via aria-describedby
|
|
200
|
+
<Input
|
|
201
|
+
id="email"
|
|
202
|
+
aria-invalid={!!error}
|
|
203
|
+
aria-describedby={error ? "email-error" : undefined}
|
|
204
|
+
/>
|
|
205
|
+
{error && (
|
|
206
|
+
<p id="email-error" className="text-sm text-destructive">
|
|
207
|
+
{error}
|
|
208
|
+
</p>
|
|
209
|
+
)}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
### Moderate Issues — Note for Polish
|
|
215
|
+
|
|
216
|
+
#### 10. Heading Hierarchy (WCAG 1.3.1)
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
// BAD: Skipped levels
|
|
220
|
+
<h1>Page Title</h1>
|
|
221
|
+
<h3>Section Title</h3> {/* Skipped h2 */}
|
|
222
|
+
|
|
223
|
+
// GOOD: Proper hierarchy
|
|
224
|
+
<h1>Page Title</h1>
|
|
225
|
+
<h2>Section Title</h2>
|
|
226
|
+
<h3>Subsection</h3>
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
#### 11. Positive tabIndex (WCAG 2.4.3)
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
// BAD: Disrupts natural tab order
|
|
233
|
+
<button tabIndex={1}>First</button>
|
|
234
|
+
<button tabIndex={2}>Second</button>
|
|
235
|
+
|
|
236
|
+
// GOOD: Natural order or 0/-1
|
|
237
|
+
<button>First</button> {/* Natural order */}
|
|
238
|
+
<button tabIndex={0}>Focusable</button>
|
|
239
|
+
<div tabIndex={-1}>Programmatically focusable only</div>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
#### 12. Missing Live Regions (WCAG 4.1.3)
|
|
243
|
+
|
|
244
|
+
```tsx
|
|
245
|
+
// BAD: Toast appears without announcement
|
|
246
|
+
{showToast && <div>Item saved!</div>}
|
|
247
|
+
|
|
248
|
+
// GOOD: Announce to screen readers
|
|
249
|
+
<div aria-live="polite" aria-atomic="true">
|
|
250
|
+
{showToast && <span>Item saved!</span>}
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
// BEST: Use toast component (already handles this)
|
|
254
|
+
import { toast } from 'sonner'
|
|
255
|
+
toast.success('Item saved!')
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Component Quality Checklist
|
|
261
|
+
|
|
262
|
+
### State Coverage
|
|
263
|
+
|
|
264
|
+
For every interactive component, verify these states exist:
|
|
265
|
+
|
|
266
|
+
```tsx
|
|
267
|
+
// Button states example
|
|
268
|
+
<Button>Default</Button>
|
|
269
|
+
<Button disabled>Disabled</Button>
|
|
270
|
+
<Button className="hover:bg-primary/90">Hover (usually via Tailwind)</Button>
|
|
271
|
+
<Button className="focus-visible:ring-2">Focus (usually via Tailwind)</Button>
|
|
272
|
+
<Button disabled>
|
|
273
|
+
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
274
|
+
Loading
|
|
275
|
+
</Button>
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Form State Checklist
|
|
279
|
+
|
|
280
|
+
```tsx
|
|
281
|
+
// Complete form input
|
|
282
|
+
<div className="space-y-2">
|
|
283
|
+
<Label htmlFor="name" className={error ? 'text-destructive' : ''}>
|
|
284
|
+
Name <span className="text-destructive">*</span>
|
|
285
|
+
</Label>
|
|
286
|
+
<Input
|
|
287
|
+
id="name"
|
|
288
|
+
value={value}
|
|
289
|
+
onChange={onChange}
|
|
290
|
+
disabled={isLoading}
|
|
291
|
+
aria-invalid={!!error}
|
|
292
|
+
aria-describedby={error ? 'name-error' : 'name-hint'}
|
|
293
|
+
aria-required="true"
|
|
294
|
+
/>
|
|
295
|
+
{error ? (
|
|
296
|
+
<p id="name-error" className="text-sm text-destructive">{error}</p>
|
|
297
|
+
) : (
|
|
298
|
+
<p id="name-hint" className="text-sm text-muted-foreground">
|
|
299
|
+
Enter your full name
|
|
300
|
+
</p>
|
|
301
|
+
)}
|
|
302
|
+
</div>
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Empty States
|
|
306
|
+
|
|
307
|
+
```tsx
|
|
308
|
+
// BAD: No empty state
|
|
309
|
+
{items.map(item => <Item key={item.id} {...item} />)}
|
|
310
|
+
|
|
311
|
+
// GOOD: Empty state handled
|
|
312
|
+
{items.length === 0 ? (
|
|
313
|
+
<div className="flex flex-col items-center justify-center py-12 text-center">
|
|
314
|
+
<Package className="h-12 w-12 text-muted-foreground mb-4" />
|
|
315
|
+
<h3 className="text-lg font-medium">No items yet</h3>
|
|
316
|
+
<p className="text-sm text-muted-foreground mt-1">
|
|
317
|
+
Get started by adding your first item
|
|
318
|
+
</p>
|
|
319
|
+
<Button className="mt-4">Add Item</Button>
|
|
320
|
+
</div>
|
|
321
|
+
) : (
|
|
322
|
+
items.map(item => <Item key={item.id} {...item} />)
|
|
323
|
+
)}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## TypeScript Quality
|
|
329
|
+
|
|
330
|
+
### Props Typing
|
|
331
|
+
|
|
332
|
+
```tsx
|
|
333
|
+
// BAD: Missing types
|
|
334
|
+
function UserCard({ user, onEdit }) {
|
|
335
|
+
return <div>{user.name}</div>
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// GOOD: Properly typed
|
|
339
|
+
interface UserCardProps {
|
|
340
|
+
user: User
|
|
341
|
+
onEdit: (id: string) => void
|
|
342
|
+
className?: string
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function UserCard({ user, onEdit, className }: UserCardProps) {
|
|
346
|
+
return <div className={className}>{user.name}</div>
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Avoid `any`
|
|
351
|
+
|
|
352
|
+
```tsx
|
|
353
|
+
// BAD
|
|
354
|
+
const handleChange = (e: any) => setValue(e.target.value)
|
|
355
|
+
const data: any = await fetchData()
|
|
356
|
+
|
|
357
|
+
// GOOD
|
|
358
|
+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => setValue(e.target.value)
|
|
359
|
+
const data: ApiResponse = await fetchData()
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## Testing Procedures
|
|
365
|
+
|
|
366
|
+
When reviewing, mentally test:
|
|
367
|
+
|
|
368
|
+
1. **Keyboard Navigation**
|
|
369
|
+
- Can all interactive elements be reached with Tab?
|
|
370
|
+
- Can they be activated with Enter/Space?
|
|
371
|
+
- Is there a visible focus indicator?
|
|
372
|
+
|
|
373
|
+
2. **Screen Reader**
|
|
374
|
+
- Do images have alt text?
|
|
375
|
+
- Are form fields labeled?
|
|
376
|
+
- Is dynamic content announced?
|
|
377
|
+
|
|
378
|
+
3. **State Coverage**
|
|
379
|
+
- What happens when it's loading?
|
|
380
|
+
- What happens on error?
|
|
381
|
+
- What happens when empty?
|
|
382
|
+
|
|
383
|
+
4. **Responsive**
|
|
384
|
+
- Does it work at 320px width?
|
|
385
|
+
- Are touch targets big enough on mobile?
|