@ewjdev/anyclick-react 1.3.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 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 page
51
+ - 📸 **Screenshot Capture** - Automatic screenshots of target, container, and viewport
47
52
  - 🔒 **Role-Based Menu Items** - Show different options based on user roles
48
- - 📱 **Submenus** - Organize menu items with nested submenus
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
- ## Props
126
+ ### HighlightConfig
53
127
 
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 |
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
- ## Scoped Providers
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
- ## Nested Theming
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
- ## Theme Configuration
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, Lightbulb, Heart } from "lucide-react";
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
- ## Role-Based Filtering
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
- ## Role-Based Presets
262
+ ### Role-Based Presets
192
263
 
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.
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
- // Or: listPresets() to show available roles, createPresetMenu("developer", { includeComingSoon: false })
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
- Preset defaults (examples):
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
- - 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)
293
+ ### useAnyclick Hook
218
294
 
219
- ## Highlight Configuration
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
- highlightConfig: {
226
- enabled: true,
227
- colors: {
228
- targetColor: "#3b82f6",
229
- containerColor: "#8b5cf6",
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
- ## useAnyclick Hook
340
+ **Available CSS Variables:**
240
341
 
241
- Access anyclick context from child components:
242
-
243
- ```tsx
244
- import { useAnyclick } from "@ewjdev/anyclick-react";
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
- function MyComponent() {
247
- const { isSubmitting, openMenu, closeMenu, theme, scoped, providerId } =
248
- useAnyclick();
356
+ ## Performance Considerations
249
357
 
250
- // Open menu programmatically
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
- return <button onClick={handleClick}>Open Feedback</button>;
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