@np-dev/ui-ai-anotation 0.1.0 → 0.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 +106 -21
- package/dist/cjs/index.cjs +247 -14
- package/dist/cjs/index.cjs.map +4 -4
- package/dist/cjs/index.native.cjs +11 -11
- package/dist/cjs/index.native.cjs.map +3 -3
- package/dist/cjs/index.web.cjs +5 -5
- package/dist/cjs/index.web.cjs.map +2 -2
- package/dist/esm/index.js +248 -14
- package/dist/esm/index.js.map +4 -4
- package/dist/esm/index.native.js +11 -11
- package/dist/esm/index.native.js.map +3 -3
- package/dist/esm/index.web.js +5 -5
- package/dist/esm/index.web.js.map +2 -2
- package/dist/types/components/ErrorBoundary.d.ts +159 -0
- package/dist/types/index.d.ts +5 -3
- package/dist/types/index.web.d.ts +2 -2
- package/dist/types/store.d.ts +2 -2
- package/package.json +1 -1
- package/src/components/AnnotationInput.tsx +2 -2
- package/src/components/AnnotationList.tsx +2 -2
- package/src/components/ErrorBoundary.tsx +426 -0
- package/src/components/Highlighter.tsx +2 -2
- package/src/components/Toolbar.tsx +4 -3
- package/src/components/native/AnnotationInput.tsx +2 -2
- package/src/components/native/AnnotationList.tsx +2 -2
- package/src/components/native/Highlighter.tsx +2 -2
- package/src/components/native/Toolbar.tsx +2 -2
- package/src/components/web/AnnotationInput.tsx +2 -2
- package/src/components/web/AnnotationList.tsx +2 -2
- package/src/components/web/Highlighter.tsx +2 -2
- package/src/components/web/Toolbar.tsx +2 -2
- package/src/extension.tsx +1 -1
- package/src/index.native.tsx +4 -4
- package/src/index.tsx +6 -4
- package/src/index.web.tsx +3 -3
- package/src/store.tsx +3 -3
package/dist/types/store.d.ts
CHANGED
|
@@ -57,10 +57,10 @@ type Action = {
|
|
|
57
57
|
} | {
|
|
58
58
|
type: 'RESET_HOVER';
|
|
59
59
|
};
|
|
60
|
-
export declare function
|
|
60
|
+
export declare function AgentAnnotationProvider({ children }: {
|
|
61
61
|
children: ReactNode;
|
|
62
62
|
}): import("react/jsx-runtime").JSX.Element;
|
|
63
|
-
export declare function
|
|
63
|
+
export declare function useAgentAnnotation(): {
|
|
64
64
|
state: State;
|
|
65
65
|
dispatch: React.Dispatch<Action>;
|
|
66
66
|
};
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useAgentAnnotation } from '../store';
|
|
3
3
|
import type { ComponentDetails } from '../store';
|
|
4
4
|
import { X } from 'lucide-react';
|
|
5
5
|
|
|
@@ -64,7 +64,7 @@ function formatComponentDetails(details: ComponentDetails): string {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
export function AnnotationInput({ onClose, componentName, componentDetails }: AnnotationInputProps) {
|
|
67
|
-
const { dispatch } =
|
|
67
|
+
const { dispatch } = useAgentAnnotation();
|
|
68
68
|
const [note, setNote] = useState('');
|
|
69
69
|
const [includeDetails, setIncludeDetails] = useState(true);
|
|
70
70
|
const [isVisible, setIsVisible] = useState(false);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useAgentAnnotation } from '../store';
|
|
3
3
|
import { X, Trash2, Trash, ChevronDown, ChevronRight } from 'lucide-react';
|
|
4
4
|
|
|
5
5
|
export function AnnotationList() {
|
|
6
|
-
const { state, dispatch } =
|
|
6
|
+
const { state, dispatch } = useAgentAnnotation();
|
|
7
7
|
const [expandedId, setExpandedId] = useState<string | null>(null);
|
|
8
8
|
|
|
9
9
|
if (!state.showList) return null;
|
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
import React, { Component, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Error information passed to fallback components
|
|
5
|
+
*/
|
|
6
|
+
export interface ErrorInfo {
|
|
7
|
+
error: Error;
|
|
8
|
+
errorInfo: React.ErrorInfo;
|
|
9
|
+
/** Formatted error message for copying/display */
|
|
10
|
+
formattedError: string;
|
|
11
|
+
/** Reset the error state and retry rendering */
|
|
12
|
+
reset: () => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Props for custom fallback component
|
|
17
|
+
*/
|
|
18
|
+
export interface FallbackProps extends ErrorInfo {
|
|
19
|
+
/** Copy error details to clipboard */
|
|
20
|
+
copyToClipboard: () => Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Button configuration for default error UI
|
|
25
|
+
*/
|
|
26
|
+
export interface ErrorButtonConfig {
|
|
27
|
+
/** Button label text */
|
|
28
|
+
label: string;
|
|
29
|
+
/** Click handler */
|
|
30
|
+
onClick: (errorInfo: ErrorInfo) => void;
|
|
31
|
+
/** Optional button style override */
|
|
32
|
+
style?: React.CSSProperties;
|
|
33
|
+
/** Optional className */
|
|
34
|
+
className?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Props for ErrorBoundary component
|
|
39
|
+
*/
|
|
40
|
+
export interface ErrorBoundaryProps {
|
|
41
|
+
children: ReactNode;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Custom fallback component to render when error occurs.
|
|
45
|
+
* Takes full control of error UI.
|
|
46
|
+
*/
|
|
47
|
+
fallback?: React.ComponentType<FallbackProps>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Fallback element (simpler alternative to fallback component)
|
|
51
|
+
*/
|
|
52
|
+
fallbackElement?: ReactNode;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Custom title for default error page
|
|
56
|
+
* @default "Something went wrong"
|
|
57
|
+
*/
|
|
58
|
+
title?: string;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Custom subtitle/description for default error page
|
|
62
|
+
* @default "An unexpected error occurred"
|
|
63
|
+
*/
|
|
64
|
+
subtitle?: string;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Whether to show error details in default UI
|
|
68
|
+
* @default true
|
|
69
|
+
*/
|
|
70
|
+
showErrorDetails?: boolean;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Whether to show the "Copy Error" button in default UI
|
|
74
|
+
* @default true
|
|
75
|
+
*/
|
|
76
|
+
showCopyButton?: boolean;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Whether to show the "Try Again" button in default UI
|
|
80
|
+
* @default true
|
|
81
|
+
*/
|
|
82
|
+
showRetryButton?: boolean;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Custom retry button label
|
|
86
|
+
* @default "Try Again"
|
|
87
|
+
*/
|
|
88
|
+
retryButtonLabel?: string;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Custom copy button label
|
|
92
|
+
* @default "Copy Error Details"
|
|
93
|
+
*/
|
|
94
|
+
copyButtonLabel?: string;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Additional custom buttons to show in default UI
|
|
98
|
+
*/
|
|
99
|
+
customButtons?: ErrorButtonConfig[];
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Custom styles for the default error container
|
|
103
|
+
*/
|
|
104
|
+
containerStyle?: React.CSSProperties;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Custom styles for the error details section
|
|
108
|
+
*/
|
|
109
|
+
errorDetailsStyle?: React.CSSProperties;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Callback when an error is caught
|
|
113
|
+
*/
|
|
114
|
+
onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Callback when reset/retry is triggered
|
|
118
|
+
*/
|
|
119
|
+
onReset?: () => void;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
interface ErrorBoundaryState {
|
|
123
|
+
hasError: boolean;
|
|
124
|
+
error: Error | null;
|
|
125
|
+
errorInfo: React.ErrorInfo | null;
|
|
126
|
+
copied: boolean;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Default styles for the error boundary UI
|
|
131
|
+
*/
|
|
132
|
+
const defaultStyles = {
|
|
133
|
+
container: {
|
|
134
|
+
display: 'flex',
|
|
135
|
+
flexDirection: 'column' as const,
|
|
136
|
+
alignItems: 'center',
|
|
137
|
+
justifyContent: 'center',
|
|
138
|
+
minHeight: '100vh',
|
|
139
|
+
padding: '24px',
|
|
140
|
+
backgroundColor: '#1e1e1e',
|
|
141
|
+
color: '#e5e7eb',
|
|
142
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
143
|
+
},
|
|
144
|
+
content: {
|
|
145
|
+
maxWidth: '600px',
|
|
146
|
+
width: '100%',
|
|
147
|
+
textAlign: 'center' as const,
|
|
148
|
+
},
|
|
149
|
+
icon: {
|
|
150
|
+
fontSize: '48px',
|
|
151
|
+
marginBottom: '16px',
|
|
152
|
+
},
|
|
153
|
+
title: {
|
|
154
|
+
fontSize: '24px',
|
|
155
|
+
fontWeight: 600,
|
|
156
|
+
marginBottom: '8px',
|
|
157
|
+
color: '#f87171',
|
|
158
|
+
},
|
|
159
|
+
subtitle: {
|
|
160
|
+
fontSize: '16px',
|
|
161
|
+
color: '#9ca3af',
|
|
162
|
+
marginBottom: '24px',
|
|
163
|
+
},
|
|
164
|
+
errorBox: {
|
|
165
|
+
backgroundColor: '#2d2d2d',
|
|
166
|
+
border: '1px solid #404040',
|
|
167
|
+
borderRadius: '8px',
|
|
168
|
+
padding: '16px',
|
|
169
|
+
marginBottom: '24px',
|
|
170
|
+
textAlign: 'left' as const,
|
|
171
|
+
maxHeight: '200px',
|
|
172
|
+
overflow: 'auto',
|
|
173
|
+
},
|
|
174
|
+
errorText: {
|
|
175
|
+
fontFamily: 'monospace',
|
|
176
|
+
fontSize: '12px',
|
|
177
|
+
color: '#f87171',
|
|
178
|
+
whiteSpace: 'pre-wrap' as const,
|
|
179
|
+
wordBreak: 'break-word' as const,
|
|
180
|
+
margin: 0,
|
|
181
|
+
},
|
|
182
|
+
buttonContainer: {
|
|
183
|
+
display: 'flex',
|
|
184
|
+
gap: '12px',
|
|
185
|
+
justifyContent: 'center',
|
|
186
|
+
flexWrap: 'wrap' as const,
|
|
187
|
+
},
|
|
188
|
+
button: {
|
|
189
|
+
padding: '10px 20px',
|
|
190
|
+
borderRadius: '6px',
|
|
191
|
+
border: 'none',
|
|
192
|
+
fontSize: '14px',
|
|
193
|
+
fontWeight: 500,
|
|
194
|
+
cursor: 'pointer',
|
|
195
|
+
transition: 'all 0.2s',
|
|
196
|
+
},
|
|
197
|
+
primaryButton: {
|
|
198
|
+
backgroundColor: '#3b82f6',
|
|
199
|
+
color: 'white',
|
|
200
|
+
},
|
|
201
|
+
secondaryButton: {
|
|
202
|
+
backgroundColor: '#404040',
|
|
203
|
+
color: '#e5e7eb',
|
|
204
|
+
},
|
|
205
|
+
successButton: {
|
|
206
|
+
backgroundColor: '#22c55e',
|
|
207
|
+
color: 'white',
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* ErrorBoundary component with customizable error UI
|
|
213
|
+
*
|
|
214
|
+
* @example Basic usage
|
|
215
|
+
* ```tsx
|
|
216
|
+
* <ErrorBoundary>
|
|
217
|
+
* <App />
|
|
218
|
+
* </ErrorBoundary>
|
|
219
|
+
* ```
|
|
220
|
+
*
|
|
221
|
+
* @example Custom title and buttons
|
|
222
|
+
* ```tsx
|
|
223
|
+
* <ErrorBoundary
|
|
224
|
+
* title="Oops! Something broke"
|
|
225
|
+
* subtitle="Please try again or contact support"
|
|
226
|
+
* showCopyButton={true}
|
|
227
|
+
* customButtons={[
|
|
228
|
+
* { label: "Go Home", onClick: () => window.location.href = "/" }
|
|
229
|
+
* ]}
|
|
230
|
+
* >
|
|
231
|
+
* <App />
|
|
232
|
+
* </ErrorBoundary>
|
|
233
|
+
* ```
|
|
234
|
+
*
|
|
235
|
+
* @example Fully custom fallback
|
|
236
|
+
* ```tsx
|
|
237
|
+
* <ErrorBoundary
|
|
238
|
+
* fallback={({ error, reset, copyToClipboard }) => (
|
|
239
|
+
* <div>
|
|
240
|
+
* <h1>Error: {error.message}</h1>
|
|
241
|
+
* <button onClick={reset}>Retry</button>
|
|
242
|
+
* <button onClick={copyToClipboard}>Copy</button>
|
|
243
|
+
* </div>
|
|
244
|
+
* )}
|
|
245
|
+
* >
|
|
246
|
+
* <App />
|
|
247
|
+
* </ErrorBoundary>
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
|
251
|
+
constructor(props: ErrorBoundaryProps) {
|
|
252
|
+
super(props);
|
|
253
|
+
this.state = {
|
|
254
|
+
hasError: false,
|
|
255
|
+
error: null,
|
|
256
|
+
errorInfo: null,
|
|
257
|
+
copied: false,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {
|
|
262
|
+
return { hasError: true, error };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
|
|
266
|
+
this.setState({ errorInfo });
|
|
267
|
+
this.props.onError?.(error, errorInfo);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private formatError(): string {
|
|
271
|
+
const { error, errorInfo } = this.state;
|
|
272
|
+
if (!error) return '';
|
|
273
|
+
|
|
274
|
+
const lines: string[] = [
|
|
275
|
+
'='.repeat(50),
|
|
276
|
+
'ERROR REPORT',
|
|
277
|
+
'='.repeat(50),
|
|
278
|
+
'',
|
|
279
|
+
`Error: ${error.name}`,
|
|
280
|
+
`Message: ${error.message}`,
|
|
281
|
+
'',
|
|
282
|
+
'Stack Trace:',
|
|
283
|
+
error.stack || 'No stack trace available',
|
|
284
|
+
];
|
|
285
|
+
|
|
286
|
+
if (errorInfo?.componentStack) {
|
|
287
|
+
lines.push('', 'Component Stack:', errorInfo.componentStack);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
lines.push('', `Timestamp: ${new Date().toISOString()}`);
|
|
291
|
+
lines.push(`User Agent: ${typeof navigator !== 'undefined' ? navigator.userAgent : 'N/A'}`);
|
|
292
|
+
|
|
293
|
+
return lines.join('\n');
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
private handleReset = () => {
|
|
297
|
+
this.props.onReset?.();
|
|
298
|
+
this.setState({
|
|
299
|
+
hasError: false,
|
|
300
|
+
error: null,
|
|
301
|
+
errorInfo: null,
|
|
302
|
+
copied: false,
|
|
303
|
+
});
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
private handleCopyToClipboard = async () => {
|
|
307
|
+
const text = this.formatError();
|
|
308
|
+
try {
|
|
309
|
+
await navigator.clipboard.writeText(text);
|
|
310
|
+
this.setState({ copied: true });
|
|
311
|
+
setTimeout(() => this.setState({ copied: false }), 2000);
|
|
312
|
+
} catch (err) {
|
|
313
|
+
console.error('Failed to copy error details:', err);
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
private getErrorInfo(): ErrorInfo {
|
|
318
|
+
return {
|
|
319
|
+
error: this.state.error!,
|
|
320
|
+
errorInfo: this.state.errorInfo!,
|
|
321
|
+
formattedError: this.formatError(),
|
|
322
|
+
reset: this.handleReset,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
private renderDefaultFallback() {
|
|
327
|
+
const {
|
|
328
|
+
title = 'Something went wrong',
|
|
329
|
+
subtitle = 'An unexpected error occurred',
|
|
330
|
+
showErrorDetails = true,
|
|
331
|
+
showCopyButton = true,
|
|
332
|
+
showRetryButton = true,
|
|
333
|
+
retryButtonLabel = 'Try Again',
|
|
334
|
+
copyButtonLabel = 'Copy Error Details',
|
|
335
|
+
customButtons = [],
|
|
336
|
+
containerStyle,
|
|
337
|
+
errorDetailsStyle,
|
|
338
|
+
} = this.props;
|
|
339
|
+
|
|
340
|
+
const { error, copied } = this.state;
|
|
341
|
+
const errorInfo = this.getErrorInfo();
|
|
342
|
+
|
|
343
|
+
return (
|
|
344
|
+
<div style={{ ...defaultStyles.container, ...containerStyle }}>
|
|
345
|
+
<div style={defaultStyles.content}>
|
|
346
|
+
<div style={defaultStyles.icon}>⚠️</div>
|
|
347
|
+
<h1 style={defaultStyles.title}>{title}</h1>
|
|
348
|
+
<p style={defaultStyles.subtitle}>{subtitle}</p>
|
|
349
|
+
|
|
350
|
+
{showErrorDetails && error && (
|
|
351
|
+
<div style={{ ...defaultStyles.errorBox, ...errorDetailsStyle }}>
|
|
352
|
+
<pre style={defaultStyles.errorText}>
|
|
353
|
+
{error.name}: {error.message}
|
|
354
|
+
{error.stack && `\n\n${error.stack.split('\n').slice(1, 5).join('\n')}`}
|
|
355
|
+
</pre>
|
|
356
|
+
</div>
|
|
357
|
+
)}
|
|
358
|
+
|
|
359
|
+
<div style={defaultStyles.buttonContainer}>
|
|
360
|
+
{showRetryButton && (
|
|
361
|
+
<button
|
|
362
|
+
onClick={this.handleReset}
|
|
363
|
+
style={{ ...defaultStyles.button, ...defaultStyles.primaryButton }}
|
|
364
|
+
>
|
|
365
|
+
{retryButtonLabel}
|
|
366
|
+
</button>
|
|
367
|
+
)}
|
|
368
|
+
|
|
369
|
+
{showCopyButton && (
|
|
370
|
+
<button
|
|
371
|
+
onClick={this.handleCopyToClipboard}
|
|
372
|
+
style={{
|
|
373
|
+
...defaultStyles.button,
|
|
374
|
+
...(copied ? defaultStyles.successButton : defaultStyles.secondaryButton),
|
|
375
|
+
}}
|
|
376
|
+
>
|
|
377
|
+
{copied ? '✓ Copied!' : copyButtonLabel}
|
|
378
|
+
</button>
|
|
379
|
+
)}
|
|
380
|
+
|
|
381
|
+
{customButtons.map((btn, index) => (
|
|
382
|
+
<button
|
|
383
|
+
key={index}
|
|
384
|
+
onClick={() => btn.onClick(errorInfo)}
|
|
385
|
+
style={{ ...defaultStyles.button, ...defaultStyles.secondaryButton, ...btn.style }}
|
|
386
|
+
className={btn.className}
|
|
387
|
+
>
|
|
388
|
+
{btn.label}
|
|
389
|
+
</button>
|
|
390
|
+
))}
|
|
391
|
+
</div>
|
|
392
|
+
</div>
|
|
393
|
+
</div>
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
render() {
|
|
398
|
+
const { hasError } = this.state;
|
|
399
|
+
const { children, fallback: FallbackComponent, fallbackElement } = this.props;
|
|
400
|
+
|
|
401
|
+
if (hasError) {
|
|
402
|
+
// Custom fallback component takes priority
|
|
403
|
+
if (FallbackComponent) {
|
|
404
|
+
const errorInfo = this.getErrorInfo();
|
|
405
|
+
return (
|
|
406
|
+
<FallbackComponent
|
|
407
|
+
{...errorInfo}
|
|
408
|
+
copyToClipboard={this.handleCopyToClipboard}
|
|
409
|
+
/>
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Simple fallback element
|
|
414
|
+
if (fallbackElement) {
|
|
415
|
+
return <>{fallbackElement}</>;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Default error UI
|
|
419
|
+
return this.renderDefaultFallback();
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return children;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export default ErrorBoundary;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { useAgentAnnotation } from "../store";
|
|
3
3
|
import { AnnotationInput } from "./AnnotationInput";
|
|
4
4
|
import { captureScreenshot } from "../utils/screenshot";
|
|
5
5
|
import { getComponentDetails } from "../utils/fiber";
|
|
6
6
|
|
|
7
7
|
export function Highlighter() {
|
|
8
|
-
const { state, dispatch } =
|
|
8
|
+
const { state, dispatch } = useAgentAnnotation();
|
|
9
9
|
const { hoveredElement, mode, hoveredComponentInfo } = state;
|
|
10
10
|
|
|
11
11
|
const [rect, setRect] = useState<DOMRect | null>(null);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import React, { useState, useEffect, useRef } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useAgentAnnotation } from '../store';
|
|
3
3
|
import { Draggable } from './Draggable';
|
|
4
4
|
import { GripVertical, MousePointer2, List, Copy, Minus, Maximize2, Ban, Check } from 'lucide-react';
|
|
5
5
|
import { Highlighter } from './Highlighter';
|
|
6
6
|
import { AnnotationList } from './AnnotationList';
|
|
7
7
|
|
|
8
8
|
export function Toolbar() {
|
|
9
|
-
const { state, dispatch } =
|
|
9
|
+
const { state, dispatch } = useAgentAnnotation();
|
|
10
10
|
const [showCopied, setShowCopied] = useState(false);
|
|
11
11
|
const [isAnimating, setIsAnimating] = useState(false);
|
|
12
12
|
const contentRef = useRef<HTMLDivElement>(null);
|
|
@@ -40,7 +40,8 @@ export function Toolbar() {
|
|
|
40
40
|
|
|
41
41
|
// Section header
|
|
42
42
|
lines.push(`${'='.repeat(50)}`);
|
|
43
|
-
lines.push(`Annotation ${index + 1}
|
|
43
|
+
lines.push(`Annotation ${index + 1}`);
|
|
44
|
+
lines.push(`Component: ${a.componentName}`);
|
|
44
45
|
lines.push(`${'='.repeat(50)}`);
|
|
45
46
|
lines.push('');
|
|
46
47
|
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
KeyboardAvoidingView,
|
|
11
11
|
Platform,
|
|
12
12
|
} from 'react-native';
|
|
13
|
-
import {
|
|
13
|
+
import { useAgentAnnotation } from '../../store';
|
|
14
14
|
|
|
15
15
|
interface AnnotationInputProps {
|
|
16
16
|
onClose: () => void;
|
|
@@ -18,7 +18,7 @@ interface AnnotationInputProps {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export function AnnotationInput({ onClose, componentName }: AnnotationInputProps) {
|
|
21
|
-
const { dispatch } =
|
|
21
|
+
const { dispatch } = useAgentAnnotation();
|
|
22
22
|
const [note, setNote] = useState('');
|
|
23
23
|
const [fadeAnim] = useState(new Animated.Value(0));
|
|
24
24
|
const [scaleAnim] = useState(new Animated.Value(0.95));
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
ScrollView,
|
|
8
8
|
StyleSheet,
|
|
9
9
|
} from 'react-native';
|
|
10
|
-
import {
|
|
10
|
+
import { useAgentAnnotation } from '../../store';
|
|
11
11
|
|
|
12
12
|
export function AnnotationList() {
|
|
13
|
-
const { state, dispatch } =
|
|
13
|
+
const { state, dispatch } = useAgentAnnotation();
|
|
14
14
|
|
|
15
15
|
if (!state.showList) return null;
|
|
16
16
|
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
Dimensions,
|
|
8
8
|
GestureResponderEvent,
|
|
9
9
|
} from 'react-native';
|
|
10
|
-
import {
|
|
10
|
+
import { useAgentAnnotation } from '../../store';
|
|
11
11
|
import { AnnotationInput } from './AnnotationInput';
|
|
12
12
|
|
|
13
13
|
interface HighlightRect {
|
|
@@ -29,7 +29,7 @@ interface HighlighterProps {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export function Highlighter({ onInspect }: HighlighterProps) {
|
|
32
|
-
const { state, dispatch } =
|
|
32
|
+
const { state, dispatch } = useAgentAnnotation();
|
|
33
33
|
const { mode } = state;
|
|
34
34
|
|
|
35
35
|
const [highlightRect, setHighlightRect] = useState<HighlightRect | null>(null);
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
StyleSheet,
|
|
7
7
|
Platform,
|
|
8
8
|
} from 'react-native';
|
|
9
|
-
import {
|
|
9
|
+
import { useAgentAnnotation } from '../../store';
|
|
10
10
|
import { Draggable } from './Draggable';
|
|
11
11
|
import { Highlighter } from './Highlighter';
|
|
12
12
|
import { AnnotationList } from './AnnotationList';
|
|
@@ -29,7 +29,7 @@ const copyToClipboard = async (text: string) => {
|
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
export function Toolbar() {
|
|
32
|
-
const { state, dispatch } =
|
|
32
|
+
const { state, dispatch } = useAgentAnnotation();
|
|
33
33
|
const [showCopied, setShowCopied] = useState(false);
|
|
34
34
|
|
|
35
35
|
const handleCopy = async () => {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useAgentAnnotation } from '../../store';
|
|
3
3
|
import { X } from 'lucide-react';
|
|
4
4
|
|
|
5
5
|
export function AnnotationInput({ onClose, componentName }: { onClose: () => void; componentName: string }) {
|
|
6
|
-
const { dispatch } =
|
|
6
|
+
const { dispatch } = useAgentAnnotation();
|
|
7
7
|
const [note, setNote] = useState('');
|
|
8
8
|
const [isVisible, setIsVisible] = useState(false);
|
|
9
9
|
const [isClosing, setIsClosing] = useState(false);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useAgentAnnotation } from '../../store';
|
|
3
3
|
import { X, Trash2, Trash } from 'lucide-react';
|
|
4
4
|
|
|
5
5
|
export function AnnotationList() {
|
|
6
|
-
const { state, dispatch } =
|
|
6
|
+
const { state, dispatch } = useAgentAnnotation();
|
|
7
7
|
|
|
8
8
|
if (!state.showList) return null;
|
|
9
9
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { useAgentAnnotation } from "../../store";
|
|
3
3
|
import { AnnotationInput } from "./AnnotationInput";
|
|
4
4
|
import { captureScreenshot } from "../../utils/screenshot";
|
|
5
5
|
import { getReactFiber, getComponentDisplayName } from "../../utils/fiber";
|
|
6
6
|
|
|
7
7
|
export function Highlighter() {
|
|
8
|
-
const { state, dispatch } =
|
|
8
|
+
const { state, dispatch } = useAgentAnnotation();
|
|
9
9
|
const { hoveredElement, mode, hoveredComponentInfo } = state;
|
|
10
10
|
|
|
11
11
|
const [rect, setRect] = useState<DOMRect | null>(null);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import React, { useState, useEffect, useRef } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useAgentAnnotation } from '../../store';
|
|
3
3
|
import { Draggable } from './Draggable';
|
|
4
4
|
import { GripVertical, MousePointer2, List, Copy, Minus, Maximize2, Ban, Check } from 'lucide-react';
|
|
5
5
|
import { Highlighter } from './Highlighter';
|
|
6
6
|
import { AnnotationList } from './AnnotationList';
|
|
7
7
|
|
|
8
8
|
export function Toolbar() {
|
|
9
|
-
const { state, dispatch } =
|
|
9
|
+
const { state, dispatch } = useAgentAnnotation();
|
|
10
10
|
const [showCopied, setShowCopied] = useState(false);
|
|
11
11
|
const [isAnimating, setIsAnimating] = useState(false);
|
|
12
12
|
const contentRef = useRef<HTMLDivElement>(null);
|
package/src/extension.tsx
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// Re-export web components directly
|
|
7
|
-
export {
|
|
7
|
+
export { AgentAnnotationProvider, useAgentAnnotation } from './index.web';
|
|
8
8
|
export type { Annotation, Mode, HoveredElement, HoveredComponentInfo } from './index.web';
|
|
9
9
|
|
|
10
10
|
// Export web components
|
package/src/index.native.tsx
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { View } from 'react-native';
|
|
3
|
-
import {
|
|
3
|
+
import { AgentAnnotationProvider as Provider } from './store';
|
|
4
4
|
import { Toolbar } from './components/native/Toolbar';
|
|
5
5
|
|
|
6
|
-
export interface
|
|
6
|
+
export interface AgentAnnotationProviderProps {
|
|
7
7
|
children: React.ReactNode;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* React Native
|
|
11
|
+
* React Native Agent Annotation Provider
|
|
12
12
|
* Wraps your app to provide annotation functionality
|
|
13
13
|
*/
|
|
14
|
-
export function
|
|
14
|
+
export function AgentAnnotationProvider({ children }: AgentAnnotationProviderProps) {
|
|
15
15
|
return (
|
|
16
16
|
<Provider>
|
|
17
17
|
<View style={{ flex: 1 }}>
|