@juho0719/cckit 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 (111) hide show
  1. package/assets/agents/architect.md +211 -0
  2. package/assets/agents/build-error-resolver.md +114 -0
  3. package/assets/agents/ccwin-code-reviewer.md +224 -0
  4. package/assets/agents/database-reviewer.md +91 -0
  5. package/assets/agents/doc-updater.md +107 -0
  6. package/assets/agents/e2e-runner.md +107 -0
  7. package/assets/agents/planner.md +212 -0
  8. package/assets/agents/python-reviewer.md +98 -0
  9. package/assets/agents/refactor-cleaner.md +85 -0
  10. package/assets/agents/security-reviewer.md +108 -0
  11. package/assets/agents/superpower-code-reviewer.md +48 -0
  12. package/assets/agents/tdd-guide.md +80 -0
  13. package/assets/commands/build-fix.md +62 -0
  14. package/assets/commands/checkpoint.md +74 -0
  15. package/assets/commands/code-review.md +40 -0
  16. package/assets/commands/e2e.md +362 -0
  17. package/assets/commands/eval.md +120 -0
  18. package/assets/commands/orchestrate.md +172 -0
  19. package/assets/commands/plan.md +113 -0
  20. package/assets/commands/python-review.md +297 -0
  21. package/assets/commands/refactor-clean.md +80 -0
  22. package/assets/commands/sessions.md +305 -0
  23. package/assets/commands/tdd.md +326 -0
  24. package/assets/commands/test-coverage.md +69 -0
  25. package/assets/commands/update-codemaps.md +72 -0
  26. package/assets/commands/update-docs.md +84 -0
  27. package/assets/commands/verify.md +59 -0
  28. package/assets/hooks/post-edit-format.js +49 -0
  29. package/assets/hooks/post-edit-typecheck.js +96 -0
  30. package/assets/mcps/mcp-servers.json +92 -0
  31. package/assets/rules/common/agents.md +49 -0
  32. package/assets/rules/common/coding-style.md +48 -0
  33. package/assets/rules/common/git-workflow.md +45 -0
  34. package/assets/rules/common/hooks.md +30 -0
  35. package/assets/rules/common/patterns.md +31 -0
  36. package/assets/rules/common/performance.md +55 -0
  37. package/assets/rules/common/security.md +29 -0
  38. package/assets/rules/common/testing.md +29 -0
  39. package/assets/rules/python/coding-style.md +42 -0
  40. package/assets/rules/python/hooks.md +19 -0
  41. package/assets/rules/python/patterns.md +39 -0
  42. package/assets/rules/python/security.md +30 -0
  43. package/assets/rules/python/testing.md +38 -0
  44. package/assets/rules/typescript/coding-style.md +18 -0
  45. package/assets/rules/typescript/hooks.md +19 -0
  46. package/assets/rules/typescript/patterns.md +39 -0
  47. package/assets/rules/typescript/security.md +30 -0
  48. package/assets/rules/typescript/testing.md +38 -0
  49. package/assets/skills/api-design/SKILL.md +522 -0
  50. package/assets/skills/backend-patterns/SKILL.md +597 -0
  51. package/assets/skills/brainstorming/SKILL.md +96 -0
  52. package/assets/skills/coding-standards/SKILL.md +529 -0
  53. package/assets/skills/database-migrations/SKILL.md +334 -0
  54. package/assets/skills/deployment-patterns/SKILL.md +426 -0
  55. package/assets/skills/dispatching-parallel-agents/SKILL.md +180 -0
  56. package/assets/skills/docker-patterns/SKILL.md +363 -0
  57. package/assets/skills/e2e-testing/SKILL.md +325 -0
  58. package/assets/skills/eval-harness/SKILL.md +235 -0
  59. package/assets/skills/executing-plans/SKILL.md +84 -0
  60. package/assets/skills/finishing-a-development-branch/SKILL.md +200 -0
  61. package/assets/skills/frontend-patterns/SKILL.md +641 -0
  62. package/assets/skills/iterative-retrieval/SKILL.md +210 -0
  63. package/assets/skills/postgres-patterns/SKILL.md +145 -0
  64. package/assets/skills/python-patterns/SKILL.md +749 -0
  65. package/assets/skills/python-testing/SKILL.md +815 -0
  66. package/assets/skills/receiving-code-review/SKILL.md +213 -0
  67. package/assets/skills/requesting-code-review/SKILL.md +105 -0
  68. package/assets/skills/requesting-code-review/code-reviewer-template.md +146 -0
  69. package/assets/skills/subagent-driven-development/SKILL.md +242 -0
  70. package/assets/skills/subagent-driven-development/code-quality-reviewer-prompt.md +20 -0
  71. package/assets/skills/subagent-driven-development/implementer-prompt.md +78 -0
  72. package/assets/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
  73. package/assets/skills/systematic-debugging/CREATION-LOG.md +114 -0
  74. package/assets/skills/systematic-debugging/SKILL.md +296 -0
  75. package/assets/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  76. package/assets/skills/systematic-debugging/condition-based-waiting.md +115 -0
  77. package/assets/skills/systematic-debugging/defense-in-depth.md +122 -0
  78. package/assets/skills/systematic-debugging/root-cause-tracing.md +169 -0
  79. package/assets/skills/systematic-debugging/scripts/find-polluter.sh +63 -0
  80. package/assets/skills/systematic-debugging/test-academic.md +14 -0
  81. package/assets/skills/systematic-debugging/test-pressure-1.md +58 -0
  82. package/assets/skills/systematic-debugging/test-pressure-2.md +68 -0
  83. package/assets/skills/systematic-debugging/test-pressure-3.md +69 -0
  84. package/assets/skills/tdd-workflow/SKILL.md +409 -0
  85. package/assets/skills/test-driven-development/SKILL.md +371 -0
  86. package/assets/skills/test-driven-development/testing-anti-patterns.md +299 -0
  87. package/assets/skills/using-git-worktrees/SKILL.md +218 -0
  88. package/assets/skills/verification-before-completion/SKILL.md +139 -0
  89. package/assets/skills/verification-loop/SKILL.md +125 -0
  90. package/assets/skills/writing-plans/SKILL.md +116 -0
  91. package/dist/agents-AEKT67A6.js +9 -0
  92. package/dist/chunk-3GUKEMND.js +28 -0
  93. package/dist/chunk-3UNN3IBE.js +54 -0
  94. package/dist/chunk-3Y26YU4R.js +27 -0
  95. package/dist/chunk-5XOKKPAA.js +21 -0
  96. package/dist/chunk-6B46AIFM.js +136 -0
  97. package/dist/chunk-EYY2IZ7N.js +27 -0
  98. package/dist/chunk-K25UZZVG.js +17 -0
  99. package/dist/chunk-KEENFBLL.js +24 -0
  100. package/dist/chunk-RMUKD7CW.js +44 -0
  101. package/dist/chunk-W63UKEIT.js +50 -0
  102. package/dist/cli-VZRGF733.js +238 -0
  103. package/dist/commands-P5LILVZ5.js +9 -0
  104. package/dist/hooks-IIG2XK4I.js +9 -0
  105. package/dist/index.js +131 -0
  106. package/dist/mcps-67Q7TBGW.js +6 -0
  107. package/dist/paths-FT6KBIRD.js +10 -0
  108. package/dist/registry-EGXWYWWK.js +17 -0
  109. package/dist/rules-2CPBVNNJ.js +7 -0
  110. package/dist/skills-ULMW3UCM.js +8 -0
  111. package/package.json +36 -0
