@girardmedia/bootspring 3.3.2 → 3.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/assets/agents/accessibility-auditor.md +39 -0
- package/assets/agents/api-designer.md +40 -0
- package/assets/agents/auth-implementer.md +64 -0
- package/assets/agents/bug-hunter.md +42 -0
- package/assets/agents/bundle-analyzer.md +40 -0
- package/assets/agents/cache-optimizer.md +55 -0
- package/assets/agents/changelog-writer.md +55 -0
- package/assets/agents/ci-cd-builder.md +40 -0
- package/assets/agents/code-explainer.md +39 -0
- package/assets/agents/code-reviewer.md +39 -0
- package/assets/agents/cost-optimizer.md +57 -0
- package/assets/agents/cron-scheduler.md +51 -0
- package/assets/agents/data-seeder.md +56 -0
- package/assets/agents/database-architect.md +40 -0
- package/assets/agents/dependency-updater.md +40 -0
- package/assets/agents/deploy-checker.md +40 -0
- package/assets/agents/docker-optimizer.md +40 -0
- package/assets/agents/documentation-writer.md +40 -0
- package/assets/agents/email-builder.md +55 -0
- package/assets/agents/env-setup.md +40 -0
- package/assets/agents/error-handler.md +40 -0
- package/assets/agents/eslint-fixer.md +46 -0
- package/assets/agents/feature-flagger.md +69 -0
- package/assets/agents/git-detective.md +39 -0
- package/assets/agents/graphql-builder.md +60 -0
- package/assets/agents/incident-responder.md +59 -0
- package/assets/agents/log-analyzer.md +39 -0
- package/assets/agents/migration-planner.md +41 -0
- package/assets/agents/monorepo-navigator.md +39 -0
- package/assets/agents/nextjs-expert.md +57 -0
- package/assets/agents/notification-builder.md +56 -0
- package/assets/agents/onboarding-guide.md +39 -0
- package/assets/agents/performance-profiler.md +40 -0
- package/assets/agents/prisma-expert.md +57 -0
- package/assets/agents/rate-limiter.md +58 -0
- package/assets/agents/react-expert.md +58 -0
- package/assets/agents/refactorer.md +42 -0
- package/assets/agents/regex-builder.md +46 -0
- package/assets/agents/release-manager.md +40 -0
- package/assets/agents/s3-manager.md +58 -0
- package/assets/agents/schema-validator.md +40 -0
- package/assets/agents/search-builder.md +62 -0
- package/assets/agents/security-auditor.md +39 -0
- package/assets/agents/sitemap-generator.md +53 -0
- package/assets/agents/stripe-integrator.md +59 -0
- package/assets/agents/tailwind-expert.md +55 -0
- package/assets/agents/tech-debt-tracker.md +39 -0
- package/assets/agents/test-writer.md +42 -0
- package/assets/agents/type-fixer.md +45 -0
- package/assets/agents/webhook-builder.md +54 -0
- package/assets/rules/cpp.md +53 -0
- package/assets/rules/css.md +52 -0
- package/assets/rules/go.md +50 -0
- package/assets/rules/html.md +52 -0
- package/assets/rules/java.md +51 -0
- package/assets/rules/kotlin.md +50 -0
- package/assets/rules/php.md +51 -0
- package/assets/rules/python.md +51 -0
- package/assets/rules/ruby.md +51 -0
- package/assets/rules/rust.md +49 -0
- package/assets/rules/shell.md +52 -0
- package/assets/rules/sql.md +49 -0
- package/assets/rules/swift.md +50 -0
- package/assets/rules/typescript.md +52 -0
- package/assets/rules/yaml-json.md +51 -0
- package/assets/skills/accessibility.md +210 -0
- package/assets/skills/agent-patterns.md +387 -0
- package/assets/skills/ai-integration.md +263 -0
- package/assets/skills/animation-patterns.md +224 -0
- package/assets/skills/api-design.md +218 -0
- package/assets/skills/api-gateway.md +341 -0
- package/assets/skills/api-versioning.md +226 -0
- package/assets/skills/astro-patterns.md +233 -0
- package/assets/skills/auth-patterns.md +248 -0
- package/assets/skills/aws-patterns.md +171 -0
- package/assets/skills/background-jobs.md +162 -0
- package/assets/skills/browser-extensions.md +309 -0
- package/assets/skills/caching-patterns.md +253 -0
- package/assets/skills/ci-cd.md +251 -0
- package/assets/skills/cli-development.md +296 -0
- package/assets/skills/code-review.md +185 -0
- package/assets/skills/cron-patterns.md +327 -0
- package/assets/skills/data-fetching.md +231 -0
- package/assets/skills/database-migrations.md +346 -0
- package/assets/skills/database-patterns.md +219 -0
- package/assets/skills/debugging.md +281 -0
- package/assets/skills/design-system.md +289 -0
- package/assets/skills/django-patterns.md +182 -0
- package/assets/skills/docker-patterns.md +235 -0
- package/assets/skills/e2e-testing.md +287 -0
- package/assets/skills/edge-computing.md +268 -0
- package/assets/skills/electron-patterns.md +266 -0
- package/assets/skills/email-templates.md +206 -0
- package/assets/skills/error-handling.md +265 -0
- package/assets/skills/event-driven.md +232 -0
- package/assets/skills/express-patterns.md +239 -0
- package/assets/skills/fastapi-patterns.md +198 -0
- package/assets/skills/feature-flags.md +212 -0
- package/assets/skills/figma-to-code.md +298 -0
- package/assets/skills/file-upload.md +228 -0
- package/assets/skills/forms-patterns.md +264 -0
- package/assets/skills/gcp-patterns.md +189 -0
- package/assets/skills/git-workflow.md +187 -0
- package/assets/skills/golang-patterns.md +185 -0
- package/assets/skills/graphql-patterns.md +244 -0
- package/assets/skills/i18n-patterns.md +172 -0
- package/assets/skills/image-processing.md +350 -0
- package/assets/skills/java-springboot.md +226 -0
- package/assets/skills/kotlin-patterns.md +207 -0
- package/assets/skills/kubernetes-patterns.md +326 -0
- package/assets/skills/laravel-patterns.md +261 -0
- package/assets/skills/llm-fine-tuning.md +335 -0
- package/assets/skills/load-testing.md +303 -0
- package/assets/skills/logging-observability.md +228 -0
- package/assets/skills/markdown-processing.md +318 -0
- package/assets/skills/mcp-server-patterns.md +292 -0
- package/assets/skills/microservices.md +272 -0
- package/assets/skills/migration-patterns.md +239 -0
- package/assets/skills/mongodb-patterns.md +189 -0
- package/assets/skills/monorepo-patterns.md +287 -0
- package/assets/skills/nextjs-app-router.md +237 -0
- package/assets/skills/notification-patterns.md +348 -0
- package/assets/skills/oauth-patterns.md +246 -0
- package/assets/skills/payment-integration.md +222 -0
- package/assets/skills/pdf-generation.md +307 -0
- package/assets/skills/performance-optimization.md +277 -0
- package/assets/skills/php-patterns.md +210 -0
- package/assets/skills/prisma-patterns.md +241 -0
- package/assets/skills/prompt-engineering.md +193 -0
- package/assets/skills/pwa-patterns.md +247 -0
- package/assets/skills/python-patterns.md +158 -0
- package/assets/skills/python-testing.md +172 -0
- package/assets/skills/queue-patterns.md +295 -0
- package/assets/skills/rag-patterns.md +159 -0
- package/assets/skills/rate-limiting.md +319 -0
- package/assets/skills/react-components.md +201 -0
- package/assets/skills/react-native-patterns.md +299 -0
- package/assets/skills/real-time-patterns.md +181 -0
- package/assets/skills/redis-patterns.md +188 -0
- package/assets/skills/refactoring.md +218 -0
- package/assets/skills/regex-patterns.md +191 -0
- package/assets/skills/remix-patterns.md +262 -0
- package/assets/skills/responsive-design.md +199 -0
- package/assets/skills/ruby-rails-patterns.md +178 -0
- package/assets/skills/rust-patterns.md +211 -0
- package/assets/skills/search-patterns.md +227 -0
- package/assets/skills/security-hardening.md +237 -0
- package/assets/skills/seo-patterns.md +179 -0
- package/assets/skills/serverless-patterns.md +223 -0
- package/assets/skills/sql-optimization.md +154 -0
- package/assets/skills/state-management.md +254 -0
- package/assets/skills/storybook-patterns.md +330 -0
- package/assets/skills/svelte-patterns.md +258 -0
- package/assets/skills/swift-patterns.md +227 -0
- package/assets/skills/tailwind-patterns.md +272 -0
- package/assets/skills/tdd-workflow.md +199 -0
- package/assets/skills/terraform-patterns.md +270 -0
- package/assets/skills/testing-react.md +240 -0
- package/assets/skills/testing-vitest.md +232 -0
- package/assets/skills/typescript-strict.md +159 -0
- package/assets/skills/video-processing.md +340 -0
- package/assets/skills/vue-patterns.md +247 -0
- package/assets/skills/web-workers.md +327 -0
- package/assets/skills/webhooks-patterns.md +283 -0
- package/assets/skills/websocket-patterns.md +306 -0
- package/dist/cli/index.js +941 -958
- package/dist/core/index.d.ts +341 -11
- package/dist/core.js +58 -95
- package/dist/mcp/index.d.ts +33 -1
- package/dist/mcp-server.js +177 -255
- package/package.json +4 -1
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: debugging
|
|
3
|
+
description: Debug effectively with Chrome DevTools, Node inspector, console methods, memory leak detection, and performance profiling.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Debugging Techniques
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
|
|
10
|
+
Use these techniques when something is broken and you don't know why, when
|
|
11
|
+
performance degrades unexpectedly, or when you need to understand unfamiliar
|
|
12
|
+
code. The best debuggers are systematic — they narrow down the problem space
|
|
13
|
+
with each step instead of making random changes.
|
|
14
|
+
|
|
15
|
+
## How It Works
|
|
16
|
+
|
|
17
|
+
### 1. The Debugging Process
|
|
18
|
+
|
|
19
|
+
Before touching tools, follow this sequence:
|
|
20
|
+
|
|
21
|
+
1. **Reproduce** — Write down exact steps to trigger the bug
|
|
22
|
+
2. **Isolate** — Find the smallest input or condition that causes it
|
|
23
|
+
3. **Hypothesize** — Form a specific theory about what's wrong
|
|
24
|
+
4. **Test** — Verify with a targeted check (breakpoint, log, test)
|
|
25
|
+
5. **Fix** — Change one thing, confirm it resolves the issue
|
|
26
|
+
6. **Verify** — Run the full reproduction to confirm, add a regression test
|
|
27
|
+
|
|
28
|
+
### 2. Chrome DevTools — Sources Panel
|
|
29
|
+
|
|
30
|
+
Set breakpoints directly in your code:
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
// Conditional breakpoint — only breaks when condition is true
|
|
34
|
+
// Right-click the line number → "Add conditional breakpoint"
|
|
35
|
+
// Condition: user.id === 'usr_problem_account'
|
|
36
|
+
|
|
37
|
+
// Logpoint — logs without pausing (no console.log commits needed)
|
|
38
|
+
// Right-click → "Add logpoint"
|
|
39
|
+
// Expression: 'Order total:', order.total, 'items:', order.items.length
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Useful breakpoint types:
|
|
43
|
+
| Type | How to set | When it breaks |
|
|
44
|
+
|------|-----------|---------------|
|
|
45
|
+
| Line | Click line number | Every time that line executes |
|
|
46
|
+
| Conditional | Right-click → condition | Only when expression is truthy |
|
|
47
|
+
| DOM | Elements → right-click node → Break on | When DOM node is modified |
|
|
48
|
+
| XHR/Fetch | Sources → XHR breakpoints | When URL pattern matches |
|
|
49
|
+
| Event listener | Sources → Event Listener Breakpoints | On click, keydown, etc. |
|
|
50
|
+
| Exception | Sources → Pause on exceptions | On thrown error |
|
|
51
|
+
|
|
52
|
+
### 3. Node.js Inspector
|
|
53
|
+
|
|
54
|
+
Debug server-side code with Chrome DevTools.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Start with inspector
|
|
58
|
+
node --inspect dist/server.js
|
|
59
|
+
|
|
60
|
+
# Break on first line (useful for startup issues)
|
|
61
|
+
node --inspect-brk dist/server.js
|
|
62
|
+
|
|
63
|
+
# Attach to a running process
|
|
64
|
+
kill -USR1 <pid> # enables inspector on the process
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Open `chrome://inspect` in Chrome, click "inspect" on your process.
|
|
68
|
+
|
|
69
|
+
For Vitest:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Debug a specific test
|
|
73
|
+
node --inspect-brk ./node_modules/.bin/vitest run --no-file-parallelism src/auth.test.ts
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 4. Console Methods Beyond console.log
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// Structured table output
|
|
80
|
+
console.table(users.map(u => ({ id: u.id, name: u.name, role: u.role })));
|
|
81
|
+
|
|
82
|
+
// Group related logs
|
|
83
|
+
console.group('Order Processing');
|
|
84
|
+
console.log('Validating items:', items.length);
|
|
85
|
+
console.log('Calculating total:', total);
|
|
86
|
+
console.warn('Discount code expired');
|
|
87
|
+
console.groupEnd();
|
|
88
|
+
|
|
89
|
+
// Measure execution time
|
|
90
|
+
console.time('db-query');
|
|
91
|
+
const result = await db.query(sql);
|
|
92
|
+
console.timeEnd('db-query'); // db-query: 42.3ms
|
|
93
|
+
|
|
94
|
+
// Count occurrences
|
|
95
|
+
function processEvent(event: Event) {
|
|
96
|
+
console.count(event.type); // click: 1, click: 2, click: 3
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Assert — logs only when condition is false
|
|
100
|
+
console.assert(user.age >= 0, 'Negative age:', user);
|
|
101
|
+
|
|
102
|
+
// Trace — print call stack
|
|
103
|
+
function unexpectedCall() {
|
|
104
|
+
console.trace('Who called this?');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Dir — inspect object properties
|
|
108
|
+
console.dir(complexObject, { depth: 4, colors: true });
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 5. Source Maps
|
|
112
|
+
|
|
113
|
+
Ensure source maps work in development so stack traces point to original
|
|
114
|
+
TypeScript, not compiled JavaScript.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// vite.config.ts
|
|
118
|
+
export default defineConfig({
|
|
119
|
+
build: {
|
|
120
|
+
sourcemap: true, // generates .map files
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// tsconfig.json
|
|
125
|
+
{
|
|
126
|
+
"compilerOptions": {
|
|
127
|
+
"sourceMap": true,
|
|
128
|
+
"declarationMap": true
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
For production error tracking (Sentry, etc.), upload source maps during build
|
|
134
|
+
but don't serve them publicly:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Upload to Sentry, don't include in deployment
|
|
138
|
+
sentry-cli sourcemaps upload --release=v1.2.3 ./dist
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 6. Memory Leak Detection
|
|
142
|
+
|
|
143
|
+
Signs of a memory leak: increasing memory over time, page becoming sluggish,
|
|
144
|
+
"out of memory" crashes.
|
|
145
|
+
|
|
146
|
+
**Browser — DevTools Memory panel:**
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
1. Open Memory tab
|
|
150
|
+
2. Take heap snapshot (baseline)
|
|
151
|
+
3. Perform the suspected leaking action several times
|
|
152
|
+
4. Take another snapshot
|
|
153
|
+
5. Select "Comparison" view between snapshots
|
|
154
|
+
6. Sort by "# New" to find objects that accumulate
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Common React memory leaks:**
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
// Leak: effect cleanup missing
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
const interval = setInterval(fetchData, 5000);
|
|
163
|
+
// Missing: return () => clearInterval(interval);
|
|
164
|
+
}, []);
|
|
165
|
+
|
|
166
|
+
// Leak: event listener not removed
|
|
167
|
+
useEffect(() => {
|
|
168
|
+
window.addEventListener('resize', handleResize);
|
|
169
|
+
return () => window.removeEventListener('resize', handleResize); // fix
|
|
170
|
+
}, []);
|
|
171
|
+
|
|
172
|
+
// Leak: updating state on unmounted component
|
|
173
|
+
useEffect(() => {
|
|
174
|
+
let cancelled = false;
|
|
175
|
+
fetchData().then(data => {
|
|
176
|
+
if (!cancelled) setData(data); // guard against unmounted update
|
|
177
|
+
});
|
|
178
|
+
return () => { cancelled = true; };
|
|
179
|
+
}, []);
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Node.js — heap snapshots:**
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
# Take a snapshot at runtime
|
|
186
|
+
node --inspect dist/server.js
|
|
187
|
+
# In DevTools: Memory → Take snapshot
|
|
188
|
+
|
|
189
|
+
# Or programmatically
|
|
190
|
+
node -e "
|
|
191
|
+
const v8 = require('v8');
|
|
192
|
+
const fs = require('fs');
|
|
193
|
+
const snapshot = v8.writeHeapSnapshot();
|
|
194
|
+
console.log('Snapshot written to:', snapshot);
|
|
195
|
+
"
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 7. Performance Profiling
|
|
199
|
+
|
|
200
|
+
**Browser — Performance panel:**
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
1. Open Performance tab
|
|
204
|
+
2. Click Record
|
|
205
|
+
3. Perform the slow action
|
|
206
|
+
4. Stop recording
|
|
207
|
+
5. Look for: long tasks (>50ms), layout thrashing, excessive re-renders
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**React Profiler:**
|
|
211
|
+
|
|
212
|
+
```tsx
|
|
213
|
+
import { Profiler } from 'react';
|
|
214
|
+
|
|
215
|
+
function onRender(id: string, phase: string, actualDuration: number) {
|
|
216
|
+
if (actualDuration > 16) { // longer than one frame
|
|
217
|
+
console.warn(`Slow render: ${id} took ${actualDuration.toFixed(1)}ms`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
<Profiler id="Dashboard" onRender={onRender}>
|
|
222
|
+
<Dashboard />
|
|
223
|
+
</Profiler>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Install React DevTools browser extension for the dedicated Profiler tab with
|
|
227
|
+
flame graphs and component render reasons.
|
|
228
|
+
|
|
229
|
+
**Node.js — CPU profiling:**
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
# Profile for 10 seconds
|
|
233
|
+
node --prof dist/server.js
|
|
234
|
+
# Generate readable output
|
|
235
|
+
node --prof-process isolate-*.log > profile.txt
|
|
236
|
+
|
|
237
|
+
# Or use clinic.js for automated analysis
|
|
238
|
+
npx clinic doctor -- node dist/server.js
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### 8. Network Debugging
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
# Watch all requests/responses
|
|
245
|
+
# Chrome DevTools → Network tab → Preserve log
|
|
246
|
+
|
|
247
|
+
# cURL to reproduce API issues
|
|
248
|
+
curl -v -X POST https://api.example.com/users \
|
|
249
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
250
|
+
-H "Content-Type: application/json" \
|
|
251
|
+
-d '{"name": "test"}'
|
|
252
|
+
|
|
253
|
+
# DNS resolution issues
|
|
254
|
+
nslookup api.example.com
|
|
255
|
+
dig api.example.com
|
|
256
|
+
|
|
257
|
+
# Test connectivity
|
|
258
|
+
curl -o /dev/null -s -w "HTTP %{http_code}, Time: %{time_total}s\n" https://api.example.com/health
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Examples
|
|
262
|
+
|
|
263
|
+
| Problem | Tool | What to look for |
|
|
264
|
+
|---------|------|-----------------|
|
|
265
|
+
| Function returns wrong value | Conditional breakpoint | Variable values at the branch point |
|
|
266
|
+
| Slow page load | Network tab | Large responses, waterfall gaps |
|
|
267
|
+
| Growing memory | Memory snapshots | Comparison view, increasing object counts |
|
|
268
|
+
| Slow interaction | Performance panel | Long tasks, excessive layout recalc |
|
|
269
|
+
| Can't reproduce locally | Logpoints | Non-intrusive data collection |
|
|
270
|
+
| Regression in recent commits | `git bisect` | First commit that breaks the test |
|
|
271
|
+
|
|
272
|
+
## Checklist
|
|
273
|
+
|
|
274
|
+
- [ ] Bug report includes exact reproduction steps before debugging starts
|
|
275
|
+
- [ ] Source maps are enabled in development for readable stack traces
|
|
276
|
+
- [ ] `console.log` debugging is replaced with breakpoints or logpoints before committing
|
|
277
|
+
- [ ] Memory-intensive pages are profiled with heap snapshots
|
|
278
|
+
- [ ] Effects and event listeners always clean up in the return function
|
|
279
|
+
- [ ] Performance profiling targets specific slow interactions, not the whole page
|
|
280
|
+
- [ ] Production errors are tracked with Sentry or equivalent (with source maps uploaded)
|
|
281
|
+
- [ ] No `console.log` or `debugger` statements are committed to the codebase
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: design-system
|
|
3
|
+
description: Build design systems — tokens, component APIs, variants, compound components, Storybook, and theming.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Design System Patterns
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
|
|
10
|
+
Build a design system when your application has more than a handful of shared
|
|
11
|
+
UI components, or when multiple teams or projects share a visual language.
|
|
12
|
+
This skill covers design tokens, component API design, variant patterns,
|
|
13
|
+
compound components, Storybook documentation, and theming. Apply early —
|
|
14
|
+
retrofitting consistency into an ad-hoc component library is expensive.
|
|
15
|
+
|
|
16
|
+
## How It Works
|
|
17
|
+
|
|
18
|
+
### 1. Design Tokens — The Foundation
|
|
19
|
+
|
|
20
|
+
Tokens are named values that encode design decisions. Define once, use everywhere.
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
// tokens.ts — single source of truth
|
|
24
|
+
export const tokens = {
|
|
25
|
+
color: {
|
|
26
|
+
primary: { 50: '#eff6ff', 100: '#dbeafe', 500: '#3b82f6', 600: '#2563eb', 700: '#1d4ed8', 900: '#1e3a5f' },
|
|
27
|
+
neutral: { 50: '#fafafa', 100: '#f5f5f5', 200: '#e5e5e5', 500: '#737373', 700: '#404040', 900: '#171717' },
|
|
28
|
+
success: { 500: '#22c55e', 700: '#15803d' },
|
|
29
|
+
warning: { 500: '#f59e0b', 700: '#b45309' },
|
|
30
|
+
danger: { 500: '#ef4444', 700: '#b91c1c' },
|
|
31
|
+
},
|
|
32
|
+
spacing: {
|
|
33
|
+
0: '0', 1: '0.25rem', 2: '0.5rem', 3: '0.75rem',
|
|
34
|
+
4: '1rem', 5: '1.25rem', 6: '1.5rem', 8: '2rem',
|
|
35
|
+
10: '2.5rem', 12: '3rem', 16: '4rem', 20: '5rem',
|
|
36
|
+
},
|
|
37
|
+
radius: {
|
|
38
|
+
none: '0', sm: '0.25rem', md: '0.375rem',
|
|
39
|
+
lg: '0.5rem', xl: '0.75rem', full: '9999px',
|
|
40
|
+
},
|
|
41
|
+
font: {
|
|
42
|
+
family: { sans: 'Inter, system-ui, sans-serif', mono: 'JetBrains Mono, monospace' },
|
|
43
|
+
size: { xs: '0.75rem', sm: '0.875rem', base: '1rem', lg: '1.125rem', xl: '1.25rem', '2xl': '1.5rem' },
|
|
44
|
+
weight: { normal: '400', medium: '500', semibold: '600', bold: '700' },
|
|
45
|
+
},
|
|
46
|
+
shadow: {
|
|
47
|
+
sm: '0 1px 2px rgba(0,0,0,0.05)',
|
|
48
|
+
md: '0 4px 6px -1px rgba(0,0,0,0.1)',
|
|
49
|
+
lg: '0 10px 15px -3px rgba(0,0,0,0.1)',
|
|
50
|
+
},
|
|
51
|
+
} as const;
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 2. Component API Design — Props as Variants
|
|
55
|
+
|
|
56
|
+
Use a constrained set of variants, not arbitrary style props.
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
60
|
+
|
|
61
|
+
const buttonVariants = cva(
|
|
62
|
+
// Base styles
|
|
63
|
+
'inline-flex items-center justify-center font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50',
|
|
64
|
+
{
|
|
65
|
+
variants: {
|
|
66
|
+
variant: {
|
|
67
|
+
primary: 'bg-primary-600 text-white hover:bg-primary-700',
|
|
68
|
+
secondary: 'bg-neutral-100 text-neutral-900 hover:bg-neutral-200',
|
|
69
|
+
ghost: 'hover:bg-neutral-100 text-neutral-700',
|
|
70
|
+
danger: 'bg-danger-500 text-white hover:bg-danger-700',
|
|
71
|
+
},
|
|
72
|
+
size: {
|
|
73
|
+
sm: 'h-8 px-3 text-sm rounded-md gap-1.5',
|
|
74
|
+
md: 'h-10 px-4 text-sm rounded-md gap-2',
|
|
75
|
+
lg: 'h-12 px-6 text-base rounded-lg gap-2',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
defaultVariants: {
|
|
79
|
+
variant: 'primary',
|
|
80
|
+
size: 'md',
|
|
81
|
+
},
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
interface ButtonProps
|
|
86
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
87
|
+
VariantProps<typeof buttonVariants> {
|
|
88
|
+
loading?: boolean;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function Button({ variant, size, loading, children, className, ...props }: ButtonProps) {
|
|
92
|
+
return (
|
|
93
|
+
<button
|
|
94
|
+
className={buttonVariants({ variant, size, className })}
|
|
95
|
+
disabled={props.disabled || loading}
|
|
96
|
+
{...props}
|
|
97
|
+
>
|
|
98
|
+
{loading && <Spinner className="animate-spin h-4 w-4" />}
|
|
99
|
+
{children}
|
|
100
|
+
</button>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 3. Compound Components — Complex UI Composition
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
// Card with slot-based composition
|
|
109
|
+
interface CardProps { children: React.ReactNode; className?: string }
|
|
110
|
+
|
|
111
|
+
function Card({ children, className }: CardProps) {
|
|
112
|
+
return <div className={cn('rounded-lg border bg-white shadow-sm', className)}>{children}</div>;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function CardHeader({ children, className }: CardProps) {
|
|
116
|
+
return <div className={cn('p-6 pb-0', className)}>{children}</div>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function CardTitle({ children, className }: CardProps) {
|
|
120
|
+
return <h3 className={cn('text-lg font-semibold', className)}>{children}</h3>;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function CardContent({ children, className }: CardProps) {
|
|
124
|
+
return <div className={cn('p-6', className)}>{children}</div>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function CardFooter({ children, className }: CardProps) {
|
|
128
|
+
return <div className={cn('p-6 pt-0 flex gap-2', className)}>{children}</div>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Usage — composable and explicit
|
|
132
|
+
<Card>
|
|
133
|
+
<CardHeader>
|
|
134
|
+
<CardTitle>Order Summary</CardTitle>
|
|
135
|
+
</CardHeader>
|
|
136
|
+
<CardContent>
|
|
137
|
+
<OrderDetails order={order} />
|
|
138
|
+
</CardContent>
|
|
139
|
+
<CardFooter>
|
|
140
|
+
<Button variant="primary">Confirm</Button>
|
|
141
|
+
<Button variant="ghost">Cancel</Button>
|
|
142
|
+
</CardFooter>
|
|
143
|
+
</Card>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### 4. Theming — Light/Dark Mode
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
// CSS custom properties for runtime theming
|
|
150
|
+
const themes = {
|
|
151
|
+
light: {
|
|
152
|
+
'--color-bg': tokens.color.neutral[50],
|
|
153
|
+
'--color-surface': '#ffffff',
|
|
154
|
+
'--color-text': tokens.color.neutral[900],
|
|
155
|
+
'--color-text-muted': tokens.color.neutral[500],
|
|
156
|
+
'--color-border': tokens.color.neutral[200],
|
|
157
|
+
'--color-primary': tokens.color.primary[600],
|
|
158
|
+
},
|
|
159
|
+
dark: {
|
|
160
|
+
'--color-bg': tokens.color.neutral[900],
|
|
161
|
+
'--color-surface': '#262626',
|
|
162
|
+
'--color-text': tokens.color.neutral[50],
|
|
163
|
+
'--color-text-muted': tokens.color.neutral[500],
|
|
164
|
+
'--color-border': '#404040',
|
|
165
|
+
'--color-primary': tokens.color.primary[500],
|
|
166
|
+
},
|
|
167
|
+
} as const;
|
|
168
|
+
|
|
169
|
+
// ThemeProvider
|
|
170
|
+
function ThemeProvider({ children }: { children: React.ReactNode }) {
|
|
171
|
+
const [theme, setTheme] = useState<'light' | 'dark'>(() => {
|
|
172
|
+
if (typeof window === 'undefined') return 'light';
|
|
173
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
const root = document.documentElement;
|
|
178
|
+
const vars = themes[theme];
|
|
179
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
180
|
+
root.style.setProperty(key, value);
|
|
181
|
+
}
|
|
182
|
+
root.setAttribute('data-theme', theme);
|
|
183
|
+
}, [theme]);
|
|
184
|
+
|
|
185
|
+
return (
|
|
186
|
+
<ThemeContext.Provider value={{ theme, setTheme }}>
|
|
187
|
+
{children}
|
|
188
|
+
</ThemeContext.Provider>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### 5. Storybook — Living Documentation
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// Button.stories.tsx
|
|
197
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
198
|
+
import { Button } from './Button';
|
|
199
|
+
|
|
200
|
+
const meta: Meta<typeof Button> = {
|
|
201
|
+
title: 'Components/Button',
|
|
202
|
+
component: Button,
|
|
203
|
+
argTypes: {
|
|
204
|
+
variant: { control: 'select', options: ['primary', 'secondary', 'ghost', 'danger'] },
|
|
205
|
+
size: { control: 'select', options: ['sm', 'md', 'lg'] },
|
|
206
|
+
loading: { control: 'boolean' },
|
|
207
|
+
disabled: { control: 'boolean' },
|
|
208
|
+
},
|
|
209
|
+
tags: ['autodocs'],
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
export default meta;
|
|
213
|
+
type Story = StoryObj<typeof Button>;
|
|
214
|
+
|
|
215
|
+
export const Primary: Story = {
|
|
216
|
+
args: { children: 'Button', variant: 'primary' },
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
export const AllVariants: Story = {
|
|
220
|
+
render: () => (
|
|
221
|
+
<div className="flex gap-2">
|
|
222
|
+
<Button variant="primary">Primary</Button>
|
|
223
|
+
<Button variant="secondary">Secondary</Button>
|
|
224
|
+
<Button variant="ghost">Ghost</Button>
|
|
225
|
+
<Button variant="danger">Danger</Button>
|
|
226
|
+
</div>
|
|
227
|
+
),
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
export const Loading: Story = {
|
|
231
|
+
args: { children: 'Saving...', loading: true },
|
|
232
|
+
};
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### 6. Accessibility in Components
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
// Always forward refs, support aria attributes, handle keyboard
|
|
239
|
+
const Input = forwardRef<HTMLInputElement, InputProps>(
|
|
240
|
+
({ label, error, id: providedId, ...props }, ref) => {
|
|
241
|
+
const id = providedId ?? useId();
|
|
242
|
+
const errorId = `${id}-error`;
|
|
243
|
+
|
|
244
|
+
return (
|
|
245
|
+
<div>
|
|
246
|
+
<label htmlFor={id} className="block text-sm font-medium">
|
|
247
|
+
{label}
|
|
248
|
+
</label>
|
|
249
|
+
<input
|
|
250
|
+
ref={ref}
|
|
251
|
+
id={id}
|
|
252
|
+
aria-invalid={!!error}
|
|
253
|
+
aria-describedby={error ? errorId : undefined}
|
|
254
|
+
className={cn('input-base', error && 'border-danger-500')}
|
|
255
|
+
{...props}
|
|
256
|
+
/>
|
|
257
|
+
{error && (
|
|
258
|
+
<p id={errorId} role="alert" className="text-sm text-danger-500 mt-1">
|
|
259
|
+
{error}
|
|
260
|
+
</p>
|
|
261
|
+
)}
|
|
262
|
+
</div>
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
);
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Examples
|
|
269
|
+
|
|
270
|
+
| Pattern | Purpose | Benefit |
|
|
271
|
+
|---------|---------|---------|
|
|
272
|
+
| Design tokens | Centralized values | Change once, update everywhere |
|
|
273
|
+
| CVA variants | Constrained component API | Type-safe, predictable styling |
|
|
274
|
+
| Compound components | Flexible composition | Explicit slots, no prop drilling |
|
|
275
|
+
| CSS custom properties | Runtime theming | Dark mode without rebuilding |
|
|
276
|
+
| Storybook autodocs | Living documentation | Always in sync with code |
|
|
277
|
+
|
|
278
|
+
## Checklist
|
|
279
|
+
|
|
280
|
+
- [ ] Design tokens defined in a single file, not scattered in components
|
|
281
|
+
- [ ] Components use variant props (not arbitrary `style` or `className` overrides)
|
|
282
|
+
- [ ] Compound components used for multi-slot layouts (Card, Dialog, Dropdown)
|
|
283
|
+
- [ ] All interactive components are keyboard accessible and have ARIA attributes
|
|
284
|
+
- [ ] Theming uses CSS custom properties for runtime switching
|
|
285
|
+
- [ ] Storybook stories cover all variants, states, and edge cases
|
|
286
|
+
- [ ] Color contrast meets WCAG AA (4.5:1 for text, 3:1 for UI elements)
|
|
287
|
+
- [ ] Components forward refs and spread native HTML attributes
|
|
288
|
+
- [ ] Token naming is semantic (`color.primary`) not descriptive (`color.blue`)
|
|
289
|
+
- [ ] Component API reviewed: no boolean explosion, sensible defaults
|