@caddis/cli 0.0.0 → 0.1.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 (153) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +150 -1
  3. package/bundles/antigravity-plugin/agents/code-reviewer.md +47 -0
  4. package/bundles/antigravity-plugin/agents/preflight.md +53 -0
  5. package/bundles/antigravity-plugin/guard_agy.py +338 -0
  6. package/bundles/antigravity-plugin/hooks.json +36 -0
  7. package/bundles/antigravity-plugin/mcp_config.json +8 -0
  8. package/bundles/antigravity-plugin/mcp_ping_server.py +55 -0
  9. package/bundles/antigravity-plugin/plugin.json +5 -0
  10. package/bundles/antigravity-plugin/session_end_agy.py +57 -0
  11. package/bundles/antigravity-plugin/skills/_registry.md +115 -0
  12. package/bundles/antigravity-plugin/skills/add-rules/SKILL.md +45 -0
  13. package/bundles/antigravity-plugin/skills/api-design/SKILL.md +249 -0
  14. package/bundles/antigravity-plugin/skills/backend-development/SKILL.md +305 -0
  15. package/bundles/antigravity-plugin/skills/best-practices/SKILL.md +500 -0
  16. package/bundles/antigravity-plugin/skills/best-practices/agents/best-practices-referencer.md +263 -0
  17. package/bundles/antigravity-plugin/skills/best-practices/agents/codebase-context-builder.md +326 -0
  18. package/bundles/antigravity-plugin/skills/best-practices/agents/task-intent-analyzer.md +245 -0
  19. package/bundles/antigravity-plugin/skills/best-practices/references/anti-patterns.md +571 -0
  20. package/bundles/antigravity-plugin/skills/best-practices/references/before-after-examples.md +1114 -0
  21. package/bundles/antigravity-plugin/skills/best-practices/references/best-practices-guide.md +513 -0
  22. package/bundles/antigravity-plugin/skills/best-practices/references/common-workflows.md +692 -0
  23. package/bundles/antigravity-plugin/skills/best-practices/references/prompt-patterns.md +547 -0
  24. package/bundles/antigravity-plugin/skills/brainstorming/SKILL.md +57 -0
  25. package/bundles/antigravity-plugin/skills/ci-cd-pipeline/SKILL.md +315 -0
  26. package/bundles/antigravity-plugin/skills/code-documentation/SKILL.md +271 -0
  27. package/bundles/antigravity-plugin/skills/code-review/SKILL.md +122 -0
  28. package/bundles/antigravity-plugin/skills/codebase-audit/SKILL.md +204 -0
  29. package/bundles/antigravity-plugin/skills/context-curator/SKILL.md +157 -0
  30. package/bundles/antigravity-plugin/skills/cross-review/SKILL.md +40 -0
  31. package/bundles/antigravity-plugin/skills/css-architecture/SKILL.md +305 -0
  32. package/bundles/antigravity-plugin/skills/css-architecture/references/RESPONSIVE-DESIGN.md +604 -0
  33. package/bundles/antigravity-plugin/skills/database-design/SKILL.md +177 -0
  34. package/bundles/antigravity-plugin/skills/db-diagram/SKILL.md +148 -0
  35. package/bundles/antigravity-plugin/skills/db-diagram/scripts/sql_to_graph.py +1212 -0
  36. package/bundles/antigravity-plugin/skills/digress/SKILL.md +61 -0
  37. package/bundles/antigravity-plugin/skills/draw-io/SKILL.md +162 -0
  38. package/bundles/antigravity-plugin/skills/draw-io/references/aws-icons.md +677 -0
  39. package/bundles/antigravity-plugin/skills/draw-io/references/layout-guidelines.md +142 -0
  40. package/bundles/antigravity-plugin/skills/draw-io/references/troubleshooting.md +118 -0
  41. package/bundles/antigravity-plugin/skills/draw-io/references/workflows.md +103 -0
  42. package/bundles/antigravity-plugin/skills/draw-io/scripts/convert-drawio-to-png.sh +25 -0
  43. package/bundles/antigravity-plugin/skills/draw-io/scripts/find_aws_icon.py +79 -0
  44. package/bundles/antigravity-plugin/skills/error-handling/SKILL.md +260 -0
  45. package/bundles/antigravity-plugin/skills/excalidraw-db/SKILL.md +38 -0
  46. package/bundles/antigravity-plugin/skills/fastapi-dev/SKILL.md +300 -0
  47. package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +198 -0
  48. package/bundles/antigravity-plugin/skills/frontend-design/SKILL.md +193 -0
  49. package/bundles/antigravity-plugin/skills/frontend-design/references/my-tech-stack.md +127 -0
  50. package/bundles/antigravity-plugin/skills/gh-cli/SKILL.md +195 -0
  51. package/bundles/antigravity-plugin/skills/git-commit/SKILL.md +285 -0
  52. package/bundles/antigravity-plugin/skills/golden-plan/SKILL.md +577 -0
  53. package/bundles/antigravity-plugin/skills/handoff/SKILL.md +100 -0
  54. package/bundles/antigravity-plugin/skills/implement/SKILL.md +114 -0
  55. package/bundles/antigravity-plugin/skills/javascript-typescript/SKILL.md +142 -0
  56. package/bundles/antigravity-plugin/skills/kb/SKILL.md +60 -0
  57. package/bundles/antigravity-plugin/skills/mermaid-db/SKILL.md +33 -0
  58. package/bundles/antigravity-plugin/skills/mermaid-diagrams/SKILL.md +236 -0
  59. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/ENHANCEMENTS.md +264 -0
  60. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/MERMAID-SUMMARY.md +137 -0
  61. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/advanced-features.md +556 -0
  62. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/architecture-diagrams.md +192 -0
  63. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/c4-diagrams.md +410 -0
  64. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/class-diagrams.md +361 -0
  65. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/erd-diagrams.md +510 -0
  66. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/flowcharts.md +450 -0
  67. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/sequence-diagrams.md +394 -0
  68. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/troubleshooting.md +335 -0
  69. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/workflows.md +418 -0
  70. package/bundles/antigravity-plugin/skills/migrate-dir/SKILL.md +68 -0
  71. package/bundles/antigravity-plugin/skills/mockup/SKILL.md +242 -0
  72. package/bundles/antigravity-plugin/skills/particle-art/SKILL.md +243 -0
  73. package/bundles/antigravity-plugin/skills/particle-art/references/canvas-utils.ts +171 -0
  74. package/bundles/antigravity-plugin/skills/particle-art/references/dot-field.template.tsx +203 -0
  75. package/bundles/antigravity-plugin/skills/particle-art/references/flow-field.template.tsx +263 -0
  76. package/bundles/antigravity-plugin/skills/particle-art/references/node-shape.template.tsx +261 -0
  77. package/bundles/antigravity-plugin/skills/particle-art/references/shape-sampler.ts +281 -0
  78. package/bundles/antigravity-plugin/skills/particle-art/references/stipple-morph.template.tsx +167 -0
  79. package/bundles/antigravity-plugin/skills/particle-art/references/stipple.template.tsx +175 -0
  80. package/bundles/antigravity-plugin/skills/particle-art/references/trail-ghost.template.tsx +266 -0
  81. package/bundles/antigravity-plugin/skills/particle-art/references/usage-examples.md +320 -0
  82. package/bundles/antigravity-plugin/skills/playwright/API_REFERENCE.md +653 -0
  83. package/bundles/antigravity-plugin/skills/playwright/SKILL.md +454 -0
  84. package/bundles/antigravity-plugin/skills/playwright/lib/helpers.js +441 -0
  85. package/bundles/antigravity-plugin/skills/playwright/package.json +26 -0
  86. package/bundles/antigravity-plugin/skills/playwright/run.js +228 -0
  87. package/bundles/antigravity-plugin/skills/prd/SKILL.md +107 -0
  88. package/bundles/antigravity-plugin/skills/preflight/SKILL.md +435 -0
  89. package/bundles/antigravity-plugin/skills/python/SKILL.md +388 -0
  90. package/bundles/antigravity-plugin/skills/react-best-practices/SKILL.md +269 -0
  91. package/bundles/antigravity-plugin/skills/react-dev/README.md +404 -0
  92. package/bundles/antigravity-plugin/skills/react-dev/SKILL.md +459 -0
  93. package/bundles/antigravity-plugin/skills/react-dev/examples/generic-components.md +579 -0
  94. package/bundles/antigravity-plugin/skills/react-dev/examples/server-components.md +579 -0
  95. package/bundles/antigravity-plugin/skills/react-dev/references/event-handlers.md +574 -0
  96. package/bundles/antigravity-plugin/skills/react-dev/references/hooks.md +456 -0
  97. package/bundles/antigravity-plugin/skills/react-dev/references/react-19-patterns.md +638 -0
  98. package/bundles/antigravity-plugin/skills/react-dev/references/react-router.md +1002 -0
  99. package/bundles/antigravity-plugin/skills/react-dev/references/tanstack-router.md +587 -0
  100. package/bundles/antigravity-plugin/skills/refactoring/SKILL.md +486 -0
  101. package/bundles/antigravity-plugin/skills/resume/SKILL.md +36 -0
  102. package/bundles/antigravity-plugin/skills/security-review/SKILL.md +196 -0
  103. package/bundles/antigravity-plugin/skills/setup-project-ai/SKILL.md +61 -0
  104. package/bundles/antigravity-plugin/skills/ship/SKILL.md +107 -0
  105. package/bundles/antigravity-plugin/skills/ship-merge/SKILL.md +103 -0
  106. package/bundles/antigravity-plugin/skills/ship-pr/SKILL.md +102 -0
  107. package/bundles/antigravity-plugin/skills/skill-creator/LICENSE.txt +202 -0
  108. package/bundles/antigravity-plugin/skills/skill-creator/SKILL.md +491 -0
  109. package/bundles/antigravity-plugin/skills/skill-creator/agents/analyzer.md +274 -0
  110. package/bundles/antigravity-plugin/skills/skill-creator/agents/comparator.md +202 -0
  111. package/bundles/antigravity-plugin/skills/skill-creator/agents/grader.md +223 -0
  112. package/bundles/antigravity-plugin/skills/skill-creator/assets/eval_review.html +146 -0
  113. package/bundles/antigravity-plugin/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  114. package/bundles/antigravity-plugin/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  115. package/bundles/antigravity-plugin/skills/skill-creator/references/schemas.md +430 -0
  116. package/bundles/antigravity-plugin/skills/skill-creator/scripts/__init__.py +0 -0
  117. package/bundles/antigravity-plugin/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  118. package/bundles/antigravity-plugin/skills/skill-creator/scripts/generate_report.py +326 -0
  119. package/bundles/antigravity-plugin/skills/skill-creator/scripts/improve_description.py +247 -0
  120. package/bundles/antigravity-plugin/skills/skill-creator/scripts/package_skill.py +136 -0
  121. package/bundles/antigravity-plugin/skills/skill-creator/scripts/quick_validate.py +103 -0
  122. package/bundles/antigravity-plugin/skills/skill-creator/scripts/run_eval.py +310 -0
  123. package/bundles/antigravity-plugin/skills/skill-creator/scripts/run_loop.py +328 -0
  124. package/bundles/antigravity-plugin/skills/skill-creator/scripts/utils.py +47 -0
  125. package/bundles/antigravity-plugin/skills/sql/SKILL.md +321 -0
  126. package/bundles/antigravity-plugin/skills/tdd/SKILL.md +37 -0
  127. package/bundles/antigravity-plugin/skills/tdd-workflow/SKILL.md +188 -0
  128. package/bundles/antigravity-plugin/skills/technical-writing/SKILL.md +286 -0
  129. package/bundles/antigravity-plugin/skills/test-strategy/SKILL.md +155 -0
  130. package/bundles/antigravity-plugin/skills/ui-brief/SKILL.md +84 -0
  131. package/bundles/antigravity-plugin/skills/ui-review/SKILL.md +176 -0
  132. package/bundles/antigravity-plugin/skills/ui-review/references/framework-fixes.md +471 -0
  133. package/bundles/antigravity-plugin/skills/ui-review/references/visual-checklist.md +236 -0
  134. package/bundles/antigravity-plugin/skills/usage-review/SKILL.md +77 -0
  135. package/bundles/antigravity-plugin/skills/use-model/SKILL.md +64 -0
  136. package/bundles/antigravity-plugin/skills/using-git-worktrees/SKILL.md +217 -0
  137. package/bundles/antigravity-plugin/skills/version/SKILL.md +18 -0
  138. package/bundles/antigravity-plugin/skills/warm-editorial-ui/DESIGN_TOKENS.md +487 -0
  139. package/bundles/antigravity-plugin/skills/warm-editorial-ui/IMPLEMENTATION_GUIDE.md +177 -0
  140. package/bundles/antigravity-plugin/skills/warm-editorial-ui/SKILL.md +732 -0
  141. package/bundles/antigravity-plugin/skills/webapp-testing/LICENSE.txt +202 -0
  142. package/bundles/antigravity-plugin/skills/webapp-testing/SKILL.md +97 -0
  143. package/bundles/antigravity-plugin/skills/webapp-testing/examples/console_logging.py +35 -0
  144. package/bundles/antigravity-plugin/skills/webapp-testing/examples/element_discovery.py +40 -0
  145. package/bundles/antigravity-plugin/skills/webapp-testing/examples/static_html_automation.py +33 -0
  146. package/bundles/antigravity-plugin/skills/webapp-testing/scripts/with_server.py +106 -0
  147. package/bundles/antigravity-plugin/skills/windows-deployment/SKILL.md +880 -0
  148. package/bundles/antigravity-plugin/skills/writing-plans/SKILL.md +384 -0
  149. package/bundles/antigravity-plugin/statusline-command-agy.sh +91 -0
  150. package/bundles/antigravity-plugin/warm_start_agy.py +149 -0
  151. package/bundles/manifest.json +6 -0
  152. package/dist/cli.js +5363 -0
  153. package/package.json +61 -4