@@ -0,0 +1,641 @@
1
+ ---
2
+ name: frontend-patterns
3
+ description: Frontend development patterns for React, Next.js, state management, performance optimization, and UI best practices.
4
+ ---
5
+
6
+ # Frontend Development Patterns
7
+
8
+ Modern frontend patterns for React, Next.js, and performant user interfaces.
9
+
10
+ ## When to Activate
11
+
12
+ - Building React components (composition, props, rendering)
13
+ - Managing state (useState, useReducer, Zustand, Context)
14
+ - Implementing data fetching (SWR, React Query, server components)
15
+ - Optimizing performance (memoization, virtualization, code splitting)
16
+ - Working with forms (validation, controlled inputs, Zod schemas)
17
+ - Handling client-side routing and navigation
18
+ - Building accessible, responsive UI patterns
19
+
20
+ ## Component Patterns
21
+
22
+ ### Composition Over Inheritance
23
+
24
+ ```typescript
25
+ // ✅ GOOD: Component composition
26
+ interface CardProps {
27
+ children: React.ReactNode
28
+ variant?: 'default' | 'outlined'
29
+ }
30
+
31
+ export function Card({ children, variant = 'default' }: CardProps) {
32
+ return <div className={`card card-${variant}`}>{children}</div>
33
+ }
34
+
35
+ export function CardHeader({ children }: { children: React.ReactNode }) {
36
+ return <div className="card-header">{children}</div>
37
+ }
38
+
39
+ export function CardBody({ children }: { children: React.ReactNode }) {
40
+ return <div className="card-body">{children}</div>
41
+ }
42
+
43
+ // Usage
44
+ <Card>
45
+ <CardHeader>Title</CardHeader>
46
+ <CardBody>Content</CardBody>
47
+ </Card>
48
+ ```
49
+
50
+ ### Compound Components
51
+
52
+ ```typescript
53
+ interface TabsContextValue {
54
+ activeTab: string
55
+ setActiveTab: (tab: string) => void
56
+ }
57
+
58
+ const TabsContext = createContext<TabsContextValue | undefined>(undefined)
59
+
60
+ export function Tabs({ children, defaultTab }: {
61
+ children: React.ReactNode
62
+ defaultTab: string
63
+ }) {
64
+ const [activeTab, setActiveTab] = useState(defaultTab)
65
+
66
+ return (
67
+ <TabsContext.Provider value={{ activeTab, setActiveTab }}>
68
+ {children}
69
+ </TabsContext.Provider>
70
+ )
71
+ }
72
+
73
+ export function TabList({ children }: { children: React.ReactNode }) {
74
+ return <div className="tab-list">{children}</div>
75
+ }
76
+
77
+ export function Tab({ id, children }: { id: string, children: React.ReactNode }) {
78
+ const context = useContext(TabsContext)
79
+ if (!context) throw new Error('Tab must be used within Tabs')
80
+
81
+ return (
82
+ <button
83
+ className={context.activeTab === id ? 'active' : ''}
84
+ onClick={() => context.setActiveTab(id)}
85
+ >
86
+ {children}
87
+ </button>
88
+ )
89
+ }
90
+
91
+ // Usage
92
+ <Tabs defaultTab="overview">
93
+ <TabList>
94
+ <Tab id="overview">Overview</Tab>
95
+ <Tab id="details">Details</Tab>
96
+ </TabList>
97
+ </Tabs>
98
+ ```
99
+
100
+ ### Render Props Pattern
101
+
102
+ ```typescript
103
+ interface DataLoaderProps<T> {
104
+ url: string
105
+ children: (data: T | null, loading: boolean, error: Error | null) => React.ReactNode
106
+ }
107
+
108
+ export function DataLoader<T>({ url, children }: DataLoaderProps<T>) {
109
+ const [data, setData] = useState<T | null>(null)
110
+ const [loading, setLoading] = useState(true)
111
+ const [error, setError] = useState<Error | null>(null)
112
+
113
+ useEffect(() => {
114
+ fetch(url)
115
+ .then(res => res.json())
116
+ .then(setData)
117
+ .catch(setError)
118
+ .finally(() => setLoading(false))
119
+ }, [url])
120
+
121
+ return <>{children(data, loading, error)}</>
122
+ }
123
+
124
+ // Usage
125
+ <DataLoader<Market[]> url="/api/markets">
126
+ {(markets, loading, error) => {
127
+ if (loading) return <Spinner />
128
+ if (error) return <Error error={error} />
129
+ return <MarketList markets={markets!} />
130
+ }}
131
+ </DataLoader>
132
+ ```
133
+
134
+ ## Custom Hooks Patterns
135
+
136
+ ### State Management Hook
137
+
138
+ ```typescript
139
+ export function useToggle(initialValue = false): [boolean, () => void] {
140
+ const [value, setValue] = useState(initialValue)
141
+
142
+ const toggle = useCallback(() => {
143
+ setValue(v => !v)
144
+ }, [])
145
+
146
+ return [value, toggle]
147
+ }
148
+
149
+ // Usage
150
+ const [isOpen, toggleOpen] = useToggle()
151
+ ```
152
+
153
+ ### Async Data Fetching Hook
154
+
155
+ ```typescript
156
+ interface UseQueryOptions<T> {
157
+ onSuccess?: (data: T) => void
158
+ onError?: (error: Error) => void
159
+ enabled?: boolean
160
+ }
161
+
162
+ export function useQuery<T>(
163
+ key: string,
164
+ fetcher: () => Promise<T>,
165
+ options?: UseQueryOptions<T>
166
+ ) {
167
+ const [data, setData] = useState<T | null>(null)
168
+ const [error, setError] = useState<Error | null>(null)
169
+ const [loading, setLoading] = useState(false)
170
+
171
+ const refetch = useCallback(async () => {
172
+ setLoading(true)
173
+ setError(null)
174
+
175
+ try {
176
+ const result = await fetcher()
177
+ setData(result)
178
+ options?.onSuccess?.(result)
179
+ } catch (err) {
180
+ const error = err as Error
181
+ setError(error)
182
+ options?.onError?.(error)
183
+ } finally {
184
+ setLoading(false)
185
+ }
186
+ }, [fetcher, options])
187
+
188
+ useEffect(() => {
189
+ if (options?.enabled !== false) {
190
+ refetch()
191
+ }
192
+ }, [key, refetch, options?.enabled])
193
+
194
+ return { data, error, loading, refetch }
195
+ }
196
+
197
+ // Usage
198
+ const { data: markets, loading, error, refetch } = useQuery(
199
+ 'markets',
200
+ () => fetch('/api/markets').then(r => r.json()),
201
+ {
202
+ onSuccess: data => console.log('Fetched', data.length, 'markets'),
203
+ onError: err => console.error('Failed:', err)
204
+ }
205
+ )
206
+ ```
207
+
208
+ ### Debounce Hook
209
+
210
+ ```typescript
211
+ export function useDebounce<T>(value: T, delay: number): T {
212
+ const [debouncedValue, setDebouncedValue] = useState<T>(value)
213
+
214
+ useEffect(() => {
215
+ const handler = setTimeout(() => {
216
+ setDebouncedValue(value)
217
+ }, delay)
218
+
219
+ return () => clearTimeout(handler)
220
+ }, [value, delay])
221
+
222
+ return debouncedValue
223
+ }
224
+
225
+ // Usage
226
+ const [searchQuery, setSearchQuery] = useState('')
227
+ const debouncedQuery = useDebounce(searchQuery, 500)
228
+
229
+ useEffect(() => {
230
+ if (debouncedQuery) {
231
+ performSearch(debouncedQuery)
232
+ }
233
+ }, [debouncedQuery])
234
+ ```
235
+
236
+ ## State Management Patterns
237
+
238
+ ### Context + Reducer Pattern
239
+
240
+ ```typescript
241
+ interface State {
242
+ markets: Market[]
243
+ selectedMarket: Market | null
244
+ loading: boolean
245
+ }
246
+
247
+ type Action =
248
+ | { type: 'SET_MARKETS'; payload: Market[] }
249
+ | { type: 'SELECT_MARKET'; payload: Market }
250
+ | { type: 'SET_LOADING'; payload: boolean }
251
+
252
+ function reducer(state: State, action: Action): State {
253
+ switch (action.type) {
254
+ case 'SET_MARKETS':
255
+ return { ...state, markets: action.payload }
256
+ case 'SELECT_MARKET':
257
+ return { ...state, selectedMarket: action.payload }
258
+ case 'SET_LOADING':
259
+ return { ...state, loading: action.payload }
260
+ default:
261
+ return state
262
+ }
263
+ }
264
+
265
+ const MarketContext = createContext<{
266
+ state: State
267
+ dispatch: Dispatch<Action>
268
+ } | undefined>(undefined)
269
+
270
+ export function MarketProvider({ children }: { children: React.ReactNode }) {
271
+ const [state, dispatch] = useReducer(reducer, {
272
+ markets: [],
273
+ selectedMarket: null,
274
+ loading: false
275
+ })
276
+
277
+ return (
278
+ <MarketContext.Provider value={{ state, dispatch }}>
279
+ {children}
280
+ </MarketContext.Provider>
281
+ )
282
+ }
283
+
284
+ export function useMarkets() {
285
+ const context = useContext(MarketContext)
286
+ if (!context) throw new Error('useMarkets must be used within MarketProvider')
287
+ return context
288
+ }
289
+ ```
290
+
291
+ ## Performance Optimization
292
+
293
+ ### Memoization
294
+
295
+ ```typescript
296
+ // ✅ useMemo for expensive computations
297
+ const sortedMarkets = useMemo(() => {
298
+ return markets.sort((a, b) => b.volume - a.volume)
299
+ }, [markets])
300
+
301
+ // ✅ useCallback for functions passed to children
302
+ const handleSearch = useCallback((query: string) => {
303
+ setSearchQuery(query)
304
+ }, [])
305
+
306
+ // ✅ React.memo for pure components
307
+ export const MarketCard = React.memo<MarketCardProps>(({ market }) => {
308
+ return (
309
+ <div className="market-card">
310
+ <h3>{market.name}</h3>
311
+ <p>{market.description}</p>
312
+ </div>
313
+ )
314
+ })
315
+ ```
316
+
317
+ ### Code Splitting & Lazy Loading
318
+
319
+ ```typescript
320
+ import { lazy, Suspense } from 'react'
321
+
322
+ // ✅ Lazy load heavy components
323
+ const HeavyChart = lazy(() => import('./HeavyChart'))
324
+ const ThreeJsBackground = lazy(() => import('./ThreeJsBackground'))
325
+
326
+ export function Dashboard() {
327
+ return (
328
+ <div>
329
+ <Suspense fallback={<ChartSkeleton />}>
330
+ <HeavyChart data={data} />
331
+ </Suspense>
332
+
333
+ <Suspense fallback={null}>
334
+ <ThreeJsBackground />
335
+ </Suspense>
336
+ </div>
337
+ )
338
+ }
339
+ ```
340
+
341
+ ### Virtualization for Long Lists
342
+
343
+ ```typescript
344
+ import { useVirtualizer } from '@tanstack/react-virtual'
345
+
346
+ export function VirtualMarketList({ markets }: { markets: Market[] }) {
347
+ const parentRef = useRef<HTMLDivElement>(null)
348
+
349
+ const virtualizer = useVirtualizer({
350
+ count: markets.length,
351
+ getScrollElement: () => parentRef.current,
352
+ estimateSize: () => 100, // Estimated row height
353
+ overscan: 5 // Extra items to render
354
+ })
355
+
356
+ return (
357
+ <div ref={parentRef} style={{ height: '600px', overflow: 'auto' }}>
358
+ <div
359
+ style={{
360
+ height: `${virtualizer.getTotalSize()}px`,
361
+ position: 'relative'
362
+ }}
363
+ >
364
+ {virtualizer.getVirtualItems().map(virtualRow => (
365
+ <div
366
+ key={virtualRow.index}
367
+ style={{
368
+ position: 'absolute',
369
+ top: 0,
370
+ left: 0,
371
+ width: '100%',
372
+ height: `${virtualRow.size}px`,
373
+ transform: `translateY(${virtualRow.start}px)`
374
+ }}
375
+ >
376
+ <MarketCard market={markets[virtualRow.index]} />
377
+ </div>
378
+ ))}
379
+ </div>
380
+ </div>
381
+ )
382
+ }
383
+ ```
384
+
385
+ ## Form Handling Patterns
386
+
387
+ ### Controlled Form with Validation
388
+
389
+ ```typescript
390
+ interface FormData {
391
+ name: string
392
+ description: string
393
+ endDate: string
394
+ }
395
+
396
+ interface FormErrors {
397
+ name?: string
398
+ description?: string
399
+ endDate?: string
400
+ }
401
+
402
+ export function CreateMarketForm() {
403
+ const [formData, setFormData] = useState<FormData>({
404
+ name: '',
405
+ description: '',
406
+ endDate: ''
407
+ })
408
+
409
+ const [errors, setErrors] = useState<FormErrors>({})
410
+
411
+ const validate = (): boolean => {
412
+ const newErrors: FormErrors = {}
413
+
414
+ if (!formData.name.trim()) {
415
+ newErrors.name = 'Name is required'
416
+ } else if (formData.name.length > 200) {
417
+ newErrors.name = 'Name must be under 200 characters'
418
+ }
419
+
420
+ if (!formData.description.trim()) {
421
+ newErrors.description = 'Description is required'
422
+ }
423
+
424
+ if (!formData.endDate) {
425
+ newErrors.endDate = 'End date is required'
426
+ }
427
+
428
+ setErrors(newErrors)
429
+ return Object.keys(newErrors).length === 0
430
+ }
431
+
432
+ const handleSubmit = async (e: React.FormEvent) => {
433
+ e.preventDefault()
434
+
435
+ if (!validate()) return
436
+
437
+ try {
438
+ await createMarket(formData)
439
+ // Success handling
440
+ } catch (error) {
441
+ // Error handling
442
+ }
443
+ }
444
+
445
+ return (
446
+ <form onSubmit={handleSubmit}>
447
+ <input
448
+ value={formData.name}
449
+ onChange={e => setFormData(prev => ({ ...prev, name: e.target.value }))}
450
+ placeholder="Market name"
451
+ />
452
+ {errors.name && <span className="error">{errors.name}</span>}
453
+
454
+ {/* Other fields */}
455
+
456
+ <button type="submit">Create Market</button>
457
+ </form>
458
+ )
459
+ }
460
+ ```
461
+
462
+ ## Error Boundary Pattern
463
+
464
+ ```typescript
465
+ interface ErrorBoundaryState {
466
+ hasError: boolean
467
+ error: Error | null
468
+ }
469
+
470
+ export class ErrorBoundary extends React.Component<
471
+ { children: React.ReactNode },
472
+ ErrorBoundaryState
473
+ > {
474
+ state: ErrorBoundaryState = {
475
+ hasError: false,
476
+ error: null
477
+ }
478
+
479
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState {
480
+ return { hasError: true, error }
481
+ }
482
+
483
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
484
+ console.error('Error boundary caught:', error, errorInfo)
485
+ }
486
+
487
+ render() {
488
+ if (this.state.hasError) {
489
+ return (
490
+ <div className="error-fallback">
491
+ <h2>Something went wrong</h2>
492
+ <p>{this.state.error?.message}</p>
493
+ <button onClick={() => this.setState({ hasError: false })}>
494
+ Try again
495
+ </button>
496
+ </div>
497
+ )
498
+ }
499
+
500
+ return this.props.children
501
+ }
502
+ }
503
+
504
+ // Usage
505
+ <ErrorBoundary>
506
+ <App />
507
+ </ErrorBoundary>
508
+ ```
509
+
510
+ ## Animation Patterns
511
+
512
+ ### Framer Motion Animations
513
+
514
+ ```typescript
515
+ import { motion, AnimatePresence } from 'framer-motion'
516
+
517
+ // ✅ List animations
518
+ export function AnimatedMarketList({ markets }: { markets: Market[] }) {
519
+ return (
520
+ <AnimatePresence>
521
+ {markets.map(market => (
522
+ <motion.div
523
+ key={market.id}
524
+ initial={{ opacity: 0, y: 20 }}
525
+ animate={{ opacity: 1, y: 0 }}
526
+ exit={{ opacity: 0, y: -20 }}
527
+ transition={{ duration: 0.3 }}
528
+ >
529
+ <MarketCard market={market} />
530
+ </motion.div>
531
+ ))}
532
+ </AnimatePresence>
533
+ )
534
+ }
535
+
536
+ // ✅ Modal animations
537
+ export function Modal({ isOpen, onClose, children }: ModalProps) {
538
+ return (
539
+ <AnimatePresence>
540
+ {isOpen && (
541
+ <>
542
+ <motion.div
543
+ className="modal-overlay"
544
+ initial={{ opacity: 0 }}
545
+ animate={{ opacity: 1 }}
546
+ exit={{ opacity: 0 }}
547
+ onClick={onClose}
548
+ />
549
+ <motion.div
550
+ className="modal-content"
551
+ initial={{ opacity: 0, scale: 0.9, y: 20 }}
552
+ animate={{ opacity: 1, scale: 1, y: 0 }}
553
+ exit={{ opacity: 0, scale: 0.9, y: 20 }}
554
+ >
555
+ {children}
556
+ </motion.div>
557
+ </>
558
+ )}
559
+ </AnimatePresence>
560
+ )
561
+ }
562
+ ```
563
+
564
+ ## Accessibility Patterns
565
+
566
+ ### Keyboard Navigation
567
+
568
+ ```typescript
569
+ export function Dropdown({ options, onSelect }: DropdownProps) {
570
+ const [isOpen, setIsOpen] = useState(false)
571
+ const [activeIndex, setActiveIndex] = useState(0)
572
+
573
+ const handleKeyDown = (e: React.KeyboardEvent) => {
574
+ switch (e.key) {
575
+ case 'ArrowDown':
576
+ e.preventDefault()
577
+ setActiveIndex(i => Math.min(i + 1, options.length - 1))
578
+ break
579
+ case 'ArrowUp':
580
+ e.preventDefault()
581
+ setActiveIndex(i => Math.max(i - 1, 0))
582
+ break
583
+ case 'Enter':
584
+ e.preventDefault()
585
+ onSelect(options[activeIndex])
586
+ setIsOpen(false)
587
+ break
588
+ case 'Escape':
589
+ setIsOpen(false)
590
+ break
591
+ }
592
+ }
593
+
594
+ return (
595
+ <div
596
+ role="combobox"
597
+ aria-expanded={isOpen}
598
+ aria-haspopup="listbox"
599
+ onKeyDown={handleKeyDown}
600
+ >
601
+ {/* Dropdown implementation */}
602
+ </div>
603
+ )
604
+ }
605
+ ```
606
+
607
+ ### Focus Management
608
+
609
+ ```typescript
610
+ export function Modal({ isOpen, onClose, children }: ModalProps) {
611
+ const modalRef = useRef<HTMLDivElement>(null)
612
+ const previousFocusRef = useRef<HTMLElement | null>(null)
613
+
614
+ useEffect(() => {
615
+ if (isOpen) {
616
+ // Save currently focused element
617
+ previousFocusRef.current = document.activeElement as HTMLElement
618
+
619
+ // Focus modal
620
+ modalRef.current?.focus()
621
+ } else {
622
+ // Restore focus when closing
623
+ previousFocusRef.current?.focus()
624
+ }
625
+ }, [isOpen])
626
+
627
+ return isOpen ? (
628
+ <div
629
+ ref={modalRef}
630
+ role="dialog"
631
+ aria-modal="true"
632
+ tabIndex={-1}
633
+ onKeyDown={e => e.key === 'Escape' && onClose()}
634
+ >
635
+ {children}
636
+ </div>
637
+ ) : null
638
+ }
639
+ ```
640
+
641
+ **Remember**: Modern frontend patterns enable maintainable, performant user interfaces. Choose patterns that fit your project complexity.