@ewjdev/anyclick-react 2.0.0 → 3.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/dist/index.d.mts +375 -4
- package/dist/index.d.ts +375 -4
- package/dist/index.js +1945 -308
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1921 -276
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
package/dist/index.mjs
CHANGED
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
// src/AnyclickProvider.tsx
|
|
4
4
|
import {
|
|
5
|
-
useCallback as
|
|
6
|
-
useEffect as
|
|
5
|
+
useCallback as useCallback4,
|
|
6
|
+
useEffect as useEffect4,
|
|
7
7
|
useId,
|
|
8
8
|
useLayoutEffect,
|
|
9
|
-
useMemo as
|
|
10
|
-
useRef as
|
|
11
|
-
useState as
|
|
9
|
+
useMemo as useMemo3,
|
|
10
|
+
useRef as useRef4,
|
|
11
|
+
useState as useState5
|
|
12
12
|
} from "react";
|
|
13
13
|
import { createAnyclickClient } from "@ewjdev/anyclick-core";
|
|
14
14
|
|
|
15
15
|
// src/ContextMenu.tsx
|
|
16
|
-
import
|
|
16
|
+
import React3, { useCallback as useCallback3, useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
|
|
17
17
|
import {
|
|
18
18
|
DEFAULT_SCREENSHOT_CONFIG,
|
|
19
19
|
captureAllScreenshots,
|
|
@@ -26,11 +26,1356 @@ import {
|
|
|
26
26
|
FlagIcon,
|
|
27
27
|
GripVertical,
|
|
28
28
|
PlusIcon,
|
|
29
|
+
Sparkles,
|
|
29
30
|
ThumbsUpIcon
|
|
30
31
|
} from "lucide-react";
|
|
31
32
|
|
|
33
|
+
// src/QuickChat/QuickChat.tsx
|
|
34
|
+
import React, {
|
|
35
|
+
useCallback as useCallback2,
|
|
36
|
+
useEffect as useEffect2,
|
|
37
|
+
useMemo,
|
|
38
|
+
useRef as useRef2,
|
|
39
|
+
useState as useState2
|
|
40
|
+
} from "react";
|
|
41
|
+
import {
|
|
42
|
+
AlertCircle,
|
|
43
|
+
ChevronDown,
|
|
44
|
+
ChevronLeft,
|
|
45
|
+
ChevronUp,
|
|
46
|
+
Copy,
|
|
47
|
+
ExternalLink,
|
|
48
|
+
Pin,
|
|
49
|
+
PinOff,
|
|
50
|
+
RefreshCw,
|
|
51
|
+
Send,
|
|
52
|
+
X
|
|
53
|
+
} from "lucide-react";
|
|
54
|
+
|
|
55
|
+
// src/QuickChat/styles.ts
|
|
56
|
+
var quickChatStyles = {
|
|
57
|
+
// Inline container - inside the context menu
|
|
58
|
+
container: {
|
|
59
|
+
display: "flex",
|
|
60
|
+
flexDirection: "column",
|
|
61
|
+
width: "100%",
|
|
62
|
+
maxHeight: "320px",
|
|
63
|
+
overflow: "hidden"
|
|
64
|
+
},
|
|
65
|
+
// Pinned drawer - anchored to right side of screen
|
|
66
|
+
pinnedContainer: {
|
|
67
|
+
position: "fixed",
|
|
68
|
+
top: 0,
|
|
69
|
+
right: 0,
|
|
70
|
+
bottom: 0,
|
|
71
|
+
width: "340px",
|
|
72
|
+
display: "flex",
|
|
73
|
+
flexDirection: "column",
|
|
74
|
+
backgroundColor: "var(--anyclick-menu-bg, #ffffff)",
|
|
75
|
+
borderLeft: "1px solid var(--anyclick-menu-border, #e5e5e5)",
|
|
76
|
+
boxShadow: "-4px 0 24px rgba(0, 0, 0, 0.15)",
|
|
77
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
78
|
+
fontSize: "14px",
|
|
79
|
+
overflow: "hidden",
|
|
80
|
+
zIndex: 9998
|
|
81
|
+
},
|
|
82
|
+
// Pinned messages area (taller)
|
|
83
|
+
pinnedMessagesArea: {
|
|
84
|
+
flex: 1,
|
|
85
|
+
overflowY: "auto",
|
|
86
|
+
padding: "12px",
|
|
87
|
+
display: "flex",
|
|
88
|
+
flexDirection: "column",
|
|
89
|
+
gap: "8px",
|
|
90
|
+
minHeight: "200px"
|
|
91
|
+
},
|
|
92
|
+
// Header - minimal design
|
|
93
|
+
header: {
|
|
94
|
+
display: "flex",
|
|
95
|
+
alignItems: "center",
|
|
96
|
+
justifyContent: "space-between",
|
|
97
|
+
padding: "6px 8px",
|
|
98
|
+
gap: "8px"
|
|
99
|
+
},
|
|
100
|
+
headerTitle: {
|
|
101
|
+
fontSize: "11px",
|
|
102
|
+
fontWeight: 600,
|
|
103
|
+
textTransform: "uppercase",
|
|
104
|
+
letterSpacing: "0.5px",
|
|
105
|
+
color: "var(--anyclick-menu-text-muted, #666)"
|
|
106
|
+
},
|
|
107
|
+
headerActions: {
|
|
108
|
+
display: "flex",
|
|
109
|
+
alignItems: "center",
|
|
110
|
+
gap: "2px"
|
|
111
|
+
},
|
|
112
|
+
iconButton: {
|
|
113
|
+
display: "flex",
|
|
114
|
+
alignItems: "center",
|
|
115
|
+
justifyContent: "center",
|
|
116
|
+
width: "24px",
|
|
117
|
+
height: "24px",
|
|
118
|
+
border: "none",
|
|
119
|
+
borderRadius: "4px",
|
|
120
|
+
backgroundColor: "transparent",
|
|
121
|
+
color: "var(--anyclick-menu-text-muted, #666)",
|
|
122
|
+
cursor: "pointer",
|
|
123
|
+
transition: "all 0.15s ease"
|
|
124
|
+
},
|
|
125
|
+
iconButtonActive: {
|
|
126
|
+
backgroundColor: "var(--anyclick-menu-accent, #0066cc)",
|
|
127
|
+
color: "#fff"
|
|
128
|
+
},
|
|
129
|
+
// Context badge in header
|
|
130
|
+
contextBadge: {
|
|
131
|
+
display: "inline-flex",
|
|
132
|
+
alignItems: "center",
|
|
133
|
+
gap: "4px",
|
|
134
|
+
padding: "3px 8px",
|
|
135
|
+
fontSize: "10px",
|
|
136
|
+
fontWeight: 500,
|
|
137
|
+
border: "1px solid var(--anyclick-menu-border, #e5e5e5)",
|
|
138
|
+
borderRadius: "10px",
|
|
139
|
+
backgroundColor: "transparent",
|
|
140
|
+
color: "var(--anyclick-menu-text-muted, #666)",
|
|
141
|
+
cursor: "pointer",
|
|
142
|
+
transition: "all 0.15s ease"
|
|
143
|
+
},
|
|
144
|
+
contextBadgeActive: {
|
|
145
|
+
borderColor: "var(--anyclick-menu-accent, #0066cc)",
|
|
146
|
+
backgroundColor: "rgba(0, 102, 204, 0.08)"
|
|
147
|
+
},
|
|
148
|
+
// Context dropdown (in normal flow, not absolute)
|
|
149
|
+
contextDropdown: {
|
|
150
|
+
display: "flex",
|
|
151
|
+
flexDirection: "column",
|
|
152
|
+
gap: "2px",
|
|
153
|
+
padding: "6px 8px",
|
|
154
|
+
margin: "0 8px 6px 8px",
|
|
155
|
+
backgroundColor: "var(--anyclick-menu-hover, #f5f5f5)",
|
|
156
|
+
borderRadius: "6px",
|
|
157
|
+
maxHeight: "80px",
|
|
158
|
+
overflowY: "auto"
|
|
159
|
+
},
|
|
160
|
+
// Messages area
|
|
161
|
+
messagesArea: {
|
|
162
|
+
flex: 1,
|
|
163
|
+
overflowY: "auto",
|
|
164
|
+
padding: "8px 12px",
|
|
165
|
+
display: "flex",
|
|
166
|
+
flexDirection: "column",
|
|
167
|
+
gap: "8px",
|
|
168
|
+
minHeight: "40px",
|
|
169
|
+
maxHeight: "140px"
|
|
170
|
+
},
|
|
171
|
+
emptyState: {
|
|
172
|
+
display: "none"
|
|
173
|
+
// Hide empty state, placeholder in input is enough
|
|
174
|
+
},
|
|
175
|
+
// Message bubble
|
|
176
|
+
message: {
|
|
177
|
+
display: "flex",
|
|
178
|
+
flexDirection: "column",
|
|
179
|
+
gap: "4px",
|
|
180
|
+
maxWidth: "100%"
|
|
181
|
+
},
|
|
182
|
+
messageUser: {
|
|
183
|
+
alignSelf: "flex-end",
|
|
184
|
+
backgroundColor: "var(--anyclick-menu-accent, #0066cc)",
|
|
185
|
+
color: "#fff",
|
|
186
|
+
padding: "6px 10px",
|
|
187
|
+
borderRadius: "12px 12px 4px 12px",
|
|
188
|
+
fontSize: "13px",
|
|
189
|
+
maxWidth: "85%",
|
|
190
|
+
wordBreak: "break-word"
|
|
191
|
+
},
|
|
192
|
+
messageAssistant: {
|
|
193
|
+
alignSelf: "flex-start",
|
|
194
|
+
backgroundColor: "var(--anyclick-menu-hover, #f5f5f5)",
|
|
195
|
+
color: "var(--anyclick-menu-text, #333)",
|
|
196
|
+
padding: "8px 10px",
|
|
197
|
+
borderRadius: "12px 12px 12px 4px",
|
|
198
|
+
fontSize: "13px",
|
|
199
|
+
maxWidth: "100%",
|
|
200
|
+
wordBreak: "break-word",
|
|
201
|
+
lineHeight: 1.4
|
|
202
|
+
},
|
|
203
|
+
messageActions: {
|
|
204
|
+
display: "flex",
|
|
205
|
+
gap: "4px",
|
|
206
|
+
marginTop: "4px",
|
|
207
|
+
flexWrap: "wrap"
|
|
208
|
+
},
|
|
209
|
+
actionButton: {
|
|
210
|
+
display: "inline-flex",
|
|
211
|
+
alignItems: "center",
|
|
212
|
+
gap: "4px",
|
|
213
|
+
padding: "3px 8px",
|
|
214
|
+
fontSize: "11px",
|
|
215
|
+
fontWeight: 500,
|
|
216
|
+
border: "1px solid var(--anyclick-menu-border, #e5e5e5)",
|
|
217
|
+
borderRadius: "4px",
|
|
218
|
+
backgroundColor: "transparent",
|
|
219
|
+
color: "var(--anyclick-menu-text-muted, #666)",
|
|
220
|
+
cursor: "pointer",
|
|
221
|
+
transition: "all 0.15s ease"
|
|
222
|
+
},
|
|
223
|
+
streamingIndicator: {
|
|
224
|
+
display: "inline-block",
|
|
225
|
+
width: "4px",
|
|
226
|
+
height: "14px",
|
|
227
|
+
backgroundColor: "var(--anyclick-menu-accent, #0066cc)",
|
|
228
|
+
borderRadius: "1px",
|
|
229
|
+
animation: "blink 1s infinite"
|
|
230
|
+
},
|
|
231
|
+
// Suggestions - compact horizontal scroll
|
|
232
|
+
suggestionsContainer: {
|
|
233
|
+
display: "flex",
|
|
234
|
+
gap: "6px",
|
|
235
|
+
padding: "6px 8px",
|
|
236
|
+
overflowX: "auto",
|
|
237
|
+
overflowY: "hidden",
|
|
238
|
+
scrollbarWidth: "none",
|
|
239
|
+
msOverflowStyle: "none"
|
|
240
|
+
},
|
|
241
|
+
suggestionChip: {
|
|
242
|
+
display: "inline-flex",
|
|
243
|
+
alignItems: "center",
|
|
244
|
+
padding: "4px 10px",
|
|
245
|
+
fontSize: "11px",
|
|
246
|
+
border: "1px solid var(--anyclick-menu-border, #e5e5e5)",
|
|
247
|
+
borderRadius: "12px",
|
|
248
|
+
backgroundColor: "var(--anyclick-menu-hover, #f5f5f5)",
|
|
249
|
+
color: "var(--anyclick-menu-text, #333)",
|
|
250
|
+
cursor: "pointer",
|
|
251
|
+
transition: "all 0.15s ease",
|
|
252
|
+
whiteSpace: "nowrap",
|
|
253
|
+
flexShrink: 0
|
|
254
|
+
},
|
|
255
|
+
suggestionChipHover: {
|
|
256
|
+
backgroundColor: "var(--anyclick-menu-bg, #fff)",
|
|
257
|
+
borderColor: "var(--anyclick-menu-accent, #0066cc)"
|
|
258
|
+
},
|
|
259
|
+
// Context redaction - now in dropdown
|
|
260
|
+
contextContainer: {
|
|
261
|
+
display: "flex",
|
|
262
|
+
flexDirection: "column",
|
|
263
|
+
gap: "4px"
|
|
264
|
+
},
|
|
265
|
+
contextHeader: {
|
|
266
|
+
display: "flex",
|
|
267
|
+
alignItems: "center",
|
|
268
|
+
justifyContent: "space-between",
|
|
269
|
+
marginBottom: "4px"
|
|
270
|
+
},
|
|
271
|
+
contextTitle: {
|
|
272
|
+
fontSize: "10px",
|
|
273
|
+
fontWeight: 600,
|
|
274
|
+
textTransform: "uppercase",
|
|
275
|
+
letterSpacing: "0.5px",
|
|
276
|
+
color: "var(--anyclick-menu-text-muted, #666)"
|
|
277
|
+
},
|
|
278
|
+
contextToggle: {
|
|
279
|
+
fontSize: "10px",
|
|
280
|
+
color: "var(--anyclick-menu-accent, #0066cc)",
|
|
281
|
+
background: "none",
|
|
282
|
+
border: "none",
|
|
283
|
+
cursor: "pointer",
|
|
284
|
+
padding: 0
|
|
285
|
+
},
|
|
286
|
+
contextToggleSmall: {
|
|
287
|
+
fontSize: "9px",
|
|
288
|
+
fontWeight: 500,
|
|
289
|
+
color: "var(--anyclick-menu-text-muted, #666)",
|
|
290
|
+
background: "none",
|
|
291
|
+
border: "none",
|
|
292
|
+
cursor: "pointer",
|
|
293
|
+
padding: "2px 4px",
|
|
294
|
+
borderRadius: "3px",
|
|
295
|
+
transition: "all 0.15s ease"
|
|
296
|
+
},
|
|
297
|
+
contextChunks: {
|
|
298
|
+
display: "flex",
|
|
299
|
+
flexDirection: "column",
|
|
300
|
+
gap: "4px"
|
|
301
|
+
},
|
|
302
|
+
contextChunk: {
|
|
303
|
+
display: "flex",
|
|
304
|
+
alignItems: "center",
|
|
305
|
+
gap: "6px",
|
|
306
|
+
padding: "4px 6px",
|
|
307
|
+
borderRadius: "4px",
|
|
308
|
+
fontSize: "11px",
|
|
309
|
+
backgroundColor: "var(--anyclick-menu-hover, #f5f5f5)",
|
|
310
|
+
cursor: "pointer",
|
|
311
|
+
transition: "opacity 0.15s ease"
|
|
312
|
+
},
|
|
313
|
+
contextChunkCompact: {
|
|
314
|
+
display: "flex",
|
|
315
|
+
alignItems: "center",
|
|
316
|
+
gap: "6px",
|
|
317
|
+
padding: "2px 4px",
|
|
318
|
+
borderRadius: "3px",
|
|
319
|
+
fontSize: "10px",
|
|
320
|
+
cursor: "pointer",
|
|
321
|
+
transition: "opacity 0.15s ease"
|
|
322
|
+
},
|
|
323
|
+
contextChunkExcluded: {
|
|
324
|
+
opacity: 0.5,
|
|
325
|
+
textDecoration: "line-through"
|
|
326
|
+
},
|
|
327
|
+
contextCheckbox: {
|
|
328
|
+
width: "12px",
|
|
329
|
+
height: "12px",
|
|
330
|
+
accentColor: "var(--anyclick-menu-accent, #0066cc)"
|
|
331
|
+
},
|
|
332
|
+
contextLabel: {
|
|
333
|
+
flex: 1,
|
|
334
|
+
overflow: "hidden",
|
|
335
|
+
textOverflow: "ellipsis",
|
|
336
|
+
whiteSpace: "nowrap",
|
|
337
|
+
color: "var(--anyclick-menu-text, #333)"
|
|
338
|
+
},
|
|
339
|
+
contextSize: {
|
|
340
|
+
fontSize: "10px",
|
|
341
|
+
color: "var(--anyclick-menu-text-muted, #666)"
|
|
342
|
+
},
|
|
343
|
+
// Input area
|
|
344
|
+
inputContainer: {
|
|
345
|
+
display: "flex",
|
|
346
|
+
alignItems: "flex-end",
|
|
347
|
+
gap: "8px",
|
|
348
|
+
padding: "8px"
|
|
349
|
+
},
|
|
350
|
+
input: {
|
|
351
|
+
flex: 1,
|
|
352
|
+
padding: "8px 12px",
|
|
353
|
+
fontSize: "13px",
|
|
354
|
+
border: "1px solid var(--anyclick-menu-input-border, #ddd)",
|
|
355
|
+
borderRadius: "18px",
|
|
356
|
+
backgroundColor: "var(--anyclick-menu-input-bg, #fff)",
|
|
357
|
+
color: "var(--anyclick-menu-text, #333)",
|
|
358
|
+
outline: "none",
|
|
359
|
+
resize: "none",
|
|
360
|
+
fontFamily: "inherit",
|
|
361
|
+
lineHeight: 1.4,
|
|
362
|
+
maxHeight: "80px",
|
|
363
|
+
minHeight: "36px"
|
|
364
|
+
},
|
|
365
|
+
inputFocused: {
|
|
366
|
+
borderColor: "var(--anyclick-menu-accent, #0066cc)",
|
|
367
|
+
boxShadow: "0 0 0 2px rgba(0, 102, 204, 0.1)"
|
|
368
|
+
},
|
|
369
|
+
sendButton: {
|
|
370
|
+
display: "flex",
|
|
371
|
+
alignItems: "center",
|
|
372
|
+
justifyContent: "center",
|
|
373
|
+
width: "32px",
|
|
374
|
+
height: "32px",
|
|
375
|
+
border: "none",
|
|
376
|
+
borderRadius: "50%",
|
|
377
|
+
backgroundColor: "var(--anyclick-menu-accent, #0066cc)",
|
|
378
|
+
color: "#fff",
|
|
379
|
+
cursor: "pointer",
|
|
380
|
+
transition: "all 0.15s ease",
|
|
381
|
+
flexShrink: 0
|
|
382
|
+
},
|
|
383
|
+
sendButtonDisabled: {
|
|
384
|
+
backgroundColor: "var(--anyclick-menu-border, #e5e5e5)",
|
|
385
|
+
cursor: "not-allowed"
|
|
386
|
+
},
|
|
387
|
+
// Loading states
|
|
388
|
+
loadingDots: {
|
|
389
|
+
display: "flex",
|
|
390
|
+
gap: "4px",
|
|
391
|
+
padding: "8px"
|
|
392
|
+
},
|
|
393
|
+
loadingDot: {
|
|
394
|
+
width: "6px",
|
|
395
|
+
height: "6px",
|
|
396
|
+
borderRadius: "50%",
|
|
397
|
+
backgroundColor: "var(--anyclick-menu-text-muted, #666)",
|
|
398
|
+
animation: "bounce 1.4s infinite ease-in-out both"
|
|
399
|
+
},
|
|
400
|
+
// Error states
|
|
401
|
+
errorContainer: {
|
|
402
|
+
display: "flex",
|
|
403
|
+
flexDirection: "column",
|
|
404
|
+
alignItems: "center",
|
|
405
|
+
gap: "8px",
|
|
406
|
+
padding: "16px",
|
|
407
|
+
textAlign: "center"
|
|
408
|
+
},
|
|
409
|
+
errorIcon: {
|
|
410
|
+
color: "#ef4444"
|
|
411
|
+
},
|
|
412
|
+
errorText: {
|
|
413
|
+
fontSize: "12px",
|
|
414
|
+
color: "#ef4444",
|
|
415
|
+
maxWidth: "200px"
|
|
416
|
+
},
|
|
417
|
+
errorRetry: {
|
|
418
|
+
display: "inline-flex",
|
|
419
|
+
alignItems: "center",
|
|
420
|
+
gap: "4px",
|
|
421
|
+
padding: "4px 10px",
|
|
422
|
+
fontSize: "11px",
|
|
423
|
+
fontWeight: 500,
|
|
424
|
+
border: "1px solid #ef4444",
|
|
425
|
+
borderRadius: "4px",
|
|
426
|
+
backgroundColor: "transparent",
|
|
427
|
+
color: "#ef4444",
|
|
428
|
+
cursor: "pointer",
|
|
429
|
+
transition: "all 0.15s ease"
|
|
430
|
+
},
|
|
431
|
+
// Truncation indicator
|
|
432
|
+
truncated: {
|
|
433
|
+
fontSize: "10px",
|
|
434
|
+
color: "var(--anyclick-menu-text-muted, #666)",
|
|
435
|
+
fontStyle: "italic",
|
|
436
|
+
marginTop: "4px"
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
var quickChatKeyframes = `
|
|
440
|
+
@keyframes blink {
|
|
441
|
+
0%, 50% { opacity: 1; }
|
|
442
|
+
51%, 100% { opacity: 0; }
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
@keyframes bounce {
|
|
446
|
+
0%, 80%, 100% { transform: scale(0); }
|
|
447
|
+
40% { transform: scale(1); }
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
@keyframes slideIn {
|
|
451
|
+
from {
|
|
452
|
+
opacity: 0;
|
|
453
|
+
transform: translateY(-8px);
|
|
454
|
+
}
|
|
455
|
+
to {
|
|
456
|
+
opacity: 1;
|
|
457
|
+
transform: translateY(0);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
@keyframes slideInFromRight {
|
|
462
|
+
from {
|
|
463
|
+
transform: translateX(100%);
|
|
464
|
+
}
|
|
465
|
+
to {
|
|
466
|
+
transform: translateX(0);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
@keyframes slideOutToRight {
|
|
471
|
+
from {
|
|
472
|
+
transform: translateX(0);
|
|
473
|
+
}
|
|
474
|
+
to {
|
|
475
|
+
transform: translateX(100%);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
@keyframes fadeIn {
|
|
480
|
+
from { opacity: 0; }
|
|
481
|
+
to { opacity: 1; }
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
@keyframes spin {
|
|
485
|
+
from { transform: rotate(0deg); }
|
|
486
|
+
to { transform: rotate(360deg); }
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
@keyframes pulse {
|
|
490
|
+
0%, 100% { opacity: 1; }
|
|
491
|
+
50% { opacity: 0.5; }
|
|
492
|
+
}
|
|
493
|
+
`;
|
|
494
|
+
|
|
495
|
+
// src/QuickChat/useQuickChat.ts
|
|
496
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
497
|
+
import { getElementInspectInfo } from "@ewjdev/anyclick-core";
|
|
498
|
+
|
|
499
|
+
// src/QuickChat/types.ts
|
|
500
|
+
var DEFAULT_T3CHAT_CONFIG = {
|
|
501
|
+
enabled: true,
|
|
502
|
+
baseUrl: "https://t3.chat",
|
|
503
|
+
label: "Ask t3.chat"
|
|
504
|
+
};
|
|
505
|
+
var DEFAULT_QUICK_CHAT_CONFIG = {
|
|
506
|
+
endpoint: "/api/anyclick/chat",
|
|
507
|
+
model: "gpt-5-mini",
|
|
508
|
+
prePassModel: "gpt-5-nano",
|
|
509
|
+
maxResponseLength: 500,
|
|
510
|
+
showRedactionUI: true,
|
|
511
|
+
showSuggestions: true,
|
|
512
|
+
systemPrompt: "You are a helpful assistant that provides quick, concise answers about web elements and UI. Keep responses brief and actionable.",
|
|
513
|
+
placeholder: "Ask about this element...",
|
|
514
|
+
title: "Quick Ask",
|
|
515
|
+
t3chat: DEFAULT_T3CHAT_CONFIG
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
// src/QuickChat/useQuickChat.ts
|
|
519
|
+
var PINNED_STATE_KEY = "anyclick-quick-chat-pinned";
|
|
520
|
+
var CHAT_HISTORY_KEY = "anyclick-quick-chat-history";
|
|
521
|
+
function generateId() {
|
|
522
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
523
|
+
}
|
|
524
|
+
function getPinnedState() {
|
|
525
|
+
if (typeof window === "undefined") return false;
|
|
526
|
+
try {
|
|
527
|
+
return sessionStorage.getItem(PINNED_STATE_KEY) === "true";
|
|
528
|
+
} catch {
|
|
529
|
+
return false;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
function getChatHistory() {
|
|
533
|
+
if (typeof window === "undefined") return [];
|
|
534
|
+
try {
|
|
535
|
+
const stored = sessionStorage.getItem(CHAT_HISTORY_KEY);
|
|
536
|
+
if (stored) {
|
|
537
|
+
const parsed = JSON.parse(stored);
|
|
538
|
+
return parsed.map((msg) => ({
|
|
539
|
+
...msg,
|
|
540
|
+
isStreaming: false,
|
|
541
|
+
actions: void 0
|
|
542
|
+
}));
|
|
543
|
+
}
|
|
544
|
+
} catch {
|
|
545
|
+
}
|
|
546
|
+
return [];
|
|
547
|
+
}
|
|
548
|
+
function saveChatHistory(messages) {
|
|
549
|
+
if (typeof window === "undefined") return;
|
|
550
|
+
try {
|
|
551
|
+
const toStore = messages.slice(-10).map((msg) => ({
|
|
552
|
+
id: msg.id,
|
|
553
|
+
role: msg.role,
|
|
554
|
+
content: msg.content,
|
|
555
|
+
timestamp: msg.timestamp
|
|
556
|
+
}));
|
|
557
|
+
sessionStorage.setItem(CHAT_HISTORY_KEY, JSON.stringify(toStore));
|
|
558
|
+
} catch {
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
function clearChatHistory() {
|
|
562
|
+
if (typeof window === "undefined") return;
|
|
563
|
+
try {
|
|
564
|
+
sessionStorage.removeItem(CHAT_HISTORY_KEY);
|
|
565
|
+
} catch {
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
function extractContextChunks(targetElement, containerElement) {
|
|
569
|
+
const chunks = [];
|
|
570
|
+
if (!targetElement) return chunks;
|
|
571
|
+
try {
|
|
572
|
+
const info = getElementInspectInfo(targetElement);
|
|
573
|
+
const tagContent = `<${info.tagName.toLowerCase()}${info.id ? ` id="${info.id}"` : ""}${info.classNames.length > 0 ? ` class="${info.classNames.join(" ")}"` : ""}>`;
|
|
574
|
+
chunks.push({
|
|
575
|
+
id: "element-tag",
|
|
576
|
+
label: "Element Tag",
|
|
577
|
+
content: tagContent,
|
|
578
|
+
type: "element",
|
|
579
|
+
included: true,
|
|
580
|
+
size: tagContent.length
|
|
581
|
+
});
|
|
582
|
+
if (info.innerText && info.innerText.length > 0) {
|
|
583
|
+
const textContent = info.innerText.slice(0, 200);
|
|
584
|
+
chunks.push({
|
|
585
|
+
id: "element-text",
|
|
586
|
+
label: "Text Content",
|
|
587
|
+
content: textContent,
|
|
588
|
+
type: "text",
|
|
589
|
+
included: true,
|
|
590
|
+
size: textContent.length
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
if (info.computedStyles) {
|
|
594
|
+
const styleEntries = [];
|
|
595
|
+
for (const [category, styles] of Object.entries(info.computedStyles)) {
|
|
596
|
+
if (styles && typeof styles === "object") {
|
|
597
|
+
const entries = Object.entries(styles).slice(0, 2);
|
|
598
|
+
for (const [k, v] of entries) {
|
|
599
|
+
if (v) styleEntries.push(`${k}: ${v}`);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
if (styleEntries.length >= 8) break;
|
|
603
|
+
}
|
|
604
|
+
const stylesContent = styleEntries.join("; ");
|
|
605
|
+
if (stylesContent) {
|
|
606
|
+
chunks.push({
|
|
607
|
+
id: "element-styles",
|
|
608
|
+
label: "Key Styles",
|
|
609
|
+
content: stylesContent,
|
|
610
|
+
type: "element",
|
|
611
|
+
included: true,
|
|
612
|
+
size: stylesContent.length
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
if (info.accessibility) {
|
|
617
|
+
const a11yContent = [
|
|
618
|
+
info.accessibility.role && `role="${info.accessibility.role}"`,
|
|
619
|
+
info.accessibility.accessibleName && `aria-label="${info.accessibility.accessibleName}"`
|
|
620
|
+
].filter(Boolean).join(", ");
|
|
621
|
+
if (a11yContent) {
|
|
622
|
+
chunks.push({
|
|
623
|
+
id: "element-a11y",
|
|
624
|
+
label: "Accessibility",
|
|
625
|
+
content: a11yContent,
|
|
626
|
+
type: "element",
|
|
627
|
+
included: true,
|
|
628
|
+
size: a11yContent.length
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
if (info.boxModel) {
|
|
633
|
+
const boxContent = `${Math.round(info.boxModel.content.width)}x${Math.round(info.boxModel.content.height)}px`;
|
|
634
|
+
chunks.push({
|
|
635
|
+
id: "element-dimensions",
|
|
636
|
+
label: "Dimensions",
|
|
637
|
+
content: boxContent,
|
|
638
|
+
type: "element",
|
|
639
|
+
included: true,
|
|
640
|
+
size: boxContent.length
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
} catch (error) {
|
|
644
|
+
console.error("Failed to extract context:", error);
|
|
645
|
+
}
|
|
646
|
+
return chunks;
|
|
647
|
+
}
|
|
648
|
+
function buildContextString(chunks) {
|
|
649
|
+
const includedChunks = chunks.filter((c) => c.included);
|
|
650
|
+
if (includedChunks.length === 0) return "";
|
|
651
|
+
return includedChunks.map((c) => `[${c.label}]: ${c.content}`).join("\n");
|
|
652
|
+
}
|
|
653
|
+
function useQuickChat(targetElement, containerElement, config = {}) {
|
|
654
|
+
const mergedConfig = { ...DEFAULT_QUICK_CHAT_CONFIG, ...config };
|
|
655
|
+
const abortControllerRef = useRef(null);
|
|
656
|
+
const initializedRef = useRef(false);
|
|
657
|
+
const [state, setState] = useState({
|
|
658
|
+
input: "",
|
|
659
|
+
messages: [],
|
|
660
|
+
isLoadingSuggestions: false,
|
|
661
|
+
isSending: false,
|
|
662
|
+
isStreaming: false,
|
|
663
|
+
suggestedPrompts: [],
|
|
664
|
+
contextChunks: [],
|
|
665
|
+
error: null
|
|
666
|
+
});
|
|
667
|
+
useEffect(() => {
|
|
668
|
+
if (initializedRef.current) return;
|
|
669
|
+
initializedRef.current = true;
|
|
670
|
+
const isPinned = getPinnedState();
|
|
671
|
+
if (isPinned) {
|
|
672
|
+
const history = getChatHistory();
|
|
673
|
+
if (history.length > 0) {
|
|
674
|
+
setState((prev) => ({ ...prev, messages: history }));
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}, []);
|
|
678
|
+
useEffect(() => {
|
|
679
|
+
if (targetElement) {
|
|
680
|
+
const chunks = extractContextChunks(targetElement, containerElement);
|
|
681
|
+
setState((prev) => ({ ...prev, contextChunks: chunks }));
|
|
682
|
+
}
|
|
683
|
+
}, [targetElement, containerElement]);
|
|
684
|
+
useEffect(() => {
|
|
685
|
+
if (!mergedConfig.showSuggestions || state.contextChunks.length === 0 || state.suggestedPrompts.length > 0) {
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
const fetchSuggestions = async () => {
|
|
689
|
+
setState((prev) => ({ ...prev, isLoadingSuggestions: true }));
|
|
690
|
+
try {
|
|
691
|
+
const contextString = buildContextString(state.contextChunks);
|
|
692
|
+
const response = await fetch(mergedConfig.endpoint, {
|
|
693
|
+
method: "POST",
|
|
694
|
+
headers: { "Content-Type": "application/json" },
|
|
695
|
+
body: JSON.stringify({
|
|
696
|
+
action: "suggest",
|
|
697
|
+
context: contextString,
|
|
698
|
+
model: mergedConfig.prePassModel
|
|
699
|
+
})
|
|
700
|
+
});
|
|
701
|
+
if (response.ok) {
|
|
702
|
+
const data = await response.json();
|
|
703
|
+
if (data.suggestions && Array.isArray(data.suggestions)) {
|
|
704
|
+
setState((prev) => ({
|
|
705
|
+
...prev,
|
|
706
|
+
suggestedPrompts: data.suggestions.map(
|
|
707
|
+
(text, i) => ({
|
|
708
|
+
id: `suggestion-${i}`,
|
|
709
|
+
text
|
|
710
|
+
})
|
|
711
|
+
),
|
|
712
|
+
isLoadingSuggestions: false
|
|
713
|
+
}));
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
} catch (error) {
|
|
718
|
+
console.error("Failed to fetch suggestions:", error);
|
|
719
|
+
}
|
|
720
|
+
setState((prev) => ({
|
|
721
|
+
...prev,
|
|
722
|
+
suggestedPrompts: [
|
|
723
|
+
{ id: "s1", text: "What is this element?" },
|
|
724
|
+
{ id: "s2", text: "How can I style this?" },
|
|
725
|
+
{ id: "s3", text: "Is this accessible?" }
|
|
726
|
+
],
|
|
727
|
+
isLoadingSuggestions: false
|
|
728
|
+
}));
|
|
729
|
+
};
|
|
730
|
+
fetchSuggestions();
|
|
731
|
+
}, [
|
|
732
|
+
state.contextChunks,
|
|
733
|
+
state.suggestedPrompts.length,
|
|
734
|
+
mergedConfig.showSuggestions,
|
|
735
|
+
mergedConfig.endpoint,
|
|
736
|
+
mergedConfig.prePassModel
|
|
737
|
+
]);
|
|
738
|
+
const setInput = useCallback((value) => {
|
|
739
|
+
setState((prev) => ({ ...prev, input: value }));
|
|
740
|
+
}, []);
|
|
741
|
+
const toggleChunk = useCallback((chunkId) => {
|
|
742
|
+
setState((prev) => ({
|
|
743
|
+
...prev,
|
|
744
|
+
contextChunks: prev.contextChunks.map(
|
|
745
|
+
(chunk) => chunk.id === chunkId ? { ...chunk, included: !chunk.included } : chunk
|
|
746
|
+
)
|
|
747
|
+
}));
|
|
748
|
+
}, []);
|
|
749
|
+
const toggleAllChunks = useCallback((included) => {
|
|
750
|
+
setState((prev) => ({
|
|
751
|
+
...prev,
|
|
752
|
+
contextChunks: prev.contextChunks.map((chunk) => ({
|
|
753
|
+
...chunk,
|
|
754
|
+
included
|
|
755
|
+
}))
|
|
756
|
+
}));
|
|
757
|
+
}, []);
|
|
758
|
+
const selectSuggestion = useCallback((prompt) => {
|
|
759
|
+
setState((prev) => ({ ...prev, input: prompt.text }));
|
|
760
|
+
}, []);
|
|
761
|
+
const sendMessage = useCallback(
|
|
762
|
+
async (messageText) => {
|
|
763
|
+
const text = (messageText || state.input).trim();
|
|
764
|
+
if (!text) return;
|
|
765
|
+
if (abortControllerRef.current) {
|
|
766
|
+
abortControllerRef.current.abort();
|
|
767
|
+
}
|
|
768
|
+
abortControllerRef.current = new AbortController();
|
|
769
|
+
const userMessage = {
|
|
770
|
+
id: generateId(),
|
|
771
|
+
role: "user",
|
|
772
|
+
content: text,
|
|
773
|
+
timestamp: Date.now()
|
|
774
|
+
};
|
|
775
|
+
const assistantMessageId = generateId();
|
|
776
|
+
const assistantMessage = {
|
|
777
|
+
id: assistantMessageId,
|
|
778
|
+
role: "assistant",
|
|
779
|
+
content: "",
|
|
780
|
+
timestamp: Date.now(),
|
|
781
|
+
isStreaming: true
|
|
782
|
+
};
|
|
783
|
+
setState((prev) => ({
|
|
784
|
+
...prev,
|
|
785
|
+
input: "",
|
|
786
|
+
messages: [...prev.messages, userMessage, assistantMessage],
|
|
787
|
+
isSending: true,
|
|
788
|
+
isStreaming: true,
|
|
789
|
+
error: null
|
|
790
|
+
}));
|
|
791
|
+
try {
|
|
792
|
+
const contextString = buildContextString(state.contextChunks);
|
|
793
|
+
const response = await fetch(mergedConfig.endpoint, {
|
|
794
|
+
method: "POST",
|
|
795
|
+
headers: { "Content-Type": "application/json" },
|
|
796
|
+
body: JSON.stringify({
|
|
797
|
+
action: "chat",
|
|
798
|
+
message: text,
|
|
799
|
+
context: contextString,
|
|
800
|
+
model: mergedConfig.model,
|
|
801
|
+
systemPrompt: mergedConfig.systemPrompt,
|
|
802
|
+
maxLength: mergedConfig.maxResponseLength
|
|
803
|
+
}),
|
|
804
|
+
signal: abortControllerRef.current.signal
|
|
805
|
+
});
|
|
806
|
+
if (!response.ok) {
|
|
807
|
+
throw new Error(`Request failed: ${response.status}`);
|
|
808
|
+
}
|
|
809
|
+
const reader = response.body?.getReader();
|
|
810
|
+
if (!reader) {
|
|
811
|
+
throw new Error("No response body");
|
|
812
|
+
}
|
|
813
|
+
const decoder = new TextDecoder();
|
|
814
|
+
let fullContent = "";
|
|
815
|
+
while (true) {
|
|
816
|
+
const { done, value } = await reader.read();
|
|
817
|
+
if (done) break;
|
|
818
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
819
|
+
fullContent += chunk;
|
|
820
|
+
if (fullContent.length > mergedConfig.maxResponseLength) {
|
|
821
|
+
fullContent = fullContent.slice(0, mergedConfig.maxResponseLength) + "...";
|
|
822
|
+
}
|
|
823
|
+
setState((prev) => ({
|
|
824
|
+
...prev,
|
|
825
|
+
messages: prev.messages.map(
|
|
826
|
+
(msg) => msg.id === assistantMessageId ? { ...msg, content: fullContent } : msg
|
|
827
|
+
)
|
|
828
|
+
}));
|
|
829
|
+
}
|
|
830
|
+
setState((prev) => ({
|
|
831
|
+
...prev,
|
|
832
|
+
messages: prev.messages.map(
|
|
833
|
+
(msg) => msg.id === assistantMessageId ? {
|
|
834
|
+
...msg,
|
|
835
|
+
content: fullContent,
|
|
836
|
+
isStreaming: false,
|
|
837
|
+
actions: [
|
|
838
|
+
{
|
|
839
|
+
id: "copy",
|
|
840
|
+
label: "Copy",
|
|
841
|
+
onClick: () => {
|
|
842
|
+
navigator.clipboard.writeText(fullContent);
|
|
843
|
+
}
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
id: "research",
|
|
847
|
+
label: "Research more",
|
|
848
|
+
onClick: () => {
|
|
849
|
+
setState((p) => ({
|
|
850
|
+
...p,
|
|
851
|
+
input: `Tell me more about: ${text}`
|
|
852
|
+
}));
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
]
|
|
856
|
+
} : msg
|
|
857
|
+
),
|
|
858
|
+
isSending: false,
|
|
859
|
+
isStreaming: false
|
|
860
|
+
}));
|
|
861
|
+
} catch (error) {
|
|
862
|
+
if (error.name === "AbortError") {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
console.error("Chat error:", error);
|
|
866
|
+
setState((prev) => ({
|
|
867
|
+
...prev,
|
|
868
|
+
messages: prev.messages.map(
|
|
869
|
+
(msg) => msg.id === assistantMessageId ? {
|
|
870
|
+
...msg,
|
|
871
|
+
content: "Sorry, I couldn't process your request. Please try again.",
|
|
872
|
+
isStreaming: false
|
|
873
|
+
} : msg
|
|
874
|
+
),
|
|
875
|
+
isSending: false,
|
|
876
|
+
isStreaming: false,
|
|
877
|
+
error: error.message
|
|
878
|
+
}));
|
|
879
|
+
}
|
|
880
|
+
},
|
|
881
|
+
[state.input, state.contextChunks, mergedConfig]
|
|
882
|
+
);
|
|
883
|
+
const clearMessages = useCallback(() => {
|
|
884
|
+
if (abortControllerRef.current) {
|
|
885
|
+
abortControllerRef.current.abort();
|
|
886
|
+
}
|
|
887
|
+
clearChatHistory();
|
|
888
|
+
setState((prev) => ({
|
|
889
|
+
...prev,
|
|
890
|
+
messages: [],
|
|
891
|
+
error: null
|
|
892
|
+
}));
|
|
893
|
+
}, []);
|
|
894
|
+
useEffect(() => {
|
|
895
|
+
if (state.messages.length > 0 && getPinnedState()) {
|
|
896
|
+
const completedMessages = state.messages.filter(
|
|
897
|
+
(msg) => !msg.isStreaming
|
|
898
|
+
);
|
|
899
|
+
if (completedMessages.length > 0) {
|
|
900
|
+
saveChatHistory(completedMessages);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
}, [state.messages]);
|
|
904
|
+
useEffect(() => {
|
|
905
|
+
return () => {
|
|
906
|
+
if (abortControllerRef.current) {
|
|
907
|
+
abortControllerRef.current.abort();
|
|
908
|
+
}
|
|
909
|
+
};
|
|
910
|
+
}, []);
|
|
911
|
+
return {
|
|
912
|
+
...state,
|
|
913
|
+
config: mergedConfig,
|
|
914
|
+
setInput,
|
|
915
|
+
toggleChunk,
|
|
916
|
+
toggleAllChunks,
|
|
917
|
+
selectSuggestion,
|
|
918
|
+
sendMessage,
|
|
919
|
+
clearMessages
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// src/QuickChat/QuickChat.tsx
|
|
924
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
925
|
+
var PINNED_STATE_KEY2 = "anyclick-quick-chat-pinned";
|
|
926
|
+
function getStoredPinnedState() {
|
|
927
|
+
if (typeof window === "undefined") return false;
|
|
928
|
+
try {
|
|
929
|
+
return sessionStorage.getItem(PINNED_STATE_KEY2) === "true";
|
|
930
|
+
} catch {
|
|
931
|
+
return false;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
function setStoredPinnedState(pinned) {
|
|
935
|
+
if (typeof window === "undefined") return;
|
|
936
|
+
try {
|
|
937
|
+
if (pinned) {
|
|
938
|
+
sessionStorage.setItem(PINNED_STATE_KEY2, "true");
|
|
939
|
+
} else {
|
|
940
|
+
sessionStorage.removeItem(PINNED_STATE_KEY2);
|
|
941
|
+
}
|
|
942
|
+
} catch {
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
var stylesInjected = false;
|
|
946
|
+
function injectStyles() {
|
|
947
|
+
if (stylesInjected || typeof document === "undefined") return;
|
|
948
|
+
const style = document.createElement("style");
|
|
949
|
+
style.textContent = quickChatKeyframes;
|
|
950
|
+
document.head.appendChild(style);
|
|
951
|
+
stylesInjected = true;
|
|
952
|
+
}
|
|
953
|
+
var LoadingDots = React.memo(function LoadingDots2() {
|
|
954
|
+
return /* @__PURE__ */ jsx("div", { style: quickChatStyles.loadingDots, children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(
|
|
955
|
+
"div",
|
|
956
|
+
{
|
|
957
|
+
style: {
|
|
958
|
+
...quickChatStyles.loadingDot,
|
|
959
|
+
animationDelay: `${i * 0.16}s`
|
|
960
|
+
}
|
|
961
|
+
},
|
|
962
|
+
i
|
|
963
|
+
)) });
|
|
964
|
+
});
|
|
965
|
+
function QuickChat({
|
|
966
|
+
visible,
|
|
967
|
+
targetElement,
|
|
968
|
+
containerElement,
|
|
969
|
+
onClose,
|
|
970
|
+
onPin,
|
|
971
|
+
isPinned: isPinnedProp = false,
|
|
972
|
+
config,
|
|
973
|
+
style,
|
|
974
|
+
className,
|
|
975
|
+
initialInput,
|
|
976
|
+
onInitialInputConsumed
|
|
977
|
+
}) {
|
|
978
|
+
const inputRef = useRef2(null);
|
|
979
|
+
const messagesEndRef = useRef2(null);
|
|
980
|
+
const [inputFocused, setInputFocused] = useState2(false);
|
|
981
|
+
const [showContext, setShowContext] = useState2(false);
|
|
982
|
+
const [hoveredSuggestion, setHoveredSuggestion] = useState2(
|
|
983
|
+
null
|
|
984
|
+
);
|
|
985
|
+
const [localPinned, setLocalPinned] = useState2(() => getStoredPinnedState());
|
|
986
|
+
const isPinned = isPinnedProp || localPinned;
|
|
987
|
+
const handlePinToggle = useCallback2(() => {
|
|
988
|
+
const newPinned = !isPinned;
|
|
989
|
+
setLocalPinned(newPinned);
|
|
990
|
+
setStoredPinnedState(newPinned);
|
|
991
|
+
onPin?.(newPinned);
|
|
992
|
+
}, [isPinned, onPin]);
|
|
993
|
+
const handleClose = useCallback2(() => {
|
|
994
|
+
if (isPinned) {
|
|
995
|
+
setLocalPinned(false);
|
|
996
|
+
setStoredPinnedState(false);
|
|
997
|
+
onPin?.(false);
|
|
998
|
+
}
|
|
999
|
+
onClose();
|
|
1000
|
+
}, [isPinned, onPin, onClose]);
|
|
1001
|
+
const {
|
|
1002
|
+
input,
|
|
1003
|
+
messages,
|
|
1004
|
+
isLoadingSuggestions,
|
|
1005
|
+
isSending,
|
|
1006
|
+
isStreaming,
|
|
1007
|
+
suggestedPrompts,
|
|
1008
|
+
contextChunks,
|
|
1009
|
+
error,
|
|
1010
|
+
setInput,
|
|
1011
|
+
toggleChunk,
|
|
1012
|
+
toggleAllChunks,
|
|
1013
|
+
selectSuggestion,
|
|
1014
|
+
sendMessage,
|
|
1015
|
+
clearMessages,
|
|
1016
|
+
config: mergedConfig
|
|
1017
|
+
} = useQuickChat(targetElement, containerElement, config);
|
|
1018
|
+
useEffect2(() => {
|
|
1019
|
+
injectStyles();
|
|
1020
|
+
}, []);
|
|
1021
|
+
useEffect2(() => {
|
|
1022
|
+
if (visible && inputRef.current) {
|
|
1023
|
+
const timer = setTimeout(() => {
|
|
1024
|
+
inputRef.current?.focus();
|
|
1025
|
+
}, 100);
|
|
1026
|
+
return () => clearTimeout(timer);
|
|
1027
|
+
}
|
|
1028
|
+
}, [visible]);
|
|
1029
|
+
useEffect2(() => {
|
|
1030
|
+
if (initialInput && visible) {
|
|
1031
|
+
setInput(initialInput);
|
|
1032
|
+
onInitialInputConsumed?.();
|
|
1033
|
+
if (inputRef.current) {
|
|
1034
|
+
inputRef.current.focus();
|
|
1035
|
+
inputRef.current.setSelectionRange(
|
|
1036
|
+
initialInput.length,
|
|
1037
|
+
initialInput.length
|
|
1038
|
+
);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}, [initialInput, visible, setInput, onInitialInputConsumed]);
|
|
1042
|
+
useEffect2(() => {
|
|
1043
|
+
if (messagesEndRef.current) {
|
|
1044
|
+
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
|
|
1045
|
+
}
|
|
1046
|
+
}, [messages]);
|
|
1047
|
+
const handleInputChange = useCallback2(
|
|
1048
|
+
(e) => {
|
|
1049
|
+
setInput(e.target.value);
|
|
1050
|
+
const target = e.target;
|
|
1051
|
+
target.style.height = "auto";
|
|
1052
|
+
target.style.height = `${Math.min(target.scrollHeight, 80)}px`;
|
|
1053
|
+
},
|
|
1054
|
+
[setInput]
|
|
1055
|
+
);
|
|
1056
|
+
const handleKeyDown = useCallback2(
|
|
1057
|
+
(e) => {
|
|
1058
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
1059
|
+
e.preventDefault();
|
|
1060
|
+
sendMessage();
|
|
1061
|
+
} else if (e.key === "Escape") {
|
|
1062
|
+
onClose();
|
|
1063
|
+
}
|
|
1064
|
+
},
|
|
1065
|
+
[sendMessage, onClose]
|
|
1066
|
+
);
|
|
1067
|
+
const handleSend = useCallback2(() => {
|
|
1068
|
+
sendMessage();
|
|
1069
|
+
}, [sendMessage]);
|
|
1070
|
+
const handleSendToT3Chat = useCallback2(() => {
|
|
1071
|
+
if (typeof window === "undefined") return;
|
|
1072
|
+
const query = input.trim();
|
|
1073
|
+
const baseUrl = mergedConfig.t3chat?.baseUrl ?? "https://t3.chat";
|
|
1074
|
+
const url = query ? `${baseUrl}/?q=${encodeURIComponent(query)}` : baseUrl;
|
|
1075
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
1076
|
+
}, [input, mergedConfig.t3chat?.baseUrl]);
|
|
1077
|
+
const handleCopy = useCallback2((text) => {
|
|
1078
|
+
navigator.clipboard.writeText(text);
|
|
1079
|
+
}, []);
|
|
1080
|
+
const includedCount = useMemo(
|
|
1081
|
+
() => contextChunks.filter((c) => c.included).length,
|
|
1082
|
+
[contextChunks]
|
|
1083
|
+
);
|
|
1084
|
+
if (!visible) return null;
|
|
1085
|
+
const containerStyles = isPinned ? {
|
|
1086
|
+
...quickChatStyles.pinnedContainer,
|
|
1087
|
+
animation: "slideInFromRight 0.25s ease-out",
|
|
1088
|
+
...style
|
|
1089
|
+
} : {
|
|
1090
|
+
...quickChatStyles.container,
|
|
1091
|
+
animation: "fadeIn 0.15s ease-out",
|
|
1092
|
+
...style
|
|
1093
|
+
};
|
|
1094
|
+
return /* @__PURE__ */ jsxs("div", { className, style: containerStyles, children: [
|
|
1095
|
+
/* @__PURE__ */ jsxs(
|
|
1096
|
+
"div",
|
|
1097
|
+
{
|
|
1098
|
+
style: {
|
|
1099
|
+
...quickChatStyles.header,
|
|
1100
|
+
padding: isPinned ? "12px 12px 8px 12px" : "6px 8px"
|
|
1101
|
+
},
|
|
1102
|
+
children: [
|
|
1103
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
|
|
1104
|
+
!isPinned && /* @__PURE__ */ jsx(
|
|
1105
|
+
"button",
|
|
1106
|
+
{
|
|
1107
|
+
type: "button",
|
|
1108
|
+
onClick: onClose,
|
|
1109
|
+
style: {
|
|
1110
|
+
...quickChatStyles.iconButton,
|
|
1111
|
+
marginLeft: "-4px"
|
|
1112
|
+
},
|
|
1113
|
+
title: "Back to menu",
|
|
1114
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { size: 16 })
|
|
1115
|
+
}
|
|
1116
|
+
),
|
|
1117
|
+
mergedConfig.showRedactionUI && contextChunks.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1118
|
+
/* @__PURE__ */ jsxs(
|
|
1119
|
+
"button",
|
|
1120
|
+
{
|
|
1121
|
+
type: "button",
|
|
1122
|
+
onClick: () => setShowContext(!showContext),
|
|
1123
|
+
style: {
|
|
1124
|
+
...quickChatStyles.contextBadge,
|
|
1125
|
+
...showContext ? quickChatStyles.contextBadgeActive : {}
|
|
1126
|
+
},
|
|
1127
|
+
title: "Edit context",
|
|
1128
|
+
children: [
|
|
1129
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
1130
|
+
includedCount,
|
|
1131
|
+
"/",
|
|
1132
|
+
contextChunks.length
|
|
1133
|
+
] }),
|
|
1134
|
+
showContext ? /* @__PURE__ */ jsx(ChevronUp, { size: 10 }) : /* @__PURE__ */ jsx(ChevronDown, { size: 10 })
|
|
1135
|
+
]
|
|
1136
|
+
}
|
|
1137
|
+
),
|
|
1138
|
+
showContext && /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "2px" }, children: [
|
|
1139
|
+
/* @__PURE__ */ jsx(
|
|
1140
|
+
"button",
|
|
1141
|
+
{
|
|
1142
|
+
type: "button",
|
|
1143
|
+
onClick: () => toggleAllChunks(true),
|
|
1144
|
+
style: quickChatStyles.contextToggleSmall,
|
|
1145
|
+
title: "Include all",
|
|
1146
|
+
children: "All"
|
|
1147
|
+
}
|
|
1148
|
+
),
|
|
1149
|
+
/* @__PURE__ */ jsx(
|
|
1150
|
+
"button",
|
|
1151
|
+
{
|
|
1152
|
+
type: "button",
|
|
1153
|
+
onClick: () => toggleAllChunks(false),
|
|
1154
|
+
style: quickChatStyles.contextToggleSmall,
|
|
1155
|
+
title: "Exclude all",
|
|
1156
|
+
children: "None"
|
|
1157
|
+
}
|
|
1158
|
+
)
|
|
1159
|
+
] })
|
|
1160
|
+
] })
|
|
1161
|
+
] }),
|
|
1162
|
+
/* @__PURE__ */ jsxs("div", { style: quickChatStyles.headerActions, children: [
|
|
1163
|
+
messages.length > 0 && /* @__PURE__ */ jsx(
|
|
1164
|
+
"button",
|
|
1165
|
+
{
|
|
1166
|
+
type: "button",
|
|
1167
|
+
onClick: clearMessages,
|
|
1168
|
+
style: quickChatStyles.iconButton,
|
|
1169
|
+
title: "Clear chat",
|
|
1170
|
+
children: /* @__PURE__ */ jsx(RefreshCw, { size: 14 })
|
|
1171
|
+
}
|
|
1172
|
+
),
|
|
1173
|
+
/* @__PURE__ */ jsx(
|
|
1174
|
+
"button",
|
|
1175
|
+
{
|
|
1176
|
+
type: "button",
|
|
1177
|
+
onClick: handlePinToggle,
|
|
1178
|
+
style: {
|
|
1179
|
+
...quickChatStyles.iconButton,
|
|
1180
|
+
...isPinned ? quickChatStyles.iconButtonActive : {}
|
|
1181
|
+
},
|
|
1182
|
+
title: isPinned ? "Unpin (closes with menu)" : "Pin (stays open)",
|
|
1183
|
+
children: isPinned ? /* @__PURE__ */ jsx(PinOff, { size: 14 }) : /* @__PURE__ */ jsx(Pin, { size: 14 })
|
|
1184
|
+
}
|
|
1185
|
+
),
|
|
1186
|
+
/* @__PURE__ */ jsx(
|
|
1187
|
+
"button",
|
|
1188
|
+
{
|
|
1189
|
+
type: "button",
|
|
1190
|
+
onClick: handleClose,
|
|
1191
|
+
style: quickChatStyles.iconButton,
|
|
1192
|
+
title: "Close",
|
|
1193
|
+
children: /* @__PURE__ */ jsx(X, { size: 14 })
|
|
1194
|
+
}
|
|
1195
|
+
)
|
|
1196
|
+
] })
|
|
1197
|
+
]
|
|
1198
|
+
}
|
|
1199
|
+
),
|
|
1200
|
+
showContext && contextChunks.length > 0 && /* @__PURE__ */ jsx("div", { style: quickChatStyles.contextDropdown, children: contextChunks.map((chunk) => /* @__PURE__ */ jsxs(
|
|
1201
|
+
"label",
|
|
1202
|
+
{
|
|
1203
|
+
style: {
|
|
1204
|
+
...quickChatStyles.contextChunkCompact,
|
|
1205
|
+
...chunk.included ? {} : quickChatStyles.contextChunkExcluded
|
|
1206
|
+
},
|
|
1207
|
+
children: [
|
|
1208
|
+
/* @__PURE__ */ jsx(
|
|
1209
|
+
"input",
|
|
1210
|
+
{
|
|
1211
|
+
type: "checkbox",
|
|
1212
|
+
checked: chunk.included,
|
|
1213
|
+
onChange: () => toggleChunk(chunk.id),
|
|
1214
|
+
style: quickChatStyles.contextCheckbox
|
|
1215
|
+
}
|
|
1216
|
+
),
|
|
1217
|
+
/* @__PURE__ */ jsx("span", { style: quickChatStyles.contextLabel, children: chunk.label })
|
|
1218
|
+
]
|
|
1219
|
+
},
|
|
1220
|
+
chunk.id
|
|
1221
|
+
)) }),
|
|
1222
|
+
mergedConfig.showSuggestions && messages.length === 0 && suggestedPrompts.length > 0 && /* @__PURE__ */ jsx("div", { style: quickChatStyles.suggestionsContainer, children: isLoadingSuggestions ? /* @__PURE__ */ jsx(LoadingDots, {}) : suggestedPrompts.map((prompt) => /* @__PURE__ */ jsx(
|
|
1223
|
+
"button",
|
|
1224
|
+
{
|
|
1225
|
+
type: "button",
|
|
1226
|
+
onClick: () => selectSuggestion(prompt),
|
|
1227
|
+
onMouseEnter: () => setHoveredSuggestion(prompt.id),
|
|
1228
|
+
onMouseLeave: () => setHoveredSuggestion(null),
|
|
1229
|
+
style: {
|
|
1230
|
+
...quickChatStyles.suggestionChip,
|
|
1231
|
+
...hoveredSuggestion === prompt.id ? quickChatStyles.suggestionChipHover : {}
|
|
1232
|
+
},
|
|
1233
|
+
children: prompt.text
|
|
1234
|
+
},
|
|
1235
|
+
prompt.id
|
|
1236
|
+
)) }),
|
|
1237
|
+
/* @__PURE__ */ jsxs(
|
|
1238
|
+
"div",
|
|
1239
|
+
{
|
|
1240
|
+
style: isPinned ? quickChatStyles.pinnedMessagesArea : quickChatStyles.messagesArea,
|
|
1241
|
+
children: [
|
|
1242
|
+
error && /* @__PURE__ */ jsxs("div", { style: quickChatStyles.errorContainer, children: [
|
|
1243
|
+
/* @__PURE__ */ jsx(AlertCircle, { size: 20, style: quickChatStyles.errorIcon }),
|
|
1244
|
+
/* @__PURE__ */ jsx("span", { style: quickChatStyles.errorText, children: error }),
|
|
1245
|
+
/* @__PURE__ */ jsxs(
|
|
1246
|
+
"button",
|
|
1247
|
+
{
|
|
1248
|
+
type: "button",
|
|
1249
|
+
onClick: () => sendMessage(),
|
|
1250
|
+
style: quickChatStyles.errorRetry,
|
|
1251
|
+
children: [
|
|
1252
|
+
/* @__PURE__ */ jsx(RefreshCw, { size: 10 }),
|
|
1253
|
+
"Retry"
|
|
1254
|
+
]
|
|
1255
|
+
}
|
|
1256
|
+
)
|
|
1257
|
+
] }),
|
|
1258
|
+
messages.length > 0 && messages.map((message) => /* @__PURE__ */ jsxs(
|
|
1259
|
+
"div",
|
|
1260
|
+
{
|
|
1261
|
+
style: {
|
|
1262
|
+
...quickChatStyles.message,
|
|
1263
|
+
animation: "fadeIn 0.2s ease-out"
|
|
1264
|
+
},
|
|
1265
|
+
children: [
|
|
1266
|
+
/* @__PURE__ */ jsxs(
|
|
1267
|
+
"div",
|
|
1268
|
+
{
|
|
1269
|
+
style: message.role === "user" ? quickChatStyles.messageUser : quickChatStyles.messageAssistant,
|
|
1270
|
+
children: [
|
|
1271
|
+
message.content,
|
|
1272
|
+
message.isStreaming && /* @__PURE__ */ jsx("span", { style: quickChatStyles.streamingIndicator }),
|
|
1273
|
+
message.role === "assistant" && !message.isStreaming && message.content.endsWith("...") && /* @__PURE__ */ jsx("span", { style: quickChatStyles.truncated, children: "(truncated)" })
|
|
1274
|
+
]
|
|
1275
|
+
}
|
|
1276
|
+
),
|
|
1277
|
+
message.role === "assistant" && !message.isStreaming && message.content && /* @__PURE__ */ jsxs("div", { style: quickChatStyles.messageActions, children: [
|
|
1278
|
+
/* @__PURE__ */ jsxs(
|
|
1279
|
+
"button",
|
|
1280
|
+
{
|
|
1281
|
+
type: "button",
|
|
1282
|
+
onClick: () => handleCopy(message.content),
|
|
1283
|
+
style: quickChatStyles.actionButton,
|
|
1284
|
+
children: [
|
|
1285
|
+
/* @__PURE__ */ jsx(Copy, { size: 10 }),
|
|
1286
|
+
"Copy"
|
|
1287
|
+
]
|
|
1288
|
+
}
|
|
1289
|
+
),
|
|
1290
|
+
message.actions?.map((action) => /* @__PURE__ */ jsxs(
|
|
1291
|
+
"button",
|
|
1292
|
+
{
|
|
1293
|
+
type: "button",
|
|
1294
|
+
onClick: action.onClick,
|
|
1295
|
+
style: quickChatStyles.actionButton,
|
|
1296
|
+
children: [
|
|
1297
|
+
action.icon,
|
|
1298
|
+
action.label
|
|
1299
|
+
]
|
|
1300
|
+
},
|
|
1301
|
+
action.id
|
|
1302
|
+
))
|
|
1303
|
+
] })
|
|
1304
|
+
]
|
|
1305
|
+
},
|
|
1306
|
+
message.id
|
|
1307
|
+
)),
|
|
1308
|
+
/* @__PURE__ */ jsx("div", { ref: messagesEndRef })
|
|
1309
|
+
]
|
|
1310
|
+
}
|
|
1311
|
+
),
|
|
1312
|
+
/* @__PURE__ */ jsxs("div", { style: quickChatStyles.inputContainer, children: [
|
|
1313
|
+
/* @__PURE__ */ jsx(
|
|
1314
|
+
"textarea",
|
|
1315
|
+
{
|
|
1316
|
+
ref: inputRef,
|
|
1317
|
+
value: input,
|
|
1318
|
+
onChange: handleInputChange,
|
|
1319
|
+
onKeyDown: handleKeyDown,
|
|
1320
|
+
onFocus: () => setInputFocused(true),
|
|
1321
|
+
onBlur: () => setInputFocused(false),
|
|
1322
|
+
placeholder: mergedConfig.placeholder,
|
|
1323
|
+
disabled: isSending,
|
|
1324
|
+
rows: 1,
|
|
1325
|
+
style: {
|
|
1326
|
+
...quickChatStyles.input,
|
|
1327
|
+
...inputFocused ? quickChatStyles.inputFocused : {}
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
),
|
|
1331
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "4px" }, children: [
|
|
1332
|
+
mergedConfig.t3chat?.enabled !== false && /* @__PURE__ */ jsx(
|
|
1333
|
+
"button",
|
|
1334
|
+
{
|
|
1335
|
+
type: "button",
|
|
1336
|
+
onClick: handleSendToT3Chat,
|
|
1337
|
+
disabled: !input.trim(),
|
|
1338
|
+
title: mergedConfig.t3chat?.label ?? "Ask t3.chat",
|
|
1339
|
+
style: {
|
|
1340
|
+
...quickChatStyles.sendButton,
|
|
1341
|
+
backgroundColor: "#7c3aed",
|
|
1342
|
+
...!input.trim() ? quickChatStyles.sendButtonDisabled : {}
|
|
1343
|
+
},
|
|
1344
|
+
children: /* @__PURE__ */ jsx(ExternalLink, { size: 14 })
|
|
1345
|
+
}
|
|
1346
|
+
),
|
|
1347
|
+
/* @__PURE__ */ jsx(
|
|
1348
|
+
"button",
|
|
1349
|
+
{
|
|
1350
|
+
type: "button",
|
|
1351
|
+
onClick: handleSend,
|
|
1352
|
+
disabled: isSending || !input.trim(),
|
|
1353
|
+
style: {
|
|
1354
|
+
...quickChatStyles.sendButton,
|
|
1355
|
+
...isSending || !input.trim() ? quickChatStyles.sendButtonDisabled : {}
|
|
1356
|
+
},
|
|
1357
|
+
children: isSending ? /* @__PURE__ */ jsx(
|
|
1358
|
+
"div",
|
|
1359
|
+
{
|
|
1360
|
+
style: {
|
|
1361
|
+
width: "14px",
|
|
1362
|
+
height: "14px",
|
|
1363
|
+
border: "2px solid transparent",
|
|
1364
|
+
borderTopColor: "#fff",
|
|
1365
|
+
borderRadius: "50%",
|
|
1366
|
+
animation: "spin 0.8s linear infinite"
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
) : /* @__PURE__ */ jsx(Send, { size: 14 })
|
|
1370
|
+
}
|
|
1371
|
+
)
|
|
1372
|
+
] })
|
|
1373
|
+
] })
|
|
1374
|
+
] });
|
|
1375
|
+
}
|
|
1376
|
+
|
|
32
1377
|
// src/ScreenshotPreview.tsx
|
|
33
|
-
import
|
|
1378
|
+
import React2, { useMemo as useMemo2, useState as useState3 } from "react";
|
|
34
1379
|
import { estimateTotalSize, formatBytes } from "@ewjdev/anyclick-core";
|
|
35
1380
|
import {
|
|
36
1381
|
AlertCircleIcon,
|
|
@@ -516,8 +1861,8 @@ var screenshotPreviewStyles = {
|
|
|
516
1861
|
};
|
|
517
1862
|
|
|
518
1863
|
// src/ScreenshotPreview.tsx
|
|
519
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
520
|
-
var ScreenshotPreview =
|
|
1864
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1865
|
+
var ScreenshotPreview = React2.memo(function ScreenshotPreview2({
|
|
521
1866
|
isLoading,
|
|
522
1867
|
isSubmitting,
|
|
523
1868
|
onCancel,
|
|
@@ -525,12 +1870,12 @@ var ScreenshotPreview = React.memo(function ScreenshotPreview2({
|
|
|
525
1870
|
onRetake,
|
|
526
1871
|
screenshots
|
|
527
1872
|
}) {
|
|
528
|
-
const [activeTab, setActiveTab] =
|
|
529
|
-
const [isExpanded, setIsExpanded] =
|
|
1873
|
+
const [activeTab, setActiveTab] = useState3("element");
|
|
1874
|
+
const [isExpanded, setIsExpanded] = useState3(false);
|
|
530
1875
|
const getError = (key) => {
|
|
531
1876
|
return screenshots?.errors?.[key];
|
|
532
1877
|
};
|
|
533
|
-
const tabs =
|
|
1878
|
+
const tabs = useMemo2(() => {
|
|
534
1879
|
if (!screenshots) return [];
|
|
535
1880
|
const allTabs = [
|
|
536
1881
|
{
|
|
@@ -554,29 +1899,29 @@ var ScreenshotPreview = React.memo(function ScreenshotPreview2({
|
|
|
554
1899
|
];
|
|
555
1900
|
return allTabs.filter((tab) => tab.data || tab.error);
|
|
556
1901
|
}, [screenshots]);
|
|
557
|
-
const totalSize =
|
|
1902
|
+
const totalSize = useMemo2(
|
|
558
1903
|
() => screenshots ? estimateTotalSize(screenshots) : 0,
|
|
559
1904
|
[screenshots]
|
|
560
1905
|
);
|
|
561
1906
|
if (isLoading) {
|
|
562
|
-
return /* @__PURE__ */
|
|
563
|
-
/* @__PURE__ */
|
|
1907
|
+
return /* @__PURE__ */ jsx2("div", { style: screenshotPreviewStyles.container, children: /* @__PURE__ */ jsxs2("div", { style: screenshotPreviewStyles.loadingContainer, children: [
|
|
1908
|
+
/* @__PURE__ */ jsx2(
|
|
564
1909
|
Loader2Icon,
|
|
565
1910
|
{
|
|
566
1911
|
className: "w-6 h-6 animate-spin",
|
|
567
1912
|
style: { color: "#3b82f6" }
|
|
568
1913
|
}
|
|
569
1914
|
),
|
|
570
|
-
/* @__PURE__ */
|
|
1915
|
+
/* @__PURE__ */ jsx2("span", { style: screenshotPreviewStyles.loadingText, children: "Capturing screenshots..." })
|
|
571
1916
|
] }) });
|
|
572
1917
|
}
|
|
573
1918
|
if (!screenshots) {
|
|
574
|
-
return /* @__PURE__ */
|
|
575
|
-
/* @__PURE__ */
|
|
576
|
-
/* @__PURE__ */
|
|
577
|
-
/* @__PURE__ */
|
|
578
|
-
/* @__PURE__ */
|
|
579
|
-
/* @__PURE__ */
|
|
1919
|
+
return /* @__PURE__ */ jsx2("div", { style: screenshotPreviewStyles.container, children: /* @__PURE__ */ jsxs2("div", { style: screenshotPreviewStyles.emptyContainer, children: [
|
|
1920
|
+
/* @__PURE__ */ jsx2(ImageIcon, { className: "w-8 h-8", style: { color: "#9ca3af" } }),
|
|
1921
|
+
/* @__PURE__ */ jsx2("span", { style: screenshotPreviewStyles.emptyText, children: "Screenshots unavailable" }),
|
|
1922
|
+
/* @__PURE__ */ jsx2("span", { style: screenshotPreviewStyles.emptySubtext, children: "Some elements can't be captured (e.g., gradient text)" }),
|
|
1923
|
+
/* @__PURE__ */ jsxs2("div", { style: screenshotPreviewStyles.emptyActions, children: [
|
|
1924
|
+
/* @__PURE__ */ jsxs2(
|
|
580
1925
|
"button",
|
|
581
1926
|
{
|
|
582
1927
|
type: "button",
|
|
@@ -584,12 +1929,12 @@ var ScreenshotPreview = React.memo(function ScreenshotPreview2({
|
|
|
584
1929
|
onClick: onRetake,
|
|
585
1930
|
style: screenshotPreviewStyles.retakeButtonOutline,
|
|
586
1931
|
children: [
|
|
587
|
-
/* @__PURE__ */
|
|
1932
|
+
/* @__PURE__ */ jsx2(RefreshCwIcon, { className: "w-4 h-4" }),
|
|
588
1933
|
"Try Again"
|
|
589
1934
|
]
|
|
590
1935
|
}
|
|
591
1936
|
),
|
|
592
|
-
/* @__PURE__ */
|
|
1937
|
+
/* @__PURE__ */ jsxs2(
|
|
593
1938
|
"button",
|
|
594
1939
|
{
|
|
595
1940
|
type: "button",
|
|
@@ -597,7 +1942,7 @@ var ScreenshotPreview = React.memo(function ScreenshotPreview2({
|
|
|
597
1942
|
onClick: () => onConfirm({ capturedAt: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
598
1943
|
style: screenshotPreviewStyles.continueButton,
|
|
599
1944
|
children: [
|
|
600
|
-
/* @__PURE__ */
|
|
1945
|
+
/* @__PURE__ */ jsx2(CheckIcon, { className: "w-4 h-4" }),
|
|
601
1946
|
"Continue Without"
|
|
602
1947
|
]
|
|
603
1948
|
}
|
|
@@ -607,7 +1952,7 @@ var ScreenshotPreview = React.memo(function ScreenshotPreview2({
|
|
|
607
1952
|
}
|
|
608
1953
|
const activeScreenshot = activeTab === "element" ? screenshots.element : activeTab === "container" ? screenshots.container : screenshots.viewport;
|
|
609
1954
|
const activeError = getError(activeTab);
|
|
610
|
-
return /* @__PURE__ */
|
|
1955
|
+
return /* @__PURE__ */ jsxs2(
|
|
611
1956
|
"div",
|
|
612
1957
|
{
|
|
613
1958
|
style: {
|
|
@@ -616,23 +1961,23 @@ var ScreenshotPreview = React.memo(function ScreenshotPreview2({
|
|
|
616
1961
|
padding: "8px"
|
|
617
1962
|
},
|
|
618
1963
|
children: [
|
|
619
|
-
/* @__PURE__ */
|
|
620
|
-
/* @__PURE__ */
|
|
621
|
-
/* @__PURE__ */
|
|
622
|
-
/* @__PURE__ */
|
|
623
|
-
/* @__PURE__ */
|
|
1964
|
+
/* @__PURE__ */ jsxs2("div", { style: screenshotPreviewStyles.header, children: [
|
|
1965
|
+
/* @__PURE__ */ jsx2("span", { style: screenshotPreviewStyles.headerTitle, children: "Review Screenshots" }),
|
|
1966
|
+
/* @__PURE__ */ jsxs2("div", { style: screenshotPreviewStyles.headerActions, children: [
|
|
1967
|
+
/* @__PURE__ */ jsx2("span", { style: screenshotPreviewStyles.sizeLabel, children: formatBytes(totalSize) }),
|
|
1968
|
+
/* @__PURE__ */ jsx2(
|
|
624
1969
|
"button",
|
|
625
1970
|
{
|
|
626
1971
|
type: "button",
|
|
627
1972
|
onClick: () => setIsExpanded(!isExpanded),
|
|
628
1973
|
style: screenshotPreviewStyles.iconButton,
|
|
629
1974
|
title: isExpanded ? "Collapse" : "Expand",
|
|
630
|
-
children: isExpanded ? /* @__PURE__ */
|
|
1975
|
+
children: isExpanded ? /* @__PURE__ */ jsx2(ShrinkIcon, { className: "w-4 h-4" }) : /* @__PURE__ */ jsx2(ExpandIcon, { className: "w-4 h-4" })
|
|
631
1976
|
}
|
|
632
1977
|
)
|
|
633
1978
|
] })
|
|
634
1979
|
] }),
|
|
635
|
-
/* @__PURE__ */
|
|
1980
|
+
/* @__PURE__ */ jsx2("div", { style: screenshotPreviewStyles.tabContainer, children: tabs.map((tab) => /* @__PURE__ */ jsxs2(
|
|
636
1981
|
"button",
|
|
637
1982
|
{
|
|
638
1983
|
type: "button",
|
|
@@ -643,7 +1988,7 @@ var ScreenshotPreview = React.memo(function ScreenshotPreview2({
|
|
|
643
1988
|
...tab.error && !tab.data ? screenshotPreviewStyles.tabError : {}
|
|
644
1989
|
},
|
|
645
1990
|
children: [
|
|
646
|
-
tab.error && !tab.data && /* @__PURE__ */
|
|
1991
|
+
tab.error && !tab.data && /* @__PURE__ */ jsx2(
|
|
647
1992
|
AlertCircleIcon,
|
|
648
1993
|
{
|
|
649
1994
|
className: "w-3 h-3",
|
|
@@ -651,32 +1996,32 @@ var ScreenshotPreview = React.memo(function ScreenshotPreview2({
|
|
|
651
1996
|
}
|
|
652
1997
|
),
|
|
653
1998
|
tab.label,
|
|
654
|
-
tab.data && /* @__PURE__ */
|
|
1999
|
+
tab.data && /* @__PURE__ */ jsx2("span", { style: screenshotPreviewStyles.tabSize, children: formatBytes(tab.data.sizeBytes) })
|
|
655
2000
|
]
|
|
656
2001
|
},
|
|
657
2002
|
tab.key
|
|
658
2003
|
)) }),
|
|
659
|
-
/* @__PURE__ */
|
|
2004
|
+
/* @__PURE__ */ jsx2(
|
|
660
2005
|
"div",
|
|
661
2006
|
{
|
|
662
2007
|
style: {
|
|
663
2008
|
...screenshotPreviewStyles.previewContainer,
|
|
664
2009
|
...isExpanded ? screenshotPreviewStyles.previewContainerExpanded : {}
|
|
665
2010
|
},
|
|
666
|
-
children: activeScreenshot ? /* @__PURE__ */
|
|
2011
|
+
children: activeScreenshot ? /* @__PURE__ */ jsx2(
|
|
667
2012
|
"img",
|
|
668
2013
|
{
|
|
669
2014
|
alt: `${activeTab} screenshot`,
|
|
670
2015
|
src: activeScreenshot.dataUrl,
|
|
671
2016
|
style: screenshotPreviewStyles.previewImage
|
|
672
2017
|
}
|
|
673
|
-
) : activeError ? /* @__PURE__ */
|
|
674
|
-
/* @__PURE__ */
|
|
675
|
-
/* @__PURE__ */
|
|
676
|
-
/* @__PURE__ */
|
|
677
|
-
] }) : /* @__PURE__ */
|
|
678
|
-
/* @__PURE__ */
|
|
679
|
-
/* @__PURE__ */
|
|
2018
|
+
) : activeError ? /* @__PURE__ */ jsxs2("div", { style: screenshotPreviewStyles.errorPreview, children: [
|
|
2019
|
+
/* @__PURE__ */ jsx2(AlertCircleIcon, { className: "w-8 h-8", style: { color: "#ef4444" } }),
|
|
2020
|
+
/* @__PURE__ */ jsx2("span", { style: screenshotPreviewStyles.errorTitle, children: "Capture Failed" }),
|
|
2021
|
+
/* @__PURE__ */ jsx2("span", { style: screenshotPreviewStyles.errorMessage, children: activeError.message })
|
|
2022
|
+
] }) : /* @__PURE__ */ jsxs2("div", { style: screenshotPreviewStyles.noPreview, children: [
|
|
2023
|
+
/* @__PURE__ */ jsx2(ImageIcon, { className: "w-6 h-6", style: { color: "#9ca3af" } }),
|
|
2024
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
680
2025
|
"No ",
|
|
681
2026
|
activeTab,
|
|
682
2027
|
" screenshot"
|
|
@@ -684,14 +2029,14 @@ var ScreenshotPreview = React.memo(function ScreenshotPreview2({
|
|
|
684
2029
|
] })
|
|
685
2030
|
}
|
|
686
2031
|
),
|
|
687
|
-
activeScreenshot && /* @__PURE__ */
|
|
2032
|
+
activeScreenshot && /* @__PURE__ */ jsxs2("div", { style: screenshotPreviewStyles.dimensionsInfo, children: [
|
|
688
2033
|
activeScreenshot.width,
|
|
689
2034
|
" \xD7 ",
|
|
690
2035
|
activeScreenshot.height,
|
|
691
2036
|
"px"
|
|
692
2037
|
] }),
|
|
693
|
-
/* @__PURE__ */
|
|
694
|
-
/* @__PURE__ */
|
|
2038
|
+
/* @__PURE__ */ jsxs2("div", { style: screenshotPreviewStyles.actions, children: [
|
|
2039
|
+
/* @__PURE__ */ jsxs2(
|
|
695
2040
|
"button",
|
|
696
2041
|
{
|
|
697
2042
|
type: "button",
|
|
@@ -699,13 +2044,13 @@ var ScreenshotPreview = React.memo(function ScreenshotPreview2({
|
|
|
699
2044
|
onClick: onRetake,
|
|
700
2045
|
style: screenshotPreviewStyles.retakeButtonSmall,
|
|
701
2046
|
children: [
|
|
702
|
-
/* @__PURE__ */
|
|
2047
|
+
/* @__PURE__ */ jsx2(RefreshCwIcon, { className: "w-3 h-3" }),
|
|
703
2048
|
"Retake"
|
|
704
2049
|
]
|
|
705
2050
|
}
|
|
706
2051
|
),
|
|
707
|
-
/* @__PURE__ */
|
|
708
|
-
/* @__PURE__ */
|
|
2052
|
+
/* @__PURE__ */ jsxs2("div", { style: screenshotPreviewStyles.actionsRight, children: [
|
|
2053
|
+
/* @__PURE__ */ jsxs2(
|
|
709
2054
|
"button",
|
|
710
2055
|
{
|
|
711
2056
|
type: "button",
|
|
@@ -714,12 +2059,12 @@ var ScreenshotPreview = React.memo(function ScreenshotPreview2({
|
|
|
714
2059
|
onClick: onCancel,
|
|
715
2060
|
style: { ...menuStyles.button, ...menuStyles.cancelButton },
|
|
716
2061
|
children: [
|
|
717
|
-
/* @__PURE__ */
|
|
2062
|
+
/* @__PURE__ */ jsx2(XIcon, { className: "w-3 h-3" }),
|
|
718
2063
|
"Cancel"
|
|
719
2064
|
]
|
|
720
2065
|
}
|
|
721
2066
|
),
|
|
722
|
-
/* @__PURE__ */
|
|
2067
|
+
/* @__PURE__ */ jsx2(
|
|
723
2068
|
"button",
|
|
724
2069
|
{
|
|
725
2070
|
type: "button",
|
|
@@ -730,11 +2075,11 @@ var ScreenshotPreview = React.memo(function ScreenshotPreview2({
|
|
|
730
2075
|
...menuStyles.submitButton,
|
|
731
2076
|
...isSubmitting ? menuStyles.submitButtonDisabled : {}
|
|
732
2077
|
},
|
|
733
|
-
children: isSubmitting ? /* @__PURE__ */
|
|
734
|
-
/* @__PURE__ */
|
|
2078
|
+
children: isSubmitting ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
2079
|
+
/* @__PURE__ */ jsx2(Loader2Icon, { className: "w-3 h-3 animate-spin" }),
|
|
735
2080
|
"Sending..."
|
|
736
|
-
] }) : /* @__PURE__ */
|
|
737
|
-
/* @__PURE__ */
|
|
2081
|
+
] }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
2082
|
+
/* @__PURE__ */ jsx2(CheckIcon, { className: "w-3 h-3" }),
|
|
738
2083
|
"Send"
|
|
739
2084
|
] })
|
|
740
2085
|
}
|
|
@@ -831,7 +2176,7 @@ svg.${HIGHLIGHT_CONTAINER_CLASS},
|
|
|
831
2176
|
}
|
|
832
2177
|
`;
|
|
833
2178
|
}
|
|
834
|
-
function
|
|
2179
|
+
function injectStyles2(colors) {
|
|
835
2180
|
if (typeof document === "undefined") return;
|
|
836
2181
|
const existingStyle = document.getElementById(STYLE_ID);
|
|
837
2182
|
if (existingStyle) {
|
|
@@ -879,12 +2224,12 @@ function findContainerParent(element, config) {
|
|
|
879
2224
|
}
|
|
880
2225
|
function highlightTarget(element, colors) {
|
|
881
2226
|
const mergedColors = { ...defaultHighlightColors, ...colors };
|
|
882
|
-
|
|
2227
|
+
injectStyles2(mergedColors);
|
|
883
2228
|
element.classList.add(HIGHLIGHT_TARGET_CLASS);
|
|
884
2229
|
}
|
|
885
2230
|
function highlightContainer(element, colors) {
|
|
886
2231
|
const mergedColors = { ...defaultHighlightColors, ...colors };
|
|
887
|
-
|
|
2232
|
+
injectStyles2(mergedColors);
|
|
888
2233
|
element.classList.add(HIGHLIGHT_CONTAINER_CLASS);
|
|
889
2234
|
}
|
|
890
2235
|
function clearHighlights() {
|
|
@@ -911,12 +2256,12 @@ function applyHighlights(targetElement, config) {
|
|
|
911
2256
|
}
|
|
912
2257
|
|
|
913
2258
|
// src/ContextMenu.tsx
|
|
914
|
-
import { jsx as
|
|
2259
|
+
import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
915
2260
|
var VIEWPORT_PADDING = 10;
|
|
916
2261
|
var defaultIcons = {
|
|
917
|
-
feature: /* @__PURE__ */
|
|
918
|
-
issue: /* @__PURE__ */
|
|
919
|
-
like: /* @__PURE__ */
|
|
2262
|
+
feature: /* @__PURE__ */ jsx3(PlusIcon, { className: "w-4 h-4" }),
|
|
2263
|
+
issue: /* @__PURE__ */ jsx3(FlagIcon, { className: "w-4 h-4" }),
|
|
2264
|
+
like: /* @__PURE__ */ jsx3(ThumbsUpIcon, { className: "w-4 h-4" })
|
|
920
2265
|
};
|
|
921
2266
|
var OFFSCREEN_POSITION = { x: -9999, y: -9999 };
|
|
922
2267
|
var DefaultHeader = ({
|
|
@@ -925,25 +2270,25 @@ var DefaultHeader = ({
|
|
|
925
2270
|
styles,
|
|
926
2271
|
title = "Send Feedback"
|
|
927
2272
|
}) => {
|
|
928
|
-
return /* @__PURE__ */
|
|
929
|
-
/* @__PURE__ */
|
|
2273
|
+
return /* @__PURE__ */ jsxs3("div", { style: styles, className, children: [
|
|
2274
|
+
/* @__PURE__ */ jsx3("span", { children: title }),
|
|
930
2275
|
children
|
|
931
2276
|
] });
|
|
932
2277
|
};
|
|
933
|
-
var MenuItem =
|
|
2278
|
+
var MenuItem = React3.memo(function MenuItem2({
|
|
934
2279
|
disabled,
|
|
935
2280
|
hasChildren,
|
|
936
2281
|
item,
|
|
937
2282
|
onClick
|
|
938
2283
|
}) {
|
|
939
|
-
const [isHovered, setIsHovered] =
|
|
940
|
-
const [isPressed, setIsPressed] =
|
|
2284
|
+
const [isHovered, setIsHovered] = useState4(false);
|
|
2285
|
+
const [isPressed, setIsPressed] = useState4(false);
|
|
941
2286
|
const isComingSoon = item.status === "comingSoon";
|
|
942
2287
|
const badgeLabel = item.badge?.label ?? (isComingSoon ? "Coming soon" : null);
|
|
943
2288
|
const badgeTone = item.badge?.tone ?? (isComingSoon ? "neutral" : "neutral");
|
|
944
2289
|
const badgeStyle = badgeLabel ? getBadgeStyle(badgeTone) : void 0;
|
|
945
2290
|
const iconNode = item.icon ?? defaultIcons[item.type];
|
|
946
|
-
return /* @__PURE__ */
|
|
2291
|
+
return /* @__PURE__ */ jsxs3(
|
|
947
2292
|
"button",
|
|
948
2293
|
{
|
|
949
2294
|
type: "button",
|
|
@@ -964,22 +2309,22 @@ var MenuItem = React2.memo(function MenuItem2({
|
|
|
964
2309
|
...disabled ? menuStyles.itemDisabled : {}
|
|
965
2310
|
},
|
|
966
2311
|
children: [
|
|
967
|
-
iconNode ? /* @__PURE__ */
|
|
968
|
-
/* @__PURE__ */
|
|
2312
|
+
iconNode ? /* @__PURE__ */ jsx3("span", { style: menuStyles.itemIcon, children: iconNode }) : null,
|
|
2313
|
+
/* @__PURE__ */ jsxs3("span", { style: menuStyles.itemLabel, children: [
|
|
969
2314
|
item.label,
|
|
970
|
-
badgeLabel && /* @__PURE__ */
|
|
2315
|
+
badgeLabel && /* @__PURE__ */ jsx3("span", { style: badgeStyle, children: badgeLabel })
|
|
971
2316
|
] }),
|
|
972
|
-
hasChildren && /* @__PURE__ */
|
|
2317
|
+
hasChildren && /* @__PURE__ */ jsx3(ChevronRightIcon, { className: "w-4 h-4", style: menuStyles.submenuIcon })
|
|
973
2318
|
]
|
|
974
2319
|
}
|
|
975
2320
|
);
|
|
976
2321
|
});
|
|
977
|
-
var BackButton =
|
|
2322
|
+
var BackButton = React3.memo(function BackButton2({
|
|
978
2323
|
onClick
|
|
979
2324
|
}) {
|
|
980
|
-
const [isHovered, setIsHovered] =
|
|
981
|
-
const [isPressed, setIsPressed] =
|
|
982
|
-
return /* @__PURE__ */
|
|
2325
|
+
const [isHovered, setIsHovered] = useState4(false);
|
|
2326
|
+
const [isPressed, setIsPressed] = useState4(false);
|
|
2327
|
+
return /* @__PURE__ */ jsxs3(
|
|
983
2328
|
"button",
|
|
984
2329
|
{
|
|
985
2330
|
type: "button",
|
|
@@ -999,26 +2344,26 @@ var BackButton = React2.memo(function BackButton2({
|
|
|
999
2344
|
...isHovered || isPressed ? menuStyles.itemHover : {}
|
|
1000
2345
|
},
|
|
1001
2346
|
children: [
|
|
1002
|
-
/* @__PURE__ */
|
|
1003
|
-
/* @__PURE__ */
|
|
2347
|
+
/* @__PURE__ */ jsx3(ChevronLeftIcon, { className: "w-4 h-4", style: { opacity: 0.5 } }),
|
|
2348
|
+
/* @__PURE__ */ jsx3("span", { style: { opacity: 0.7 }, children: "Back" })
|
|
1004
2349
|
]
|
|
1005
2350
|
}
|
|
1006
2351
|
);
|
|
1007
2352
|
});
|
|
1008
|
-
var CommentForm =
|
|
2353
|
+
var CommentForm = React3.memo(function CommentForm2({
|
|
1009
2354
|
isSubmitting,
|
|
1010
2355
|
onCancel,
|
|
1011
2356
|
onSubmit
|
|
1012
2357
|
}) {
|
|
1013
|
-
const [comment, setComment] =
|
|
1014
|
-
const inputRef =
|
|
1015
|
-
|
|
2358
|
+
const [comment, setComment] = useState4("");
|
|
2359
|
+
const inputRef = useRef3(null);
|
|
2360
|
+
useEffect3(() => {
|
|
1016
2361
|
inputRef.current?.focus();
|
|
1017
2362
|
}, []);
|
|
1018
|
-
const handleSubmit =
|
|
2363
|
+
const handleSubmit = useCallback3(() => {
|
|
1019
2364
|
onSubmit(comment);
|
|
1020
2365
|
}, [comment, onSubmit]);
|
|
1021
|
-
const handleKeyDown =
|
|
2366
|
+
const handleKeyDown = useCallback3(
|
|
1022
2367
|
(e) => {
|
|
1023
2368
|
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
1024
2369
|
handleSubmit();
|
|
@@ -1028,8 +2373,8 @@ var CommentForm = React2.memo(function CommentForm2({
|
|
|
1028
2373
|
},
|
|
1029
2374
|
[handleSubmit, onCancel]
|
|
1030
2375
|
);
|
|
1031
|
-
return /* @__PURE__ */
|
|
1032
|
-
/* @__PURE__ */
|
|
2376
|
+
return /* @__PURE__ */ jsxs3("div", { style: menuStyles.commentSection, children: [
|
|
2377
|
+
/* @__PURE__ */ jsx3(
|
|
1033
2378
|
"textarea",
|
|
1034
2379
|
{
|
|
1035
2380
|
ref: inputRef,
|
|
@@ -1041,8 +2386,8 @@ var CommentForm = React2.memo(function CommentForm2({
|
|
|
1041
2386
|
value: comment
|
|
1042
2387
|
}
|
|
1043
2388
|
),
|
|
1044
|
-
/* @__PURE__ */
|
|
1045
|
-
/* @__PURE__ */
|
|
2389
|
+
/* @__PURE__ */ jsxs3("div", { style: menuStyles.buttonRow, children: [
|
|
2390
|
+
/* @__PURE__ */ jsx3(
|
|
1046
2391
|
"button",
|
|
1047
2392
|
{
|
|
1048
2393
|
type: "button",
|
|
@@ -1052,7 +2397,7 @@ var CommentForm = React2.memo(function CommentForm2({
|
|
|
1052
2397
|
children: "Cancel"
|
|
1053
2398
|
}
|
|
1054
2399
|
),
|
|
1055
|
-
/* @__PURE__ */
|
|
2400
|
+
/* @__PURE__ */ jsx3(
|
|
1056
2401
|
"button",
|
|
1057
2402
|
{
|
|
1058
2403
|
type: "button",
|
|
@@ -1100,26 +2445,35 @@ function ContextMenu({
|
|
|
1100
2445
|
onSelect,
|
|
1101
2446
|
position,
|
|
1102
2447
|
positionMode = "inView",
|
|
2448
|
+
quickChatConfig,
|
|
1103
2449
|
screenshotConfig,
|
|
1104
2450
|
style,
|
|
1105
2451
|
targetElement,
|
|
1106
2452
|
visible
|
|
1107
2453
|
}) {
|
|
1108
|
-
const [selectedType, setSelectedType] =
|
|
1109
|
-
const [currentView, setCurrentView] =
|
|
1110
|
-
const [pendingComment, setPendingComment] =
|
|
1111
|
-
const [submenuStack, setSubmenuStack] =
|
|
1112
|
-
const [screenshots, setScreenshots] =
|
|
1113
|
-
const [isCapturing, setIsCapturing] =
|
|
1114
|
-
const
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
2454
|
+
const [selectedType, setSelectedType] = useState4(null);
|
|
2455
|
+
const [currentView, setCurrentView] = useState4("menu");
|
|
2456
|
+
const [pendingComment, setPendingComment] = useState4();
|
|
2457
|
+
const [submenuStack, setSubmenuStack] = useState4([]);
|
|
2458
|
+
const [screenshots, setScreenshots] = useState4(null);
|
|
2459
|
+
const [isCapturing, setIsCapturing] = useState4(false);
|
|
2460
|
+
const [isQuickChatPinned, setIsQuickChatPinned] = useState4(() => {
|
|
2461
|
+
if (typeof window === "undefined") return false;
|
|
2462
|
+
try {
|
|
2463
|
+
return sessionStorage.getItem("anyclick-quick-chat-pinned") === "true";
|
|
2464
|
+
} catch {
|
|
2465
|
+
return false;
|
|
2466
|
+
}
|
|
2467
|
+
});
|
|
2468
|
+
const menuRef = useRef3(null);
|
|
2469
|
+
const [adjustedPosition, setAdjustedPosition] = useState4(OFFSCREEN_POSITION);
|
|
2470
|
+
const [isDragging, setIsDragging] = useState4(false);
|
|
2471
|
+
const [dragOffset, setDragOffset] = useState4({
|
|
1118
2472
|
x: 0,
|
|
1119
2473
|
y: 0
|
|
1120
2474
|
});
|
|
1121
|
-
const dragStartRef =
|
|
1122
|
-
const mergedScreenshotConfig =
|
|
2475
|
+
const dragStartRef = useRef3(null);
|
|
2476
|
+
const mergedScreenshotConfig = React3.useMemo(
|
|
1123
2477
|
() => ({
|
|
1124
2478
|
...DEFAULT_SCREENSHOT_CONFIG,
|
|
1125
2479
|
...screenshotConfig
|
|
@@ -1128,7 +2482,7 @@ function ContextMenu({
|
|
|
1128
2482
|
);
|
|
1129
2483
|
const showPreview = mergedScreenshotConfig.showPreview && isScreenshotSupported();
|
|
1130
2484
|
const currentItems = submenuStack.length > 0 ? submenuStack[submenuStack.length - 1] : items;
|
|
1131
|
-
const captureScreenshots =
|
|
2485
|
+
const captureScreenshots = useCallback3(async () => {
|
|
1132
2486
|
if (!targetElement || !showPreview) return;
|
|
1133
2487
|
setIsCapturing(true);
|
|
1134
2488
|
try {
|
|
@@ -1145,7 +2499,7 @@ function ContextMenu({
|
|
|
1145
2499
|
setIsCapturing(false);
|
|
1146
2500
|
}
|
|
1147
2501
|
}, [containerElement, mergedScreenshotConfig, showPreview, targetElement]);
|
|
1148
|
-
|
|
2502
|
+
useEffect3(() => {
|
|
1149
2503
|
if (!visible) {
|
|
1150
2504
|
setSelectedType(null);
|
|
1151
2505
|
setCurrentView("menu");
|
|
@@ -1159,7 +2513,7 @@ function ContextMenu({
|
|
|
1159
2513
|
dragStartRef.current = null;
|
|
1160
2514
|
}
|
|
1161
2515
|
}, [visible]);
|
|
1162
|
-
|
|
2516
|
+
useEffect3(() => {
|
|
1163
2517
|
if (visible && targetElement) {
|
|
1164
2518
|
clearHighlights();
|
|
1165
2519
|
applyHighlights(targetElement, highlightConfig);
|
|
@@ -1170,7 +2524,7 @@ function ContextMenu({
|
|
|
1170
2524
|
clearHighlights();
|
|
1171
2525
|
};
|
|
1172
2526
|
}, [highlightConfig, targetElement, visible]);
|
|
1173
|
-
|
|
2527
|
+
useEffect3(() => {
|
|
1174
2528
|
if (!visible) {
|
|
1175
2529
|
return;
|
|
1176
2530
|
}
|
|
@@ -1189,13 +2543,13 @@ function ContextMenu({
|
|
|
1189
2543
|
document.removeEventListener("pointerdown", handlePointerDown);
|
|
1190
2544
|
};
|
|
1191
2545
|
}, [onClose, visible]);
|
|
1192
|
-
|
|
2546
|
+
useEffect3(() => {
|
|
1193
2547
|
if (visible) {
|
|
1194
2548
|
setAdjustedPosition(position);
|
|
1195
2549
|
setDragOffset({ x: 0, y: 0 });
|
|
1196
2550
|
}
|
|
1197
2551
|
}, [position.x, position.y, visible]);
|
|
1198
|
-
|
|
2552
|
+
useEffect3(() => {
|
|
1199
2553
|
if (!visible || !menuRef.current) return;
|
|
1200
2554
|
const updatePosition = () => {
|
|
1201
2555
|
const menuElement = menuRef.current;
|
|
@@ -1219,7 +2573,7 @@ function ContextMenu({
|
|
|
1219
2573
|
window.addEventListener("resize", updatePosition);
|
|
1220
2574
|
return () => window.removeEventListener("resize", updatePosition);
|
|
1221
2575
|
}, [currentView, dragOffset, position, positionMode, visible]);
|
|
1222
|
-
|
|
2576
|
+
useEffect3(() => {
|
|
1223
2577
|
if (!visible || positionMode !== "dynamic") return;
|
|
1224
2578
|
const handlePointerMove = (event) => {
|
|
1225
2579
|
if (!isDragging || !dragStartRef.current) return;
|
|
@@ -1246,7 +2600,7 @@ function ContextMenu({
|
|
|
1246
2600
|
};
|
|
1247
2601
|
}
|
|
1248
2602
|
}, [isDragging, positionMode, visible]);
|
|
1249
|
-
const handleDragStart =
|
|
2603
|
+
const handleDragStart = useCallback3(
|
|
1250
2604
|
(event) => {
|
|
1251
2605
|
if (positionMode !== "dynamic") return;
|
|
1252
2606
|
event.preventDefault();
|
|
@@ -1255,7 +2609,8 @@ function ContextMenu({
|
|
|
1255
2609
|
},
|
|
1256
2610
|
[positionMode]
|
|
1257
2611
|
);
|
|
1258
|
-
|
|
2612
|
+
const [initialChatInput, setInitialChatInput] = useState4("");
|
|
2613
|
+
useEffect3(() => {
|
|
1259
2614
|
const handleKeyDown = (e) => {
|
|
1260
2615
|
if (e.key === "Escape") {
|
|
1261
2616
|
if (currentView === "screenshot-preview") {
|
|
@@ -1264,19 +2619,38 @@ function ContextMenu({
|
|
|
1264
2619
|
setCurrentView("menu");
|
|
1265
2620
|
setSelectedType(null);
|
|
1266
2621
|
setPendingComment(void 0);
|
|
2622
|
+
} else if (currentView === "quick-chat") {
|
|
2623
|
+
if (!isQuickChatPinned) {
|
|
2624
|
+
setCurrentView("menu");
|
|
2625
|
+
}
|
|
1267
2626
|
} else if (submenuStack.length > 0) {
|
|
1268
2627
|
setSubmenuStack((prev) => prev.slice(0, -1));
|
|
1269
2628
|
} else {
|
|
1270
2629
|
onClose();
|
|
1271
2630
|
}
|
|
2631
|
+
return;
|
|
2632
|
+
}
|
|
2633
|
+
if (quickChatConfig && currentView === "menu" && !isQuickChatPinned && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
2634
|
+
if (e.key.length === 1 && e.key.match(/[a-zA-Z0-9\s.,!?'"]/)) {
|
|
2635
|
+
e.preventDefault();
|
|
2636
|
+
setInitialChatInput(e.key);
|
|
2637
|
+
setCurrentView("quick-chat");
|
|
2638
|
+
}
|
|
1272
2639
|
}
|
|
1273
2640
|
};
|
|
1274
2641
|
if (visible) {
|
|
1275
2642
|
document.addEventListener("keydown", handleKeyDown);
|
|
1276
2643
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
1277
2644
|
}
|
|
1278
|
-
}, [
|
|
1279
|
-
|
|
2645
|
+
}, [
|
|
2646
|
+
currentView,
|
|
2647
|
+
isQuickChatPinned,
|
|
2648
|
+
onClose,
|
|
2649
|
+
quickChatConfig,
|
|
2650
|
+
submenuStack.length,
|
|
2651
|
+
visible
|
|
2652
|
+
]);
|
|
2653
|
+
useEffect3(() => {
|
|
1280
2654
|
const menuElement = menuRef.current;
|
|
1281
2655
|
if (!visible || !menuElement) return;
|
|
1282
2656
|
const preventTouchDefault = (e) => {
|
|
@@ -1293,9 +2667,6 @@ function ContextMenu({
|
|
|
1293
2667
|
menuElement.removeEventListener("touchmove", preventTouchDefault);
|
|
1294
2668
|
};
|
|
1295
2669
|
}, [visible]);
|
|
1296
|
-
if (!visible || !targetElement) {
|
|
1297
|
-
return null;
|
|
1298
|
-
}
|
|
1299
2670
|
const handleItemClick = (item) => {
|
|
1300
2671
|
if (item.status === "comingSoon") {
|
|
1301
2672
|
return;
|
|
@@ -1364,85 +2735,166 @@ function ContextMenu({
|
|
|
1364
2735
|
const handleRetakeScreenshots = () => {
|
|
1365
2736
|
captureScreenshots();
|
|
1366
2737
|
};
|
|
1367
|
-
const
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
{
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
2738
|
+
const handleQuickChatToggle = () => {
|
|
2739
|
+
if (currentView === "quick-chat" && !isQuickChatPinned) {
|
|
2740
|
+
setCurrentView("menu");
|
|
2741
|
+
} else {
|
|
2742
|
+
setCurrentView("quick-chat");
|
|
2743
|
+
}
|
|
2744
|
+
};
|
|
2745
|
+
const handleQuickChatPin = (pinned) => {
|
|
2746
|
+
setIsQuickChatPinned(pinned);
|
|
2747
|
+
try {
|
|
2748
|
+
if (pinned) {
|
|
2749
|
+
sessionStorage.setItem("anyclick-quick-chat-pinned", "true");
|
|
2750
|
+
} else {
|
|
2751
|
+
sessionStorage.removeItem("anyclick-quick-chat-pinned");
|
|
2752
|
+
}
|
|
2753
|
+
} catch {
|
|
2754
|
+
}
|
|
2755
|
+
if (pinned) {
|
|
2756
|
+
setCurrentView("menu");
|
|
2757
|
+
}
|
|
2758
|
+
};
|
|
2759
|
+
const handleQuickChatClose = () => {
|
|
2760
|
+
setIsQuickChatPinned(false);
|
|
2761
|
+
try {
|
|
2762
|
+
sessionStorage.removeItem("anyclick-quick-chat-pinned");
|
|
2763
|
+
} catch {
|
|
2764
|
+
}
|
|
2765
|
+
setCurrentView("menu");
|
|
2766
|
+
};
|
|
2767
|
+
const containerWidth = currentView === "screenshot-preview" ? 360 : currentView === "quick-chat" && !isQuickChatPinned ? 320 : void 0;
|
|
2768
|
+
const showPinnedDrawer = isQuickChatPinned && quickChatConfig;
|
|
2769
|
+
const showMenu = visible && targetElement;
|
|
2770
|
+
return /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
2771
|
+
showPinnedDrawer && /* @__PURE__ */ jsx3(
|
|
2772
|
+
QuickChat,
|
|
2773
|
+
{
|
|
2774
|
+
visible: true,
|
|
2775
|
+
targetElement,
|
|
2776
|
+
containerElement,
|
|
2777
|
+
onClose: handleQuickChatClose,
|
|
2778
|
+
onPin: handleQuickChatPin,
|
|
2779
|
+
isPinned: true,
|
|
2780
|
+
config: quickChatConfig
|
|
2781
|
+
}
|
|
2782
|
+
),
|
|
2783
|
+
showMenu && /* @__PURE__ */ jsxs3(
|
|
2784
|
+
"div",
|
|
2785
|
+
{
|
|
2786
|
+
ref: menuRef,
|
|
2787
|
+
"aria-label": "Feedback options",
|
|
2788
|
+
className,
|
|
2789
|
+
role: "menu",
|
|
2790
|
+
style: {
|
|
2791
|
+
...menuStyles.container,
|
|
2792
|
+
left: adjustedPosition.x,
|
|
2793
|
+
top: adjustedPosition.y,
|
|
2794
|
+
...containerWidth ? { minWidth: containerWidth, width: containerWidth } : {},
|
|
2795
|
+
touchAction: "none",
|
|
2796
|
+
userSelect: "none",
|
|
2797
|
+
WebkitTouchCallout: "none",
|
|
2798
|
+
WebkitUserSelect: "none",
|
|
2799
|
+
...isDragging ? { cursor: "grabbing" } : {},
|
|
2800
|
+
...style
|
|
2801
|
+
},
|
|
2802
|
+
children: [
|
|
2803
|
+
!header && currentView !== "screenshot-preview" && currentView !== "quick-chat" && /* @__PURE__ */ jsxs3(DefaultHeader, { styles: menuStyles.header, title: "Send Feedback", children: [
|
|
2804
|
+
positionMode === "dynamic" && /* @__PURE__ */ jsx3(
|
|
2805
|
+
"div",
|
|
2806
|
+
{
|
|
2807
|
+
"data-drag-handle": true,
|
|
2808
|
+
onMouseEnter: (e) => {
|
|
2809
|
+
e.currentTarget.style.opacity = "1";
|
|
2810
|
+
},
|
|
2811
|
+
onMouseLeave: (e) => {
|
|
2812
|
+
e.currentTarget.style.opacity = "0.5";
|
|
2813
|
+
},
|
|
2814
|
+
onPointerDown: handleDragStart,
|
|
2815
|
+
style: {
|
|
2816
|
+
...menuStyles.dragHandle,
|
|
2817
|
+
cursor: isDragging ? "grabbing" : "grab"
|
|
2818
|
+
},
|
|
2819
|
+
title: "Drag to move",
|
|
2820
|
+
children: /* @__PURE__ */ jsx3(GripVertical, { className: "w-4 h-4" })
|
|
2821
|
+
}
|
|
2822
|
+
),
|
|
2823
|
+
showPreview && /* @__PURE__ */ jsx3("div", { style: menuStyles.screenshotIndicator, children: /* @__PURE__ */ jsx3(CameraIcon, { className: "w-3 h-3" }) }),
|
|
2824
|
+
quickChatConfig && /* @__PURE__ */ jsx3(
|
|
2825
|
+
"button",
|
|
2826
|
+
{
|
|
2827
|
+
type: "button",
|
|
2828
|
+
onClick: handleQuickChatToggle,
|
|
2829
|
+
style: {
|
|
2830
|
+
display: "flex",
|
|
2831
|
+
alignItems: "center",
|
|
2832
|
+
justifyContent: "center",
|
|
2833
|
+
width: "24px",
|
|
2834
|
+
height: "24px",
|
|
2835
|
+
border: "none",
|
|
2836
|
+
borderRadius: "4px",
|
|
2837
|
+
backgroundColor: isQuickChatPinned ? "var(--anyclick-menu-accent, #0066cc)" : "transparent",
|
|
2838
|
+
color: isQuickChatPinned ? "#fff" : "var(--anyclick-menu-accent, #0066cc)",
|
|
2839
|
+
cursor: "pointer",
|
|
2840
|
+
transition: "all 0.15s ease"
|
|
2841
|
+
},
|
|
2842
|
+
title: isQuickChatPinned ? "Quick Chat (pinned)" : "Quick Ask AI",
|
|
2843
|
+
children: /* @__PURE__ */ jsx3(Sparkles, { className: "w-3.5 h-3.5" })
|
|
2844
|
+
}
|
|
2845
|
+
)
|
|
2846
|
+
] }),
|
|
2847
|
+
!!header && header,
|
|
2848
|
+
currentView === "menu" && /* @__PURE__ */ jsxs3("div", { style: menuStyles.itemList, children: [
|
|
2849
|
+
submenuStack.length > 0 && /* @__PURE__ */ jsx3(BackButton, { onClick: handleBack }),
|
|
2850
|
+
currentItems.map((item) => /* @__PURE__ */ jsx3(
|
|
2851
|
+
MenuItem,
|
|
2852
|
+
{
|
|
2853
|
+
disabled: isSubmitting,
|
|
2854
|
+
hasChildren: item.children && item.children.length > 0,
|
|
2855
|
+
item,
|
|
2856
|
+
onClick: () => handleItemClick(item)
|
|
1404
2857
|
},
|
|
1405
|
-
|
|
1406
|
-
|
|
2858
|
+
item.type
|
|
2859
|
+
))
|
|
2860
|
+
] }),
|
|
2861
|
+
currentView === "comment" && /* @__PURE__ */ jsx3(
|
|
2862
|
+
CommentForm,
|
|
2863
|
+
{
|
|
2864
|
+
isSubmitting,
|
|
2865
|
+
onCancel: handleCommentCancel,
|
|
2866
|
+
onSubmit: handleCommentSubmit
|
|
1407
2867
|
}
|
|
1408
|
-
)
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
currentView === "menu" && /* @__PURE__ */ jsxs2("div", { style: menuStyles.itemList, children: [
|
|
1412
|
-
submenuStack.length > 0 && /* @__PURE__ */ jsx2(BackButton, { onClick: handleBack }),
|
|
1413
|
-
currentItems.map((item) => /* @__PURE__ */ jsx2(
|
|
1414
|
-
MenuItem,
|
|
2868
|
+
),
|
|
2869
|
+
currentView === "screenshot-preview" && /* @__PURE__ */ jsx3(
|
|
2870
|
+
ScreenshotPreview,
|
|
1415
2871
|
{
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
)
|
|
1443
|
-
]
|
|
1444
|
-
}
|
|
1445
|
-
);
|
|
2872
|
+
isLoading: isCapturing,
|
|
2873
|
+
isSubmitting,
|
|
2874
|
+
onCancel: handleScreenshotCancel,
|
|
2875
|
+
onConfirm: handleScreenshotConfirm,
|
|
2876
|
+
onRetake: handleRetakeScreenshots,
|
|
2877
|
+
screenshots
|
|
2878
|
+
}
|
|
2879
|
+
),
|
|
2880
|
+
currentView === "quick-chat" && quickChatConfig && !isQuickChatPinned && /* @__PURE__ */ jsx3(
|
|
2881
|
+
QuickChat,
|
|
2882
|
+
{
|
|
2883
|
+
visible: true,
|
|
2884
|
+
targetElement,
|
|
2885
|
+
containerElement,
|
|
2886
|
+
onClose: handleQuickChatClose,
|
|
2887
|
+
onPin: handleQuickChatPin,
|
|
2888
|
+
isPinned: false,
|
|
2889
|
+
config: quickChatConfig,
|
|
2890
|
+
initialInput: initialChatInput,
|
|
2891
|
+
onInitialInputConsumed: () => setInitialChatInput("")
|
|
2892
|
+
}
|
|
2893
|
+
)
|
|
2894
|
+
]
|
|
2895
|
+
}
|
|
2896
|
+
)
|
|
2897
|
+
] });
|
|
1446
2898
|
}
|
|
1447
2899
|
|
|
1448
2900
|
// src/context.ts
|
|
@@ -1626,7 +3078,7 @@ function dispatchContextMenuEvent(event, element) {
|
|
|
1626
3078
|
}
|
|
1627
3079
|
|
|
1628
3080
|
// src/AnyclickProvider.tsx
|
|
1629
|
-
import { jsx as
|
|
3081
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1630
3082
|
var defaultMenuItems = [
|
|
1631
3083
|
{ label: "Report an issue", showComment: true, type: "issue" },
|
|
1632
3084
|
{ label: "Request a feature", showComment: true, type: "feature" },
|
|
@@ -1649,6 +3101,7 @@ function AnyclickProvider({
|
|
|
1649
3101
|
metadata,
|
|
1650
3102
|
onSubmitError,
|
|
1651
3103
|
onSubmitSuccess,
|
|
3104
|
+
quickChatConfig,
|
|
1652
3105
|
scoped = false,
|
|
1653
3106
|
screenshotConfig,
|
|
1654
3107
|
stripAttributes,
|
|
@@ -1657,18 +3110,18 @@ function AnyclickProvider({
|
|
|
1657
3110
|
touchHoldDurationMs,
|
|
1658
3111
|
touchMoveThreshold
|
|
1659
3112
|
}) {
|
|
1660
|
-
const [isSubmitting, setIsSubmitting] =
|
|
1661
|
-
const [menuVisible, setMenuVisible] =
|
|
1662
|
-
const [menuPosition, setMenuPosition] =
|
|
1663
|
-
const [targetElement, setTargetElement] =
|
|
1664
|
-
const [containerElement, setContainerElement] =
|
|
3113
|
+
const [isSubmitting, setIsSubmitting] = useState5(false);
|
|
3114
|
+
const [menuVisible, setMenuVisible] = useState5(false);
|
|
3115
|
+
const [menuPosition, setMenuPosition] = useState5(OFFSCREEN_POSITION2);
|
|
3116
|
+
const [targetElement, setTargetElement] = useState5(null);
|
|
3117
|
+
const [containerElement, setContainerElement] = useState5(
|
|
1665
3118
|
null
|
|
1666
3119
|
);
|
|
1667
3120
|
const providerId = useId();
|
|
1668
|
-
const containerRef =
|
|
1669
|
-
const [containerReady, setContainerReady] =
|
|
1670
|
-
const clientRef =
|
|
1671
|
-
const setContainerRef =
|
|
3121
|
+
const containerRef = useRef4(null);
|
|
3122
|
+
const [containerReady, setContainerReady] = useState5(!scoped);
|
|
3123
|
+
const clientRef = useRef4(null);
|
|
3124
|
+
const setContainerRef = useCallback4(
|
|
1672
3125
|
(node) => {
|
|
1673
3126
|
containerRef.current = node;
|
|
1674
3127
|
if (scoped && node) {
|
|
@@ -1697,7 +3150,7 @@ function AnyclickProvider({
|
|
|
1697
3150
|
updateProvider
|
|
1698
3151
|
} = useProviderStore();
|
|
1699
3152
|
const parentId = parentContext?.providerId ?? null;
|
|
1700
|
-
const actualDepth =
|
|
3153
|
+
const actualDepth = useMemo3(() => {
|
|
1701
3154
|
if (!parentContext) return 0;
|
|
1702
3155
|
let d = 0;
|
|
1703
3156
|
let currentId = parentId;
|
|
@@ -1711,7 +3164,7 @@ function AnyclickProvider({
|
|
|
1711
3164
|
}, [parentContext, parentId]);
|
|
1712
3165
|
const isDisabledByTheme = theme === null || theme?.disabled === true;
|
|
1713
3166
|
const effectiveDisabled = disabled || isDisabledByTheme;
|
|
1714
|
-
const localTheme =
|
|
3167
|
+
const localTheme = useMemo3(() => {
|
|
1715
3168
|
if (theme === null) {
|
|
1716
3169
|
return { disabled: true };
|
|
1717
3170
|
}
|
|
@@ -1726,7 +3179,7 @@ function AnyclickProvider({
|
|
|
1726
3179
|
...theme
|
|
1727
3180
|
};
|
|
1728
3181
|
}, [highlightConfig, menuClassName, menuStyle, screenshotConfig, theme]);
|
|
1729
|
-
const handleContextMenu =
|
|
3182
|
+
const handleContextMenu = useCallback4(
|
|
1730
3183
|
(event, element) => {
|
|
1731
3184
|
if (!scoped && isElementInDisabledScope(element)) {
|
|
1732
3185
|
return false;
|
|
@@ -1780,7 +3233,7 @@ function AnyclickProvider({
|
|
|
1780
3233
|
scoped,
|
|
1781
3234
|
unregisterProvider
|
|
1782
3235
|
]);
|
|
1783
|
-
|
|
3236
|
+
useEffect4(() => {
|
|
1784
3237
|
updateProvider(providerId, {
|
|
1785
3238
|
disabled: effectiveDisabled,
|
|
1786
3239
|
onContextMenu: handleContextMenu,
|
|
@@ -1793,7 +3246,7 @@ function AnyclickProvider({
|
|
|
1793
3246
|
providerId,
|
|
1794
3247
|
updateProvider
|
|
1795
3248
|
]);
|
|
1796
|
-
|
|
3249
|
+
useEffect4(() => {
|
|
1797
3250
|
if (isDisabledByAncestor(providerId)) {
|
|
1798
3251
|
return;
|
|
1799
3252
|
}
|
|
@@ -1841,7 +3294,7 @@ function AnyclickProvider({
|
|
|
1841
3294
|
touchHoldDurationMs,
|
|
1842
3295
|
touchMoveThreshold
|
|
1843
3296
|
]);
|
|
1844
|
-
const submitAnyclick =
|
|
3297
|
+
const submitAnyclick = useCallback4(
|
|
1845
3298
|
async (element, type, comment, screenshots) => {
|
|
1846
3299
|
const client = clientRef.current;
|
|
1847
3300
|
if (!client) return;
|
|
@@ -1862,7 +3315,7 @@ function AnyclickProvider({
|
|
|
1862
3315
|
},
|
|
1863
3316
|
[metadata]
|
|
1864
3317
|
);
|
|
1865
|
-
const openMenu =
|
|
3318
|
+
const openMenu = useCallback4(
|
|
1866
3319
|
(element, position) => {
|
|
1867
3320
|
setTargetElement(element);
|
|
1868
3321
|
const mergedTheme2 = getMergedTheme(providerId);
|
|
@@ -1876,13 +3329,13 @@ function AnyclickProvider({
|
|
|
1876
3329
|
},
|
|
1877
3330
|
[getMergedTheme, highlightConfig, providerId]
|
|
1878
3331
|
);
|
|
1879
|
-
const closeMenu =
|
|
3332
|
+
const closeMenu = useCallback4(() => {
|
|
1880
3333
|
setMenuVisible(false);
|
|
1881
3334
|
setMenuPosition(OFFSCREEN_POSITION2);
|
|
1882
3335
|
setTargetElement(null);
|
|
1883
3336
|
setContainerElement(null);
|
|
1884
3337
|
}, []);
|
|
1885
|
-
const handleMenuSelect =
|
|
3338
|
+
const handleMenuSelect = useCallback4(
|
|
1886
3339
|
(type, comment, screenshots) => {
|
|
1887
3340
|
if (targetElement) {
|
|
1888
3341
|
submitAnyclick(targetElement, type, comment, screenshots);
|
|
@@ -1891,7 +3344,7 @@ function AnyclickProvider({
|
|
|
1891
3344
|
[submitAnyclick, targetElement]
|
|
1892
3345
|
);
|
|
1893
3346
|
const inheritedTheme = getMergedTheme(providerId);
|
|
1894
|
-
const mergedTheme =
|
|
3347
|
+
const mergedTheme = useMemo3(
|
|
1895
3348
|
() => ({
|
|
1896
3349
|
...inheritedTheme,
|
|
1897
3350
|
...localTheme,
|
|
@@ -1914,7 +3367,7 @@ function AnyclickProvider({
|
|
|
1914
3367
|
const effectiveMenuClassName = mergedTheme.menuClassName ?? menuClassName;
|
|
1915
3368
|
const effectiveHighlightConfig = mergedTheme.highlightConfig ?? highlightConfig;
|
|
1916
3369
|
const effectiveScreenshotConfig = mergedTheme.screenshotConfig ?? screenshotConfig;
|
|
1917
|
-
const contextValue =
|
|
3370
|
+
const contextValue = useMemo3(
|
|
1918
3371
|
() => ({
|
|
1919
3372
|
closeMenu,
|
|
1920
3373
|
isEnabled: !effectiveDisabled && !isDisabledByAncestor(providerId),
|
|
@@ -1937,7 +3390,7 @@ function AnyclickProvider({
|
|
|
1937
3390
|
submitAnyclick
|
|
1938
3391
|
]
|
|
1939
3392
|
);
|
|
1940
|
-
const content = scoped ? /* @__PURE__ */
|
|
3393
|
+
const content = scoped ? /* @__PURE__ */ jsx4(
|
|
1941
3394
|
"div",
|
|
1942
3395
|
{
|
|
1943
3396
|
ref: setContainerRef,
|
|
@@ -1946,9 +3399,9 @@ function AnyclickProvider({
|
|
|
1946
3399
|
children
|
|
1947
3400
|
}
|
|
1948
3401
|
) : children;
|
|
1949
|
-
return /* @__PURE__ */
|
|
3402
|
+
return /* @__PURE__ */ jsxs4(AnyclickContext.Provider, { value: contextValue, children: [
|
|
1950
3403
|
content,
|
|
1951
|
-
/* @__PURE__ */
|
|
3404
|
+
/* @__PURE__ */ jsx4(
|
|
1952
3405
|
ContextMenu,
|
|
1953
3406
|
{
|
|
1954
3407
|
className: effectiveMenuClassName,
|
|
@@ -1960,6 +3413,7 @@ function AnyclickProvider({
|
|
|
1960
3413
|
onClose: closeMenu,
|
|
1961
3414
|
onSelect: handleMenuSelect,
|
|
1962
3415
|
position: menuPosition,
|
|
3416
|
+
quickChatConfig,
|
|
1963
3417
|
screenshotConfig: effectiveScreenshotConfig,
|
|
1964
3418
|
style: effectiveMenuStyle,
|
|
1965
3419
|
targetElement,
|
|
@@ -1971,7 +3425,7 @@ function AnyclickProvider({
|
|
|
1971
3425
|
var FeedbackProvider = AnyclickProvider;
|
|
1972
3426
|
|
|
1973
3427
|
// src/FunModeBridge.tsx
|
|
1974
|
-
import { useEffect as
|
|
3428
|
+
import { useEffect as useEffect5, useMemo as useMemo4, useRef as useRef5 } from "react";
|
|
1975
3429
|
import {
|
|
1976
3430
|
usePointer
|
|
1977
3431
|
} from "@ewjdev/anyclick-pointer";
|
|
@@ -2020,9 +3474,9 @@ function buildFunConfig(theme, container) {
|
|
|
2020
3474
|
function FunModeBridge() {
|
|
2021
3475
|
const { setConfig } = usePointer();
|
|
2022
3476
|
const providerStore = useProviderStore();
|
|
2023
|
-
const activeProviderRef =
|
|
2024
|
-
const cachedConfigs =
|
|
2025
|
-
const findActiveFunProvider =
|
|
3477
|
+
const activeProviderRef = useRef5(null);
|
|
3478
|
+
const cachedConfigs = useRef5({});
|
|
3479
|
+
const findActiveFunProvider = useMemo4(() => {
|
|
2026
3480
|
return (el) => {
|
|
2027
3481
|
if (!el) return null;
|
|
2028
3482
|
const providers = providerStore.findProvidersForElement(el);
|
|
@@ -2034,7 +3488,7 @@ function FunModeBridge() {
|
|
|
2034
3488
|
return null;
|
|
2035
3489
|
};
|
|
2036
3490
|
}, [providerStore]);
|
|
2037
|
-
|
|
3491
|
+
useEffect5(() => {
|
|
2038
3492
|
const handleMove = (event) => {
|
|
2039
3493
|
const el = document.elementFromPoint(event.clientX, event.clientY);
|
|
2040
3494
|
const provider = findActiveFunProvider(el);
|
|
@@ -2069,15 +3523,15 @@ function FunModeBridge() {
|
|
|
2069
3523
|
}
|
|
2070
3524
|
|
|
2071
3525
|
// src/InspectDialog/InspectDialogManager.tsx
|
|
2072
|
-
import { useCallback as
|
|
3526
|
+
import { useCallback as useCallback5, useEffect as useEffect7, useState as useState7 } from "react";
|
|
2073
3527
|
|
|
2074
3528
|
// src/InspectDialog/InspectSimple.tsx
|
|
2075
|
-
import { useEffect as
|
|
3529
|
+
import { useEffect as useEffect6, useMemo as useMemo5, useRef as useRef6, useState as useState6 } from "react";
|
|
2076
3530
|
import {
|
|
2077
3531
|
captureScreenshot,
|
|
2078
|
-
getElementInspectInfo
|
|
3532
|
+
getElementInspectInfo as getElementInspectInfo2
|
|
2079
3533
|
} from "@ewjdev/anyclick-core";
|
|
2080
|
-
import { Camera, Code, Copy, ExternalLink, FileText, X } from "lucide-react";
|
|
3534
|
+
import { Camera, Code, Copy as Copy2, ExternalLink as ExternalLink2, FileText, X as X2 } from "lucide-react";
|
|
2081
3535
|
|
|
2082
3536
|
// src/ide.ts
|
|
2083
3537
|
var DEFAULT_IDE_CONFIG = {
|
|
@@ -2179,7 +3633,7 @@ function formatSourceLocation(location) {
|
|
|
2179
3633
|
}
|
|
2180
3634
|
|
|
2181
3635
|
// src/InspectDialog/InspectSimple.tsx
|
|
2182
|
-
import { Fragment as
|
|
3636
|
+
import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2183
3637
|
var DEFAULT_COMPACT_CONFIG = {
|
|
2184
3638
|
scale: 0.5,
|
|
2185
3639
|
fonts: {
|
|
@@ -2241,8 +3695,8 @@ function downloadDataUrl(dataUrl, filename) {
|
|
|
2241
3695
|
link.click();
|
|
2242
3696
|
}
|
|
2243
3697
|
function useIsMobile() {
|
|
2244
|
-
const [isMobile, setIsMobile] =
|
|
2245
|
-
|
|
3698
|
+
const [isMobile, setIsMobile] = useState6(false);
|
|
3699
|
+
useEffect6(() => {
|
|
2246
3700
|
const mq = window.matchMedia("(max-width: 640px)");
|
|
2247
3701
|
setIsMobile(mq.matches);
|
|
2248
3702
|
const handler = (e) => setIsMobile(e.matches);
|
|
@@ -2260,20 +3714,20 @@ function InspectSimple({
|
|
|
2260
3714
|
className,
|
|
2261
3715
|
highlightColors
|
|
2262
3716
|
}) {
|
|
2263
|
-
const [info, setInfo] =
|
|
2264
|
-
const [sourceLocation, setSourceLocation] =
|
|
3717
|
+
const [info, setInfo] = useState6(null);
|
|
3718
|
+
const [sourceLocation, setSourceLocation] = useState6(
|
|
2265
3719
|
null
|
|
2266
3720
|
);
|
|
2267
|
-
const [status, setStatus] =
|
|
2268
|
-
const [saving, setSaving] =
|
|
2269
|
-
const dialogRef =
|
|
3721
|
+
const [status, setStatus] = useState6(null);
|
|
3722
|
+
const [saving, setSaving] = useState6(false);
|
|
3723
|
+
const dialogRef = useRef6(null);
|
|
2270
3724
|
const isMobile = useIsMobile();
|
|
2271
|
-
|
|
3725
|
+
useEffect6(() => {
|
|
2272
3726
|
if (!status) return;
|
|
2273
3727
|
const timer = setTimeout(() => setStatus(null), 5e3);
|
|
2274
3728
|
return () => clearTimeout(timer);
|
|
2275
3729
|
}, [status]);
|
|
2276
|
-
|
|
3730
|
+
useEffect6(() => {
|
|
2277
3731
|
if (!visible || !targetElement) return;
|
|
2278
3732
|
try {
|
|
2279
3733
|
clearHighlights();
|
|
@@ -2282,7 +3736,7 @@ function InspectSimple({
|
|
|
2282
3736
|
if (container) highlightContainer(container, highlightColors);
|
|
2283
3737
|
} catch {
|
|
2284
3738
|
}
|
|
2285
|
-
const nextInfo =
|
|
3739
|
+
const nextInfo = getElementInspectInfo2(targetElement);
|
|
2286
3740
|
setInfo(nextInfo);
|
|
2287
3741
|
setSourceLocation(
|
|
2288
3742
|
findSourceLocationInAncestors(targetElement) ?? nextInfo.sourceLocation ?? null
|
|
@@ -2291,7 +3745,7 @@ function InspectSimple({
|
|
|
2291
3745
|
clearHighlights();
|
|
2292
3746
|
};
|
|
2293
3747
|
}, [visible, targetElement, highlightColors]);
|
|
2294
|
-
|
|
3748
|
+
useEffect6(() => {
|
|
2295
3749
|
if (!visible) return;
|
|
2296
3750
|
const handleClickOutside = (e) => {
|
|
2297
3751
|
if (dialogRef.current && !dialogRef.current.contains(e.target)) {
|
|
@@ -2306,7 +3760,7 @@ function InspectSimple({
|
|
|
2306
3760
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
2307
3761
|
};
|
|
2308
3762
|
}, [visible, onClose]);
|
|
2309
|
-
const identityLabel =
|
|
3763
|
+
const identityLabel = useMemo5(() => {
|
|
2310
3764
|
if (!info) return "Select an element";
|
|
2311
3765
|
const classes = info.classNames[0] ? `.${info.classNames[0]}` : "";
|
|
2312
3766
|
const id = info.id ? `#${info.id}` : "";
|
|
@@ -2392,8 +3846,8 @@ function InspectSimple({
|
|
|
2392
3846
|
overflow: "hidden",
|
|
2393
3847
|
...style
|
|
2394
3848
|
};
|
|
2395
|
-
return /* @__PURE__ */
|
|
2396
|
-
/* @__PURE__ */
|
|
3849
|
+
return /* @__PURE__ */ jsxs5(Fragment4, { children: [
|
|
3850
|
+
/* @__PURE__ */ jsx5(
|
|
2397
3851
|
"div",
|
|
2398
3852
|
{
|
|
2399
3853
|
style: {
|
|
@@ -2408,14 +3862,14 @@ function InspectSimple({
|
|
|
2408
3862
|
role: "presentation"
|
|
2409
3863
|
}
|
|
2410
3864
|
),
|
|
2411
|
-
/* @__PURE__ */
|
|
3865
|
+
/* @__PURE__ */ jsxs5(
|
|
2412
3866
|
"div",
|
|
2413
3867
|
{
|
|
2414
3868
|
ref: dialogRef,
|
|
2415
3869
|
className: `anyclick-tiny-inspect ${className ?? ""}`,
|
|
2416
3870
|
style: dialogStyles,
|
|
2417
3871
|
children: [
|
|
2418
|
-
/* @__PURE__ */
|
|
3872
|
+
/* @__PURE__ */ jsxs5(
|
|
2419
3873
|
"div",
|
|
2420
3874
|
{
|
|
2421
3875
|
style: {
|
|
@@ -2427,7 +3881,7 @@ function InspectSimple({
|
|
|
2427
3881
|
borderBottom: "1px solid #1e293b"
|
|
2428
3882
|
},
|
|
2429
3883
|
children: [
|
|
2430
|
-
isMobile && /* @__PURE__ */
|
|
3884
|
+
isMobile && /* @__PURE__ */ jsx5(
|
|
2431
3885
|
"div",
|
|
2432
3886
|
{
|
|
2433
3887
|
style: {
|
|
@@ -2442,8 +3896,8 @@ function InspectSimple({
|
|
|
2442
3896
|
}
|
|
2443
3897
|
}
|
|
2444
3898
|
),
|
|
2445
|
-
/* @__PURE__ */
|
|
2446
|
-
/* @__PURE__ */
|
|
3899
|
+
/* @__PURE__ */ jsxs5("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
3900
|
+
/* @__PURE__ */ jsx5(
|
|
2447
3901
|
"span",
|
|
2448
3902
|
{
|
|
2449
3903
|
style: {
|
|
@@ -2458,31 +3912,31 @@ function InspectSimple({
|
|
|
2458
3912
|
children: identityLabel
|
|
2459
3913
|
}
|
|
2460
3914
|
),
|
|
2461
|
-
sourceLocation && /* @__PURE__ */
|
|
3915
|
+
sourceLocation && /* @__PURE__ */ jsx5(
|
|
2462
3916
|
"button",
|
|
2463
3917
|
{
|
|
2464
3918
|
type: "button",
|
|
2465
3919
|
onClick: handleOpenIDE,
|
|
2466
3920
|
title: formatSourceLocation(sourceLocation),
|
|
2467
3921
|
style: iconBtnStyle,
|
|
2468
|
-
children: /* @__PURE__ */
|
|
3922
|
+
children: /* @__PURE__ */ jsx5(ExternalLink2, { size: 14 })
|
|
2469
3923
|
}
|
|
2470
3924
|
)
|
|
2471
3925
|
] }),
|
|
2472
|
-
/* @__PURE__ */
|
|
3926
|
+
/* @__PURE__ */ jsx5(
|
|
2473
3927
|
"button",
|
|
2474
3928
|
{
|
|
2475
3929
|
type: "button",
|
|
2476
3930
|
onClick: onClose,
|
|
2477
3931
|
style: iconBtnStyle,
|
|
2478
3932
|
"aria-label": "Close inspector",
|
|
2479
|
-
children: /* @__PURE__ */
|
|
3933
|
+
children: /* @__PURE__ */ jsx5(X2, { size: 16 })
|
|
2480
3934
|
}
|
|
2481
3935
|
)
|
|
2482
3936
|
]
|
|
2483
3937
|
}
|
|
2484
3938
|
),
|
|
2485
|
-
/* @__PURE__ */
|
|
3939
|
+
/* @__PURE__ */ jsxs5(
|
|
2486
3940
|
"div",
|
|
2487
3941
|
{
|
|
2488
3942
|
style: {
|
|
@@ -2492,7 +3946,7 @@ function InspectSimple({
|
|
|
2492
3946
|
gap: 8
|
|
2493
3947
|
},
|
|
2494
3948
|
children: [
|
|
2495
|
-
info?.selector && /* @__PURE__ */
|
|
3949
|
+
info?.selector && /* @__PURE__ */ jsx5(
|
|
2496
3950
|
"code",
|
|
2497
3951
|
{
|
|
2498
3952
|
style: {
|
|
@@ -2507,7 +3961,7 @@ function InspectSimple({
|
|
|
2507
3961
|
children: info.selector
|
|
2508
3962
|
}
|
|
2509
3963
|
),
|
|
2510
|
-
status && /* @__PURE__ */
|
|
3964
|
+
status && /* @__PURE__ */ jsx5(
|
|
2511
3965
|
"div",
|
|
2512
3966
|
{
|
|
2513
3967
|
style: {
|
|
@@ -2519,7 +3973,7 @@ function InspectSimple({
|
|
|
2519
3973
|
children: status
|
|
2520
3974
|
}
|
|
2521
3975
|
),
|
|
2522
|
-
/* @__PURE__ */
|
|
3976
|
+
/* @__PURE__ */ jsxs5(
|
|
2523
3977
|
"div",
|
|
2524
3978
|
{
|
|
2525
3979
|
style: {
|
|
@@ -2528,7 +3982,7 @@ function InspectSimple({
|
|
|
2528
3982
|
gap: 6
|
|
2529
3983
|
},
|
|
2530
3984
|
children: [
|
|
2531
|
-
/* @__PURE__ */
|
|
3985
|
+
/* @__PURE__ */ jsx5(
|
|
2532
3986
|
"button",
|
|
2533
3987
|
{
|
|
2534
3988
|
type: "button",
|
|
@@ -2536,10 +3990,10 @@ function InspectSimple({
|
|
|
2536
3990
|
style: iconActionStyle,
|
|
2537
3991
|
title: "Copy CSS selector",
|
|
2538
3992
|
"aria-label": "Copy CSS selector",
|
|
2539
|
-
children: /* @__PURE__ */
|
|
3993
|
+
children: /* @__PURE__ */ jsx5(Copy2, { size: 15 })
|
|
2540
3994
|
}
|
|
2541
3995
|
),
|
|
2542
|
-
/* @__PURE__ */
|
|
3996
|
+
/* @__PURE__ */ jsx5(
|
|
2543
3997
|
"button",
|
|
2544
3998
|
{
|
|
2545
3999
|
type: "button",
|
|
@@ -2547,10 +4001,10 @@ function InspectSimple({
|
|
|
2547
4001
|
style: iconActionStyle,
|
|
2548
4002
|
title: "Copy text content",
|
|
2549
4003
|
"aria-label": "Copy text content",
|
|
2550
|
-
children: /* @__PURE__ */
|
|
4004
|
+
children: /* @__PURE__ */ jsx5(FileText, { size: 15 })
|
|
2551
4005
|
}
|
|
2552
4006
|
),
|
|
2553
|
-
/* @__PURE__ */
|
|
4007
|
+
/* @__PURE__ */ jsx5(
|
|
2554
4008
|
"button",
|
|
2555
4009
|
{
|
|
2556
4010
|
type: "button",
|
|
@@ -2558,10 +4012,10 @@ function InspectSimple({
|
|
|
2558
4012
|
style: iconActionStyle,
|
|
2559
4013
|
title: "Copy HTML markup",
|
|
2560
4014
|
"aria-label": "Copy HTML markup",
|
|
2561
|
-
children: /* @__PURE__ */
|
|
4015
|
+
children: /* @__PURE__ */ jsx5(Code, { size: 15 })
|
|
2562
4016
|
}
|
|
2563
4017
|
),
|
|
2564
|
-
/* @__PURE__ */
|
|
4018
|
+
/* @__PURE__ */ jsx5(
|
|
2565
4019
|
"button",
|
|
2566
4020
|
{
|
|
2567
4021
|
type: "button",
|
|
@@ -2573,7 +4027,7 @@ function InspectSimple({
|
|
|
2573
4027
|
disabled: saving,
|
|
2574
4028
|
title: "Save screenshot",
|
|
2575
4029
|
"aria-label": "Save screenshot",
|
|
2576
|
-
children: /* @__PURE__ */
|
|
4030
|
+
children: /* @__PURE__ */ jsx5(Camera, { size: 15 })
|
|
2577
4031
|
}
|
|
2578
4032
|
)
|
|
2579
4033
|
]
|
|
@@ -2616,7 +4070,7 @@ var iconActionStyle = {
|
|
|
2616
4070
|
};
|
|
2617
4071
|
|
|
2618
4072
|
// src/InspectDialog/InspectDialogManager.tsx
|
|
2619
|
-
import { jsx as
|
|
4073
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
2620
4074
|
var INSPECT_DIALOG_EVENT = "anyclick:inspect";
|
|
2621
4075
|
function openInspectDialog(targetElement) {
|
|
2622
4076
|
if (typeof window === "undefined") return;
|
|
@@ -2639,16 +4093,16 @@ function InspectDialogManager({
|
|
|
2639
4093
|
initialPinnedPosition = "floating",
|
|
2640
4094
|
compactConfig
|
|
2641
4095
|
}) {
|
|
2642
|
-
const [visible, setVisible] =
|
|
2643
|
-
const [targetElement, setTargetElement] =
|
|
2644
|
-
const handleClose =
|
|
4096
|
+
const [visible, setVisible] = useState7(false);
|
|
4097
|
+
const [targetElement, setTargetElement] = useState7(null);
|
|
4098
|
+
const handleClose = useCallback5(() => {
|
|
2645
4099
|
setVisible(false);
|
|
2646
4100
|
setTargetElement(null);
|
|
2647
4101
|
}, []);
|
|
2648
|
-
const handleSelectElement =
|
|
4102
|
+
const handleSelectElement = useCallback5((element) => {
|
|
2649
4103
|
setTargetElement(element);
|
|
2650
4104
|
}, []);
|
|
2651
|
-
|
|
4105
|
+
useEffect7(() => {
|
|
2652
4106
|
const handleInspectEvent = (event) => {
|
|
2653
4107
|
const customEvent = event;
|
|
2654
4108
|
if (customEvent.detail?.targetElement) {
|
|
@@ -2661,7 +4115,7 @@ function InspectDialogManager({
|
|
|
2661
4115
|
window.removeEventListener(INSPECT_DIALOG_EVENT, handleInspectEvent);
|
|
2662
4116
|
};
|
|
2663
4117
|
}, []);
|
|
2664
|
-
return /* @__PURE__ */
|
|
4118
|
+
return /* @__PURE__ */ jsx6(
|
|
2665
4119
|
InspectSimple,
|
|
2666
4120
|
{
|
|
2667
4121
|
visible,
|
|
@@ -2723,6 +4177,20 @@ var presetDefaults = {
|
|
|
2723
4177
|
showComment: false,
|
|
2724
4178
|
type: "search_google"
|
|
2725
4179
|
},
|
|
4180
|
+
{
|
|
4181
|
+
label: "Ask t3.chat",
|
|
4182
|
+
onClick: ({ closeMenu }) => {
|
|
4183
|
+
closeMenu();
|
|
4184
|
+
if (typeof window === "undefined") return false;
|
|
4185
|
+
const selection = window.getSelection()?.toString().trim();
|
|
4186
|
+
const query = selection && selection.length > 0 ? selection : "";
|
|
4187
|
+
const url = query ? `https://t3.chat/?q=${encodeURIComponent(query)}` : "https://t3.chat";
|
|
4188
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
4189
|
+
return false;
|
|
4190
|
+
},
|
|
4191
|
+
showComment: false,
|
|
4192
|
+
type: "ask_t3chat"
|
|
4193
|
+
},
|
|
2726
4194
|
{
|
|
2727
4195
|
label: "Share\u2026",
|
|
2728
4196
|
onClick: async ({ closeMenu }) => {
|
|
@@ -2992,6 +4460,172 @@ function listPresets() {
|
|
|
2992
4460
|
}))
|
|
2993
4461
|
}));
|
|
2994
4462
|
}
|
|
4463
|
+
function createT3ChatMenuItem(options = {}) {
|
|
4464
|
+
const { label = "Ask t3.chat", baseUrl = "https://t3.chat" } = options;
|
|
4465
|
+
return {
|
|
4466
|
+
label,
|
|
4467
|
+
onClick: ({ closeMenu }) => {
|
|
4468
|
+
closeMenu();
|
|
4469
|
+
if (typeof window === "undefined") return false;
|
|
4470
|
+
const selection = window.getSelection()?.toString().trim();
|
|
4471
|
+
const query = selection && selection.length > 0 ? selection : "";
|
|
4472
|
+
const url = query ? `${baseUrl}/?q=${encodeURIComponent(query)}` : baseUrl;
|
|
4473
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
4474
|
+
return false;
|
|
4475
|
+
},
|
|
4476
|
+
showComment: false,
|
|
4477
|
+
type: "ask_t3chat"
|
|
4478
|
+
};
|
|
4479
|
+
}
|
|
4480
|
+
function getSelectedText() {
|
|
4481
|
+
if (typeof window === "undefined") return "";
|
|
4482
|
+
return window.getSelection()?.toString().trim() ?? "";
|
|
4483
|
+
}
|
|
4484
|
+
function hasTextSelection() {
|
|
4485
|
+
return getSelectedText().length > 0;
|
|
4486
|
+
}
|
|
4487
|
+
function detectImageElement(element) {
|
|
4488
|
+
if (!element) return { isImage: false };
|
|
4489
|
+
if (element.tagName === "IMG") {
|
|
4490
|
+
const img = element;
|
|
4491
|
+
return {
|
|
4492
|
+
isImage: true,
|
|
4493
|
+
src: img.src || img.currentSrc,
|
|
4494
|
+
type: "img"
|
|
4495
|
+
};
|
|
4496
|
+
}
|
|
4497
|
+
if (element.tagName === "PICTURE") {
|
|
4498
|
+
const img = element.querySelector("img");
|
|
4499
|
+
return {
|
|
4500
|
+
isImage: true,
|
|
4501
|
+
src: img?.src || img?.currentSrc,
|
|
4502
|
+
type: "picture"
|
|
4503
|
+
};
|
|
4504
|
+
}
|
|
4505
|
+
if (element.tagName === "SVG" || element.tagName === "svg") {
|
|
4506
|
+
return {
|
|
4507
|
+
isImage: true,
|
|
4508
|
+
type: "svg"
|
|
4509
|
+
};
|
|
4510
|
+
}
|
|
4511
|
+
if (element.tagName === "CANVAS") {
|
|
4512
|
+
return {
|
|
4513
|
+
isImage: true,
|
|
4514
|
+
type: "canvas"
|
|
4515
|
+
};
|
|
4516
|
+
}
|
|
4517
|
+
if (typeof window !== "undefined") {
|
|
4518
|
+
const computedStyle = window.getComputedStyle(element);
|
|
4519
|
+
const backgroundImage = computedStyle.backgroundImage;
|
|
4520
|
+
if (backgroundImage && backgroundImage !== "none") {
|
|
4521
|
+
const urlMatch = backgroundImage.match(/url\(["']?(.+?)["']?\)/);
|
|
4522
|
+
if (urlMatch) {
|
|
4523
|
+
return {
|
|
4524
|
+
isImage: true,
|
|
4525
|
+
src: urlMatch[1],
|
|
4526
|
+
type: "background"
|
|
4527
|
+
};
|
|
4528
|
+
}
|
|
4529
|
+
}
|
|
4530
|
+
}
|
|
4531
|
+
const imgChild = element.querySelector("img");
|
|
4532
|
+
if (imgChild) {
|
|
4533
|
+
return {
|
|
4534
|
+
isImage: true,
|
|
4535
|
+
src: imgChild.src || imgChild.currentSrc,
|
|
4536
|
+
type: "img"
|
|
4537
|
+
};
|
|
4538
|
+
}
|
|
4539
|
+
return { isImage: false };
|
|
4540
|
+
}
|
|
4541
|
+
function createUploadThingMenuItem(options = {}) {
|
|
4542
|
+
const {
|
|
4543
|
+
label = "Upload to UploadThing",
|
|
4544
|
+
endpoint = "/api/uploadthing",
|
|
4545
|
+
onUploadComplete,
|
|
4546
|
+
onUploadError
|
|
4547
|
+
} = options;
|
|
4548
|
+
return {
|
|
4549
|
+
label,
|
|
4550
|
+
onClick: async ({ closeMenu, targetElement }) => {
|
|
4551
|
+
if (!targetElement) {
|
|
4552
|
+
onUploadError?.(new Error("No target element"));
|
|
4553
|
+
return false;
|
|
4554
|
+
}
|
|
4555
|
+
try {
|
|
4556
|
+
const imageInfo = detectImageElement(targetElement);
|
|
4557
|
+
if (imageInfo.isImage && imageInfo.src) {
|
|
4558
|
+
const response = await fetch(imageInfo.src);
|
|
4559
|
+
const blob = await response.blob();
|
|
4560
|
+
const formData = new FormData();
|
|
4561
|
+
const filename = `image-${Date.now()}.${blob.type.split("/")[1] || "png"}`;
|
|
4562
|
+
formData.append("file", blob, filename);
|
|
4563
|
+
const uploadResponse = await fetch(endpoint, {
|
|
4564
|
+
method: "POST",
|
|
4565
|
+
body: formData
|
|
4566
|
+
});
|
|
4567
|
+
if (!uploadResponse.ok) {
|
|
4568
|
+
throw new Error(`Upload failed: ${uploadResponse.status}`);
|
|
4569
|
+
}
|
|
4570
|
+
const result = await uploadResponse.json();
|
|
4571
|
+
onUploadComplete?.(result);
|
|
4572
|
+
} else if (imageInfo.isImage && imageInfo.type === "canvas") {
|
|
4573
|
+
const canvas = targetElement;
|
|
4574
|
+
const dataUrl = canvas.toDataURL("image/png");
|
|
4575
|
+
const response = await fetch(dataUrl);
|
|
4576
|
+
const blob = await response.blob();
|
|
4577
|
+
const formData = new FormData();
|
|
4578
|
+
formData.append("file", blob, `canvas-${Date.now()}.png`);
|
|
4579
|
+
const uploadResponse = await fetch(endpoint, {
|
|
4580
|
+
method: "POST",
|
|
4581
|
+
body: formData
|
|
4582
|
+
});
|
|
4583
|
+
if (!uploadResponse.ok) {
|
|
4584
|
+
throw new Error(`Upload failed: ${uploadResponse.status}`);
|
|
4585
|
+
}
|
|
4586
|
+
const result = await uploadResponse.json();
|
|
4587
|
+
onUploadComplete?.(result);
|
|
4588
|
+
} else {
|
|
4589
|
+
onUploadError?.(
|
|
4590
|
+
new Error(
|
|
4591
|
+
"Element is not an image. Screenshot upload requires anyclick-core."
|
|
4592
|
+
)
|
|
4593
|
+
);
|
|
4594
|
+
}
|
|
4595
|
+
} catch (error) {
|
|
4596
|
+
onUploadError?.(
|
|
4597
|
+
error instanceof Error ? error : new Error(String(error))
|
|
4598
|
+
);
|
|
4599
|
+
}
|
|
4600
|
+
closeMenu();
|
|
4601
|
+
return false;
|
|
4602
|
+
},
|
|
4603
|
+
showComment: false,
|
|
4604
|
+
type: "upload_image"
|
|
4605
|
+
};
|
|
4606
|
+
}
|
|
4607
|
+
function createUploadScreenshotMenuItem(options = {}) {
|
|
4608
|
+
const {
|
|
4609
|
+
label = "Upload Screenshot",
|
|
4610
|
+
endpoint = "/api/uploadthing",
|
|
4611
|
+
onUploadComplete,
|
|
4612
|
+
onUploadError
|
|
4613
|
+
} = options;
|
|
4614
|
+
return {
|
|
4615
|
+
label,
|
|
4616
|
+
badge: { label: "Coming soon", tone: "info" },
|
|
4617
|
+
status: "comingSoon",
|
|
4618
|
+
onClick: async ({ closeMenu }) => {
|
|
4619
|
+
onUploadError?.(
|
|
4620
|
+
new Error("Screenshot upload will be available in a future release")
|
|
4621
|
+
);
|
|
4622
|
+
closeMenu();
|
|
4623
|
+
return false;
|
|
4624
|
+
},
|
|
4625
|
+
showComment: false,
|
|
4626
|
+
type: "upload_screenshot"
|
|
4627
|
+
};
|
|
4628
|
+
}
|
|
2995
4629
|
|
|
2996
4630
|
// src/types.ts
|
|
2997
4631
|
function filterMenuItemsByRole(items, userContext) {
|
|
@@ -3021,7 +4655,7 @@ import {
|
|
|
3021
4655
|
} from "@ewjdev/anyclick-core";
|
|
3022
4656
|
|
|
3023
4657
|
// src/AnyclickLogo.tsx
|
|
3024
|
-
import { jsx as
|
|
4658
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
3025
4659
|
function AnyclickLogo({
|
|
3026
4660
|
size = 64,
|
|
3027
4661
|
borderWidth = 2,
|
|
@@ -3033,7 +4667,7 @@ function AnyclickLogo({
|
|
|
3033
4667
|
}) {
|
|
3034
4668
|
const cursorSize = size * 0.45;
|
|
3035
4669
|
const cursorStroke = borderWidth;
|
|
3036
|
-
return /* @__PURE__ */
|
|
4670
|
+
return /* @__PURE__ */ jsxs6(
|
|
3037
4671
|
"svg",
|
|
3038
4672
|
{
|
|
3039
4673
|
width: size,
|
|
@@ -3047,7 +4681,7 @@ function AnyclickLogo({
|
|
|
3047
4681
|
role: onClick ? "button" : "img",
|
|
3048
4682
|
"aria-label": "Anyclick Logo",
|
|
3049
4683
|
children: [
|
|
3050
|
-
/* @__PURE__ */
|
|
4684
|
+
/* @__PURE__ */ jsx7(
|
|
3051
4685
|
"circle",
|
|
3052
4686
|
{
|
|
3053
4687
|
cx: size / 2,
|
|
@@ -3058,11 +4692,11 @@ function AnyclickLogo({
|
|
|
3058
4692
|
strokeWidth: borderWidth
|
|
3059
4693
|
}
|
|
3060
4694
|
),
|
|
3061
|
-
/* @__PURE__ */
|
|
4695
|
+
/* @__PURE__ */ jsx7(
|
|
3062
4696
|
"g",
|
|
3063
4697
|
{
|
|
3064
4698
|
transform: `translate(${(size - cursorSize) / 2}, ${(size - cursorSize) / 2})`,
|
|
3065
|
-
children: /* @__PURE__ */
|
|
4699
|
+
children: /* @__PURE__ */ jsx7(
|
|
3066
4700
|
"path",
|
|
3067
4701
|
{
|
|
3068
4702
|
d: `
|
|
@@ -3095,7 +4729,7 @@ import {
|
|
|
3095
4729
|
getAccessibilityInfo,
|
|
3096
4730
|
getBoxModelInfo,
|
|
3097
4731
|
getAttributes,
|
|
3098
|
-
getElementInspectInfo as
|
|
4732
|
+
getElementInspectInfo as getElementInspectInfo3,
|
|
3099
4733
|
formatStylesAsCSS,
|
|
3100
4734
|
formatBoxModel,
|
|
3101
4735
|
CURATED_STYLE_PROPERTIES,
|
|
@@ -3109,6 +4743,7 @@ export {
|
|
|
3109
4743
|
CURATED_STYLE_PROPERTIES,
|
|
3110
4744
|
ContextMenu,
|
|
3111
4745
|
DEFAULT_COMPACT_CONFIG,
|
|
4746
|
+
DEFAULT_QUICK_CHAT_CONFIG,
|
|
3112
4747
|
DEFAULT_SCREENSHOT_CONFIG2 as DEFAULT_SCREENSHOT_CONFIG,
|
|
3113
4748
|
DEFAULT_SENSITIVE_SELECTORS,
|
|
3114
4749
|
FeedbackContext,
|
|
@@ -3117,6 +4752,7 @@ export {
|
|
|
3117
4752
|
INSPECT_DIALOG_EVENT,
|
|
3118
4753
|
InspectDialogManager,
|
|
3119
4754
|
InspectSimple,
|
|
4755
|
+
QuickChat,
|
|
3120
4756
|
ScreenshotPreview,
|
|
3121
4757
|
applyHighlights,
|
|
3122
4758
|
buildIDEUrl,
|
|
@@ -3125,9 +4761,13 @@ export {
|
|
|
3125
4761
|
clearHighlights,
|
|
3126
4762
|
createIDEOpener,
|
|
3127
4763
|
createPresetMenu,
|
|
4764
|
+
createT3ChatMenuItem,
|
|
4765
|
+
createUploadScreenshotMenuItem,
|
|
4766
|
+
createUploadThingMenuItem,
|
|
3128
4767
|
darkMenuStyles,
|
|
3129
4768
|
defaultContainerSelectors,
|
|
3130
4769
|
defaultHighlightColors,
|
|
4770
|
+
detectImageElement,
|
|
3131
4771
|
detectPreferredIDE,
|
|
3132
4772
|
dispatchContextMenuEvent,
|
|
3133
4773
|
estimateTotalSize2 as estimateTotalSize,
|
|
@@ -3144,8 +4784,10 @@ export {
|
|
|
3144
4784
|
getBadgeStyle,
|
|
3145
4785
|
getBoxModelInfo,
|
|
3146
4786
|
getComputedStyles,
|
|
3147
|
-
|
|
4787
|
+
getElementInspectInfo3 as getElementInspectInfo,
|
|
4788
|
+
getSelectedText,
|
|
3148
4789
|
getSourceLocationFromElement,
|
|
4790
|
+
hasTextSelection,
|
|
3149
4791
|
highlightContainer,
|
|
3150
4792
|
highlightTarget,
|
|
3151
4793
|
isIDEProtocolSupported,
|
|
@@ -3156,8 +4798,11 @@ export {
|
|
|
3156
4798
|
openInIDE,
|
|
3157
4799
|
openInspectDialog,
|
|
3158
4800
|
presetDefaults,
|
|
4801
|
+
quickChatKeyframes,
|
|
4802
|
+
quickChatStyles,
|
|
3159
4803
|
useAnyclick,
|
|
3160
4804
|
useFeedback,
|
|
3161
|
-
useProviderStore
|
|
4805
|
+
useProviderStore,
|
|
4806
|
+
useQuickChat
|
|
3162
4807
|
};
|
|
3163
4808
|
//# sourceMappingURL=index.mjs.map
|