memory-journal-mcp 7.0.1 → 7.2.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.
Files changed (124) hide show
  1. package/README.md +75 -66
  2. package/dist/{chunk-6J4RPJ4I.js → chunk-GR4T3SRW.js} +146 -105
  3. package/dist/{chunk-ARLH46WS.js → chunk-IWKLHSPU.js} +89 -3
  4. package/dist/{chunk-2BJHLTYP.js → chunk-ORV7ZZOE.js} +1086 -86
  5. package/dist/cli.js +30 -4
  6. package/dist/github-integration-2TFMXHIJ.js +1 -0
  7. package/dist/index.d.ts +6 -2
  8. package/dist/index.js +3 -3
  9. package/dist/{tools-FFFGXIKN.js → tools-CXR2FEB2.js} +2 -2
  10. package/package.json +2 -2
  11. package/skills/README.md +77 -0
  12. package/skills/autonomous-dev/SKILL.md +56 -0
  13. package/skills/bin/sync.js +50 -0
  14. package/skills/bun/SKILL.md +156 -0
  15. package/skills/github-commander/SKILL.md +1 -1
  16. package/skills/github-commander/workflows/code-quality-audit.md +7 -5
  17. package/skills/github-commander/workflows/issue-triage.md +13 -4
  18. package/skills/github-commander/workflows/milestone-sprint.md +9 -1
  19. package/skills/github-commander/workflows/perf-audit.md +2 -0
  20. package/skills/github-commander/workflows/pr-review.md +9 -3
  21. package/skills/github-commander/workflows/roadmap-kickoff.md +79 -0
  22. package/skills/github-commander/workflows/security-audit.md +3 -3
  23. package/skills/github-commander/workflows/update-deps.md +2 -2
  24. package/skills/gitlab/SKILL.md +115 -0
  25. package/skills/gitlab/package-lock.json +392 -0
  26. package/skills/gitlab/package.json +14 -0
  27. package/skills/gitlab/scripts/gitlab-client.ts +125 -0
  28. package/skills/gitlab/scripts/gitlab-helper.ts +80 -0
  29. package/skills/golang/SKILL.md +54 -0
  30. package/skills/mysql/SKILL.md +30 -0
  31. package/skills/package.json +48 -0
  32. package/skills/playwright-standard/SKILL.md +58 -0
  33. package/skills/playwright-standard/examples/fixtures.ts +66 -0
  34. package/skills/playwright-standard/examples/type-stubs.d.ts +10 -0
  35. package/skills/playwright-standard/references/advanced-scenarios.md +59 -0
  36. package/skills/playwright-standard/references/infrastructure.md +43 -0
  37. package/skills/postgres/SKILL.md +33 -0
  38. package/skills/react-best-practices/AGENTS.md +2883 -0
  39. package/skills/react-best-practices/README.md +127 -0
  40. package/skills/react-best-practices/SKILL.md +138 -0
  41. package/skills/react-best-practices/metadata.json +17 -0
  42. package/skills/react-best-practices/rules/_sections.md +46 -0
  43. package/skills/react-best-practices/rules/_template.md +28 -0
  44. package/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  45. package/skills/react-best-practices/rules/advanced-init-once.md +42 -0
  46. package/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
  47. package/skills/react-best-practices/rules/async-api-routes.md +35 -0
  48. package/skills/react-best-practices/rules/async-defer-await.md +80 -0
  49. package/skills/react-best-practices/rules/async-dependencies.md +48 -0
  50. package/skills/react-best-practices/rules/async-parallel.md +24 -0
  51. package/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  52. package/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  53. package/skills/react-best-practices/rules/bundle-conditional.md +37 -0
  54. package/skills/react-best-practices/rules/bundle-defer-third-party.md +48 -0
  55. package/skills/react-best-practices/rules/bundle-dynamic-imports.md +34 -0
  56. package/skills/react-best-practices/rules/bundle-preload.md +44 -0
  57. package/skills/react-best-practices/rules/client-event-listeners.md +78 -0
  58. package/skills/react-best-practices/rules/client-localstorage-schema.md +74 -0
  59. package/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  60. package/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  61. package/skills/react-best-practices/rules/js-batch-dom-css.md +110 -0
  62. package/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  63. package/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  64. package/skills/react-best-practices/rules/js-cache-storage.md +68 -0
  65. package/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  66. package/skills/react-best-practices/rules/js-early-exit.md +50 -0
  67. package/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  68. package/skills/react-best-practices/rules/js-index-maps.md +37 -0
  69. package/skills/react-best-practices/rules/js-length-check-first.md +50 -0
  70. package/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  71. package/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  72. package/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  73. package/skills/react-best-practices/rules/rendering-activity.md +24 -0
  74. package/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +38 -0
  75. package/skills/react-best-practices/rules/rendering-conditional-render.md +32 -0
  76. package/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  77. package/skills/react-best-practices/rules/rendering-hoist-jsx.md +36 -0
  78. package/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +72 -0
  79. package/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md +26 -0
  80. package/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  81. package/skills/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  82. package/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  83. package/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  84. package/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  85. package/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  86. package/skills/react-best-practices/rules/rerender-functional-setstate.md +77 -0
  87. package/skills/react-best-practices/rules/rerender-lazy-state-init.md +56 -0
  88. package/skills/react-best-practices/rules/rerender-memo-with-default-value.md +36 -0
  89. package/skills/react-best-practices/rules/rerender-memo.md +44 -0
  90. package/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  91. package/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  92. package/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  93. package/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  94. package/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  95. package/skills/react-best-practices/rules/server-auth-actions.md +96 -0
  96. package/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  97. package/skills/react-best-practices/rules/server-cache-react.md +76 -0
  98. package/skills/react-best-practices/rules/server-dedup-props.md +65 -0
  99. package/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
  100. package/skills/react-best-practices/rules/server-serialization.md +38 -0
  101. package/skills/rust/SKILL.md +86 -0
  102. package/skills/shadcn-ui/SKILL.md +72 -0
  103. package/skills/skill-builder/SKILL.md +457 -0
  104. package/skills/skill-builder/checklist.md +65 -0
  105. package/skills/sqlite/SKILL.md +38 -0
  106. package/skills/typescript/SKILL.md +453 -0
  107. package/skills/typescript/assets/eslint-template.js +102 -0
  108. package/skills/typescript/assets/tsconfig-template.json +45 -0
  109. package/skills/typescript/references/enterprise-patterns.md +531 -0
  110. package/skills/typescript/references/generics.md +493 -0
  111. package/skills/typescript/references/nestjs-integration.md +579 -0
  112. package/skills/typescript/references/react-integration.md +616 -0
  113. package/skills/typescript/references/toolchain.md +547 -0
  114. package/skills/typescript/references/type-system.md +481 -0
  115. package/skills/vitest-standard/SKILL.md +82 -0
  116. package/skills/vitest-standard/examples/service-mock.ts +60 -0
  117. package/skills/vitest-standard/examples/tdd-calculator.ts +41 -0
  118. package/skills/vitest-standard/examples/type-stubs.d.ts +18 -0
  119. package/skills/vitest-standard/references/async-and-errors.md +58 -0
  120. package/skills/vitest-standard/references/coverage-and-config.md +53 -0
  121. package/skills/vitest-standard/references/mocking.md +61 -0
  122. package/skills/vitest-standard/references/tdd-patterns.md +60 -0
  123. package/dist/github-integration-PDRLXKGM.js +0 -1
  124. package/skills/github-commander/workflows/full-audit.md +0 -134
