@ewjdev/anyclick-react 1.4.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +199 -63
- package/dist/index.d.mts +799 -222
- package/dist/index.d.ts +799 -222
- package/dist/index.js +2520 -2608
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2410 -2499
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
15
|
npm install @ewjdev/anyclick-react
|
|
16
|
+
# or
|
|
17
|
+
yarn add @ewjdev/anyclick-react
|
|
18
|
+
# or
|
|
19
|
+
pnpm add @ewjdev/anyclick-react
|
|
16
20
|
```
|
|
17
21
|
|
|
18
22
|
## Requirements
|
|
@@ -25,8 +29,8 @@ npm install @ewjdev/anyclick-react
|
|
|
25
29
|
```tsx
|
|
26
30
|
"use client";
|
|
27
31
|
|
|
28
|
-
import { AnyclickProvider } from "@ewjdev/anyclick-react";
|
|
29
32
|
import { createHttpAdapter } from "@ewjdev/anyclick-github";
|
|
33
|
+
import { AnyclickProvider } from "@ewjdev/anyclick-react";
|
|
30
34
|
|
|
31
35
|
const adapter = createHttpAdapter({
|
|
32
36
|
endpoint: "/api/feedback",
|
|
@@ -42,27 +46,106 @@ That's it! Users can now right-click any element to submit feedback.
|
|
|
42
46
|
## Features
|
|
43
47
|
|
|
44
48
|
- 🖱️ **Right-Click Context Menu** - Native feel with customizable items
|
|
49
|
+
- 📱 **Touch Support** - Press-and-hold on mobile devices
|
|
45
50
|
- 🎨 **Element Highlighting** - Visual feedback for target and container elements
|
|
46
|
-
- 📸 **Screenshot Capture** - Automatic screenshots of target, container, and
|
|
51
|
+
- 📸 **Screenshot Capture** - Automatic screenshots of target, container, and viewport
|
|
47
52
|
- 🔒 **Role-Based Menu Items** - Show different options based on user roles
|
|
48
|
-
-
|
|
53
|
+
- 📁 **Submenus** - Organize menu items with nested submenus
|
|
49
54
|
- 🎯 **Scoped Providers** - Limit feedback capture to specific components
|
|
50
55
|
- 🎨 **Nested Theming** - Override themes for specific sections of your app
|
|
56
|
+
- 🔍 **Element Inspector** - Chrome DevTools-style inspect dialog
|
|
57
|
+
- ⚡ **Performance Optimized** - Memoized components and efficient re-renders
|
|
58
|
+
|
|
59
|
+
## API Reference
|
|
60
|
+
|
|
61
|
+
### AnyclickProvider Props
|
|
62
|
+
|
|
63
|
+
| Prop | Type | Default | Description |
|
|
64
|
+
| --------------------- | -------------------------- | ----------- | ---------------------------------------------- |
|
|
65
|
+
| `adapter` | `AnyclickAdapter` | Required | The adapter for submitting feedback |
|
|
66
|
+
| `menuItems` | `ContextMenuItem[]` | Default set | Custom menu items |
|
|
67
|
+
| `metadata` | `Record<string, unknown>` | `undefined` | Additional data included with every submission |
|
|
68
|
+
| `theme` | `AnyclickTheme \| null` | `undefined` | Theme configuration (inherits from parent) |
|
|
69
|
+
| `scoped` | `boolean` | `false` | Limit capture to this provider's children only |
|
|
70
|
+
| `disabled` | `boolean` | `false` | Disable anyclick capture |
|
|
71
|
+
| `highlightConfig` | `HighlightConfig` | Default | Element highlighting configuration |
|
|
72
|
+
| `screenshotConfig` | `ScreenshotConfig` | Default | Screenshot capture configuration |
|
|
73
|
+
| `onSubmitSuccess` | `(payload) => void` | `undefined` | Success callback |
|
|
74
|
+
| `onSubmitError` | `(error, payload) => void` | `undefined` | Error callback |
|
|
75
|
+
| `touchHoldDurationMs` | `number` | `500` | Touch hold duration before triggering menu |
|
|
76
|
+
| `touchMoveThreshold` | `number` | `10` | Max movement in px before touch hold cancels |
|
|
77
|
+
|
|
78
|
+
### AnyclickTheme
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
interface AnyclickTheme {
|
|
82
|
+
/** Custom styles for the context menu */
|
|
83
|
+
menuStyle?: CSSProperties;
|
|
84
|
+
/** Custom class name for the context menu */
|
|
85
|
+
menuClassName?: string;
|
|
86
|
+
/** Configuration for element highlighting */
|
|
87
|
+
highlightConfig?: HighlightConfig;
|
|
88
|
+
/** Configuration for screenshot capture */
|
|
89
|
+
screenshotConfig?: ScreenshotConfig;
|
|
90
|
+
/** Disable anyclick in this subtree */
|
|
91
|
+
disabled?: boolean;
|
|
92
|
+
/** Enable fun mode (go-kart cursor) */
|
|
93
|
+
funMode?: boolean | FunModeThemeConfig;
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### ContextMenuItem
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
interface ContextMenuItem {
|
|
101
|
+
/** Unique type identifier */
|
|
102
|
+
type: string;
|
|
103
|
+
/** Display label */
|
|
104
|
+
label: string;
|
|
105
|
+
/** Optional icon */
|
|
106
|
+
icon?: ReactNode;
|
|
107
|
+
/** Show comment input after selection */
|
|
108
|
+
showComment?: boolean;
|
|
109
|
+
/** Status badge (e.g., "comingSoon") */
|
|
110
|
+
status?: "available" | "comingSoon";
|
|
111
|
+
/** Visual badge configuration */
|
|
112
|
+
badge?: { label: string; tone?: "neutral" | "info" | "warning" | "success" };
|
|
113
|
+
/** Required roles to see this item */
|
|
114
|
+
requiredRoles?: string[];
|
|
115
|
+
/** Nested submenu items */
|
|
116
|
+
children?: ContextMenuItem[];
|
|
117
|
+
/** Custom click handler */
|
|
118
|
+
onClick?: (context: {
|
|
119
|
+
targetElement: Element | null;
|
|
120
|
+
containerElement: Element | null;
|
|
121
|
+
closeMenu: () => void;
|
|
122
|
+
}) => void | boolean | Promise<void | boolean>;
|
|
123
|
+
}
|
|
124
|
+
```
|
|
51
125
|
|
|
52
|
-
|
|
126
|
+
### HighlightConfig
|
|
53
127
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
128
|
+
```tsx
|
|
129
|
+
interface HighlightConfig {
|
|
130
|
+
/** Enable/disable highlighting */
|
|
131
|
+
enabled?: boolean;
|
|
132
|
+
/** Custom highlight colors */
|
|
133
|
+
colors?: {
|
|
134
|
+
targetColor?: string; // Default: "#3b82f6"
|
|
135
|
+
containerColor?: string; // Default: "#8b5cf6"
|
|
136
|
+
targetShadowOpacity?: number; // Default: 0.25
|
|
137
|
+
containerShadowOpacity?: number; // Default: 0.1
|
|
138
|
+
};
|
|
139
|
+
/** CSS selectors to identify container elements */
|
|
140
|
+
containerSelectors?: string[];
|
|
141
|
+
/** Minimum children count for auto-container detection */
|
|
142
|
+
minChildrenForContainer?: number;
|
|
143
|
+
}
|
|
144
|
+
```
|
|
64
145
|
|
|
65
|
-
##
|
|
146
|
+
## Examples
|
|
147
|
+
|
|
148
|
+
### Scoped Providers
|
|
66
149
|
|
|
67
150
|
Limit feedback capture to specific sections of your app:
|
|
68
151
|
|
|
@@ -90,7 +173,7 @@ function App() {
|
|
|
90
173
|
}
|
|
91
174
|
```
|
|
92
175
|
|
|
93
|
-
|
|
176
|
+
### Nested Theming
|
|
94
177
|
|
|
95
178
|
Override themes for specific sections:
|
|
96
179
|
|
|
@@ -131,22 +214,10 @@ function App() {
|
|
|
131
214
|
}
|
|
132
215
|
```
|
|
133
216
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
```tsx
|
|
137
|
-
interface AnyclickTheme {
|
|
138
|
-
menuStyle?: CSSProperties;
|
|
139
|
-
menuClassName?: string;
|
|
140
|
-
highlightConfig?: HighlightConfig;
|
|
141
|
-
screenshotConfig?: ScreenshotConfig;
|
|
142
|
-
disabled?: boolean; // Disable anyclick in this subtree
|
|
143
|
-
}
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
## Custom Menu Items
|
|
217
|
+
### Custom Menu Items
|
|
147
218
|
|
|
148
219
|
```tsx
|
|
149
|
-
import { Bug,
|
|
220
|
+
import { Bug, Heart, Lightbulb } from "lucide-react";
|
|
150
221
|
|
|
151
222
|
const menuItems = [
|
|
152
223
|
{
|
|
@@ -174,7 +245,7 @@ const menuItems = [
|
|
|
174
245
|
</AnyclickProvider>;
|
|
175
246
|
```
|
|
176
247
|
|
|
177
|
-
|
|
248
|
+
### Role-Based Filtering
|
|
178
249
|
|
|
179
250
|
```tsx
|
|
180
251
|
import { filterMenuItemsByRole } from "@ewjdev/anyclick-react";
|
|
@@ -188,15 +259,15 @@ const userContext = { roles: ["user", "developer"] };
|
|
|
188
259
|
const menuItems = filterMenuItemsByRole(allMenuItems, userContext);
|
|
189
260
|
```
|
|
190
261
|
|
|
191
|
-
|
|
262
|
+
### Role-Based Presets
|
|
192
263
|
|
|
193
|
-
Skip hand-authoring menus by pulling in a preset for common roles
|
|
264
|
+
Skip hand-authoring menus by pulling in a preset for common roles:
|
|
194
265
|
|
|
195
266
|
```tsx
|
|
196
267
|
import { AnyclickProvider, createPresetMenu } from "@ewjdev/anyclick-react";
|
|
197
268
|
|
|
198
269
|
const qaPreset = createPresetMenu("qa");
|
|
199
|
-
//
|
|
270
|
+
// Available presets: "qa", "pm", "designer", "developer", "chrome"
|
|
200
271
|
|
|
201
272
|
<AnyclickProvider
|
|
202
273
|
adapter={adapter}
|
|
@@ -209,26 +280,56 @@ const qaPreset = createPresetMenu("qa");
|
|
|
209
280
|
</AnyclickProvider>;
|
|
210
281
|
```
|
|
211
282
|
|
|
212
|
-
|
|
283
|
+
**Available Presets:**
|
|
284
|
+
|
|
285
|
+
| Preset | Description |
|
|
286
|
+
| ----------- | ----------------------------------------------------------------- |
|
|
287
|
+
| `qa` | Bug/defect, UX papercut, repro steps, + performance trace (soon) |
|
|
288
|
+
| `pm` | Feature idea, UX papercut, customer quote, + impact sizing (soon) |
|
|
289
|
+
| `designer` | Visual bug, accessibility, copy/tone, + motion glitch (soon) |
|
|
290
|
+
| `developer` | Bug, refactor request, + diagnostics submenu |
|
|
291
|
+
| `chrome` | Chrome-like menu with reload, print, search, share, inspect |
|
|
213
292
|
|
|
214
|
-
|
|
215
|
-
- PM: feature idea / UX papercut + “Impact sizing” (coming soon)
|
|
216
|
-
- Designer: visual bug / accessibility + “Motion glitch” (coming soon)
|
|
217
|
-
- Developer: bug / refactor + diagnostics submenu (console/network traces marked coming soon)
|
|
293
|
+
### useAnyclick Hook
|
|
218
294
|
|
|
219
|
-
|
|
295
|
+
Access anyclick context from child components:
|
|
296
|
+
|
|
297
|
+
```tsx
|
|
298
|
+
import { useAnyclick } from "@ewjdev/anyclick-react";
|
|
299
|
+
|
|
300
|
+
function MyComponent() {
|
|
301
|
+
const {
|
|
302
|
+
isEnabled, // Whether anyclick is active
|
|
303
|
+
isSubmitting, // Whether a submission is in progress
|
|
304
|
+
openMenu, // Open menu programmatically
|
|
305
|
+
closeMenu, // Close menu
|
|
306
|
+
theme, // Current merged theme
|
|
307
|
+
scoped, // Whether provider is scoped
|
|
308
|
+
providerId, // Unique provider ID
|
|
309
|
+
} = useAnyclick();
|
|
310
|
+
|
|
311
|
+
const handleClick = (event) => {
|
|
312
|
+
openMenu(event.currentTarget, { x: event.clientX, y: event.clientY });
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
return <button onClick={handleClick}>Open Feedback</button>;
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Custom Styling with CSS Variables
|
|
320
|
+
|
|
321
|
+
Override menu styling using CSS custom properties:
|
|
220
322
|
|
|
221
323
|
```tsx
|
|
222
324
|
<AnyclickProvider
|
|
223
325
|
adapter={adapter}
|
|
224
326
|
theme={{
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
containerSelectors: ["[data-component]", ".card"],
|
|
327
|
+
menuStyle: {
|
|
328
|
+
"--anyclick-menu-bg": "rgba(0, 0, 0, 0.9)",
|
|
329
|
+
"--anyclick-menu-text": "#ffffff",
|
|
330
|
+
"--anyclick-menu-border": "rgba(255, 255, 255, 0.1)",
|
|
331
|
+
"--anyclick-menu-hover": "rgba(255, 255, 255, 0.1)",
|
|
332
|
+
"--anyclick-menu-accent": "#f59e0b",
|
|
232
333
|
},
|
|
233
334
|
}}
|
|
234
335
|
>
|
|
@@ -236,25 +337,31 @@ Preset defaults (examples):
|
|
|
236
337
|
</AnyclickProvider>
|
|
237
338
|
```
|
|
238
339
|
|
|
239
|
-
|
|
340
|
+
**Available CSS Variables:**
|
|
240
341
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
342
|
+
| Variable | Default | Description |
|
|
343
|
+
| ------------------------------ | --------- | ------------------------ |
|
|
344
|
+
| `--anyclick-menu-bg` | `#ffffff` | Menu background color |
|
|
345
|
+
| `--anyclick-menu-hover` | `#f5f5f5` | Item hover background |
|
|
346
|
+
| `--anyclick-menu-text` | `#333333` | Primary text color |
|
|
347
|
+
| `--anyclick-menu-text-muted` | `#666666` | Muted text color |
|
|
348
|
+
| `--anyclick-menu-border` | `#e5e5e5` | Border color |
|
|
349
|
+
| `--anyclick-menu-accent` | `#0066cc` | Accent/action color |
|
|
350
|
+
| `--anyclick-menu-accent-text` | `#ffffff` | Accent text color |
|
|
351
|
+
| `--anyclick-menu-input-bg` | `#ffffff` | Input background |
|
|
352
|
+
| `--anyclick-menu-input-border` | `#dddddd` | Input border color |
|
|
353
|
+
| `--anyclick-menu-cancel-bg` | `#f0f0f0` | Cancel button background |
|
|
354
|
+
| `--anyclick-menu-cancel-text` | `#666666` | Cancel button text |
|
|
245
355
|
|
|
246
|
-
|
|
247
|
-
const { isSubmitting, openMenu, closeMenu, theme, scoped, providerId } =
|
|
248
|
-
useAnyclick();
|
|
356
|
+
## Performance Considerations
|
|
249
357
|
|
|
250
|
-
|
|
251
|
-
const handleClick = (event) => {
|
|
252
|
-
openMenu(event.currentTarget, { x: event.clientX, y: event.clientY });
|
|
253
|
-
};
|
|
358
|
+
The package is optimized for performance:
|
|
254
359
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
360
|
+
- Components use `React.memo` to prevent unnecessary re-renders
|
|
361
|
+
- Expensive computations are wrapped in `useMemo`
|
|
362
|
+
- Event handlers use `useCallback` for stable references
|
|
363
|
+
- Screenshot capture is lazy-loaded and async
|
|
364
|
+
- Touch event handling uses passive listeners where possible
|
|
258
365
|
|
|
259
366
|
## Migration from FeedbackProvider
|
|
260
367
|
|
|
@@ -263,11 +370,39 @@ The `FeedbackProvider` component has been renamed to `AnyclickProvider`. The old
|
|
|
263
370
|
```tsx
|
|
264
371
|
// Old (deprecated)
|
|
265
372
|
import { FeedbackProvider, useFeedback } from "@ewjdev/anyclick-react";
|
|
266
|
-
|
|
267
373
|
// New (recommended)
|
|
268
374
|
import { AnyclickProvider, useAnyclick } from "@ewjdev/anyclick-react";
|
|
269
375
|
```
|
|
270
376
|
|
|
377
|
+
## Exported Utilities
|
|
378
|
+
|
|
379
|
+
```tsx
|
|
380
|
+
// Components
|
|
381
|
+
export { AnyclickProvider, ContextMenu, ScreenshotPreview, InspectDialog };
|
|
382
|
+
|
|
383
|
+
// Hooks
|
|
384
|
+
export { useAnyclick, useProviderStore, useInspectStore };
|
|
385
|
+
|
|
386
|
+
// Presets
|
|
387
|
+
export { createPresetMenu, listPresets, presetDefaults };
|
|
388
|
+
|
|
389
|
+
// Utilities
|
|
390
|
+
export { filterMenuItemsByRole, getBadgeStyle };
|
|
391
|
+
export {
|
|
392
|
+
findContainerParent,
|
|
393
|
+
highlightTarget,
|
|
394
|
+
highlightContainer,
|
|
395
|
+
clearHighlights,
|
|
396
|
+
applyHighlights,
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
// Styles
|
|
400
|
+
export { menuStyles, darkMenuStyles, menuCSSVariables };
|
|
401
|
+
|
|
402
|
+
// IDE Integration
|
|
403
|
+
export { openInIDE, buildIDEUrl, detectPreferredIDE };
|
|
404
|
+
```
|
|
405
|
+
|
|
271
406
|
## Documentation
|
|
272
407
|
|
|
273
408
|
For full documentation, visit [anyclick.ewj.dev/docs/react](https://anyclick.ewj.dev/docs/react)
|
|
@@ -277,6 +412,7 @@ For full documentation, visit [anyclick.ewj.dev/docs/react](https://anyclick.ewj
|
|
|
277
412
|
- [`@ewjdev/anyclick-core`](https://www.npmjs.com/package/@ewjdev/anyclick-core) - Core library
|
|
278
413
|
- [`@ewjdev/anyclick-github`](https://www.npmjs.com/package/@ewjdev/anyclick-github) - GitHub Issues integration
|
|
279
414
|
- [`@ewjdev/anyclick-cursor`](https://www.npmjs.com/package/@ewjdev/anyclick-cursor) - Cursor AI integration
|
|
415
|
+
- [`@ewjdev/anyclick-pointer`](https://www.npmjs.com/package/@ewjdev/anyclick-pointer) - Custom pointer effects
|
|
280
416
|
|
|
281
417
|
## License
|
|
282
418
|
|