@ewjdev/anyclick-react 0.1.0 → 1.1.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 +143 -49
- package/dist/index.d.mts +197 -15
- package/dist/index.d.ts +197 -15
- package/dist/index.js +1122 -320
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1115 -319
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -23,21 +23,17 @@ npm install @ewjdev/anyclick-react
|
|
|
23
23
|
## Quick Start
|
|
24
24
|
|
|
25
25
|
```tsx
|
|
26
|
-
|
|
26
|
+
"use client";
|
|
27
27
|
|
|
28
|
-
import {
|
|
29
|
-
import { createHttpAdapter } from
|
|
28
|
+
import { AnyclickProvider } from "@ewjdev/anyclick-react";
|
|
29
|
+
import { createHttpAdapter } from "@ewjdev/anyclick-github";
|
|
30
30
|
|
|
31
31
|
const adapter = createHttpAdapter({
|
|
32
|
-
endpoint:
|
|
32
|
+
endpoint: "/api/feedback",
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
export function Providers({ children }: { children: React.ReactNode }) {
|
|
36
|
-
return
|
|
37
|
-
<FeedbackProvider adapter={adapter}>
|
|
38
|
-
{children}
|
|
39
|
-
</FeedbackProvider>
|
|
40
|
-
);
|
|
36
|
+
return <AnyclickProvider adapter={adapter}>{children}</AnyclickProvider>;
|
|
41
37
|
}
|
|
42
38
|
```
|
|
43
39
|
|
|
@@ -50,102 +46,200 @@ That's it! Users can now right-click any element to submit feedback.
|
|
|
50
46
|
- 📸 **Screenshot Capture** - Automatic screenshots of target, container, and page
|
|
51
47
|
- 🔒 **Role-Based Menu Items** - Show different options based on user roles
|
|
52
48
|
- 📱 **Submenus** - Organize menu items with nested submenus
|
|
49
|
+
- 🎯 **Scoped Providers** - Limit feedback capture to specific components
|
|
50
|
+
- 🎨 **Nested Theming** - Override themes for specific sections of your app
|
|
53
51
|
|
|
54
52
|
## Props
|
|
55
53
|
|
|
56
|
-
| Prop
|
|
57
|
-
|
|
58
|
-
| `adapter`
|
|
59
|
-
| `menuItems`
|
|
60
|
-
| `metadata`
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
| `disabled`
|
|
64
|
-
| `onSubmitSuccess` | `(payload) => void`
|
|
65
|
-
| `onSubmitError`
|
|
54
|
+
| Prop | Type | Description |
|
|
55
|
+
| ----------------- | -------------------------- | ---------------------------------------------- |
|
|
56
|
+
| `adapter` | `FeedbackAdapter` | Required. The adapter for submitting feedback |
|
|
57
|
+
| `menuItems` | `FeedbackMenuItem[]` | 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 feedback capture |
|
|
62
|
+
| `onSubmitSuccess` | `(payload) => void` | Success callback |
|
|
63
|
+
| `onSubmitError` | `(error, payload) => void` | Error callback |
|
|
64
|
+
|
|
65
|
+
## Scoped Providers
|
|
66
|
+
|
|
67
|
+
Limit feedback capture to specific sections of your app:
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
import { AnyclickProvider } from "@ewjdev/anyclick-react";
|
|
71
|
+
|
|
72
|
+
function App() {
|
|
73
|
+
return (
|
|
74
|
+
<AnyclickProvider adapter={globalAdapter}>
|
|
75
|
+
{/* Global feedback works everywhere */}
|
|
76
|
+
<Header />
|
|
77
|
+
|
|
78
|
+
{/* Scoped provider - separate configuration */}
|
|
79
|
+
<AnyclickProvider
|
|
80
|
+
adapter={dashboardAdapter}
|
|
81
|
+
scoped
|
|
82
|
+
menuItems={dashboardMenuItems}
|
|
83
|
+
>
|
|
84
|
+
<Dashboard />
|
|
85
|
+
</AnyclickProvider>
|
|
86
|
+
|
|
87
|
+
<Footer />
|
|
88
|
+
</AnyclickProvider>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Nested Theming
|
|
94
|
+
|
|
95
|
+
Override themes for specific sections:
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import { AnyclickProvider } from "@ewjdev/anyclick-react";
|
|
99
|
+
|
|
100
|
+
function App() {
|
|
101
|
+
return (
|
|
102
|
+
<AnyclickProvider
|
|
103
|
+
adapter={adapter}
|
|
104
|
+
theme={{
|
|
105
|
+
highlightConfig: {
|
|
106
|
+
colors: { targetColor: "#3b82f6" },
|
|
107
|
+
},
|
|
108
|
+
}}
|
|
109
|
+
>
|
|
110
|
+
{/* Uses blue highlights */}
|
|
111
|
+
<MainContent />
|
|
112
|
+
|
|
113
|
+
{/* Uses red highlights (overrides parent) */}
|
|
114
|
+
<AnyclickProvider
|
|
115
|
+
scoped
|
|
116
|
+
theme={{
|
|
117
|
+
highlightConfig: {
|
|
118
|
+
colors: { targetColor: "#ef4444" },
|
|
119
|
+
},
|
|
120
|
+
}}
|
|
121
|
+
>
|
|
122
|
+
<WarningSection />
|
|
123
|
+
</AnyclickProvider>
|
|
124
|
+
|
|
125
|
+
{/* Disable anyclick for this section */}
|
|
126
|
+
<AnyclickProvider scoped theme={{ disabled: true }}>
|
|
127
|
+
<SensitiveArea />
|
|
128
|
+
</AnyclickProvider>
|
|
129
|
+
</AnyclickProvider>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
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
|
+
```
|
|
66
145
|
|
|
67
146
|
## Custom Menu Items
|
|
68
147
|
|
|
69
148
|
```tsx
|
|
70
|
-
import { Bug, Lightbulb, Heart } from
|
|
149
|
+
import { Bug, Lightbulb, Heart } from "lucide-react";
|
|
71
150
|
|
|
72
151
|
const menuItems = [
|
|
73
|
-
{
|
|
74
|
-
type:
|
|
75
|
-
label:
|
|
152
|
+
{
|
|
153
|
+
type: "bug",
|
|
154
|
+
label: "Report Bug",
|
|
76
155
|
icon: <Bug className="w-4 h-4" />,
|
|
77
156
|
showComment: true,
|
|
78
157
|
},
|
|
79
|
-
{
|
|
80
|
-
type:
|
|
81
|
-
label:
|
|
158
|
+
{
|
|
159
|
+
type: "feature",
|
|
160
|
+
label: "Suggest Feature",
|
|
82
161
|
icon: <Lightbulb className="w-4 h-4" />,
|
|
83
162
|
showComment: true,
|
|
84
163
|
},
|
|
85
|
-
{
|
|
86
|
-
type:
|
|
87
|
-
label:
|
|
164
|
+
{
|
|
165
|
+
type: "love",
|
|
166
|
+
label: "Love It!",
|
|
88
167
|
icon: <Heart className="w-4 h-4" />,
|
|
89
168
|
showComment: false,
|
|
90
169
|
},
|
|
91
170
|
];
|
|
92
171
|
|
|
93
|
-
<
|
|
172
|
+
<AnyclickProvider adapter={adapter} menuItems={menuItems}>
|
|
94
173
|
{children}
|
|
95
|
-
</
|
|
174
|
+
</AnyclickProvider>;
|
|
96
175
|
```
|
|
97
176
|
|
|
98
177
|
## Role-Based Filtering
|
|
99
178
|
|
|
100
179
|
```tsx
|
|
101
|
-
import { filterMenuItemsByRole } from
|
|
180
|
+
import { filterMenuItemsByRole } from "@ewjdev/anyclick-react";
|
|
102
181
|
|
|
103
182
|
const allMenuItems = [
|
|
104
|
-
{ type:
|
|
105
|
-
{ type:
|
|
183
|
+
{ type: "bug", label: "Report Bug" },
|
|
184
|
+
{ type: "debug", label: "Debug Info", requiredRoles: ["developer"] },
|
|
106
185
|
];
|
|
107
186
|
|
|
108
|
-
const userContext = { roles: [
|
|
187
|
+
const userContext = { roles: ["user", "developer"] };
|
|
109
188
|
const menuItems = filterMenuItemsByRole(allMenuItems, userContext);
|
|
110
189
|
```
|
|
111
190
|
|
|
112
191
|
## Highlight Configuration
|
|
113
192
|
|
|
114
193
|
```tsx
|
|
115
|
-
<
|
|
194
|
+
<AnyclickProvider
|
|
116
195
|
adapter={adapter}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
196
|
+
theme={{
|
|
197
|
+
highlightConfig: {
|
|
198
|
+
enabled: true,
|
|
199
|
+
colors: {
|
|
200
|
+
targetColor: "#3b82f6",
|
|
201
|
+
containerColor: "#8b5cf6",
|
|
202
|
+
},
|
|
203
|
+
containerSelectors: ["[data-component]", ".card"],
|
|
122
204
|
},
|
|
123
|
-
containerSelectors: ['[data-component]', '.card'],
|
|
124
205
|
}}
|
|
125
206
|
>
|
|
126
207
|
{children}
|
|
127
|
-
</
|
|
208
|
+
</AnyclickProvider>
|
|
128
209
|
```
|
|
129
210
|
|
|
130
|
-
##
|
|
211
|
+
## useAnyclick Hook
|
|
131
212
|
|
|
132
|
-
Access
|
|
213
|
+
Access anyclick context from child components:
|
|
133
214
|
|
|
134
215
|
```tsx
|
|
135
|
-
import {
|
|
216
|
+
import { useAnyclick } from "@ewjdev/anyclick-react";
|
|
136
217
|
|
|
137
218
|
function MyComponent() {
|
|
138
|
-
const { isSubmitting, openMenu, closeMenu } =
|
|
139
|
-
|
|
219
|
+
const { isSubmitting, openMenu, closeMenu, theme, scoped, providerId } =
|
|
220
|
+
useAnyclick();
|
|
221
|
+
|
|
140
222
|
// Open menu programmatically
|
|
141
223
|
const handleClick = (event) => {
|
|
142
224
|
openMenu(event.currentTarget, { x: event.clientX, y: event.clientY });
|
|
143
225
|
};
|
|
144
|
-
|
|
226
|
+
|
|
145
227
|
return <button onClick={handleClick}>Open Feedback</button>;
|
|
146
228
|
}
|
|
147
229
|
```
|
|
148
230
|
|
|
231
|
+
## Migration from FeedbackProvider
|
|
232
|
+
|
|
233
|
+
The `FeedbackProvider` component has been renamed to `AnyclickProvider`. The old name is still exported for backward compatibility but is deprecated:
|
|
234
|
+
|
|
235
|
+
```tsx
|
|
236
|
+
// Old (deprecated)
|
|
237
|
+
import { FeedbackProvider, useFeedback } from "@ewjdev/anyclick-react";
|
|
238
|
+
|
|
239
|
+
// New (recommended)
|
|
240
|
+
import { AnyclickProvider, useAnyclick } from "@ewjdev/anyclick-react";
|
|
241
|
+
```
|
|
242
|
+
|
|
149
243
|
## Documentation
|
|
150
244
|
|
|
151
245
|
For full documentation, visit [anyclick.ewj.dev/docs/react](https://anyclick.ewj.dev/docs/react)
|
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,33 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { FeedbackAdapter, FeedbackType, FeedbackPayload, ScreenshotConfig, ScreenshotData } from '@ewjdev/anyclick-core';
|
|
2
|
+
import { FeedbackAdapter, FeedbackTriggerEvent, FeedbackType, FeedbackPayload, ScreenshotConfig, ScreenshotData, FeedbackMenuEvent } from '@ewjdev/anyclick-core';
|
|
3
3
|
export { DEFAULT_SCREENSHOT_CONFIG, DEFAULT_SENSITIVE_SELECTORS, ElementContext, FeedbackAdapter, FeedbackPayload, FeedbackType, PageContext, ScreenshotCapture, ScreenshotCaptureMode, ScreenshotConfig, ScreenshotData, captureAllScreenshots, captureScreenshot, estimateTotalSize, formatBytes, isScreenshotSupported } from '@ewjdev/anyclick-core';
|
|
4
4
|
import * as react from 'react';
|
|
5
5
|
import { ReactNode, CSSProperties } from 'react';
|
|
6
|
+
import * as zustand from 'zustand';
|
|
6
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Theme configuration for AnyclickProvider
|
|
10
|
+
* Supports nested theming with inheritance
|
|
11
|
+
*/
|
|
12
|
+
interface AnyclickTheme {
|
|
13
|
+
/** Custom styles for the context menu */
|
|
14
|
+
menuStyle?: CSSProperties;
|
|
15
|
+
/** Custom class name for the context menu */
|
|
16
|
+
menuClassName?: string;
|
|
17
|
+
/** Configuration for element highlighting */
|
|
18
|
+
highlightConfig?: HighlightConfig;
|
|
19
|
+
/** Configuration for screenshot capture */
|
|
20
|
+
screenshotConfig?: ScreenshotConfig;
|
|
21
|
+
/** Whether anyclick functionality is disabled in this theme */
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Menu positioning modes
|
|
26
|
+
* - static: Menu stays at exact click position (may go off-screen)
|
|
27
|
+
* - inView: Menu adjusts position to stay fully visible in viewport
|
|
28
|
+
* - dynamic: User can drag the menu to reposition it
|
|
29
|
+
*/
|
|
30
|
+
type MenuPositionMode = "static" | "inView" | "dynamic";
|
|
7
31
|
/**
|
|
8
32
|
* Configuration for highlight colors
|
|
9
33
|
*/
|
|
@@ -63,9 +87,9 @@ interface FeedbackUserContext {
|
|
|
63
87
|
*/
|
|
64
88
|
declare function filterMenuItemsByRole(items: FeedbackMenuItem[], userContext?: FeedbackUserContext): FeedbackMenuItem[];
|
|
65
89
|
/**
|
|
66
|
-
* Props for the
|
|
90
|
+
* Props for the AnyclickProvider component
|
|
67
91
|
*/
|
|
68
|
-
interface
|
|
92
|
+
interface AnyclickProviderProps {
|
|
69
93
|
/** The adapter to use for submitting feedback */
|
|
70
94
|
adapter: FeedbackAdapter;
|
|
71
95
|
/** Child components */
|
|
@@ -73,8 +97,9 @@ interface FeedbackProviderProps {
|
|
|
73
97
|
/**
|
|
74
98
|
* Filter function to determine if feedback should be captured for a target element
|
|
75
99
|
* Return true to allow feedback, false to ignore
|
|
100
|
+
* Accepts both MouseEvent (right-click) and TouchEvent (press-and-hold)
|
|
76
101
|
*/
|
|
77
|
-
targetFilter?: (event:
|
|
102
|
+
targetFilter?: (event: FeedbackTriggerEvent, target: Element) => boolean;
|
|
78
103
|
/** Custom menu items (defaults to Issue, Feature, Like) */
|
|
79
104
|
menuItems?: FeedbackMenuItem[];
|
|
80
105
|
/** Maximum length for innerText capture */
|
|
@@ -103,11 +128,33 @@ interface FeedbackProviderProps {
|
|
|
103
128
|
highlightConfig?: HighlightConfig;
|
|
104
129
|
/** Configuration for screenshot capture */
|
|
105
130
|
screenshotConfig?: ScreenshotConfig;
|
|
131
|
+
/**
|
|
132
|
+
* Whether to scope this provider to its children only.
|
|
133
|
+
* When true, events will only be captured for elements within this provider's subtree.
|
|
134
|
+
* When false (default), events are captured for the entire document.
|
|
135
|
+
*/
|
|
136
|
+
scoped?: boolean;
|
|
137
|
+
/**
|
|
138
|
+
* Theme configuration for this provider.
|
|
139
|
+
* Themes are inherited from parent providers and merged (child overrides parent).
|
|
140
|
+
* Set to null or { disabled: true } to disable anyclick in this subtree.
|
|
141
|
+
*/
|
|
142
|
+
theme?: AnyclickTheme | null;
|
|
143
|
+
/** Duration in ms to hold touch before triggering context menu (default: 500) */
|
|
144
|
+
touchHoldDurationMs?: number;
|
|
145
|
+
/** Maximum movement in px before touch hold is cancelled (default: 10) */
|
|
146
|
+
touchMoveThreshold?: number;
|
|
147
|
+
/** Menu positioning mode (default: 'inView') */
|
|
148
|
+
menuPositionMode?: MenuPositionMode;
|
|
106
149
|
}
|
|
107
150
|
/**
|
|
108
|
-
*
|
|
151
|
+
* @deprecated Use AnyclickProviderProps instead
|
|
152
|
+
*/
|
|
153
|
+
type FeedbackProviderProps = AnyclickProviderProps;
|
|
154
|
+
/**
|
|
155
|
+
* Context value exposed by AnyclickProvider
|
|
109
156
|
*/
|
|
110
|
-
interface
|
|
157
|
+
interface AnyclickContextValue {
|
|
111
158
|
/** Whether feedback is currently enabled */
|
|
112
159
|
isEnabled: boolean;
|
|
113
160
|
/** Whether a submission is in progress */
|
|
@@ -121,7 +168,17 @@ interface FeedbackContextValue {
|
|
|
121
168
|
}) => void;
|
|
122
169
|
/** Close the feedback menu */
|
|
123
170
|
closeMenu: () => void;
|
|
171
|
+
/** The current merged theme (inherited from ancestors) */
|
|
172
|
+
theme: AnyclickTheme;
|
|
173
|
+
/** Whether this provider is scoped */
|
|
174
|
+
scoped: boolean;
|
|
175
|
+
/** The provider's unique ID */
|
|
176
|
+
providerId: string;
|
|
124
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* @deprecated Use AnyclickContextValue instead
|
|
180
|
+
*/
|
|
181
|
+
type FeedbackContextValue = AnyclickContextValue;
|
|
125
182
|
/**
|
|
126
183
|
* Props for the context menu component
|
|
127
184
|
*/
|
|
@@ -153,6 +210,8 @@ interface ContextMenuProps {
|
|
|
153
210
|
highlightConfig?: HighlightConfig;
|
|
154
211
|
/** Configuration for screenshot capture */
|
|
155
212
|
screenshotConfig?: ScreenshotConfig;
|
|
213
|
+
/** Menu positioning mode (default: 'inView') */
|
|
214
|
+
positionMode?: MenuPositionMode;
|
|
156
215
|
}
|
|
157
216
|
/**
|
|
158
217
|
* Props for the screenshot preview component
|
|
@@ -173,14 +232,19 @@ interface ScreenshotPreviewProps {
|
|
|
173
232
|
}
|
|
174
233
|
|
|
175
234
|
/**
|
|
176
|
-
*
|
|
235
|
+
* AnyclickProvider component - wraps your app to enable feedback capture
|
|
236
|
+
* Supports scoped providers and nested theming
|
|
177
237
|
*/
|
|
178
|
-
declare function
|
|
238
|
+
declare function AnyclickProvider({ adapter, children, targetFilter, menuItems, maxInnerTextLength, maxOuterHTMLLength, maxAncestors, cooldownMs, stripAttributes, metadata, onSubmitSuccess, onSubmitError, menuStyle, menuClassName, disabled, highlightConfig, screenshotConfig, scoped, theme, touchHoldDurationMs, touchMoveThreshold, }: AnyclickProviderProps): react_jsx_runtime.JSX.Element;
|
|
239
|
+
/**
|
|
240
|
+
* @deprecated Use AnyclickProvider instead
|
|
241
|
+
*/
|
|
242
|
+
declare const FeedbackProvider: typeof AnyclickProvider;
|
|
179
243
|
|
|
180
244
|
/**
|
|
181
245
|
* Context menu component for selecting feedback type
|
|
182
246
|
*/
|
|
183
|
-
declare function ContextMenu({ visible, position, targetElement, containerElement, items, onSelect, onClose, isSubmitting, style, className, highlightConfig, screenshotConfig, }: ContextMenuProps): react_jsx_runtime.JSX.Element | null;
|
|
247
|
+
declare function ContextMenu({ visible, position, targetElement, containerElement, items, onSelect, onClose, isSubmitting, style, className, highlightConfig, screenshotConfig, positionMode, }: ContextMenuProps): react_jsx_runtime.JSX.Element | null;
|
|
184
248
|
|
|
185
249
|
/**
|
|
186
250
|
* Screenshot preview component - shows captured screenshots before sending
|
|
@@ -188,15 +252,133 @@ declare function ContextMenu({ visible, position, targetElement, containerElemen
|
|
|
188
252
|
declare function ScreenshotPreview({ screenshots, isLoading, onConfirm, onCancel, onRetake, isSubmitting, }: ScreenshotPreviewProps): react_jsx_runtime.JSX.Element;
|
|
189
253
|
|
|
190
254
|
/**
|
|
191
|
-
* React context for
|
|
255
|
+
* React context for anyclick functionality
|
|
256
|
+
*/
|
|
257
|
+
declare const AnyclickContext: react.Context<AnyclickContextValue | null>;
|
|
258
|
+
/**
|
|
259
|
+
* @deprecated Use AnyclickContext instead
|
|
260
|
+
*/
|
|
261
|
+
declare const FeedbackContext: react.Context<AnyclickContextValue | null>;
|
|
262
|
+
/**
|
|
263
|
+
* Hook to access anyclick context
|
|
264
|
+
* @throws Error if used outside of AnyclickProvider
|
|
265
|
+
*/
|
|
266
|
+
declare function useAnyclick(): AnyclickContextValue;
|
|
267
|
+
/**
|
|
268
|
+
* @deprecated Use useAnyclick instead
|
|
269
|
+
*/
|
|
270
|
+
declare function useFeedback(): AnyclickContextValue;
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Registered provider instance
|
|
274
|
+
*/
|
|
275
|
+
interface ProviderInstance {
|
|
276
|
+
/** Unique identifier for this provider instance */
|
|
277
|
+
id: string;
|
|
278
|
+
/** Reference to the provider's container element (null if not scoped) */
|
|
279
|
+
containerRef: React.RefObject<Element | null>;
|
|
280
|
+
/** Whether this provider is scoped to its container */
|
|
281
|
+
scoped: boolean;
|
|
282
|
+
/** The provider's theme configuration */
|
|
283
|
+
theme: AnyclickTheme | null;
|
|
284
|
+
/** Whether this provider is disabled */
|
|
285
|
+
disabled: boolean;
|
|
286
|
+
/** Parent provider ID (if nested) */
|
|
287
|
+
parentId: string | null;
|
|
288
|
+
/** Depth in the provider hierarchy (0 = root) */
|
|
289
|
+
depth: number;
|
|
290
|
+
/** Handler to call when an event occurs in this provider's scope */
|
|
291
|
+
onContextMenu?: (event: FeedbackMenuEvent, element: Element) => boolean | void;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Provider registry store state
|
|
295
|
+
*/
|
|
296
|
+
interface ProviderStore {
|
|
297
|
+
/** Map of provider ID to provider instance */
|
|
298
|
+
providers: Map<string, ProviderInstance>;
|
|
299
|
+
/**
|
|
300
|
+
* Register a new provider
|
|
301
|
+
*/
|
|
302
|
+
registerProvider: (provider: ProviderInstance) => void;
|
|
303
|
+
/**
|
|
304
|
+
* Unregister a provider
|
|
305
|
+
*/
|
|
306
|
+
unregisterProvider: (id: string) => void;
|
|
307
|
+
/**
|
|
308
|
+
* Update a provider's configuration
|
|
309
|
+
*/
|
|
310
|
+
updateProvider: (id: string, updates: Partial<ProviderInstance>) => void;
|
|
311
|
+
/**
|
|
312
|
+
* Find all providers that contain a given element, sorted by depth (nearest first)
|
|
313
|
+
*/
|
|
314
|
+
findProvidersForElement: (element: Element) => ProviderInstance[];
|
|
315
|
+
/**
|
|
316
|
+
* Find the nearest parent provider for a given container
|
|
317
|
+
*/
|
|
318
|
+
findParentProvider: (container: Element | null, excludeId?: string) => ProviderInstance | null;
|
|
319
|
+
/**
|
|
320
|
+
* Get merged theme for a provider (includes inherited parent themes)
|
|
321
|
+
*/
|
|
322
|
+
getMergedTheme: (providerId: string) => AnyclickTheme;
|
|
323
|
+
/**
|
|
324
|
+
* Check if any ancestor provider has disabled anyclick
|
|
325
|
+
*/
|
|
326
|
+
isDisabledByAncestor: (providerId: string) => boolean;
|
|
327
|
+
/**
|
|
328
|
+
* Check if an element is inside a disabled scoped provider's container
|
|
329
|
+
* This is used to prevent the global provider from handling events
|
|
330
|
+
* in areas where a disabled scoped provider should block them
|
|
331
|
+
*/
|
|
332
|
+
isElementInDisabledScope: (element: Element) => boolean;
|
|
333
|
+
/**
|
|
334
|
+
* Check if an element is inside any scoped provider's container (enabled or not)
|
|
335
|
+
* This is used to prevent the global provider from handling touch events
|
|
336
|
+
* that should be handled by a scoped provider instead
|
|
337
|
+
*/
|
|
338
|
+
isElementInAnyScopedProvider: (element: Element) => boolean;
|
|
339
|
+
}
|
|
340
|
+
declare function generateProviderId(): string;
|
|
341
|
+
/**
|
|
342
|
+
* Zustand store for managing provider instances
|
|
192
343
|
*/
|
|
193
|
-
declare const
|
|
344
|
+
declare const useProviderStore: zustand.UseBoundStore<zustand.StoreApi<ProviderStore>>;
|
|
194
345
|
/**
|
|
195
|
-
*
|
|
196
|
-
* @throws Error if used outside of FeedbackProvider
|
|
346
|
+
* Dispatch a context menu event to all matching providers (bubble up)
|
|
197
347
|
*/
|
|
198
|
-
declare function
|
|
348
|
+
declare function dispatchContextMenuEvent(event: MouseEvent, element: Element): void;
|
|
199
349
|
|
|
350
|
+
/**
|
|
351
|
+
* CSS custom properties for menu theming.
|
|
352
|
+
* These can be overridden via the `style` prop on AnyclickProvider.
|
|
353
|
+
*
|
|
354
|
+
* Example:
|
|
355
|
+
* ```tsx
|
|
356
|
+
* <AnyclickProvider
|
|
357
|
+
* theme={{
|
|
358
|
+
* menuStyle: {
|
|
359
|
+
* '--anyclick-menu-bg': 'rgba(0, 0, 0, 0.9)',
|
|
360
|
+
* '--anyclick-menu-text': '#ffffff',
|
|
361
|
+
* '--anyclick-menu-border': 'rgba(255, 255, 255, 0.1)',
|
|
362
|
+
* '--anyclick-menu-hover': 'rgba(255, 255, 255, 0.1)',
|
|
363
|
+
* '--anyclick-menu-accent': '#f59e0b',
|
|
364
|
+
* }
|
|
365
|
+
* }}
|
|
366
|
+
* />
|
|
367
|
+
* ```
|
|
368
|
+
*/
|
|
369
|
+
declare const menuCSSVariables: {
|
|
370
|
+
readonly "--anyclick-menu-bg": "#ffffff";
|
|
371
|
+
readonly "--anyclick-menu-hover": "#f5f5f5";
|
|
372
|
+
readonly "--anyclick-menu-text": "#333333";
|
|
373
|
+
readonly "--anyclick-menu-text-muted": "#666666";
|
|
374
|
+
readonly "--anyclick-menu-border": "#e5e5e5";
|
|
375
|
+
readonly "--anyclick-menu-accent": "#0066cc";
|
|
376
|
+
readonly "--anyclick-menu-accent-text": "#ffffff";
|
|
377
|
+
readonly "--anyclick-menu-input-bg": "#ffffff";
|
|
378
|
+
readonly "--anyclick-menu-input-border": "#dddddd";
|
|
379
|
+
readonly "--anyclick-menu-cancel-bg": "#f0f0f0";
|
|
380
|
+
readonly "--anyclick-menu-cancel-text": "#666666";
|
|
381
|
+
};
|
|
200
382
|
declare const menuStyles: Record<string, CSSProperties>;
|
|
201
383
|
declare const darkMenuStyles: Record<string, CSSProperties>;
|
|
202
384
|
|
|
@@ -236,4 +418,4 @@ declare function applyHighlights(targetElement: Element, config?: HighlightConfi
|
|
|
236
418
|
container: Element | null;
|
|
237
419
|
};
|
|
238
420
|
|
|
239
|
-
export { ContextMenu, type ContextMenuProps, FeedbackContext, type FeedbackContextValue, type FeedbackMenuItem, FeedbackProvider, type FeedbackProviderProps, type FeedbackUserContext, type HighlightColors, type HighlightConfig, ScreenshotPreview, type ScreenshotPreviewProps, applyHighlights, clearHighlights, darkMenuStyles, defaultContainerSelectors, defaultHighlightColors, filterMenuItemsByRole, findContainerParent, highlightContainer, highlightTarget, menuStyles, useFeedback };
|
|
421
|
+
export { AnyclickContext, type AnyclickContextValue, AnyclickProvider, type AnyclickProviderProps, type AnyclickTheme, ContextMenu, type ContextMenuProps, FeedbackContext, type FeedbackContextValue, type FeedbackMenuItem, FeedbackProvider, type FeedbackProviderProps, type FeedbackUserContext, type HighlightColors, type HighlightConfig, type MenuPositionMode, type ProviderInstance, ScreenshotPreview, type ScreenshotPreviewProps, applyHighlights, clearHighlights, darkMenuStyles, defaultContainerSelectors, defaultHighlightColors, dispatchContextMenuEvent, filterMenuItemsByRole, findContainerParent, generateProviderId, highlightContainer, highlightTarget, menuCSSVariables, menuStyles, useAnyclick, useFeedback, useProviderStore };
|