@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,574 @@
|
|
|
1
|
+
# Event Handler TypeScript Patterns
|
|
2
|
+
|
|
3
|
+
Proper event typing ensures type-safe access to event properties and target elements.
|
|
4
|
+
|
|
5
|
+
## Mouse Events
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// Click events
|
|
9
|
+
function handleClick(event: React.MouseEvent<HTMLButtonElement>) {
|
|
10
|
+
event.preventDefault();
|
|
11
|
+
event.stopPropagation();
|
|
12
|
+
|
|
13
|
+
// Target element typed correctly
|
|
14
|
+
event.currentTarget.disabled = true;
|
|
15
|
+
event.currentTarget.textContent = 'Clicked';
|
|
16
|
+
|
|
17
|
+
// Mouse position
|
|
18
|
+
console.log(event.clientX, event.clientY);
|
|
19
|
+
console.log(event.pageX, event.pageY);
|
|
20
|
+
|
|
21
|
+
// Mouse buttons
|
|
22
|
+
console.log(event.button); // 0 = left, 1 = middle, 2 = right
|
|
23
|
+
console.log(event.buttons); // Bitmask of pressed buttons
|
|
24
|
+
|
|
25
|
+
// Modifier keys
|
|
26
|
+
if (event.ctrlKey || event.metaKey) {
|
|
27
|
+
console.log('Ctrl/Cmd + Click');
|
|
28
|
+
}
|
|
29
|
+
if (event.shiftKey) {
|
|
30
|
+
console.log('Shift + Click');
|
|
31
|
+
}
|
|
32
|
+
if (event.altKey) {
|
|
33
|
+
console.log('Alt + Click');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Mouse movement
|
|
38
|
+
function handleMouseMove(event: React.MouseEvent<HTMLDivElement>) {
|
|
39
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
40
|
+
const x = event.clientX - rect.left;
|
|
41
|
+
const y = event.clientY - rect.top;
|
|
42
|
+
console.log(`Position in element: ${x}, ${y}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Hover events
|
|
46
|
+
function handleMouseEnter(event: React.MouseEvent<HTMLDivElement>) {
|
|
47
|
+
event.currentTarget.style.backgroundColor = 'lightblue';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function handleMouseLeave(event: React.MouseEvent<HTMLDivElement>) {
|
|
51
|
+
event.currentTarget.style.backgroundColor = '';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Double click
|
|
55
|
+
function handleDoubleClick(event: React.MouseEvent<HTMLElement>) {
|
|
56
|
+
console.log('Double clicked');
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Form Events
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// Form submission
|
|
64
|
+
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
|
65
|
+
event.preventDefault();
|
|
66
|
+
|
|
67
|
+
const form = event.currentTarget;
|
|
68
|
+
const formData = new FormData(form);
|
|
69
|
+
|
|
70
|
+
const data = {
|
|
71
|
+
name: formData.get('name') as string,
|
|
72
|
+
email: formData.get('email') as string,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
console.log(data);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Input change
|
|
79
|
+
function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
|
|
80
|
+
const target = event.target;
|
|
81
|
+
|
|
82
|
+
// For text inputs
|
|
83
|
+
if (target.type === 'text' || target.type === 'email') {
|
|
84
|
+
console.log(target.value); // string
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// For checkboxes
|
|
88
|
+
if (target.type === 'checkbox') {
|
|
89
|
+
console.log(target.checked); // boolean
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// For radio buttons
|
|
93
|
+
if (target.type === 'radio') {
|
|
94
|
+
console.log(target.value, target.checked);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// For number inputs
|
|
98
|
+
if (target.type === 'number') {
|
|
99
|
+
console.log(target.valueAsNumber); // number
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// For file inputs
|
|
103
|
+
if (target.type === 'file') {
|
|
104
|
+
const files = target.files; // FileList | null
|
|
105
|
+
if (files && files.length > 0) {
|
|
106
|
+
console.log(files[0].name);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Textarea change
|
|
112
|
+
function handleTextareaChange(event: React.ChangeEvent<HTMLTextAreaElement>) {
|
|
113
|
+
console.log(event.target.value);
|
|
114
|
+
console.log(event.target.selectionStart); // Cursor position
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Select change
|
|
118
|
+
function handleSelectChange(event: React.ChangeEvent<HTMLSelectElement>) {
|
|
119
|
+
const value = event.target.value;
|
|
120
|
+
const selectedIndex = event.target.selectedIndex;
|
|
121
|
+
const selectedOption = event.target.options[selectedIndex];
|
|
122
|
+
console.log(value, selectedOption.text);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Input events (fires on every keystroke)
|
|
126
|
+
function handleInput(event: React.FormEvent<HTMLInputElement>) {
|
|
127
|
+
console.log(event.currentTarget.value);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Reset event
|
|
131
|
+
function handleReset(event: React.FormEvent<HTMLFormElement>) {
|
|
132
|
+
event.preventDefault();
|
|
133
|
+
console.log('Form reset');
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Keyboard Events
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {
|
|
141
|
+
// Key identification
|
|
142
|
+
console.log(event.key); // 'Enter', 'Escape', 'a', etc.
|
|
143
|
+
console.log(event.code); // 'Enter', 'Escape', 'KeyA', etc.
|
|
144
|
+
|
|
145
|
+
// Common patterns
|
|
146
|
+
if (event.key === 'Enter') {
|
|
147
|
+
event.preventDefault();
|
|
148
|
+
console.log('Enter pressed');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (event.key === 'Escape') {
|
|
152
|
+
event.currentTarget.blur();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Arrow keys
|
|
156
|
+
if (event.key === 'ArrowUp') {
|
|
157
|
+
event.preventDefault();
|
|
158
|
+
// Navigate up
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Modifier keys
|
|
162
|
+
if (event.ctrlKey && event.key === 's') {
|
|
163
|
+
event.preventDefault();
|
|
164
|
+
console.log('Ctrl+S - Save');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (event.metaKey && event.key === 'k') {
|
|
168
|
+
event.preventDefault();
|
|
169
|
+
console.log('Cmd+K - Search');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Check multiple modifiers
|
|
173
|
+
if (event.ctrlKey && event.shiftKey && event.key === 'P') {
|
|
174
|
+
event.preventDefault();
|
|
175
|
+
console.log('Ctrl+Shift+P - Command palette');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Key combinations
|
|
179
|
+
if ((event.ctrlKey || event.metaKey) && event.key === 'Enter') {
|
|
180
|
+
console.log('Submit with Ctrl/Cmd+Enter');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function handleKeyUp(event: React.KeyboardEvent<HTMLInputElement>) {
|
|
185
|
+
console.log('Key released:', event.key);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function handleKeyPress(event: React.KeyboardEvent<HTMLInputElement>) {
|
|
189
|
+
// Deprecated - use keyDown instead
|
|
190
|
+
console.log('Key pressed:', event.key);
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Focus Events
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
function handleFocus(event: React.FocusEvent<HTMLInputElement>) {
|
|
198
|
+
// Select all text on focus
|
|
199
|
+
event.target.select();
|
|
200
|
+
|
|
201
|
+
// Add visual indicator
|
|
202
|
+
event.currentTarget.classList.add('focused');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function handleBlur(event: React.FocusEvent<HTMLInputElement>) {
|
|
206
|
+
// Validate on blur
|
|
207
|
+
const value = event.target.value;
|
|
208
|
+
if (value === '') {
|
|
209
|
+
event.currentTarget.classList.add('error');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Remove visual indicator
|
|
213
|
+
event.currentTarget.classList.remove('focused');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Focus within
|
|
217
|
+
function handleFocusWithin(event: React.FocusEvent<HTMLDivElement>) {
|
|
218
|
+
// Related target - element receiving focus
|
|
219
|
+
const relatedTarget = event.relatedTarget as HTMLElement | null;
|
|
220
|
+
console.log('Focus moved from:', relatedTarget);
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Drag and Drop Events
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
function handleDragStart(event: React.DragEvent<HTMLDivElement>) {
|
|
228
|
+
event.dataTransfer.effectAllowed = 'move';
|
|
229
|
+
event.dataTransfer.setData('text/plain', event.currentTarget.id);
|
|
230
|
+
|
|
231
|
+
// Custom drag image
|
|
232
|
+
const dragImage = document.createElement('div');
|
|
233
|
+
dragImage.textContent = 'Dragging...';
|
|
234
|
+
event.dataTransfer.setDragImage(dragImage, 0, 0);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function handleDragOver(event: React.DragEvent<HTMLDivElement>) {
|
|
238
|
+
event.preventDefault();
|
|
239
|
+
event.dataTransfer.dropEffect = 'move';
|
|
240
|
+
event.currentTarget.classList.add('drag-over');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function handleDragLeave(event: React.DragEvent<HTMLDivElement>) {
|
|
244
|
+
event.currentTarget.classList.remove('drag-over');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function handleDrop(event: React.DragEvent<HTMLDivElement>) {
|
|
248
|
+
event.preventDefault();
|
|
249
|
+
event.currentTarget.classList.remove('drag-over');
|
|
250
|
+
|
|
251
|
+
const data = event.dataTransfer.getData('text/plain');
|
|
252
|
+
console.log('Dropped:', data);
|
|
253
|
+
|
|
254
|
+
// Handle files
|
|
255
|
+
const files = event.dataTransfer.files;
|
|
256
|
+
if (files.length > 0) {
|
|
257
|
+
Array.from(files).forEach((file) => {
|
|
258
|
+
console.log(file.name, file.type, file.size);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function handleDragEnd(event: React.DragEvent<HTMLDivElement>) {
|
|
264
|
+
console.log('Drag ended');
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Clipboard Events
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
function handleCopy(event: React.ClipboardEvent<HTMLDivElement>) {
|
|
272
|
+
event.preventDefault();
|
|
273
|
+
|
|
274
|
+
// Custom copy behavior
|
|
275
|
+
const selection = window.getSelection();
|
|
276
|
+
if (selection) {
|
|
277
|
+
const text = `Copied from app: ${selection.toString()}`;
|
|
278
|
+
event.clipboardData.setData('text/plain', text);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function handleCut(event: React.ClipboardEvent<HTMLInputElement>) {
|
|
283
|
+
console.log('Cut:', event.currentTarget.value);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function handlePaste(event: React.ClipboardEvent<HTMLInputElement>) {
|
|
287
|
+
event.preventDefault();
|
|
288
|
+
|
|
289
|
+
const pastedText = event.clipboardData.getData('text/plain');
|
|
290
|
+
console.log('Pasted:', pastedText);
|
|
291
|
+
|
|
292
|
+
// Validate pasted content
|
|
293
|
+
const sanitized = pastedText.replace(/[^a-zA-Z0-9]/g, '');
|
|
294
|
+
event.currentTarget.value = sanitized;
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Composition Events (IME)
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
// For international input methods (Chinese, Japanese, etc.)
|
|
302
|
+
function handleCompositionStart(event: React.CompositionEvent<HTMLInputElement>) {
|
|
303
|
+
console.log('Composition started');
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function handleCompositionUpdate(event: React.CompositionEvent<HTMLInputElement>) {
|
|
307
|
+
console.log('Composing:', event.data);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function handleCompositionEnd(event: React.CompositionEvent<HTMLInputElement>) {
|
|
311
|
+
console.log('Composition ended:', event.data);
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## Touch Events
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
function handleTouchStart(event: React.TouchEvent<HTMLDivElement>) {
|
|
319
|
+
const touch = event.touches[0];
|
|
320
|
+
console.log('Touch start:', touch.clientX, touch.clientY);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function handleTouchMove(event: React.TouchEvent<HTMLDivElement>) {
|
|
324
|
+
event.preventDefault(); // Prevent scrolling
|
|
325
|
+
|
|
326
|
+
const touch = event.touches[0];
|
|
327
|
+
console.log('Touch move:', touch.clientX, touch.clientY);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function handleTouchEnd(event: React.TouchEvent<HTMLDivElement>) {
|
|
331
|
+
console.log('Touch ended');
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Multi-touch
|
|
335
|
+
function handleMultiTouch(event: React.TouchEvent<HTMLDivElement>) {
|
|
336
|
+
if (event.touches.length === 2) {
|
|
337
|
+
const [touch1, touch2] = event.touches;
|
|
338
|
+
|
|
339
|
+
const distance = Math.hypot(
|
|
340
|
+
touch2.clientX - touch1.clientX,
|
|
341
|
+
touch2.clientY - touch1.clientY
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
console.log('Pinch distance:', distance);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## Wheel Events
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
function handleWheel(event: React.WheelEvent<HTMLDivElement>) {
|
|
353
|
+
// Prevent default scroll
|
|
354
|
+
event.preventDefault();
|
|
355
|
+
|
|
356
|
+
// Scroll delta
|
|
357
|
+
console.log('Delta X:', event.deltaX);
|
|
358
|
+
console.log('Delta Y:', event.deltaY);
|
|
359
|
+
console.log('Delta Z:', event.deltaZ);
|
|
360
|
+
|
|
361
|
+
// Delta mode (0 = pixels, 1 = lines, 2 = pages)
|
|
362
|
+
console.log('Delta mode:', event.deltaMode);
|
|
363
|
+
|
|
364
|
+
// Zoom with Ctrl+Wheel
|
|
365
|
+
if (event.ctrlKey) {
|
|
366
|
+
const zoomDelta = event.deltaY > 0 ? -0.1 : 0.1;
|
|
367
|
+
console.log('Zoom:', zoomDelta);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## Generic Event Handlers
|
|
373
|
+
|
|
374
|
+
Reusable handlers with proper typing.
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
// Generic change handler
|
|
378
|
+
function createChangeHandler<T extends HTMLElement>(
|
|
379
|
+
callback: (value: string) => void
|
|
380
|
+
) {
|
|
381
|
+
return (event: React.ChangeEvent<T>) => {
|
|
382
|
+
if ('value' in event.target) {
|
|
383
|
+
callback(event.target.value);
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Usage
|
|
389
|
+
const handleNameChange = createChangeHandler<HTMLInputElement>((value) => {
|
|
390
|
+
setName(value);
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
const handleBioChange = createChangeHandler<HTMLTextAreaElement>((value) => {
|
|
394
|
+
setBio(value);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
// Generic click handler with target validation
|
|
398
|
+
function createClickHandler<T extends HTMLElement>(
|
|
399
|
+
selector: string,
|
|
400
|
+
callback: (element: T) => void
|
|
401
|
+
) {
|
|
402
|
+
return (event: React.MouseEvent<HTMLElement>) => {
|
|
403
|
+
const target = event.target as HTMLElement;
|
|
404
|
+
const match = target.closest(selector);
|
|
405
|
+
|
|
406
|
+
if (match) {
|
|
407
|
+
callback(match as T);
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Usage
|
|
413
|
+
const handleItemClick = createClickHandler<HTMLLIElement>('li[data-id]', (item) => {
|
|
414
|
+
const id = item.dataset.id;
|
|
415
|
+
console.log('Clicked item:', id);
|
|
416
|
+
});
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
## Event Handler Type Aliases
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
// Create reusable type aliases
|
|
423
|
+
type InputChangeHandler = React.ChangeEventHandler<HTMLInputElement>;
|
|
424
|
+
type ButtonClickHandler = React.MouseEventHandler<HTMLButtonElement>;
|
|
425
|
+
type FormSubmitHandler = React.FormEventHandler<HTMLFormElement>;
|
|
426
|
+
|
|
427
|
+
// Usage
|
|
428
|
+
const handleChange: InputChangeHandler = (event) => {
|
|
429
|
+
console.log(event.target.value);
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
const handleClick: ButtonClickHandler = (event) => {
|
|
433
|
+
event.currentTarget.disabled = true;
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
const handleSubmit: FormSubmitHandler = (event) => {
|
|
437
|
+
event.preventDefault();
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
// Generic handler type
|
|
441
|
+
type EventHandler<E extends HTMLElement, Evt extends React.SyntheticEvent> = (
|
|
442
|
+
event: Evt & { currentTarget: E }
|
|
443
|
+
) => void;
|
|
444
|
+
|
|
445
|
+
// Usage
|
|
446
|
+
const handleInput: EventHandler<HTMLInputElement, React.ChangeEvent<HTMLInputElement>> = (
|
|
447
|
+
event
|
|
448
|
+
) => {
|
|
449
|
+
console.log(event.currentTarget.value);
|
|
450
|
+
};
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
## Delegated Event Handlers
|
|
454
|
+
|
|
455
|
+
Type-safe event delegation.
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
function ListContainer() {
|
|
459
|
+
const handleListClick = (event: React.MouseEvent<HTMLUListElement>) => {
|
|
460
|
+
const target = event.target as HTMLElement;
|
|
461
|
+
|
|
462
|
+
// Find clicked list item
|
|
463
|
+
const listItem = target.closest('li');
|
|
464
|
+
if (!listItem) return;
|
|
465
|
+
|
|
466
|
+
// Type guard for data attributes
|
|
467
|
+
const itemId = listItem.getAttribute('data-id');
|
|
468
|
+
if (itemId) {
|
|
469
|
+
console.log('Clicked item:', itemId);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Handle button within list item
|
|
473
|
+
if (target.matches('button.delete')) {
|
|
474
|
+
event.stopPropagation();
|
|
475
|
+
console.log('Delete clicked');
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
return (
|
|
480
|
+
<ul onClick={handleListClick}>
|
|
481
|
+
<li data-id="1">
|
|
482
|
+
Item 1<button className="delete">Delete</button>
|
|
483
|
+
</li>
|
|
484
|
+
<li data-id="2">
|
|
485
|
+
Item 2<button className="delete">Delete</button>
|
|
486
|
+
</li>
|
|
487
|
+
</ul>
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
## Native vs Synthetic Events
|
|
493
|
+
|
|
494
|
+
```typescript
|
|
495
|
+
function Component() {
|
|
496
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
497
|
+
|
|
498
|
+
useEffect(() => {
|
|
499
|
+
const element = ref.current;
|
|
500
|
+
if (!element) return;
|
|
501
|
+
|
|
502
|
+
// Native event listener
|
|
503
|
+
const handleNativeClick = (event: MouseEvent) => {
|
|
504
|
+
console.log('Native click:', event.target);
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
element.addEventListener('click', handleNativeClick);
|
|
508
|
+
|
|
509
|
+
return () => {
|
|
510
|
+
element.removeEventListener('click', handleNativeClick);
|
|
511
|
+
};
|
|
512
|
+
}, []);
|
|
513
|
+
|
|
514
|
+
// React synthetic event
|
|
515
|
+
const handleReactClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
|
516
|
+
console.log('React click:', event.target);
|
|
517
|
+
|
|
518
|
+
// Access native event
|
|
519
|
+
const nativeEvent = event.nativeEvent;
|
|
520
|
+
console.log('Native event:', nativeEvent);
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
return <div ref={ref} onClick={handleReactClick}>Click me</div>;
|
|
524
|
+
}
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
## Custom Events
|
|
528
|
+
|
|
529
|
+
```typescript
|
|
530
|
+
// Define custom event type
|
|
531
|
+
type CustomEventMap = {
|
|
532
|
+
'user:login': CustomEvent<{ userId: string }>;
|
|
533
|
+
'user:logout': CustomEvent;
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
// Typed custom event dispatcher
|
|
537
|
+
function dispatchCustomEvent<K extends keyof CustomEventMap>(
|
|
538
|
+
element: HTMLElement,
|
|
539
|
+
type: K,
|
|
540
|
+
detail?: CustomEventMap[K]['detail']
|
|
541
|
+
) {
|
|
542
|
+
const event = new CustomEvent(type, { detail, bubbles: true });
|
|
543
|
+
element.dispatchEvent(event);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Component using custom events
|
|
547
|
+
function UserButton() {
|
|
548
|
+
const ref = useRef<HTMLButtonElement>(null);
|
|
549
|
+
|
|
550
|
+
const handleLogin = () => {
|
|
551
|
+
if (ref.current) {
|
|
552
|
+
dispatchCustomEvent(ref.current, 'user:login', { userId: '123' });
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
useEffect(() => {
|
|
557
|
+
const element = ref.current;
|
|
558
|
+
if (!element) return;
|
|
559
|
+
|
|
560
|
+
const handleCustomLogin = (event: Event) => {
|
|
561
|
+
const customEvent = event as CustomEvent<{ userId: string }>;
|
|
562
|
+
console.log('User logged in:', customEvent.detail.userId);
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
element.addEventListener('user:login', handleCustomLogin);
|
|
566
|
+
|
|
567
|
+
return () => {
|
|
568
|
+
element.removeEventListener('user:login', handleCustomLogin);
|
|
569
|
+
};
|
|
570
|
+
}, []);
|
|
571
|
+
|
|
572
|
+
return <button ref={ref} onClick={handleLogin}>Login</button>;
|
|
573
|
+
}
|
|
574
|
+
```
|