@@ -0,0 +1,616 @@
1
+ # React Integration Reference
2
+
3
+ > **Load when:** User asks about React with TypeScript, typed components, hooks, state management, or React patterns.
4
+
5
+ Type-safe React development patterns for React 19+.
6
+
7
+ ## Contents
8
+
9
+ - [Component Patterns](#component-patterns)
10
+ - [Hooks with TypeScript](#hooks-with-typescript)
11
+ - [State Management](#state-management)
12
+ - [Event Handling](#event-handling)
13
+ - [Context API](#context-api)
14
+
15
+ ---
16
+
17
+ ## Component Patterns
18
+
19
+ ### Functional Components
20
+
21
+ ```typescript
22
+ // Basic typed component
23
+ interface GreetingProps {
24
+ name: string;
25
+ age?: number;
26
+ }
27
+
28
+ function Greeting({ name, age }: GreetingProps) {
29
+ return (
30
+ <div>
31
+ Hello, {name}!
32
+ {age && <span> You are {age} years old.</span>}
33
+ </div>
34
+ );
35
+ }
36
+
37
+ // With React.FC (optional, some prefer explicit return type)
38
+ const GreetingFC: React.FC<GreetingProps> = ({ name, age }) => {
39
+ return <div>Hello, {name}!</div>;
40
+ };
41
+
42
+ // Component with children
43
+ interface CardProps {
44
+ title: string;
45
+ children: React.ReactNode;
46
+ }
47
+
48
+ function Card({ title, children }: CardProps) {
49
+ return (
50
+ <div className="card">
51
+ <h2>{title}</h2>
52
+ <div className="card-body">{children}</div>
53
+ </div>
54
+ );
55
+ }
56
+ ```
57
+
58
+ ### Generic Components
59
+
60
+ ```typescript
61
+ // Generic list component
62
+ interface ListProps<T> {
63
+ items: T[];
64
+ renderItem: (item: T, index: number) => React.ReactNode;
65
+ keyExtractor: (item: T) => string;
66
+ }
67
+
68
+ function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) {
69
+ return (
70
+ <ul>
71
+ {items.map((item, index) => (
72
+ <li key={keyExtractor(item)}>{renderItem(item, index)}</li>
73
+ ))}
74
+ </ul>
75
+ );
76
+ }
77
+
78
+ // Usage
79
+ interface User {
80
+ id: string;
81
+ name: string;
82
+ }
83
+
84
+ <List<User>
85
+ items={users}
86
+ keyExtractor={(user) => user.id}
87
+ renderItem={(user) => <span>{user.name}</span>}
88
+ />;
89
+
90
+ // Generic select component
91
+ interface SelectProps<T> {
92
+ options: T[];
93
+ value: T | null;
94
+ onChange: (value: T) => void;
95
+ getLabel: (option: T) => string;
96
+ getValue: (option: T) => string;
97
+ }
98
+
99
+ function Select<T>({
100
+ options,
101
+ value,
102
+ onChange,
103
+ getLabel,
104
+ getValue
105
+ }: SelectProps<T>) {
106
+ return (
107
+ <select
108
+ value={value ? getValue(value) : ""}
109
+ onChange={(e) => {
110
+ const selected = options.find((opt) => getValue(opt) === e.target.value);
111
+ if (selected) onChange(selected);
112
+ }}
113
+ >
114
+ <option value="">Select...</option>
115
+ {options.map((opt) => (
116
+ <option key={getValue(opt)} value={getValue(opt)}>
117
+ {getLabel(opt)}
118
+ </option>
119
+ ))}
120
+ </select>
121
+ );
122
+ }
123
+ ```
124
+
125
+ ### Polymorphic Components
126
+
127
+ ```typescript
128
+ // Component that can render as different elements
129
+ type ButtonProps<T extends React.ElementType> = {
130
+ as?: T;
131
+ children: React.ReactNode;
132
+ variant?: "primary" | "secondary";
133
+ } & Omit<React.ComponentPropsWithoutRef<T>, "as" | "children">;
134
+
135
+ function Button<T extends React.ElementType = "button">({
136
+ as,
137
+ children,
138
+ variant = "primary",
139
+ ...props
140
+ }: ButtonProps<T>) {
141
+ const Component = as || "button";
142
+ return (
143
+ <Component className={`btn btn-${variant}`} {...props}>
144
+ {children}
145
+ </Component>
146
+ );
147
+ }
148
+
149
+ // Usage
150
+ <Button>Click me</Button>
151
+ <Button as="a" href="/about">Link Button</Button>
152
+ <Button as={Link} to="/home">Router Link</Button>
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Hooks with TypeScript
158
+
159
+ ### useState
160
+
161
+ ```typescript
162
+ // Basic usage (type inferred)
163
+ const [count, setCount] = useState(0)
164
+
165
+ // Explicit type (for complex types or initial null)
166
+ const [user, setUser] = useState<User | null>(null)
167
+
168
+ // With union types
169
+ type Status = 'idle' | 'loading' | 'success' | 'error'
170
+ const [status, setStatus] = useState<Status>('idle')
171
+
172
+ // Lazy initialization
173
+ const [state, setState] = useState<ExpensiveState>(() => {
174
+ return computeExpensiveInitialState()
175
+ })
176
+ ```
177
+
178
+ ### useRef
179
+
180
+ ```typescript
181
+ // DOM element ref
182
+ const inputRef = useRef<HTMLInputElement>(null)
183
+
184
+ function focusInput() {
185
+ inputRef.current?.focus()
186
+ }
187
+
188
+ // Mutable ref (no initial render)
189
+ const intervalRef = useRef<NodeJS.Timeout | null>(null)
190
+
191
+ useEffect(() => {
192
+ intervalRef.current = setInterval(() => {}, 1000)
193
+ return () => {
194
+ if (intervalRef.current) {
195
+ clearInterval(intervalRef.current)
196
+ }
197
+ }
198
+ }, [])
199
+
200
+ // Ref to store previous value
201
+ function usePrevious<T>(value: T): T | undefined {
202
+ const ref = useRef<T | undefined>(undefined)
203
+
204
+ useEffect(() => {
205
+ ref.current = value
206
+ }, [value])
207
+
208
+ return ref.current
209
+ }
210
+ ```
211
+
212
+ ### useReducer
213
+
214
+ ```typescript
215
+ // Define state and actions
216
+ interface CounterState {
217
+ count: number
218
+ step: number
219
+ }
220
+
221
+ type CounterAction =
222
+ | { type: 'increment' }
223
+ | { type: 'decrement' }
224
+ | { type: 'setStep'; payload: number }
225
+ | { type: 'reset' }
226
+
227
+ function counterReducer(state: CounterState, action: CounterAction): CounterState {
228
+ switch (action.type) {
229
+ case 'increment':
230
+ return { ...state, count: state.count + state.step }
231
+ case 'decrement':
232
+ return { ...state, count: state.count - state.step }
233
+ case 'setStep':
234
+ return { ...state, step: action.payload }
235
+ case 'reset':
236
+ return { count: 0, step: 1 }
237
+ }
238
+ }
239
+
240
+ // Usage
241
+ const [state, dispatch] = useReducer(counterReducer, { count: 0, step: 1 })
242
+
243
+ dispatch({ type: 'increment' })
244
+ dispatch({ type: 'setStep', payload: 5 })
245
+ ```
246
+
247
+ ### Custom Hooks
248
+
249
+ ```typescript
250
+ // Async data fetching hook
251
+ interface UseAsyncResult<T> {
252
+ data: T | null
253
+ loading: boolean
254
+ error: Error | null
255
+ refetch: () => void
256
+ }
257
+
258
+ function useAsync<T>(
259
+ asyncFn: () => Promise<T>,
260
+ deps: React.DependencyList = []
261
+ ): UseAsyncResult<T> {
262
+ const [data, setData] = useState<T | null>(null)
263
+ const [loading, setLoading] = useState(true)
264
+ const [error, setError] = useState<Error | null>(null)
265
+
266
+ const execute = useCallback(async () => {
267
+ setLoading(true)
268
+ setError(null)
269
+ try {
270
+ const result = await asyncFn()
271
+ setData(result)
272
+ } catch (e) {
273
+ setError(e instanceof Error ? e : new Error(String(e)))
274
+ } finally {
275
+ setLoading(false)
276
+ }
277
+ }, deps)
278
+
279
+ useEffect(() => {
280
+ execute()
281
+ }, [execute])
282
+
283
+ return { data, loading, error, refetch: execute }
284
+ }
285
+
286
+ // Usage
287
+ const {
288
+ data: users,
289
+ loading,
290
+ error,
291
+ } = useAsync(() => fetch('/api/users').then((r) => r.json()), [])
292
+
293
+ // Local storage hook
294
+ function useLocalStorage<T>(
295
+ key: string,
296
+ initialValue: T
297
+ ): [T, (value: T | ((prev: T) => T)) => void] {
298
+ const [storedValue, setStoredValue] = useState<T>(() => {
299
+ try {
300
+ const item = localStorage.getItem(key)
301
+ return item ? JSON.parse(item) : initialValue
302
+ } catch {
303
+ return initialValue
304
+ }
305
+ })
306
+
307
+ const setValue = (value: T | ((prev: T) => T)) => {
308
+ const valueToStore = value instanceof Function ? value(storedValue) : value
309
+ setStoredValue(valueToStore)
310
+ localStorage.setItem(key, JSON.stringify(valueToStore))
311
+ }
312
+
313
+ return [storedValue, setValue]
314
+ }
315
+ ```
316
+
317
+ ---
318
+
319
+ ## State Management
320
+
321
+ ### Zustand with TypeScript
322
+
323
+ ```typescript
324
+ import { create } from 'zustand'
325
+ import { devtools, persist } from 'zustand/middleware'
326
+
327
+ // Define state interface
328
+ interface AuthState {
329
+ user: User | null
330
+ token: string | null
331
+ isAuthenticated: boolean
332
+ login: (email: string, password: string) => Promise<void>
333
+ logout: () => void
334
+ setUser: (user: User) => void
335
+ }
336
+
337
+ // Create typed store
338
+ const useAuthStore = create<AuthState>()(
339
+ devtools(
340
+ persist(
341
+ (set) => ({
342
+ user: null,
343
+ token: null,
344
+ isAuthenticated: false,
345
+
346
+ login: async (email, password) => {
347
+ const response = await api.login(email, password)
348
+ set({
349
+ user: response.user,
350
+ token: response.token,
351
+ isAuthenticated: true,
352
+ })
353
+ },
354
+
355
+ logout: () => {
356
+ set({ user: null, token: null, isAuthenticated: false })
357
+ },
358
+
359
+ setUser: (user) => set({ user }),
360
+ }),
361
+ { name: 'auth-storage' }
362
+ )
363
+ )
364
+ )
365
+
366
+ // Usage with selectors
367
+ const user = useAuthStore((state) => state.user)
368
+ const login = useAuthStore((state) => state.login)
369
+
370
+ // Shallow comparison for multiple values
371
+ import { useShallow } from 'zustand/react/shallow'
372
+
373
+ const { user, isAuthenticated } = useAuthStore(
374
+ useShallow((state) => ({
375
+ user: state.user,
376
+ isAuthenticated: state.isAuthenticated,
377
+ }))
378
+ )
379
+ ```
380
+
381
+ ### Redux Toolkit with TypeScript
382
+
383
+ ```typescript
384
+ import { createSlice, PayloadAction, configureStore } from '@reduxjs/toolkit'
385
+
386
+ // Define slice state
387
+ interface TodosState {
388
+ items: Todo[]
389
+ filter: 'all' | 'active' | 'completed'
390
+ loading: boolean
391
+ }
392
+
393
+ const initialState: TodosState = {
394
+ items: [],
395
+ filter: 'all',
396
+ loading: false,
397
+ }
398
+
399
+ // Create typed slice
400
+ const todosSlice = createSlice({
401
+ name: 'todos',
402
+ initialState,
403
+ reducers: {
404
+ addTodo: (state, action: PayloadAction<string>) => {
405
+ state.items.push({
406
+ id: crypto.randomUUID(),
407
+ text: action.payload,
408
+ completed: false,
409
+ })
410
+ },
411
+ toggleTodo: (state, action: PayloadAction<string>) => {
412
+ const todo = state.items.find((t) => t.id === action.payload)
413
+ if (todo) {
414
+ todo.completed = !todo.completed
415
+ }
416
+ },
417
+ setFilter: (state, action: PayloadAction<TodosState['filter']>) => {
418
+ state.filter = action.payload
419
+ },
420
+ },
421
+ })
422
+
423
+ // Configure store with type inference
424
+ const store = configureStore({
425
+ reducer: {
426
+ todos: todosSlice.reducer,
427
+ },
428
+ })
429
+
430
+ // Infer types from store
431
+ type RootState = ReturnType<typeof store.getState>
432
+ type AppDispatch = typeof store.dispatch
433
+
434
+ // Typed hooks
435
+ import { useDispatch, useSelector, TypedUseSelectorHook } from 'react-redux'
436
+
437
+ const useAppDispatch = () => useDispatch<AppDispatch>()
438
+ const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
439
+
440
+ // Usage
441
+ const todos = useAppSelector((state) => state.todos.items)
442
+ const dispatch = useAppDispatch()
443
+ dispatch(todosSlice.actions.addTodo('New todo'))
444
+ ```
445
+
446
+ ---
447
+
448
+ ## Event Handling
449
+
450
+ ### Common Event Types
451
+
452
+ ```typescript
453
+ // Click events
454
+ function handleClick(event: React.MouseEvent<HTMLButtonElement>) {
455
+ console.log(event.currentTarget.name)
456
+ }
457
+
458
+ // Form events
459
+ function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
460
+ event.preventDefault()
461
+ const formData = new FormData(event.currentTarget)
462
+ }
463
+
464
+ // Input change
465
+ function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
466
+ const { name, value, checked, type } = event.target
467
+ const inputValue = type === 'checkbox' ? checked : value
468
+ }
469
+
470
+ // Keyboard events
471
+ function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {
472
+ if (event.key === 'Enter') {
473
+ event.preventDefault()
474
+ // submit form
475
+ }
476
+ }
477
+
478
+ // Focus events
479
+ function handleFocus(event: React.FocusEvent<HTMLInputElement>) {
480
+ event.target.select()
481
+ }
482
+
483
+ // Drag events
484
+ function handleDrag(event: React.DragEvent<HTMLDivElement>) {
485
+ event.dataTransfer.setData('text/plain', 'dragged data')
486
+ }
487
+ ```
488
+
489
+ ### Form with TypeScript
490
+
491
+ ```typescript
492
+ interface FormData {
493
+ name: string;
494
+ email: string;
495
+ role: "user" | "admin";
496
+ }
497
+
498
+ function RegistrationForm() {
499
+ const [formData, setFormData] = useState<FormData>({
500
+ name: "",
501
+ email: "",
502
+ role: "user"
503
+ });
504
+
505
+ const handleChange = (
506
+ e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>
507
+ ) => {
508
+ const { name, value } = e.target;
509
+ setFormData((prev) => ({ ...prev, [name]: value }));
510
+ };
511
+
512
+ const handleSubmit = (e: React.FormEvent) => {
513
+ e.preventDefault();
514
+ console.log(formData);
515
+ };
516
+
517
+ return (
518
+ <form onSubmit={handleSubmit}>
519
+ <input
520
+ name="name"
521
+ value={formData.name}
522
+ onChange={handleChange}
523
+ />
524
+ <input
525
+ name="email"
526
+ type="email"
527
+ value={formData.email}
528
+ onChange={handleChange}
529
+ />
530
+ <select name="role" value={formData.role} onChange={handleChange}>
531
+ <option value="user">User</option>
532
+ <option value="admin">Admin</option>
533
+ </select>
534
+ <button type="submit">Register</button>
535
+ </form>
536
+ );
537
+ }
538
+ ```
539
+
540
+ ---
541
+
542
+ ## Context API
543
+
544
+ ### Typed Context
545
+
546
+ ```typescript
547
+ // Define context type
548
+ interface ThemeContextType {
549
+ theme: "light" | "dark";
550
+ toggleTheme: () => void;
551
+ }
552
+
553
+ // Create context with undefined default
554
+ const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
555
+
556
+ // Provider component
557
+ function ThemeProvider({ children }: { children: React.ReactNode }) {
558
+ const [theme, setTheme] = useState<"light" | "dark">("light");
559
+
560
+ const toggleTheme = useCallback(() => {
561
+ setTheme((prev) => (prev === "light" ? "dark" : "light"));
562
+ }, []);
563
+
564
+ const value = useMemo(() => ({ theme, toggleTheme }), [theme, toggleTheme]);
565
+
566
+ return (
567
+ <ThemeContext.Provider value={value}>
568
+ {children}
569
+ </ThemeContext.Provider>
570
+ );
571
+ }
572
+
573
+ // Custom hook with type safety
574
+ function useTheme(): ThemeContextType {
575
+ const context = useContext(ThemeContext);
576
+ if (context === undefined) {
577
+ throw new Error("useTheme must be used within ThemeProvider");
578
+ }
579
+ return context;
580
+ }
581
+
582
+ // Usage
583
+ function ThemeToggle() {
584
+ const { theme, toggleTheme } = useTheme();
585
+ return <button onClick={toggleTheme}>Current: {theme}</button>;
586
+ }
587
+ ```
588
+
589
+ ### Generic Context Factory
590
+
591
+ ```typescript
592
+ // Factory function for creating typed contexts
593
+ function createContext<T>(displayName: string) {
594
+ const Context = React.createContext<T | undefined>(undefined)
595
+ Context.displayName = displayName
596
+
597
+ function useContextHook(): T {
598
+ const context = React.useContext(Context)
599
+ if (context === undefined) {
600
+ throw new Error(`use${displayName} must be used within ${displayName}Provider`)
601
+ }
602
+ return context
603
+ }
604
+
605
+ return [Context.Provider, useContextHook] as const
606
+ }
607
+
608
+ // Usage
609
+ interface AuthContextType {
610
+ user: User | null
611
+ login: (credentials: Credentials) => Promise<void>
612
+ logout: () => void
613
+ }
614
+
615
+ const [AuthProvider, useAuth] = createContext<AuthContextType>('Auth')
616
+ ```