@@ -0,0 +1,456 @@
1
+ # Hook TypeScript Patterns
2
+
3
+ Type-safe hook patterns for useState, useRef, useReducer, useContext, and custom hooks.
4
+
5
+ ## useState
6
+
7
+ Type inference works for simple types; explicit typing needed for unions/null.
8
+
9
+ ```typescript
10
+ // Inference works
11
+ const [count, setCount] = useState(0); // number
12
+ const [name, setName] = useState(''); // string
13
+ const [items, setItems] = useState<string[]>([]); // explicit for empty arrays
14
+
15
+ // Explicit for unions/null
16
+ const [user, setUser] = useState<User | null>(null);
17
+ const [status, setStatus] = useState<'idle' | 'loading' | 'success'>('idle');
18
+
19
+ // Complex initial state
20
+ type FormData = { name: string; email: string };
21
+ const [formData, setFormData] = useState<FormData>({
22
+ name: '',
23
+ email: '',
24
+ });
25
+
26
+ // Lazy initialization
27
+ const [data, setData] = useState<Data>(() => {
28
+ const cached = localStorage.getItem('data');
29
+ return cached ? JSON.parse(cached) : defaultData;
30
+ });
31
+ ```
32
+
33
+ ## useRef
34
+
35
+ Distinguish DOM refs (null initial) from mutable value refs (value initial).
36
+
37
+ ```typescript
38
+ // DOM element ref - null initial, readonly .current
39
+ const inputRef = useRef<HTMLInputElement>(null);
40
+ const buttonRef = useRef<HTMLButtonElement>(null);
41
+ const divRef = useRef<HTMLDivElement>(null);
42
+
43
+ useEffect(() => {
44
+ inputRef.current?.focus(); // Optional chaining for null
45
+ }, []);
46
+
47
+ // Mutable value ref - non-null initial, mutable .current
48
+ const countRef = useRef<number>(0);
49
+ countRef.current += 1; // No optional chaining
50
+
51
+ const previousValueRef = useRef<string | undefined>(undefined);
52
+ previousValueRef.current = currentValue;
53
+
54
+ // Interval/timeout ref
55
+ const timeoutRef = useRef<ReturnType<typeof setTimeout>>();
56
+ const intervalRef = useRef<ReturnType<typeof setInterval>>();
57
+
58
+ useEffect(() => {
59
+ timeoutRef.current = setTimeout(() => {}, 1000);
60
+ return () => {
61
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
62
+ };
63
+ }, []);
64
+
65
+ // Callback ref for dynamic elements
66
+ const callbackRef = useCallback((node: HTMLDivElement | null) => {
67
+ if (node) {
68
+ node.scrollIntoView({ behavior: 'smooth' });
69
+ }
70
+ }, []);
71
+ ```
72
+
73
+ ## useReducer
74
+
75
+ Typed actions with discriminated unions.
76
+
77
+ ```typescript
78
+ type State = {
79
+ count: number;
80
+ status: 'idle' | 'loading' | 'success' | 'error';
81
+ error?: string;
82
+ };
83
+
84
+ type Action =
85
+ | { type: 'increment' }
86
+ | { type: 'decrement' }
87
+ | { type: 'set'; payload: number }
88
+ | { type: 'setStatus'; payload: State['status'] }
89
+ | { type: 'setError'; payload: string };
90
+
91
+ function reducer(state: State, action: Action): State {
92
+ switch (action.type) {
93
+ case 'increment':
94
+ return { ...state, count: state.count + 1 };
95
+ case 'decrement':
96
+ return { ...state, count: state.count - 1 };
97
+ case 'set':
98
+ return { ...state, count: action.payload };
99
+ case 'setStatus':
100
+ return { ...state, status: action.payload };
101
+ case 'setError':
102
+ return { ...state, status: 'error', error: action.payload };
103
+ default:
104
+ return state;
105
+ }
106
+ }
107
+
108
+ function Component() {
109
+ const [state, dispatch] = useReducer(reducer, {
110
+ count: 0,
111
+ status: 'idle',
112
+ });
113
+
114
+ dispatch({ type: 'set', payload: 10 }); // Type-safe
115
+ dispatch({ type: 'set' }); // Error: payload required
116
+ dispatch({ type: 'unknown' }); // Error: invalid action type
117
+ }
118
+ ```
119
+
120
+ ### Reducer with Context
121
+
122
+ ```typescript
123
+ type AuthState = {
124
+ user: User | null;
125
+ isAuthenticated: boolean;
126
+ };
127
+
128
+ type AuthAction =
129
+ | { type: 'login'; payload: User }
130
+ | { type: 'logout' };
131
+
132
+ type AuthContextValue = {
133
+ state: AuthState;
134
+ dispatch: React.Dispatch<AuthAction>;
135
+ };
136
+
137
+ const AuthContext = createContext<AuthContextValue | null>(null);
138
+
139
+ function authReducer(state: AuthState, action: AuthAction): AuthState {
140
+ switch (action.type) {
141
+ case 'login':
142
+ return { user: action.payload, isAuthenticated: true };
143
+ case 'logout':
144
+ return { user: null, isAuthenticated: false };
145
+ }
146
+ }
147
+
148
+ function AuthProvider({ children }: { children: React.ReactNode }) {
149
+ const [state, dispatch] = useReducer(authReducer, {
150
+ user: null,
151
+ isAuthenticated: false,
152
+ });
153
+
154
+ return (
155
+ <AuthContext.Provider value={{ state, dispatch }}>
156
+ {children}
157
+ </AuthContext.Provider>
158
+ );
159
+ }
160
+
161
+ function useAuth() {
162
+ const context = useContext(AuthContext);
163
+ if (!context) throw new Error('useAuth must be used within AuthProvider');
164
+ return context;
165
+ }
166
+ ```
167
+
168
+ ## useContext
169
+
170
+ Typed context with and without default values.
171
+
172
+ ```typescript
173
+ // Context with default value
174
+ type Theme = 'light' | 'dark';
175
+ const ThemeContext = createContext<Theme>('light');
176
+
177
+ function useTheme() {
178
+ return useContext(ThemeContext); // Always Theme, never null
179
+ }
180
+
181
+ // Context without default (must handle null)
182
+ type User = { id: string; name: string };
183
+ const UserContext = createContext<User | null>(null);
184
+
185
+ function useUser() {
186
+ const user = useContext(UserContext);
187
+ if (!user) throw new Error('useUser must be used within UserProvider');
188
+ return user; // Type narrowed to User
189
+ }
190
+
191
+ // Context with complex value
192
+ type AppContextValue = {
193
+ theme: Theme;
194
+ user: User | null;
195
+ setTheme: (theme: Theme) => void;
196
+ login: (user: User) => void;
197
+ logout: () => void;
198
+ };
199
+
200
+ const AppContext = createContext<AppContextValue | null>(null);
201
+
202
+ function useApp() {
203
+ const context = useContext(AppContext);
204
+ if (!context) throw new Error('useApp must be used within AppProvider');
205
+ return context;
206
+ }
207
+ ```
208
+
209
+ ## Custom Hooks
210
+
211
+ Return type patterns for simple and complex hooks.
212
+
213
+ ```typescript
214
+ // Object return - properties accessed by name
215
+ function useCounter(initial: number) {
216
+ const [count, setCount] = useState(initial);
217
+ const increment = () => setCount((c) => c + 1);
218
+ const decrement = () => setCount((c) => c - 1);
219
+ const reset = () => setCount(initial);
220
+
221
+ return { count, increment, decrement, reset };
222
+ }
223
+
224
+ // Usage
225
+ const { count, increment } = useCounter(0);
226
+
227
+ // Tuple return - positional destructuring
228
+ function useToggle(initial = false): [boolean, () => void, () => void, () => void] {
229
+ const [value, setValue] = useState(initial);
230
+ const toggle = () => setValue((v) => !v);
231
+ const setTrue = () => setValue(true);
232
+ const setFalse = () => setValue(false);
233
+
234
+ return [value, toggle, setTrue, setFalse];
235
+ }
236
+
237
+ // Usage
238
+ const [isOpen, toggleOpen, open, close] = useToggle();
239
+
240
+ // as const for tuple inference
241
+ function useLocalStorage<T>(key: string, initial: T) {
242
+ const [value, setValue] = useState<T>(() => {
243
+ const stored = localStorage.getItem(key);
244
+ return stored ? JSON.parse(stored) : initial;
245
+ });
246
+
247
+ useEffect(() => {
248
+ localStorage.setItem(key, JSON.stringify(value));
249
+ }, [key, value]);
250
+
251
+ return [value, setValue] as const; // readonly tuple
252
+ }
253
+
254
+ // Generic custom hook
255
+ function useFetch<T>(url: string) {
256
+ const [data, setData] = useState<T | null>(null);
257
+ const [loading, setLoading] = useState(true);
258
+ const [error, setError] = useState<Error | null>(null);
259
+
260
+ useEffect(() => {
261
+ let cancelled = false;
262
+
263
+ fetch(url)
264
+ .then((res) => res.json())
265
+ .then((json: T) => {
266
+ if (!cancelled) {
267
+ setData(json);
268
+ setLoading(false);
269
+ }
270
+ })
271
+ .catch((err) => {
272
+ if (!cancelled) {
273
+ setError(err);
274
+ setLoading(false);
275
+ }
276
+ });
277
+
278
+ return () => {
279
+ cancelled = true;
280
+ };
281
+ }, [url]);
282
+
283
+ return { data, loading, error };
284
+ }
285
+
286
+ // Usage - T inferred from usage or explicit
287
+ const { data } = useFetch<User[]>('/api/users');
288
+ ```
289
+
290
+ ## useCallback and useMemo
291
+
292
+ Typed callbacks and memoized values.
293
+
294
+ ```typescript
295
+ // useCallback with typed parameters
296
+ const handleClick = useCallback((id: string, event: React.MouseEvent) => {
297
+ console.log(id, event.target);
298
+ }, []);
299
+
300
+ // useCallback returning value
301
+ const formatDate = useCallback((date: Date): string => {
302
+ return date.toLocaleDateString();
303
+ }, []);
304
+
305
+ // useMemo with explicit return type
306
+ const sortedItems = useMemo((): Item[] => {
307
+ return [...items].sort((a, b) => a.name.localeCompare(b.name));
308
+ }, [items]);
309
+
310
+ // useMemo with complex computation
311
+ const stats = useMemo(() => {
312
+ return {
313
+ total: items.length,
314
+ average: items.reduce((a, b) => a + b.value, 0) / items.length,
315
+ max: Math.max(...items.map((i) => i.value)),
316
+ };
317
+ }, [items]);
318
+ ```
319
+
320
+ ## useImperativeHandle
321
+
322
+ Expose imperative methods from components.
323
+
324
+ ```typescript
325
+ type InputHandle = {
326
+ focus: () => void;
327
+ clear: () => void;
328
+ getValue: () => string;
329
+ };
330
+
331
+ type InputProps = {
332
+ ref?: React.Ref<InputHandle>;
333
+ label: string;
334
+ };
335
+
336
+ function CustomInput({ ref, label }: InputProps) {
337
+ const inputRef = useRef<HTMLInputElement>(null);
338
+
339
+ useImperativeHandle(ref, () => ({
340
+ focus: () => inputRef.current?.focus(),
341
+ clear: () => {
342
+ if (inputRef.current) inputRef.current.value = '';
343
+ },
344
+ getValue: () => inputRef.current?.value ?? '',
345
+ }));
346
+
347
+ return (
348
+ <div>
349
+ <label>{label}</label>
350
+ <input ref={inputRef} />
351
+ </div>
352
+ );
353
+ }
354
+
355
+ // Usage
356
+ function Form() {
357
+ const inputRef = useRef<InputHandle>(null);
358
+
359
+ const handleSubmit = () => {
360
+ const value = inputRef.current?.getValue();
361
+ inputRef.current?.clear();
362
+ };
363
+
364
+ return (
365
+ <form>
366
+ <CustomInput ref={inputRef} label="Name" />
367
+ <button onClick={() => inputRef.current?.focus()}>Focus</button>
368
+ </form>
369
+ );
370
+ }
371
+ ```
372
+
373
+ ## useLayoutEffect
374
+
375
+ Same signature as useEffect, runs synchronously after DOM mutations.
376
+
377
+ ```typescript
378
+ function Tooltip({ targetRef }: { targetRef: React.RefObject<HTMLElement> }) {
379
+ const tooltipRef = useRef<HTMLDivElement>(null);
380
+ const [position, setPosition] = useState({ top: 0, left: 0 });
381
+
382
+ useLayoutEffect(() => {
383
+ if (targetRef.current && tooltipRef.current) {
384
+ const rect = targetRef.current.getBoundingClientRect();
385
+ setPosition({
386
+ top: rect.bottom + 8,
387
+ left: rect.left,
388
+ });
389
+ }
390
+ }, [targetRef]);
391
+
392
+ return (
393
+ <div
394
+ ref={tooltipRef}
395
+ style={{ position: 'fixed', top: position.top, left: position.left }}
396
+ >
397
+ Tooltip content
398
+ </div>
399
+ );
400
+ }
401
+ ```
402
+
403
+ ## useId
404
+
405
+ Generate unique IDs for accessibility.
406
+
407
+ ```typescript
408
+ function FormField({ label }: { label: string }) {
409
+ const id = useId();
410
+ const errorId = useId();
411
+
412
+ return (
413
+ <div>
414
+ <label htmlFor={id}>{label}</label>
415
+ <input id={id} aria-describedby={errorId} />
416
+ <span id={errorId}>Error message</span>
417
+ </div>
418
+ );
419
+ }
420
+ ```
421
+
422
+ ## useSyncExternalStore
423
+
424
+ Subscribe to external stores with SSR support.
425
+
426
+ ```typescript
427
+ type Store<T> = {
428
+ getState: () => T;
429
+ subscribe: (callback: () => void) => () => void;
430
+ };
431
+
432
+ function useStore<T>(store: Store<T>): T {
433
+ return useSyncExternalStore(
434
+ store.subscribe,
435
+ store.getState,
436
+ store.getState // Server snapshot
437
+ );
438
+ }
439
+
440
+ // Example: window width store
441
+ const widthStore: Store<number> = {
442
+ getState: () => (typeof window !== 'undefined' ? window.innerWidth : 0),
443
+ subscribe: (callback) => {
444
+ window.addEventListener('resize', callback);
445
+ return () => window.removeEventListener('resize', callback);
446
+ },
447
+ };
448
+
449
+ function useWindowWidth() {
450
+ return useSyncExternalStore(
451
+ widthStore.subscribe,
452
+ widthStore.getState,
453
+ () => 0 // Server fallback
454
+ );
455
+ }
456
+ ```