@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 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 page
74
+ - 📸 **Screenshot Capture** - Automatic screenshots of target, container, and viewport
47
75
  - 🔒 **Role-Based Menu Items** - Show different options based on user roles
48
- - 📱 **Submenus** - Organize menu items with nested submenus
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
- ## Props
120
+ ### ContextMenuItem
53
121
 
54
- | Prop | Type | Description |
55
- | ----------------- | -------------------------- | ---------------------------------------------- |
56
- | `adapter` | `AnyclickAdapter` | Required. The adapter for submitting anyclick |
57
- | `menuItems` | `ContextMenuItem[]` | Custom menu items |
58
- | `metadata` | `Record<string, unknown>` | Additional data included with every submission |
59
- | `theme` | `AnyclickTheme \| null` | Theme configuration (inherits from parent) |
60
- | `scoped` | `boolean` | Limit capture to this provider's children only |
61
- | `disabled` | `boolean` | Disable anyclick capture |
62
- | `onSubmitSuccess` | `(payload) => void` | Success callback |
63
- | `onSubmitError` | `(error, payload) => void` | Error callback |
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
- ## Scoped Providers
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
- ## Nested Theming
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
- ## Theme Configuration
240
+ ### Custom Menu Items
135
241
 
136
242
  ```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
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
- ## Role-Based Filtering
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
- ## Role-Based Presets
285
+ ### Role-Based Presets
192
286
 
193
- Skip hand-authoring menus by pulling in a preset for common roles. Coming-soon actions stay visible with a badge but are disabled by default.
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
- // Or: listPresets() to show available roles, createPresetMenu("developer", { includeComingSoon: false })
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
- Preset defaults (examples):
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
- - QA: bug / repro / UX papercut + “Performance trace” (coming soon)
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
- ## Highlight Configuration
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
- highlightConfig: {
226
- enabled: true,
227
- colors: {
228
- targetColor: "#3b82f6",
229
- containerColor: "#8b5cf6",
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
- ## useAnyclick Hook
363
+ **Available CSS Variables:**
240
364
 
241
- Access anyclick context from child components:
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
- ```tsx
244
- import { useAnyclick } from "@ewjdev/anyclick-react";
379
+ ## Performance Considerations
245
380
 
246
- function MyComponent() {
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
- return <button onClick={handleClick}>Open Feedback</button>;
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