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