@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.
- package/LICENSE +21 -0
- package/README.md +150 -1
- package/bundles/antigravity-plugin/agents/code-reviewer.md +47 -0
- package/bundles/antigravity-plugin/agents/preflight.md +53 -0
- package/bundles/antigravity-plugin/guard_agy.py +338 -0
- package/bundles/antigravity-plugin/hooks.json +36 -0
- package/bundles/antigravity-plugin/mcp_config.json +8 -0
- package/bundles/antigravity-plugin/mcp_ping_server.py +55 -0
- package/bundles/antigravity-plugin/plugin.json +5 -0
- package/bundles/antigravity-plugin/session_end_agy.py +57 -0
- package/bundles/antigravity-plugin/skills/_registry.md +115 -0
- package/bundles/antigravity-plugin/skills/add-rules/SKILL.md +45 -0
- package/bundles/antigravity-plugin/skills/api-design/SKILL.md +249 -0
- package/bundles/antigravity-plugin/skills/backend-development/SKILL.md +305 -0
- package/bundles/antigravity-plugin/skills/best-practices/SKILL.md +500 -0
- package/bundles/antigravity-plugin/skills/best-practices/agents/best-practices-referencer.md +263 -0
- package/bundles/antigravity-plugin/skills/best-practices/agents/codebase-context-builder.md +326 -0
- package/bundles/antigravity-plugin/skills/best-practices/agents/task-intent-analyzer.md +245 -0
- package/bundles/antigravity-plugin/skills/best-practices/references/anti-patterns.md +571 -0
- package/bundles/antigravity-plugin/skills/best-practices/references/before-after-examples.md +1114 -0
- package/bundles/antigravity-plugin/skills/best-practices/references/best-practices-guide.md +513 -0
- package/bundles/antigravity-plugin/skills/best-practices/references/common-workflows.md +692 -0
- package/bundles/antigravity-plugin/skills/best-practices/references/prompt-patterns.md +547 -0
- package/bundles/antigravity-plugin/skills/brainstorming/SKILL.md +57 -0
- package/bundles/antigravity-plugin/skills/ci-cd-pipeline/SKILL.md +315 -0
- package/bundles/antigravity-plugin/skills/code-documentation/SKILL.md +271 -0
- package/bundles/antigravity-plugin/skills/code-review/SKILL.md +122 -0
- package/bundles/antigravity-plugin/skills/codebase-audit/SKILL.md +204 -0
- package/bundles/antigravity-plugin/skills/context-curator/SKILL.md +157 -0
- package/bundles/antigravity-plugin/skills/cross-review/SKILL.md +40 -0
- package/bundles/antigravity-plugin/skills/css-architecture/SKILL.md +305 -0
- package/bundles/antigravity-plugin/skills/css-architecture/references/RESPONSIVE-DESIGN.md +604 -0
- package/bundles/antigravity-plugin/skills/database-design/SKILL.md +177 -0
- package/bundles/antigravity-plugin/skills/db-diagram/SKILL.md +148 -0
- package/bundles/antigravity-plugin/skills/db-diagram/scripts/sql_to_graph.py +1212 -0
- package/bundles/antigravity-plugin/skills/digress/SKILL.md +61 -0
- package/bundles/antigravity-plugin/skills/draw-io/SKILL.md +162 -0
- package/bundles/antigravity-plugin/skills/draw-io/references/aws-icons.md +677 -0
- package/bundles/antigravity-plugin/skills/draw-io/references/layout-guidelines.md +142 -0
- package/bundles/antigravity-plugin/skills/draw-io/references/troubleshooting.md +118 -0
- package/bundles/antigravity-plugin/skills/draw-io/references/workflows.md +103 -0
- package/bundles/antigravity-plugin/skills/draw-io/scripts/convert-drawio-to-png.sh +25 -0
- package/bundles/antigravity-plugin/skills/draw-io/scripts/find_aws_icon.py +79 -0
- package/bundles/antigravity-plugin/skills/error-handling/SKILL.md +260 -0
- package/bundles/antigravity-plugin/skills/excalidraw-db/SKILL.md +38 -0
- package/bundles/antigravity-plugin/skills/fastapi-dev/SKILL.md +300 -0
- package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +198 -0
- package/bundles/antigravity-plugin/skills/frontend-design/SKILL.md +193 -0
- package/bundles/antigravity-plugin/skills/frontend-design/references/my-tech-stack.md +127 -0
- package/bundles/antigravity-plugin/skills/gh-cli/SKILL.md +195 -0
- package/bundles/antigravity-plugin/skills/git-commit/SKILL.md +285 -0
- package/bundles/antigravity-plugin/skills/golden-plan/SKILL.md +577 -0
- package/bundles/antigravity-plugin/skills/handoff/SKILL.md +100 -0
- package/bundles/antigravity-plugin/skills/implement/SKILL.md +114 -0
- package/bundles/antigravity-plugin/skills/javascript-typescript/SKILL.md +142 -0
- package/bundles/antigravity-plugin/skills/kb/SKILL.md +60 -0
- package/bundles/antigravity-plugin/skills/mermaid-db/SKILL.md +33 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/SKILL.md +236 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/ENHANCEMENTS.md +264 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/MERMAID-SUMMARY.md +137 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/advanced-features.md +556 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/architecture-diagrams.md +192 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/c4-diagrams.md +410 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/class-diagrams.md +361 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/erd-diagrams.md +510 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/flowcharts.md +450 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/sequence-diagrams.md +394 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/troubleshooting.md +335 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/workflows.md +418 -0
- package/bundles/antigravity-plugin/skills/migrate-dir/SKILL.md +68 -0
- package/bundles/antigravity-plugin/skills/mockup/SKILL.md +242 -0
- package/bundles/antigravity-plugin/skills/particle-art/SKILL.md +243 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/canvas-utils.ts +171 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/dot-field.template.tsx +203 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/flow-field.template.tsx +263 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/node-shape.template.tsx +261 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/shape-sampler.ts +281 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/stipple-morph.template.tsx +167 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/stipple.template.tsx +175 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/trail-ghost.template.tsx +266 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/usage-examples.md +320 -0
- package/bundles/antigravity-plugin/skills/playwright/API_REFERENCE.md +653 -0
- package/bundles/antigravity-plugin/skills/playwright/SKILL.md +454 -0
- package/bundles/antigravity-plugin/skills/playwright/lib/helpers.js +441 -0
- package/bundles/antigravity-plugin/skills/playwright/package.json +26 -0
- package/bundles/antigravity-plugin/skills/playwright/run.js +228 -0
- package/bundles/antigravity-plugin/skills/prd/SKILL.md +107 -0
- package/bundles/antigravity-plugin/skills/preflight/SKILL.md +435 -0
- package/bundles/antigravity-plugin/skills/python/SKILL.md +388 -0
- package/bundles/antigravity-plugin/skills/react-best-practices/SKILL.md +269 -0
- package/bundles/antigravity-plugin/skills/react-dev/README.md +404 -0
- package/bundles/antigravity-plugin/skills/react-dev/SKILL.md +459 -0
- package/bundles/antigravity-plugin/skills/react-dev/examples/generic-components.md +579 -0
- package/bundles/antigravity-plugin/skills/react-dev/examples/server-components.md +579 -0
- package/bundles/antigravity-plugin/skills/react-dev/references/event-handlers.md +574 -0
- package/bundles/antigravity-plugin/skills/react-dev/references/hooks.md +456 -0
- package/bundles/antigravity-plugin/skills/react-dev/references/react-19-patterns.md +638 -0
- package/bundles/antigravity-plugin/skills/react-dev/references/react-router.md +1002 -0
- package/bundles/antigravity-plugin/skills/react-dev/references/tanstack-router.md +587 -0
- package/bundles/antigravity-plugin/skills/refactoring/SKILL.md +486 -0
- package/bundles/antigravity-plugin/skills/resume/SKILL.md +36 -0
- package/bundles/antigravity-plugin/skills/security-review/SKILL.md +196 -0
- package/bundles/antigravity-plugin/skills/setup-project-ai/SKILL.md +61 -0
- package/bundles/antigravity-plugin/skills/ship/SKILL.md +107 -0
- package/bundles/antigravity-plugin/skills/ship-merge/SKILL.md +103 -0
- package/bundles/antigravity-plugin/skills/ship-pr/SKILL.md +102 -0
- package/bundles/antigravity-plugin/skills/skill-creator/LICENSE.txt +202 -0
- package/bundles/antigravity-plugin/skills/skill-creator/SKILL.md +491 -0
- package/bundles/antigravity-plugin/skills/skill-creator/agents/analyzer.md +274 -0
- package/bundles/antigravity-plugin/skills/skill-creator/agents/comparator.md +202 -0
- package/bundles/antigravity-plugin/skills/skill-creator/agents/grader.md +223 -0
- package/bundles/antigravity-plugin/skills/skill-creator/assets/eval_review.html +146 -0
- package/bundles/antigravity-plugin/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/bundles/antigravity-plugin/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/bundles/antigravity-plugin/skills/skill-creator/references/schemas.md +430 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/__init__.py +0 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/generate_report.py +326 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/improve_description.py +247 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/package_skill.py +136 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/run_eval.py +310 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/run_loop.py +328 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/utils.py +47 -0
- package/bundles/antigravity-plugin/skills/sql/SKILL.md +321 -0
- package/bundles/antigravity-plugin/skills/tdd/SKILL.md +37 -0
- package/bundles/antigravity-plugin/skills/tdd-workflow/SKILL.md +188 -0
- package/bundles/antigravity-plugin/skills/technical-writing/SKILL.md +286 -0
- package/bundles/antigravity-plugin/skills/test-strategy/SKILL.md +155 -0
- package/bundles/antigravity-plugin/skills/ui-brief/SKILL.md +84 -0
- package/bundles/antigravity-plugin/skills/ui-review/SKILL.md +176 -0
- package/bundles/antigravity-plugin/skills/ui-review/references/framework-fixes.md +471 -0
- package/bundles/antigravity-plugin/skills/ui-review/references/visual-checklist.md +236 -0
- package/bundles/antigravity-plugin/skills/usage-review/SKILL.md +77 -0
- package/bundles/antigravity-plugin/skills/use-model/SKILL.md +64 -0
- package/bundles/antigravity-plugin/skills/using-git-worktrees/SKILL.md +217 -0
- package/bundles/antigravity-plugin/skills/version/SKILL.md +18 -0
- package/bundles/antigravity-plugin/skills/warm-editorial-ui/DESIGN_TOKENS.md +487 -0
- package/bundles/antigravity-plugin/skills/warm-editorial-ui/IMPLEMENTATION_GUIDE.md +177 -0
- package/bundles/antigravity-plugin/skills/warm-editorial-ui/SKILL.md +732 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/LICENSE.txt +202 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/SKILL.md +97 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/examples/console_logging.py +35 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/examples/element_discovery.py +40 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/examples/static_html_automation.py +33 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/scripts/with_server.py +106 -0
- package/bundles/antigravity-plugin/skills/windows-deployment/SKILL.md +880 -0
- package/bundles/antigravity-plugin/skills/writing-plans/SKILL.md +384 -0
- package/bundles/antigravity-plugin/statusline-command-agy.sh +91 -0
- package/bundles/antigravity-plugin/warm_start_agy.py +149 -0
- package/bundles/manifest.json +6 -0
- package/dist/cli.js +5363 -0
- package/package.json +61 -4
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: react-dev
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
description: This skill should be used when building React components with TypeScript, typing hooks, handling events, or when React TypeScript, React 19, Server Components are mentioned. Covers type-safe patterns for React 18-19 including generic components, proper event typing, and routing integration (TanStack Router, React Router).
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# React TypeScript
|
|
8
|
+
|
|
9
|
+
Type-safe React = compile-time guarantees = confident refactoring.
|
|
10
|
+
|
|
11
|
+
<when_to_use>
|
|
12
|
+
|
|
13
|
+
- Building typed React components
|
|
14
|
+
- Implementing generic components
|
|
15
|
+
- Typing event handlers, forms, refs
|
|
16
|
+
- Using React 19 features (Actions, Server Components, use())
|
|
17
|
+
- Router integration (TanStack Router, React Router)
|
|
18
|
+
- Custom hooks with proper typing
|
|
19
|
+
|
|
20
|
+
NOT for: non-React TypeScript, vanilla JS React
|
|
21
|
+
|
|
22
|
+
</when_to_use>
|
|
23
|
+
|
|
24
|
+
<react_19_changes>
|
|
25
|
+
|
|
26
|
+
React 19 breaking changes require migration. Key patterns:
|
|
27
|
+
|
|
28
|
+
**ref as prop** - forwardRef deprecated:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// React 19 - ref as regular prop
|
|
32
|
+
type ButtonProps = {
|
|
33
|
+
ref?: React.Ref<HTMLButtonElement>;
|
|
34
|
+
} & React.ComponentPropsWithoutRef<'button'>;
|
|
35
|
+
|
|
36
|
+
function Button({ ref, children, ...props }: ButtonProps) {
|
|
37
|
+
return <button ref={ref} {...props}>{children}</button>;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**useActionState** - replaces useFormState:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { useActionState } from 'react';
|
|
45
|
+
|
|
46
|
+
type FormState = { errors?: string[]; success?: boolean };
|
|
47
|
+
|
|
48
|
+
function Form() {
|
|
49
|
+
const [state, formAction, isPending] = useActionState(submitAction, {});
|
|
50
|
+
return <form action={formAction}>...</form>;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**use()** - unwraps promises/context:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
|
|
58
|
+
const user = use(userPromise); // Suspends until resolved
|
|
59
|
+
return <div>{user.name}</div>;
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
See [react-19-patterns.md](references/react-19-patterns.md) for useOptimistic, useTransition, migration checklist.
|
|
64
|
+
|
|
65
|
+
</react_19_changes>
|
|
66
|
+
|
|
67
|
+
<component_patterns>
|
|
68
|
+
|
|
69
|
+
**Props** - extend native elements:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
type ButtonProps = {
|
|
73
|
+
variant: 'primary' | 'secondary';
|
|
74
|
+
} & React.ComponentPropsWithoutRef<'button'>;
|
|
75
|
+
|
|
76
|
+
function Button({ variant, children, ...props }: ButtonProps) {
|
|
77
|
+
return <button className={variant} {...props}>{children}</button>;
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Children typing**:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
type Props = {
|
|
85
|
+
children: React.ReactNode; // Anything renderable
|
|
86
|
+
icon: React.ReactElement; // Single element
|
|
87
|
+
render: (data: T) => React.ReactNode; // Render prop
|
|
88
|
+
};
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Discriminated unions** for variant props:
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
type ButtonProps =
|
|
95
|
+
| { variant: 'link'; href: string }
|
|
96
|
+
| { variant: 'button'; onClick: () => void };
|
|
97
|
+
|
|
98
|
+
function Button(props: ButtonProps) {
|
|
99
|
+
if (props.variant === 'link') {
|
|
100
|
+
return <a href={props.href}>Link</a>;
|
|
101
|
+
}
|
|
102
|
+
return <button onClick={props.onClick}>Button</button>;
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
</component_patterns>
|
|
107
|
+
|
|
108
|
+
<event_handlers>
|
|
109
|
+
|
|
110
|
+
Use specific event types for accurate target typing:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// Mouse
|
|
114
|
+
function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
|
|
115
|
+
e.currentTarget.disabled = true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Form
|
|
119
|
+
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
|
|
120
|
+
e.preventDefault();
|
|
121
|
+
const formData = new FormData(e.currentTarget);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Input
|
|
125
|
+
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
|
|
126
|
+
console.log(e.target.value);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Keyboard
|
|
130
|
+
function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
|
|
131
|
+
if (e.key === 'Enter') e.currentTarget.blur();
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
See [event-handlers.md](references/event-handlers.md) for focus, drag, clipboard, touch, wheel events.
|
|
136
|
+
|
|
137
|
+
</event_handlers>
|
|
138
|
+
|
|
139
|
+
<hooks_typing>
|
|
140
|
+
|
|
141
|
+
**useState** - explicit for unions/null:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
const [user, setUser] = useState<User | null>(null);
|
|
145
|
+
const [status, setStatus] = useState<'idle' | 'loading'>('idle');
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**useRef** - null for DOM, value for mutable:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
const inputRef = useRef<HTMLInputElement>(null); // DOM - use ?.
|
|
152
|
+
const countRef = useRef<number>(0); // Mutable - direct access
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**useReducer** - discriminated unions for actions:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
type Action =
|
|
159
|
+
| { type: 'increment' }
|
|
160
|
+
| { type: 'set'; payload: number };
|
|
161
|
+
|
|
162
|
+
function reducer(state: State, action: Action): State {
|
|
163
|
+
switch (action.type) {
|
|
164
|
+
case 'set': return { ...state, count: action.payload };
|
|
165
|
+
default: return state;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Custom hooks** - tuple returns with as const:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
function useToggle(initial = false) {
|
|
174
|
+
const [value, setValue] = useState(initial);
|
|
175
|
+
const toggle = () => setValue(v => !v);
|
|
176
|
+
return [value, toggle] as const;
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**useContext** - null guard pattern:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
const UserContext = createContext<User | null>(null);
|
|
184
|
+
|
|
185
|
+
function useUser() {
|
|
186
|
+
const user = useContext(UserContext);
|
|
187
|
+
if (!user) throw new Error('useUser outside UserProvider');
|
|
188
|
+
return user;
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
See [hooks.md](references/hooks.md) for useCallback, useMemo, useImperativeHandle, useSyncExternalStore.
|
|
193
|
+
|
|
194
|
+
</hooks_typing>
|
|
195
|
+
|
|
196
|
+
<generic_components>
|
|
197
|
+
|
|
198
|
+
Generic components infer types from props - no manual annotations at call site.
|
|
199
|
+
|
|
200
|
+
**Pattern** - keyof T for column keys, render props for custom rendering:
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
type Column<T> = {
|
|
204
|
+
key: keyof T;
|
|
205
|
+
header: string;
|
|
206
|
+
render?: (value: T[keyof T], item: T) => React.ReactNode;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
type TableProps<T> = {
|
|
210
|
+
data: T[];
|
|
211
|
+
columns: Column<T>[];
|
|
212
|
+
keyExtractor: (item: T) => string | number;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
function Table<T>({ data, columns, keyExtractor }: TableProps<T>) {
|
|
216
|
+
return (
|
|
217
|
+
<table>
|
|
218
|
+
<thead>
|
|
219
|
+
<tr>{columns.map(col => <th key={String(col.key)}>{col.header}</th>)}</tr>
|
|
220
|
+
</thead>
|
|
221
|
+
<tbody>
|
|
222
|
+
{data.map(item => (
|
|
223
|
+
<tr key={keyExtractor(item)}>
|
|
224
|
+
{columns.map(col => (
|
|
225
|
+
<td key={String(col.key)}>
|
|
226
|
+
{col.render ? col.render(item[col.key], item) : String(item[col.key])}
|
|
227
|
+
</td>
|
|
228
|
+
))}
|
|
229
|
+
</tr>
|
|
230
|
+
))}
|
|
231
|
+
</tbody>
|
|
232
|
+
</table>
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Constrained generics** for required properties:
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
type HasId = { id: string | number };
|
|
241
|
+
|
|
242
|
+
function List<T extends HasId>({ items }: { items: T[] }) {
|
|
243
|
+
return <ul>{items.map(item => <li key={item.id}>...</li>)}</ul>;
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
See [generic-components.md](examples/generic-components.md) for Select, List, Modal, FormField patterns.
|
|
248
|
+
|
|
249
|
+
</generic_components>
|
|
250
|
+
|
|
251
|
+
<server_components>
|
|
252
|
+
|
|
253
|
+
React 19 Server Components run on server, can be async.
|
|
254
|
+
|
|
255
|
+
**Async data fetching**:
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
export default async function UserPage({ params }: { params: { id: string } }) {
|
|
259
|
+
const user = await fetchUser(params.id);
|
|
260
|
+
return <div>{user.name}</div>;
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**Server Actions** - 'use server' for mutations:
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
'use server';
|
|
268
|
+
|
|
269
|
+
export async function updateUser(userId: string, formData: FormData) {
|
|
270
|
+
await db.user.update({ where: { id: userId }, data: { ... } });
|
|
271
|
+
revalidatePath(`/users/${userId}`);
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Client + Server Action**:
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
'use client';
|
|
279
|
+
|
|
280
|
+
import { useActionState } from 'react';
|
|
281
|
+
import { updateUser } from '@/actions/user';
|
|
282
|
+
|
|
283
|
+
function UserForm({ userId }: { userId: string }) {
|
|
284
|
+
const [state, formAction, isPending] = useActionState(
|
|
285
|
+
(prev, formData) => updateUser(userId, formData), {}
|
|
286
|
+
);
|
|
287
|
+
return <form action={formAction}>...</form>;
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**use() for promise handoff**:
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
// Server: pass promise without await
|
|
295
|
+
async function Page() {
|
|
296
|
+
const userPromise = fetchUser('123');
|
|
297
|
+
return <UserProfile userPromise={userPromise} />;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Client: unwrap with use()
|
|
301
|
+
'use client';
|
|
302
|
+
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
|
|
303
|
+
const user = use(userPromise);
|
|
304
|
+
return <div>{user.name}</div>;
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
See [server-components.md](examples/server-components.md) for parallel fetching, streaming, error boundaries.
|
|
309
|
+
|
|
310
|
+
</server_components>
|
|
311
|
+
|
|
312
|
+
<routing>
|
|
313
|
+
|
|
314
|
+
Both TanStack Router and React Router v7 provide type-safe routing solutions.
|
|
315
|
+
|
|
316
|
+
**TanStack Router** - Compile-time type safety with Zod validation:
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
import { createRoute } from '@tanstack/react-router';
|
|
320
|
+
import { z } from 'zod';
|
|
321
|
+
|
|
322
|
+
const userRoute = createRoute({
|
|
323
|
+
path: '/users/$userId',
|
|
324
|
+
component: UserPage,
|
|
325
|
+
loader: async ({ params }) => ({ user: await fetchUser(params.userId) }),
|
|
326
|
+
validateSearch: z.object({
|
|
327
|
+
tab: z.enum(['profile', 'settings']).optional(),
|
|
328
|
+
page: z.number().int().positive().default(1),
|
|
329
|
+
}),
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
function UserPage() {
|
|
333
|
+
const { user } = useLoaderData({ from: userRoute.id });
|
|
334
|
+
const { tab, page } = useSearch({ from: userRoute.id });
|
|
335
|
+
const { userId } = useParams({ from: userRoute.id });
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**React Router v7** - Automatic type generation with Framework Mode:
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
import type { Route } from "./+types/user";
|
|
343
|
+
|
|
344
|
+
export async function loader({ params }: Route.LoaderArgs) {
|
|
345
|
+
return { user: await fetchUser(params.userId) };
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export default function UserPage({ loaderData }: Route.ComponentProps) {
|
|
349
|
+
const { user } = loaderData; // Typed from loader
|
|
350
|
+
return <h1>{user.name}</h1>;
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
See [tanstack-router.md](references/tanstack-router.md) for TanStack patterns and [react-router.md](references/react-router.md) for React Router patterns.
|
|
355
|
+
|
|
356
|
+
</routing>
|
|
357
|
+
|
|
358
|
+
<rules>
|
|
359
|
+
|
|
360
|
+
ALWAYS:
|
|
361
|
+
- Specific event types (MouseEvent, ChangeEvent, etc)
|
|
362
|
+
- Explicit useState for unions/null
|
|
363
|
+
- ComponentPropsWithoutRef for native element extension
|
|
364
|
+
- Discriminated unions for variant props
|
|
365
|
+
- as const for tuple returns
|
|
366
|
+
- ref as prop in React 19 (no forwardRef)
|
|
367
|
+
- useActionState for form actions
|
|
368
|
+
- Type-safe routing patterns (see routing section)
|
|
369
|
+
|
|
370
|
+
NEVER:
|
|
371
|
+
- any for event handlers
|
|
372
|
+
- JSX.Element for children (use ReactNode)
|
|
373
|
+
- forwardRef in React 19+
|
|
374
|
+
- useFormState (deprecated)
|
|
375
|
+
- Forget null handling for DOM refs
|
|
376
|
+
- Mix Server/Client components in same file
|
|
377
|
+
- Await promises when passing to use()
|
|
378
|
+
|
|
379
|
+
</rules>
|
|
380
|
+
|
|
381
|
+
<animation>
|
|
382
|
+
|
|
383
|
+
## Framer Motion
|
|
384
|
+
|
|
385
|
+
Install: `npm i framer-motion`. Add `'use client'` to any component using motion primitives.
|
|
386
|
+
|
|
387
|
+
```tsx
|
|
388
|
+
import { motion, AnimatePresence, useInView, useMotionValue, useSpring } from 'framer-motion'
|
|
389
|
+
|
|
390
|
+
// Spring config — use for all entrance/hover animations
|
|
391
|
+
const spring = { type: 'spring', stiffness: 300, damping: 30 }
|
|
392
|
+
|
|
393
|
+
// Entrance
|
|
394
|
+
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={spring} />
|
|
395
|
+
|
|
396
|
+
// Hover lift
|
|
397
|
+
<motion.div whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98 }} transition={spring} />
|
|
398
|
+
|
|
399
|
+
// Staggered list
|
|
400
|
+
const container = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { staggerChildren: 0.08 } } }
|
|
401
|
+
const item = { hidden: { opacity: 0, y: 12 }, show: { opacity: 1, y: 0 } }
|
|
402
|
+
<motion.ul variants={container} initial="hidden" animate="show">
|
|
403
|
+
{items.map(i => <motion.li key={i.id} variants={item}>{i.name}</motion.li>)}
|
|
404
|
+
</motion.ul>
|
|
405
|
+
|
|
406
|
+
// Exit animations — AnimatePresence required for `exit` to fire
|
|
407
|
+
<AnimatePresence>
|
|
408
|
+
{open && (
|
|
409
|
+
<motion.div key="panel" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}>
|
|
410
|
+
...
|
|
411
|
+
</motion.div>
|
|
412
|
+
)}
|
|
413
|
+
</AnimatePresence>
|
|
414
|
+
|
|
415
|
+
// Scroll reveal
|
|
416
|
+
function ScrollReveal({ children }: { children: React.ReactNode }) {
|
|
417
|
+
const ref = useRef(null)
|
|
418
|
+
const inView = useInView(ref, { once: true, margin: '-80px' })
|
|
419
|
+
return (
|
|
420
|
+
<motion.div ref={ref} initial={{ opacity: 0, y: 24 }}
|
|
421
|
+
animate={inView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.5, ease: 'easeOut' }}>
|
|
422
|
+
{children}
|
|
423
|
+
</motion.div>
|
|
424
|
+
)
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Magnetic cursor follower
|
|
428
|
+
function CursorFollower() {
|
|
429
|
+
const x = useMotionValue(0), y = useMotionValue(0)
|
|
430
|
+
const springX = useSpring(x, { stiffness: 500, damping: 40 })
|
|
431
|
+
const springY = useSpring(y, { stiffness: 500, damping: 40 })
|
|
432
|
+
useEffect(() => {
|
|
433
|
+
const move = (e: MouseEvent) => { x.set(e.clientX - 8); y.set(e.clientY - 8) }
|
|
434
|
+
window.addEventListener('mousemove', move)
|
|
435
|
+
return () => window.removeEventListener('mousemove', move)
|
|
436
|
+
}, [])
|
|
437
|
+
return <motion.div className="fixed size-4 rounded-full bg-brand pointer-events-none z-[9999]" style={{ x: springX, y: springY }} />
|
|
438
|
+
}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
**Performance rules:**
|
|
442
|
+
- Animate only `transform` (translate/scale/rotate) and `opacity` — never `width`, `height`, `top`, `left`, or `margin` (causes reflow)
|
|
443
|
+
- Keep animated subtrees shallow — each `motion.div` adds reconciliation cost
|
|
444
|
+
- Use `will-change: transform` sparingly — only on elements animating constantly; remove after animation ends
|
|
445
|
+
- Wrap `AnimatePresence` around conditional renders, not lists — use `variants` + `staggerChildren` for lists
|
|
446
|
+
|
|
447
|
+
</animation>
|
|
448
|
+
|
|
449
|
+
<references>
|
|
450
|
+
|
|
451
|
+
- [hooks.md](references/hooks.md) - useState, useRef, useReducer, useContext, custom hooks
|
|
452
|
+
- [event-handlers.md](references/event-handlers.md) - all event types, generic handlers
|
|
453
|
+
- [react-19-patterns.md](references/react-19-patterns.md) - useActionState, use(), useOptimistic, migration
|
|
454
|
+
- [generic-components.md](examples/generic-components.md) - Table, Select, List, Modal patterns
|
|
455
|
+
- [server-components.md](examples/server-components.md) - async components, Server Actions, streaming
|
|
456
|
+
- [tanstack-router.md](references/tanstack-router.md) - TanStack Router typed routes, search params, navigation
|
|
457
|
+
- [react-router.md](references/react-router.md) - React Router v7 loaders, actions, type generation, forms
|
|
458
|
+
|
|
459
|
+
</references>
|