@ewjdev/anyclick-react 2.0.0 → 4.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/chunk-7KW4HSJM.mjs +35 -0
- package/dist/chunk-7KW4HSJM.mjs.map +1 -0
- package/dist/chunk-YBHJXEH6.mjs +305 -0
- package/dist/chunk-YBHJXEH6.mjs.map +1 -0
- package/dist/index.css +23 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +419 -11
- package/dist/index.d.ts +419 -11
- package/dist/index.js +2539 -310
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2514 -279
- package/dist/index.mjs.map +1 -1
- package/dist/token-EXBG54PO.mjs +66 -0
- package/dist/token-EXBG54PO.mjs.map +1 -0
- package/dist/token-util-4XOQ3GFX.mjs +6 -0
- package/dist/token-util-4XOQ3GFX.mjs.map +1 -0
- package/package.json +20 -9
package/dist/index.js
CHANGED
|
@@ -31,79 +31,1946 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
// src/index.ts
|
|
32
32
|
var index_exports = {};
|
|
33
33
|
__export(index_exports, {
|
|
34
|
-
ALL_CURATED_PROPERTIES: () =>
|
|
34
|
+
ALL_CURATED_PROPERTIES: () => import_anyclick_core8.ALL_CURATED_PROPERTIES,
|
|
35
35
|
AnyclickContext: () => AnyclickContext,
|
|
36
36
|
AnyclickLogo: () => AnyclickLogo,
|
|
37
37
|
AnyclickProvider: () => AnyclickProvider,
|
|
38
|
-
|
|
38
|
+
Button: () => Button,
|
|
39
|
+
CURATED_STYLE_PROPERTIES: () => import_anyclick_core8.CURATED_STYLE_PROPERTIES,
|
|
39
40
|
ContextMenu: () => ContextMenu,
|
|
40
41
|
DEFAULT_COMPACT_CONFIG: () => DEFAULT_COMPACT_CONFIG,
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
DEFAULT_QUICK_CHAT_CONFIG: () => DEFAULT_QUICK_CHAT_CONFIG,
|
|
43
|
+
DEFAULT_SCREENSHOT_CONFIG: () => import_anyclick_core7.DEFAULT_SCREENSHOT_CONFIG,
|
|
44
|
+
DEFAULT_SENSITIVE_SELECTORS: () => import_anyclick_core7.DEFAULT_SENSITIVE_SELECTORS,
|
|
43
45
|
FeedbackContext: () => FeedbackContext,
|
|
44
46
|
FeedbackProvider: () => FeedbackProvider,
|
|
45
47
|
FunModeBridge: () => FunModeBridge,
|
|
46
48
|
INSPECT_DIALOG_EVENT: () => INSPECT_DIALOG_EVENT,
|
|
49
|
+
Input: () => Input,
|
|
47
50
|
InspectDialogManager: () => InspectDialogManager,
|
|
48
51
|
InspectSimple: () => InspectSimple,
|
|
52
|
+
QuickChat: () => QuickChat,
|
|
49
53
|
ScreenshotPreview: () => ScreenshotPreview,
|
|
50
54
|
applyHighlights: () => applyHighlights,
|
|
51
55
|
buildIDEUrl: () => buildIDEUrl,
|
|
52
|
-
captureAllScreenshots: () =>
|
|
53
|
-
captureScreenshot: () =>
|
|
56
|
+
captureAllScreenshots: () => import_anyclick_core7.captureAllScreenshots,
|
|
57
|
+
captureScreenshot: () => import_anyclick_core7.captureScreenshot,
|
|
54
58
|
clearHighlights: () => clearHighlights,
|
|
55
59
|
createIDEOpener: () => createIDEOpener,
|
|
56
60
|
createPresetMenu: () => createPresetMenu,
|
|
61
|
+
createT3ChatMenuItem: () => createT3ChatMenuItem,
|
|
62
|
+
createUploadScreenshotMenuItem: () => createUploadScreenshotMenuItem,
|
|
63
|
+
createUploadThingMenuItem: () => createUploadThingMenuItem,
|
|
57
64
|
darkMenuStyles: () => darkMenuStyles,
|
|
58
65
|
defaultContainerSelectors: () => defaultContainerSelectors,
|
|
59
66
|
defaultHighlightColors: () => defaultHighlightColors,
|
|
67
|
+
detectImageElement: () => detectImageElement,
|
|
60
68
|
detectPreferredIDE: () => detectPreferredIDE,
|
|
61
69
|
dispatchContextMenuEvent: () => dispatchContextMenuEvent,
|
|
62
|
-
estimateTotalSize: () =>
|
|
70
|
+
estimateTotalSize: () => import_anyclick_core7.estimateTotalSize,
|
|
63
71
|
filterMenuItemsByRole: () => filterMenuItemsByRole,
|
|
64
72
|
findContainerParent: () => findContainerParent,
|
|
65
73
|
findSourceLocationInAncestors: () => findSourceLocationInAncestors,
|
|
66
|
-
formatBoxModel: () =>
|
|
67
|
-
formatBytes: () =>
|
|
74
|
+
formatBoxModel: () => import_anyclick_core8.formatBoxModel,
|
|
75
|
+
formatBytes: () => import_anyclick_core7.formatBytes,
|
|
68
76
|
formatSourceLocation: () => formatSourceLocation,
|
|
69
|
-
formatStylesAsCSS: () =>
|
|
77
|
+
formatStylesAsCSS: () => import_anyclick_core8.formatStylesAsCSS,
|
|
70
78
|
generateProviderId: () => generateProviderId,
|
|
71
|
-
getAccessibilityInfo: () =>
|
|
72
|
-
getAttributes: () =>
|
|
79
|
+
getAccessibilityInfo: () => import_anyclick_core8.getAccessibilityInfo,
|
|
80
|
+
getAttributes: () => import_anyclick_core8.getAttributes,
|
|
73
81
|
getBadgeStyle: () => getBadgeStyle,
|
|
74
|
-
getBoxModelInfo: () =>
|
|
75
|
-
getComputedStyles: () =>
|
|
76
|
-
getElementInspectInfo: () =>
|
|
82
|
+
getBoxModelInfo: () => import_anyclick_core8.getBoxModelInfo,
|
|
83
|
+
getComputedStyles: () => import_anyclick_core8.getComputedStyles,
|
|
84
|
+
getElementInspectInfo: () => import_anyclick_core8.getElementInspectInfo,
|
|
85
|
+
getSelectedText: () => getSelectedText,
|
|
77
86
|
getSourceLocationFromElement: () => getSourceLocationFromElement,
|
|
87
|
+
hasTextSelection: () => hasTextSelection,
|
|
78
88
|
highlightContainer: () => highlightContainer,
|
|
79
89
|
highlightTarget: () => highlightTarget,
|
|
80
90
|
isIDEProtocolSupported: () => isIDEProtocolSupported,
|
|
81
|
-
isScreenshotSupported: () =>
|
|
91
|
+
isScreenshotSupported: () => import_anyclick_core7.isScreenshotSupported,
|
|
82
92
|
listPresets: () => listPresets,
|
|
83
93
|
menuCSSVariables: () => menuCSSVariables,
|
|
84
94
|
menuStyles: () => menuStyles,
|
|
85
95
|
openInIDE: () => openInIDE,
|
|
86
96
|
openInspectDialog: () => openInspectDialog,
|
|
87
97
|
presetDefaults: () => presetDefaults,
|
|
98
|
+
quickChatKeyframes: () => quickChatKeyframes,
|
|
99
|
+
quickChatStyles: () => quickChatStyles,
|
|
88
100
|
useAnyclick: () => useAnyclick,
|
|
89
101
|
useFeedback: () => useFeedback,
|
|
90
|
-
useProviderStore: () => useProviderStore
|
|
102
|
+
useProviderStore: () => useProviderStore,
|
|
103
|
+
useQuickChat: () => useQuickChat
|
|
91
104
|
});
|
|
92
105
|
module.exports = __toCommonJS(index_exports);
|
|
93
106
|
|
|
94
107
|
// src/AnyclickProvider.tsx
|
|
95
|
-
var
|
|
96
|
-
var
|
|
108
|
+
var import_react7 = require("react");
|
|
109
|
+
var import_anyclick_core5 = require("@ewjdev/anyclick-core");
|
|
97
110
|
|
|
98
111
|
// src/ContextMenu.tsx
|
|
99
|
-
var
|
|
112
|
+
var import_react5 = __toESM(require("react"));
|
|
113
|
+
var import_anyclick_core4 = require("@ewjdev/anyclick-core");
|
|
114
|
+
var import_lucide_react3 = require("lucide-react");
|
|
115
|
+
|
|
116
|
+
// src/QuickChat/QuickChat.tsx
|
|
117
|
+
var import_react3 = __toESM(require("react"));
|
|
100
118
|
var import_anyclick_core2 = require("@ewjdev/anyclick-core");
|
|
101
|
-
var
|
|
119
|
+
var import_lucide_react = require("lucide-react");
|
|
120
|
+
|
|
121
|
+
// src/QuickChat/styles.ts
|
|
122
|
+
var quickChatStyles = {
|
|
123
|
+
// Inline container - inside the context menu
|
|
124
|
+
container: {
|
|
125
|
+
display: "flex",
|
|
126
|
+
flexDirection: "column",
|
|
127
|
+
width: "100%",
|
|
128
|
+
maxHeight: "320px",
|
|
129
|
+
overflow: "hidden"
|
|
130
|
+
},
|
|
131
|
+
// Pinned drawer - anchored to right side of screen
|
|
132
|
+
pinnedContainer: {
|
|
133
|
+
position: "fixed",
|
|
134
|
+
top: 0,
|
|
135
|
+
right: 0,
|
|
136
|
+
bottom: 0,
|
|
137
|
+
width: "340px",
|
|
138
|
+
display: "flex",
|
|
139
|
+
flexDirection: "column",
|
|
140
|
+
backgroundColor: "var(--anyclick-menu-bg, #ffffff)",
|
|
141
|
+
borderLeft: "1px solid var(--anyclick-menu-border, #e5e5e5)",
|
|
142
|
+
boxShadow: "-4px 0 24px rgba(0, 0, 0, 0.15)",
|
|
143
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
144
|
+
fontSize: "14px",
|
|
145
|
+
overflow: "hidden",
|
|
146
|
+
zIndex: 9998
|
|
147
|
+
},
|
|
148
|
+
// Pinned messages area (taller)
|
|
149
|
+
pinnedMessagesArea: {
|
|
150
|
+
flex: 1,
|
|
151
|
+
overflowY: "auto",
|
|
152
|
+
padding: "12px",
|
|
153
|
+
display: "flex",
|
|
154
|
+
flexDirection: "column",
|
|
155
|
+
gap: "8px",
|
|
156
|
+
minHeight: "200px"
|
|
157
|
+
},
|
|
158
|
+
// Header - minimal design
|
|
159
|
+
header: {
|
|
160
|
+
display: "flex",
|
|
161
|
+
alignItems: "center",
|
|
162
|
+
justifyContent: "space-between",
|
|
163
|
+
padding: "6px 8px",
|
|
164
|
+
gap: "8px"
|
|
165
|
+
},
|
|
166
|
+
headerTitle: {
|
|
167
|
+
fontSize: "11px",
|
|
168
|
+
fontWeight: 600,
|
|
169
|
+
textTransform: "uppercase",
|
|
170
|
+
letterSpacing: "0.5px",
|
|
171
|
+
color: "var(--anyclick-menu-text-muted, #666)"
|
|
172
|
+
},
|
|
173
|
+
headerActions: {
|
|
174
|
+
display: "flex",
|
|
175
|
+
alignItems: "center",
|
|
176
|
+
gap: "2px"
|
|
177
|
+
},
|
|
178
|
+
iconButton: {
|
|
179
|
+
display: "flex",
|
|
180
|
+
alignItems: "center",
|
|
181
|
+
justifyContent: "center",
|
|
182
|
+
width: "24px",
|
|
183
|
+
height: "24px",
|
|
184
|
+
border: "none",
|
|
185
|
+
borderRadius: "4px",
|
|
186
|
+
backgroundColor: "transparent",
|
|
187
|
+
color: "var(--anyclick-menu-text-muted, #666)",
|
|
188
|
+
cursor: "pointer",
|
|
189
|
+
transition: "all 0.15s ease"
|
|
190
|
+
},
|
|
191
|
+
iconButtonActive: {
|
|
192
|
+
backgroundColor: "var(--anyclick-menu-accent, #0066cc)",
|
|
193
|
+
color: "#fff"
|
|
194
|
+
},
|
|
195
|
+
// Context badge in header
|
|
196
|
+
contextBadge: {
|
|
197
|
+
display: "inline-flex",
|
|
198
|
+
alignItems: "center",
|
|
199
|
+
gap: "4px",
|
|
200
|
+
padding: "3px 8px",
|
|
201
|
+
fontSize: "10px",
|
|
202
|
+
fontWeight: 500,
|
|
203
|
+
border: "1px solid var(--anyclick-menu-border, #e5e5e5)",
|
|
204
|
+
borderRadius: "10px",
|
|
205
|
+
backgroundColor: "transparent",
|
|
206
|
+
color: "var(--anyclick-menu-text-muted, #666)",
|
|
207
|
+
cursor: "pointer",
|
|
208
|
+
transition: "all 0.15s ease"
|
|
209
|
+
},
|
|
210
|
+
contextBadgeActive: {
|
|
211
|
+
borderColor: "var(--anyclick-menu-accent, #0066cc)",
|
|
212
|
+
backgroundColor: "rgba(0, 102, 204, 0.08)"
|
|
213
|
+
},
|
|
214
|
+
// Context dropdown (in normal flow, not absolute)
|
|
215
|
+
contextDropdown: {
|
|
216
|
+
display: "flex",
|
|
217
|
+
flexDirection: "column",
|
|
218
|
+
gap: "2px",
|
|
219
|
+
padding: "6px 8px",
|
|
220
|
+
margin: "0 8px 6px 8px",
|
|
221
|
+
backgroundColor: "var(--anyclick-menu-hover, #f5f5f5)",
|
|
222
|
+
borderRadius: "6px",
|
|
223
|
+
maxHeight: "80px",
|
|
224
|
+
overflowY: "auto"
|
|
225
|
+
},
|
|
226
|
+
// Messages area
|
|
227
|
+
messagesArea: {
|
|
228
|
+
flex: 1,
|
|
229
|
+
overflowY: "auto",
|
|
230
|
+
padding: "8px 12px",
|
|
231
|
+
display: "flex",
|
|
232
|
+
flexDirection: "column",
|
|
233
|
+
gap: "8px",
|
|
234
|
+
minHeight: "40px",
|
|
235
|
+
maxHeight: "140px"
|
|
236
|
+
},
|
|
237
|
+
emptyState: {
|
|
238
|
+
display: "none"
|
|
239
|
+
// Hide empty state, placeholder in input is enough
|
|
240
|
+
},
|
|
241
|
+
// Message bubble
|
|
242
|
+
message: {
|
|
243
|
+
display: "flex",
|
|
244
|
+
flexDirection: "column",
|
|
245
|
+
gap: "4px",
|
|
246
|
+
maxWidth: "100%"
|
|
247
|
+
},
|
|
248
|
+
messageUser: {
|
|
249
|
+
alignSelf: "flex-end",
|
|
250
|
+
backgroundColor: "var(--anyclick-menu-accent, #0066cc)",
|
|
251
|
+
color: "#fff",
|
|
252
|
+
padding: "6px 10px",
|
|
253
|
+
borderRadius: "12px 12px 4px 12px",
|
|
254
|
+
fontSize: "13px",
|
|
255
|
+
maxWidth: "85%",
|
|
256
|
+
wordBreak: "break-word"
|
|
257
|
+
},
|
|
258
|
+
messageAssistant: {
|
|
259
|
+
alignSelf: "flex-start",
|
|
260
|
+
backgroundColor: "var(--anyclick-menu-hover, #f5f5f5)",
|
|
261
|
+
color: "var(--anyclick-menu-text, #333)",
|
|
262
|
+
padding: "8px 10px",
|
|
263
|
+
borderRadius: "12px 12px 12px 4px",
|
|
264
|
+
fontSize: "13px",
|
|
265
|
+
maxWidth: "100%",
|
|
266
|
+
wordBreak: "break-word",
|
|
267
|
+
lineHeight: 1.4
|
|
268
|
+
},
|
|
269
|
+
messageActions: {
|
|
270
|
+
display: "flex",
|
|
271
|
+
gap: "4px",
|
|
272
|
+
marginTop: "4px",
|
|
273
|
+
flexWrap: "wrap"
|
|
274
|
+
},
|
|
275
|
+
actionButton: {
|
|
276
|
+
display: "inline-flex",
|
|
277
|
+
alignItems: "center",
|
|
278
|
+
gap: "4px",
|
|
279
|
+
padding: "3px 8px",
|
|
280
|
+
fontSize: "11px",
|
|
281
|
+
fontWeight: 500,
|
|
282
|
+
border: "1px solid var(--anyclick-menu-border, #e5e5e5)",
|
|
283
|
+
borderRadius: "4px",
|
|
284
|
+
backgroundColor: "transparent",
|
|
285
|
+
color: "var(--anyclick-menu-text-muted, #666)",
|
|
286
|
+
cursor: "pointer",
|
|
287
|
+
transition: "all 0.15s ease"
|
|
288
|
+
},
|
|
289
|
+
streamingIndicator: {
|
|
290
|
+
display: "inline-block",
|
|
291
|
+
width: "4px",
|
|
292
|
+
height: "14px",
|
|
293
|
+
backgroundColor: "var(--anyclick-menu-accent, #0066cc)",
|
|
294
|
+
borderRadius: "1px",
|
|
295
|
+
animation: "blink 1s infinite"
|
|
296
|
+
},
|
|
297
|
+
// Suggestions - compact horizontal scroll
|
|
298
|
+
suggestionsContainer: {
|
|
299
|
+
display: "flex",
|
|
300
|
+
flexDirection: "column",
|
|
301
|
+
gap: "6px",
|
|
302
|
+
padding: "6px 8px",
|
|
303
|
+
overflowX: "auto",
|
|
304
|
+
overflowY: "hidden",
|
|
305
|
+
scrollbarWidth: "none",
|
|
306
|
+
msOverflowStyle: "none"
|
|
307
|
+
},
|
|
308
|
+
suggestionChip: {
|
|
309
|
+
display: "inline-flex",
|
|
310
|
+
alignItems: "center",
|
|
311
|
+
padding: "4px 10px",
|
|
312
|
+
fontSize: "11px",
|
|
313
|
+
border: "1px solid var(--anyclick-menu-border, #e5e5e5)",
|
|
314
|
+
borderRadius: "12px",
|
|
315
|
+
backgroundColor: "var(--anyclick-menu-hover, #f5f5f5)",
|
|
316
|
+
color: "var(--anyclick-menu-text, #333)",
|
|
317
|
+
cursor: "pointer",
|
|
318
|
+
transition: "all 0.15s ease",
|
|
319
|
+
whiteSpace: "nowrap",
|
|
320
|
+
flexShrink: 0
|
|
321
|
+
},
|
|
322
|
+
suggestionChipHover: {
|
|
323
|
+
backgroundColor: "var(--anyclick-menu-bg, #fff)",
|
|
324
|
+
borderColor: "var(--anyclick-menu-accent, #0066cc)"
|
|
325
|
+
},
|
|
326
|
+
// Context redaction - now in dropdown
|
|
327
|
+
contextContainer: {
|
|
328
|
+
display: "flex",
|
|
329
|
+
flexDirection: "column",
|
|
330
|
+
gap: "4px"
|
|
331
|
+
},
|
|
332
|
+
contextHeader: {
|
|
333
|
+
display: "flex",
|
|
334
|
+
alignItems: "center",
|
|
335
|
+
justifyContent: "space-between",
|
|
336
|
+
marginBottom: "4px"
|
|
337
|
+
},
|
|
338
|
+
contextTitle: {
|
|
339
|
+
fontSize: "10px",
|
|
340
|
+
fontWeight: 600,
|
|
341
|
+
textTransform: "uppercase",
|
|
342
|
+
letterSpacing: "0.5px",
|
|
343
|
+
color: "var(--anyclick-menu-text-muted, #666)"
|
|
344
|
+
},
|
|
345
|
+
contextToggle: {
|
|
346
|
+
fontSize: "10px",
|
|
347
|
+
color: "var(--anyclick-menu-accent, #0066cc)",
|
|
348
|
+
background: "none",
|
|
349
|
+
border: "none",
|
|
350
|
+
cursor: "pointer",
|
|
351
|
+
padding: 0
|
|
352
|
+
},
|
|
353
|
+
contextToggleSmall: {
|
|
354
|
+
fontSize: "9px",
|
|
355
|
+
fontWeight: 500,
|
|
356
|
+
color: "var(--anyclick-menu-text-muted, #666)",
|
|
357
|
+
background: "none",
|
|
358
|
+
border: "none",
|
|
359
|
+
cursor: "pointer",
|
|
360
|
+
padding: "2px 4px",
|
|
361
|
+
borderRadius: "3px",
|
|
362
|
+
transition: "all 0.15s ease"
|
|
363
|
+
},
|
|
364
|
+
contextChunks: {
|
|
365
|
+
display: "flex",
|
|
366
|
+
flexDirection: "column",
|
|
367
|
+
gap: "4px"
|
|
368
|
+
},
|
|
369
|
+
contextChunk: {
|
|
370
|
+
display: "flex",
|
|
371
|
+
alignItems: "center",
|
|
372
|
+
gap: "6px",
|
|
373
|
+
padding: "4px 6px",
|
|
374
|
+
borderRadius: "4px",
|
|
375
|
+
fontSize: "11px",
|
|
376
|
+
backgroundColor: "var(--anyclick-menu-hover, #f5f5f5)",
|
|
377
|
+
cursor: "pointer",
|
|
378
|
+
transition: "opacity 0.15s ease"
|
|
379
|
+
},
|
|
380
|
+
contextChunkCompact: {
|
|
381
|
+
display: "flex",
|
|
382
|
+
alignItems: "center",
|
|
383
|
+
gap: "6px",
|
|
384
|
+
padding: "2px 4px",
|
|
385
|
+
borderRadius: "3px",
|
|
386
|
+
fontSize: "10px",
|
|
387
|
+
cursor: "pointer",
|
|
388
|
+
transition: "opacity 0.15s ease"
|
|
389
|
+
},
|
|
390
|
+
contextChunkExcluded: {
|
|
391
|
+
opacity: 0.5,
|
|
392
|
+
textDecoration: "line-through"
|
|
393
|
+
},
|
|
394
|
+
contextCheckbox: {
|
|
395
|
+
width: "12px",
|
|
396
|
+
height: "12px",
|
|
397
|
+
accentColor: "var(--anyclick-menu-accent, #0066cc)"
|
|
398
|
+
},
|
|
399
|
+
contextLabel: {
|
|
400
|
+
flex: 1,
|
|
401
|
+
overflow: "hidden",
|
|
402
|
+
textOverflow: "ellipsis",
|
|
403
|
+
whiteSpace: "nowrap",
|
|
404
|
+
color: "var(--anyclick-menu-text, #333)"
|
|
405
|
+
},
|
|
406
|
+
contextSize: {
|
|
407
|
+
fontSize: "10px",
|
|
408
|
+
color: "var(--anyclick-menu-text-muted, #666)"
|
|
409
|
+
},
|
|
410
|
+
// Input area
|
|
411
|
+
inputContainer: {
|
|
412
|
+
display: "flex",
|
|
413
|
+
alignItems: "flex-end",
|
|
414
|
+
gap: "8px",
|
|
415
|
+
padding: "8px"
|
|
416
|
+
},
|
|
417
|
+
input: {
|
|
418
|
+
flex: 1,
|
|
419
|
+
padding: "8px 12px",
|
|
420
|
+
fontSize: "13px",
|
|
421
|
+
border: "1px solid var(--anyclick-menu-input-border, #ddd)",
|
|
422
|
+
borderRadius: "18px",
|
|
423
|
+
backgroundColor: "var(--anyclick-menu-input-bg, #fff)",
|
|
424
|
+
color: "var(--anyclick-menu-text, #333)",
|
|
425
|
+
outline: "none",
|
|
426
|
+
resize: "none",
|
|
427
|
+
fontFamily: "inherit",
|
|
428
|
+
lineHeight: 1.4,
|
|
429
|
+
maxHeight: "80px",
|
|
430
|
+
minHeight: "36px"
|
|
431
|
+
},
|
|
432
|
+
inputFocused: {
|
|
433
|
+
borderColor: "var(--anyclick-menu-accent, #0066cc)",
|
|
434
|
+
boxShadow: "0 0 0 2px rgba(0, 102, 204, 0.1)"
|
|
435
|
+
},
|
|
436
|
+
sendButton: {
|
|
437
|
+
display: "flex",
|
|
438
|
+
alignItems: "center",
|
|
439
|
+
justifyContent: "center",
|
|
440
|
+
width: "32px",
|
|
441
|
+
height: "32px",
|
|
442
|
+
border: "none",
|
|
443
|
+
borderRadius: "50%",
|
|
444
|
+
backgroundColor: "var(--anyclick-menu-accent, #0066cc)",
|
|
445
|
+
color: "#fff",
|
|
446
|
+
cursor: "pointer",
|
|
447
|
+
transition: "all 0.15s ease",
|
|
448
|
+
flexShrink: 0
|
|
449
|
+
},
|
|
450
|
+
sendButtonDisabled: {
|
|
451
|
+
backgroundColor: "var(--anyclick-menu-border, #e5e5e5)",
|
|
452
|
+
cursor: "not-allowed"
|
|
453
|
+
},
|
|
454
|
+
// Loading states
|
|
455
|
+
loadingDots: {
|
|
456
|
+
display: "flex",
|
|
457
|
+
gap: "4px",
|
|
458
|
+
padding: "8px"
|
|
459
|
+
},
|
|
460
|
+
loadingDot: {
|
|
461
|
+
width: "6px",
|
|
462
|
+
height: "6px",
|
|
463
|
+
borderRadius: "50%",
|
|
464
|
+
backgroundColor: "var(--anyclick-menu-text-muted, #666)",
|
|
465
|
+
animation: "bounce 1.4s infinite ease-in-out both"
|
|
466
|
+
},
|
|
467
|
+
// Error states
|
|
468
|
+
errorContainer: {
|
|
469
|
+
display: "flex",
|
|
470
|
+
flexDirection: "column",
|
|
471
|
+
alignItems: "center",
|
|
472
|
+
gap: "8px",
|
|
473
|
+
padding: "16px",
|
|
474
|
+
textAlign: "center"
|
|
475
|
+
},
|
|
476
|
+
errorIcon: {
|
|
477
|
+
color: "#ef4444"
|
|
478
|
+
},
|
|
479
|
+
errorText: {
|
|
480
|
+
fontSize: "12px",
|
|
481
|
+
color: "#ef4444",
|
|
482
|
+
maxWidth: "200px"
|
|
483
|
+
},
|
|
484
|
+
errorRetry: {
|
|
485
|
+
display: "inline-flex",
|
|
486
|
+
alignItems: "center",
|
|
487
|
+
gap: "4px",
|
|
488
|
+
padding: "4px 10px",
|
|
489
|
+
fontSize: "11px",
|
|
490
|
+
fontWeight: 500,
|
|
491
|
+
border: "1px solid #ef4444",
|
|
492
|
+
borderRadius: "4px",
|
|
493
|
+
backgroundColor: "transparent",
|
|
494
|
+
color: "#ef4444",
|
|
495
|
+
cursor: "pointer",
|
|
496
|
+
transition: "all 0.15s ease"
|
|
497
|
+
},
|
|
498
|
+
// Truncation indicator
|
|
499
|
+
truncated: {
|
|
500
|
+
fontSize: "10px",
|
|
501
|
+
color: "var(--anyclick-menu-text-muted, #666)",
|
|
502
|
+
fontStyle: "italic",
|
|
503
|
+
marginTop: "4px"
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
var quickChatKeyframes = `
|
|
507
|
+
@keyframes blink {
|
|
508
|
+
0%, 50% { opacity: 1; }
|
|
509
|
+
51%, 100% { opacity: 0; }
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
@keyframes bounce {
|
|
513
|
+
0%, 80%, 100% { transform: scale(0); }
|
|
514
|
+
40% { transform: scale(1); }
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
@keyframes slideIn {
|
|
518
|
+
from {
|
|
519
|
+
opacity: 0;
|
|
520
|
+
transform: translateY(-8px);
|
|
521
|
+
}
|
|
522
|
+
to {
|
|
523
|
+
opacity: 1;
|
|
524
|
+
transform: translateY(0);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
@keyframes slideInFromRight {
|
|
529
|
+
from {
|
|
530
|
+
transform: translateX(100%);
|
|
531
|
+
}
|
|
532
|
+
to {
|
|
533
|
+
transform: translateX(0);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
@keyframes slideOutToRight {
|
|
538
|
+
from {
|
|
539
|
+
transform: translateX(0);
|
|
540
|
+
}
|
|
541
|
+
to {
|
|
542
|
+
transform: translateX(100%);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
@keyframes fadeIn {
|
|
547
|
+
from { opacity: 0; }
|
|
548
|
+
to { opacity: 1; }
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
@keyframes spin {
|
|
552
|
+
from { transform: rotate(0deg); }
|
|
553
|
+
to { transform: rotate(360deg); }
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
@keyframes pulse {
|
|
557
|
+
0%, 100% { opacity: 1; }
|
|
558
|
+
50% { opacity: 0.5; }
|
|
559
|
+
}
|
|
560
|
+
`;
|
|
561
|
+
|
|
562
|
+
// src/QuickChat/useQuickChat.ts
|
|
563
|
+
var import_react = require("react");
|
|
564
|
+
var import_react2 = require("@ai-sdk/react");
|
|
565
|
+
var import_ai = require("ai");
|
|
566
|
+
|
|
567
|
+
// src/QuickChat/store.ts
|
|
568
|
+
var import_zustand = require("zustand");
|
|
569
|
+
var import_middleware = require("zustand/middleware");
|
|
570
|
+
var STORE_NAME = "anyclick-quick-chat-store";
|
|
571
|
+
var TWENTY_FOUR_HOURS_MS = 24 * 60 * 60 * 1e3;
|
|
572
|
+
function generateMessageId() {
|
|
573
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
574
|
+
}
|
|
575
|
+
var storage = (0, import_middleware.createJSONStorage)(() => localStorage);
|
|
576
|
+
function filterExpiredMessages(messages) {
|
|
577
|
+
const now = Date.now();
|
|
578
|
+
return messages.filter((msg) => msg.expiresAt > now);
|
|
579
|
+
}
|
|
580
|
+
var useQuickChatStore = (0, import_zustand.create)()(
|
|
581
|
+
(0, import_middleware.persist)(
|
|
582
|
+
(set, get) => ({
|
|
583
|
+
messages: [],
|
|
584
|
+
isPinned: false,
|
|
585
|
+
input: "",
|
|
586
|
+
contextChunks: [],
|
|
587
|
+
suggestedPrompts: [],
|
|
588
|
+
isLoadingSuggestions: false,
|
|
589
|
+
isSending: false,
|
|
590
|
+
isStreaming: false,
|
|
591
|
+
error: null,
|
|
592
|
+
lastSyncedAt: null,
|
|
593
|
+
setInput: (input) => set({ input }),
|
|
594
|
+
addMessage: (message) => {
|
|
595
|
+
const id = generateMessageId();
|
|
596
|
+
const now = Date.now();
|
|
597
|
+
const storedMessage = {
|
|
598
|
+
...message,
|
|
599
|
+
id,
|
|
600
|
+
timestamp: now,
|
|
601
|
+
expiresAt: now + TWENTY_FOUR_HOURS_MS
|
|
602
|
+
};
|
|
603
|
+
set((state) => {
|
|
604
|
+
const newMessages = [...state.messages, storedMessage];
|
|
605
|
+
return {
|
|
606
|
+
messages: newMessages
|
|
607
|
+
};
|
|
608
|
+
});
|
|
609
|
+
return id;
|
|
610
|
+
},
|
|
611
|
+
updateMessage: (id, updates) => {
|
|
612
|
+
set((state) => ({
|
|
613
|
+
messages: state.messages.map(
|
|
614
|
+
(msg) => msg.id === id ? { ...msg, ...updates } : msg
|
|
615
|
+
)
|
|
616
|
+
}));
|
|
617
|
+
},
|
|
618
|
+
clearMessages: () => set({ messages: [], error: null }),
|
|
619
|
+
setIsPinned: (pinned) => set({ isPinned: pinned }),
|
|
620
|
+
setContextChunks: (chunks) => set({ contextChunks: chunks }),
|
|
621
|
+
toggleChunk: (chunkId) => {
|
|
622
|
+
set((state) => ({
|
|
623
|
+
contextChunks: state.contextChunks.map(
|
|
624
|
+
(chunk) => chunk.id === chunkId ? { ...chunk, included: !chunk.included } : chunk
|
|
625
|
+
)
|
|
626
|
+
}));
|
|
627
|
+
},
|
|
628
|
+
toggleAllChunks: (included) => {
|
|
629
|
+
set((state) => ({
|
|
630
|
+
contextChunks: state.contextChunks.map((chunk) => ({
|
|
631
|
+
...chunk,
|
|
632
|
+
included
|
|
633
|
+
}))
|
|
634
|
+
}));
|
|
635
|
+
},
|
|
636
|
+
setSuggestedPrompts: (prompts) => set({ suggestedPrompts: prompts }),
|
|
637
|
+
setIsLoadingSuggestions: (loading) => set({ isLoadingSuggestions: loading }),
|
|
638
|
+
setIsSending: (sending) => set({ isSending: sending }),
|
|
639
|
+
setIsStreaming: (streaming) => set({ isStreaming: streaming }),
|
|
640
|
+
setError: (error) => set({ error }),
|
|
641
|
+
setLastSyncedAt: (timestamp) => set({ lastSyncedAt: timestamp }),
|
|
642
|
+
pruneExpiredMessages: () => {
|
|
643
|
+
set((state) => ({
|
|
644
|
+
messages: filterExpiredMessages(state.messages)
|
|
645
|
+
}));
|
|
646
|
+
},
|
|
647
|
+
getActiveMessages: () => {
|
|
648
|
+
const state = get();
|
|
649
|
+
const now = Date.now();
|
|
650
|
+
const active = state.messages.filter((msg) => msg.expiresAt > now).map(({ expiresAt, ...msg }) => msg);
|
|
651
|
+
console.log("[store] getActiveMessages", {
|
|
652
|
+
totalMessages: state.messages.length,
|
|
653
|
+
activeMessages: active.length,
|
|
654
|
+
activeIds: active.map((m) => m.id)
|
|
655
|
+
});
|
|
656
|
+
return active;
|
|
657
|
+
},
|
|
658
|
+
hydrate: (messages) => {
|
|
659
|
+
const now = Date.now();
|
|
660
|
+
const storedMessages = messages.map((msg) => ({
|
|
661
|
+
...msg,
|
|
662
|
+
expiresAt: now + TWENTY_FOUR_HOURS_MS
|
|
663
|
+
}));
|
|
664
|
+
set({ messages: storedMessages, lastSyncedAt: now });
|
|
665
|
+
}
|
|
666
|
+
}),
|
|
667
|
+
{
|
|
668
|
+
name: STORE_NAME,
|
|
669
|
+
storage,
|
|
670
|
+
partialize: (state) => ({
|
|
671
|
+
messages: state.messages,
|
|
672
|
+
isPinned: state.isPinned,
|
|
673
|
+
lastSyncedAt: state.lastSyncedAt
|
|
674
|
+
}),
|
|
675
|
+
onRehydrateStorage: () => (state) => {
|
|
676
|
+
if (state) {
|
|
677
|
+
state.pruneExpiredMessages();
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
)
|
|
682
|
+
);
|
|
683
|
+
function useActiveMessages() {
|
|
684
|
+
const messages = useQuickChatStore((state) => state.messages);
|
|
685
|
+
const now = Date.now();
|
|
686
|
+
return messages.filter((msg) => msg.expiresAt > now).map(({ expiresAt, ...msg }) => msg);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// src/QuickChat/types.ts
|
|
690
|
+
var DEFAULT_T3CHAT_CONFIG = {
|
|
691
|
+
enabled: true,
|
|
692
|
+
baseUrl: "https://t3.chat",
|
|
693
|
+
label: "Ask t3.chat"
|
|
694
|
+
};
|
|
695
|
+
var DEFAULT_QUICK_CHAT_CONFIG = {
|
|
696
|
+
endpoint: "/api/anyclick/chat",
|
|
697
|
+
model: "gpt-5-nano",
|
|
698
|
+
prePassModel: "gpt-5-nano",
|
|
699
|
+
maxResponseLength: 1e4,
|
|
700
|
+
showRedactionUI: true,
|
|
701
|
+
showSuggestions: true,
|
|
702
|
+
systemPrompt: "You are a helpful assistant that provides quick, concise answers about web elements and UI. Keep responses brief and actionable.",
|
|
703
|
+
placeholder: "Ask about this element...",
|
|
704
|
+
title: "Quick Ask",
|
|
705
|
+
t3chat: DEFAULT_T3CHAT_CONFIG
|
|
706
|
+
};
|
|
707
|
+
|
|
708
|
+
// src/QuickChat/useQuickChat.context.ts
|
|
709
|
+
var import_anyclick_core = require("@ewjdev/anyclick-core");
|
|
710
|
+
function extractContextChunks(targetElement, _containerElement) {
|
|
711
|
+
const chunks = [];
|
|
712
|
+
if (!targetElement) return chunks;
|
|
713
|
+
try {
|
|
714
|
+
const info = (0, import_anyclick_core.getElementInspectInfo)(targetElement);
|
|
715
|
+
const tagContent = `<${info.tagName.toLowerCase()}${info.id ? ` id="${info.id}"` : ""}${info.classNames.length > 0 ? ` class="${info.classNames.join(" ")}"` : ""}>`;
|
|
716
|
+
chunks.push({
|
|
717
|
+
id: "element-tag",
|
|
718
|
+
label: "Element Tag",
|
|
719
|
+
content: tagContent,
|
|
720
|
+
type: "element",
|
|
721
|
+
included: true,
|
|
722
|
+
size: tagContent.length
|
|
723
|
+
});
|
|
724
|
+
if (info.innerText && info.innerText.length > 0) {
|
|
725
|
+
const textContent = info.innerText.slice(0, 200);
|
|
726
|
+
chunks.push({
|
|
727
|
+
id: "element-text",
|
|
728
|
+
label: "Text Content",
|
|
729
|
+
content: textContent,
|
|
730
|
+
type: "text",
|
|
731
|
+
included: true,
|
|
732
|
+
size: textContent.length
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
if (info.computedStyles) {
|
|
736
|
+
const styleEntries = [];
|
|
737
|
+
for (const [, styles] of Object.entries(info.computedStyles)) {
|
|
738
|
+
if (styles && typeof styles === "object") {
|
|
739
|
+
const entries = Object.entries(styles).slice(0, 2);
|
|
740
|
+
for (const [k, v] of entries) {
|
|
741
|
+
if (v) styleEntries.push(`${k}: ${v}`);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
if (styleEntries.length >= 8) break;
|
|
745
|
+
}
|
|
746
|
+
const stylesContent = styleEntries.join("; ");
|
|
747
|
+
if (stylesContent) {
|
|
748
|
+
chunks.push({
|
|
749
|
+
id: "element-styles",
|
|
750
|
+
label: "Key Styles",
|
|
751
|
+
content: stylesContent,
|
|
752
|
+
type: "element",
|
|
753
|
+
included: true,
|
|
754
|
+
size: stylesContent.length
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
if (info.accessibility) {
|
|
759
|
+
const a11yContent = [
|
|
760
|
+
info.accessibility.role && `role="${info.accessibility.role}"`,
|
|
761
|
+
info.accessibility.accessibleName && `aria-label="${info.accessibility.accessibleName}"`
|
|
762
|
+
].filter(Boolean).join(", ");
|
|
763
|
+
if (a11yContent) {
|
|
764
|
+
chunks.push({
|
|
765
|
+
id: "element-a11y",
|
|
766
|
+
label: "Accessibility",
|
|
767
|
+
content: a11yContent,
|
|
768
|
+
type: "element",
|
|
769
|
+
included: true,
|
|
770
|
+
size: a11yContent.length
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
if (info.boxModel) {
|
|
775
|
+
const boxContent = `${Math.round(info.boxModel.content.width)}x${Math.round(
|
|
776
|
+
info.boxModel.content.height
|
|
777
|
+
)}px`;
|
|
778
|
+
chunks.push({
|
|
779
|
+
id: "element-dimensions",
|
|
780
|
+
label: "Dimensions",
|
|
781
|
+
content: boxContent,
|
|
782
|
+
type: "element",
|
|
783
|
+
included: true,
|
|
784
|
+
size: boxContent.length
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
} catch (error) {
|
|
788
|
+
console.error("[useQuickChat] Failed to extract context:", error);
|
|
789
|
+
}
|
|
790
|
+
return chunks;
|
|
791
|
+
}
|
|
792
|
+
function buildContextString(chunks) {
|
|
793
|
+
const included = chunks.filter((c) => c.included);
|
|
794
|
+
if (included.length === 0) return "";
|
|
795
|
+
return included.map((c) => `[${c.label}]: ${c.content}`).join("\n");
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// src/QuickChat/useQuickChat.debug.ts
|
|
799
|
+
function createDebugInfo(args) {
|
|
800
|
+
return {
|
|
801
|
+
status: args.status,
|
|
802
|
+
ok: args.ok,
|
|
803
|
+
contentType: args.contentType ?? null,
|
|
804
|
+
rawTextPreview: args.rawText ?? "",
|
|
805
|
+
timestamp: Date.now(),
|
|
806
|
+
error: args.error
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// src/QuickChat/useQuickChat.messages.ts
|
|
811
|
+
function getUIMessageText(msg) {
|
|
812
|
+
const partsText = msg.parts?.map((p) => {
|
|
813
|
+
const part = p;
|
|
814
|
+
if (typeof part.text === "string") return part.text;
|
|
815
|
+
if (typeof part.content === "string") return part.content;
|
|
816
|
+
return "";
|
|
817
|
+
}).join("") ?? "";
|
|
818
|
+
if (partsText) return partsText;
|
|
819
|
+
const maybeContent = msg.content;
|
|
820
|
+
return typeof maybeContent === "string" ? maybeContent : "";
|
|
821
|
+
}
|
|
822
|
+
function chatMessagesToUiMessages(messages) {
|
|
823
|
+
return messages.map((msg) => ({
|
|
824
|
+
id: msg.id,
|
|
825
|
+
role: msg.role,
|
|
826
|
+
parts: [{ type: "text", text: msg.content }]
|
|
827
|
+
}));
|
|
828
|
+
}
|
|
829
|
+
function safeCopyToClipboard(text) {
|
|
830
|
+
try {
|
|
831
|
+
if (typeof navigator === "undefined") return;
|
|
832
|
+
void navigator.clipboard.writeText(text);
|
|
833
|
+
} catch {
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
function buildAssistantActions(messageText, setInput) {
|
|
837
|
+
return [
|
|
838
|
+
{
|
|
839
|
+
id: "copy",
|
|
840
|
+
label: "Copy",
|
|
841
|
+
onClick: () => safeCopyToClipboard(messageText)
|
|
842
|
+
},
|
|
843
|
+
{
|
|
844
|
+
id: "research",
|
|
845
|
+
label: "Research more",
|
|
846
|
+
onClick: () => setInput(`Tell me more about: ${messageText.slice(0, 50)}`)
|
|
847
|
+
}
|
|
848
|
+
];
|
|
849
|
+
}
|
|
850
|
+
function uiMessagesToChatMessages(args) {
|
|
851
|
+
const { uiMessages, status, setInput } = args;
|
|
852
|
+
const last = uiMessages[uiMessages.length - 1];
|
|
853
|
+
return uiMessages.map((msg) => {
|
|
854
|
+
const text = getUIMessageText(msg);
|
|
855
|
+
const isStreaming = status === "streaming" && msg.role === "assistant" && msg === last;
|
|
856
|
+
const actions = msg.role === "assistant" && status === "ready" ? buildAssistantActions(text, setInput) : void 0;
|
|
857
|
+
return {
|
|
858
|
+
id: msg.id,
|
|
859
|
+
role: msg.role,
|
|
860
|
+
content: text,
|
|
861
|
+
timestamp: Date.now(),
|
|
862
|
+
isStreaming,
|
|
863
|
+
actions
|
|
864
|
+
};
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// src/QuickChat/useQuickChat.rateLimit.ts
|
|
869
|
+
function safeJsonParse(text) {
|
|
870
|
+
try {
|
|
871
|
+
return JSON.parse(text);
|
|
872
|
+
} catch {
|
|
873
|
+
return null;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
function formatRetryAt(retryAtMs) {
|
|
877
|
+
try {
|
|
878
|
+
const d = new Date(retryAtMs);
|
|
879
|
+
return new Intl.DateTimeFormat(void 0, {
|
|
880
|
+
hour: "numeric",
|
|
881
|
+
minute: "2-digit"
|
|
882
|
+
}).format(d);
|
|
883
|
+
} catch {
|
|
884
|
+
return new Date(retryAtMs).toLocaleTimeString();
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
function getRequestIdFromHeaders(res) {
|
|
888
|
+
return res?.headers?.get?.("X-Anyclick-Request-Id") ?? res?.headers?.get?.("x-anyclick-request-id") ?? void 0;
|
|
889
|
+
}
|
|
890
|
+
function parseRetryAfterSeconds(args) {
|
|
891
|
+
const { payload, res } = args;
|
|
892
|
+
if (typeof payload?.retryAfterSeconds === "number")
|
|
893
|
+
return payload.retryAfterSeconds;
|
|
894
|
+
const headerRetryAfter = res?.headers?.get?.("Retry-After");
|
|
895
|
+
if (!headerRetryAfter) return void 0;
|
|
896
|
+
const n = Number(headerRetryAfter);
|
|
897
|
+
return Number.isFinite(n) ? n : void 0;
|
|
898
|
+
}
|
|
899
|
+
function parseRetryAt(args) {
|
|
900
|
+
const { payload, retryAfterSeconds, nowMs } = args;
|
|
901
|
+
if (typeof payload?.retryAt === "number" && Number.isFinite(payload.retryAt)) {
|
|
902
|
+
return payload.retryAt;
|
|
903
|
+
}
|
|
904
|
+
if (typeof retryAfterSeconds === "number" && Number.isFinite(retryAfterSeconds)) {
|
|
905
|
+
return nowMs + Math.max(0, retryAfterSeconds) * 1e3;
|
|
906
|
+
}
|
|
907
|
+
return void 0;
|
|
908
|
+
}
|
|
909
|
+
function buildNotice(args) {
|
|
910
|
+
const { rawText, endpoint, res, nowMs } = args;
|
|
911
|
+
const parsed = safeJsonParse(rawText);
|
|
912
|
+
const payload = parsed && typeof parsed === "object" ? parsed : null;
|
|
913
|
+
const retryAfterSeconds = parseRetryAfterSeconds({ payload, res });
|
|
914
|
+
const retryAt = parseRetryAt({ payload, retryAfterSeconds, nowMs });
|
|
915
|
+
const timePart = retryAt ? `Try again at ${formatRetryAt(retryAt)}.` : "";
|
|
916
|
+
const message = timePart ? `Rate limited. ${timePart}` : "Rate limited.";
|
|
917
|
+
const requestId = payload?.requestId ?? getRequestIdFromHeaders(res);
|
|
918
|
+
return {
|
|
919
|
+
status: 429,
|
|
920
|
+
message,
|
|
921
|
+
retryAt,
|
|
922
|
+
retryAfterSeconds,
|
|
923
|
+
requestId,
|
|
924
|
+
endpoint,
|
|
925
|
+
raw: rawText
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
async function rateLimitNoticeFromResponse(res, endpoint) {
|
|
929
|
+
if (res.status !== 429) return null;
|
|
930
|
+
const raw = await res.text().catch(() => "");
|
|
931
|
+
return buildNotice({ rawText: raw, endpoint, res, nowMs: Date.now() });
|
|
932
|
+
}
|
|
933
|
+
function rateLimitNoticeFromError(args) {
|
|
934
|
+
const { statusCode, response, responseText, endpoint } = args;
|
|
935
|
+
if (statusCode !== 429) return null;
|
|
936
|
+
const raw = responseText ?? "";
|
|
937
|
+
return buildNotice({
|
|
938
|
+
rawText: raw,
|
|
939
|
+
endpoint,
|
|
940
|
+
res: response,
|
|
941
|
+
nowMs: Date.now()
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// src/QuickChat/useQuickChat.ts
|
|
946
|
+
function useQuickChat(targetElement, containerElement, config = {}) {
|
|
947
|
+
console.count("useQuickChat");
|
|
948
|
+
const mergedConfig = { ...DEFAULT_QUICK_CHAT_CONFIG, ...config };
|
|
949
|
+
const initializedRef = (0, import_react.useRef)(false);
|
|
950
|
+
const syncTimeoutRef = (0, import_react.useRef)(null);
|
|
951
|
+
const [manualSending, setManualSending] = (0, import_react.useState)(false);
|
|
952
|
+
const [debugInfo, setDebugInfo] = (0, import_react.useState)(null);
|
|
953
|
+
const [rateLimitNotice, setRateLimitNotice] = (0, import_react.useState)(null);
|
|
954
|
+
const {
|
|
955
|
+
input,
|
|
956
|
+
setInput,
|
|
957
|
+
isPinned,
|
|
958
|
+
setIsPinned,
|
|
959
|
+
contextChunks,
|
|
960
|
+
setContextChunks,
|
|
961
|
+
toggleChunk,
|
|
962
|
+
toggleAllChunks,
|
|
963
|
+
suggestedPrompts,
|
|
964
|
+
setSuggestedPrompts,
|
|
965
|
+
isLoadingSuggestions,
|
|
966
|
+
setIsLoadingSuggestions,
|
|
967
|
+
error,
|
|
968
|
+
setError,
|
|
969
|
+
addMessage,
|
|
970
|
+
clearMessages: storeClearMessages,
|
|
971
|
+
setLastSyncedAt,
|
|
972
|
+
lastSyncedAt,
|
|
973
|
+
setIsSending: setStoreIsSending,
|
|
974
|
+
setIsStreaming: setStoreIsStreaming
|
|
975
|
+
} = useQuickChatStore();
|
|
976
|
+
const storedMessages = useActiveMessages();
|
|
977
|
+
const contextString = (0, import_react.useMemo)(
|
|
978
|
+
() => buildContextString(contextChunks),
|
|
979
|
+
[contextChunks]
|
|
980
|
+
);
|
|
981
|
+
const chatBody = (0, import_react.useMemo)(
|
|
982
|
+
() => ({
|
|
983
|
+
action: "chat",
|
|
984
|
+
context: contextString,
|
|
985
|
+
model: mergedConfig.model,
|
|
986
|
+
systemPrompt: mergedConfig.systemPrompt,
|
|
987
|
+
maxLength: mergedConfig.maxResponseLength
|
|
988
|
+
}),
|
|
989
|
+
[
|
|
990
|
+
contextString,
|
|
991
|
+
mergedConfig.model,
|
|
992
|
+
mergedConfig.systemPrompt,
|
|
993
|
+
mergedConfig.maxResponseLength
|
|
994
|
+
]
|
|
995
|
+
);
|
|
996
|
+
const transport = (0, import_react.useMemo)(
|
|
997
|
+
() => new import_ai.DefaultChatTransport({
|
|
998
|
+
api: mergedConfig.endpoint,
|
|
999
|
+
body: chatBody
|
|
1000
|
+
}),
|
|
1001
|
+
[mergedConfig.endpoint, chatBody]
|
|
1002
|
+
);
|
|
1003
|
+
const handleRateLimitResponse = (0, import_react.useCallback)(
|
|
1004
|
+
async (res, endpoint) => {
|
|
1005
|
+
const notice = await rateLimitNoticeFromResponse(res, endpoint);
|
|
1006
|
+
if (!notice) return false;
|
|
1007
|
+
setRateLimitNotice(notice);
|
|
1008
|
+
setError(null);
|
|
1009
|
+
return true;
|
|
1010
|
+
},
|
|
1011
|
+
[setError]
|
|
1012
|
+
);
|
|
1013
|
+
const scheduleBackendSync = (0, import_react.useCallback)(() => {
|
|
1014
|
+
if (syncTimeoutRef.current) clearTimeout(syncTimeoutRef.current);
|
|
1015
|
+
syncTimeoutRef.current = setTimeout(async () => {
|
|
1016
|
+
try {
|
|
1017
|
+
const currentMessages = useQuickChatStore.getState().getActiveMessages();
|
|
1018
|
+
if (currentMessages.length === 0) return;
|
|
1019
|
+
const endpoint = `${mergedConfig.endpoint}/history`;
|
|
1020
|
+
const res = await fetch(endpoint, {
|
|
1021
|
+
method: "POST",
|
|
1022
|
+
headers: { "Content-Type": "application/json" },
|
|
1023
|
+
body: JSON.stringify({
|
|
1024
|
+
action: "save",
|
|
1025
|
+
messages: currentMessages
|
|
1026
|
+
})
|
|
1027
|
+
});
|
|
1028
|
+
if (await handleRateLimitResponse(res, endpoint)) return;
|
|
1029
|
+
if (res.ok) setLastSyncedAt(Date.now());
|
|
1030
|
+
} catch (err) {
|
|
1031
|
+
console.error("[useQuickChat] Failed to sync chat history:", err);
|
|
1032
|
+
}
|
|
1033
|
+
}, 1e3);
|
|
1034
|
+
}, [handleRateLimitResponse, mergedConfig.endpoint, setLastSyncedAt]);
|
|
1035
|
+
const {
|
|
1036
|
+
messages: aiMessages,
|
|
1037
|
+
sendMessage: aiSendMessage,
|
|
1038
|
+
status,
|
|
1039
|
+
stop,
|
|
1040
|
+
setMessages: setAiMessages
|
|
1041
|
+
} = (0, import_react2.useChat)({
|
|
1042
|
+
transport,
|
|
1043
|
+
onError: (err) => {
|
|
1044
|
+
const response = err.response ?? void 0;
|
|
1045
|
+
const statusCode = err.status ?? (response ? response.status : void 0) ?? -1;
|
|
1046
|
+
const responseText = err.responseText ?? err.message ?? "";
|
|
1047
|
+
setDebugInfo(
|
|
1048
|
+
createDebugInfo({
|
|
1049
|
+
status: statusCode,
|
|
1050
|
+
ok: false,
|
|
1051
|
+
contentType: response?.headers?.get?.("content-type") ?? null,
|
|
1052
|
+
rawText: responseText,
|
|
1053
|
+
error: err.message
|
|
1054
|
+
})
|
|
1055
|
+
);
|
|
1056
|
+
setStoreIsStreaming(false);
|
|
1057
|
+
setStoreIsSending(false);
|
|
1058
|
+
const notice = rateLimitNoticeFromError({
|
|
1059
|
+
statusCode,
|
|
1060
|
+
response,
|
|
1061
|
+
responseText,
|
|
1062
|
+
endpoint: mergedConfig.endpoint
|
|
1063
|
+
});
|
|
1064
|
+
if (notice) {
|
|
1065
|
+
setRateLimitNotice(notice);
|
|
1066
|
+
setError(null);
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
setRateLimitNotice(null);
|
|
1070
|
+
setError(err.message);
|
|
1071
|
+
},
|
|
1072
|
+
onFinish: ({ message }) => {
|
|
1073
|
+
const messageText = getUIMessageText(message);
|
|
1074
|
+
const current = useQuickChatStore.getState().getActiveMessages();
|
|
1075
|
+
const last = current[current.length - 1];
|
|
1076
|
+
const alreadyHaveSameTail = last?.role === "assistant" && last.content === messageText;
|
|
1077
|
+
if (!alreadyHaveSameTail && messageText) {
|
|
1078
|
+
addMessage({
|
|
1079
|
+
role: message.role,
|
|
1080
|
+
content: messageText,
|
|
1081
|
+
isStreaming: false
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
scheduleBackendSync();
|
|
1085
|
+
setStoreIsStreaming(false);
|
|
1086
|
+
setStoreIsSending(false);
|
|
1087
|
+
}
|
|
1088
|
+
});
|
|
1089
|
+
const loadFromBackend = (0, import_react.useCallback)(async () => {
|
|
1090
|
+
try {
|
|
1091
|
+
const endpoint = `${mergedConfig.endpoint}/history`;
|
|
1092
|
+
const response = await fetch(endpoint, {
|
|
1093
|
+
method: "POST",
|
|
1094
|
+
headers: { "Content-Type": "application/json" },
|
|
1095
|
+
body: JSON.stringify({ action: "load" })
|
|
1096
|
+
});
|
|
1097
|
+
if (await handleRateLimitResponse(response, endpoint)) return;
|
|
1098
|
+
if (!response.ok) return;
|
|
1099
|
+
const data = await response.json().catch(() => null);
|
|
1100
|
+
if (!data?.messages || !Array.isArray(data.messages)) return;
|
|
1101
|
+
if (data.messages.length === 0) return;
|
|
1102
|
+
useQuickChatStore.getState().hydrate(data.messages);
|
|
1103
|
+
setAiMessages(chatMessagesToUiMessages(data.messages));
|
|
1104
|
+
} catch (err) {
|
|
1105
|
+
console.error("[useQuickChat] Failed to load chat history:", err);
|
|
1106
|
+
}
|
|
1107
|
+
}, [handleRateLimitResponse, mergedConfig.endpoint, setAiMessages]);
|
|
1108
|
+
const messages = (0, import_react.useMemo)(
|
|
1109
|
+
() => uiMessagesToChatMessages({
|
|
1110
|
+
uiMessages: aiMessages,
|
|
1111
|
+
status,
|
|
1112
|
+
setInput
|
|
1113
|
+
}),
|
|
1114
|
+
[aiMessages, setInput, status]
|
|
1115
|
+
);
|
|
1116
|
+
const isStreaming = status === "streaming";
|
|
1117
|
+
const isSending = status === "submitted" || status === "streaming" || manualSending;
|
|
1118
|
+
(0, import_react.useEffect)(() => {
|
|
1119
|
+
if (initializedRef.current) return;
|
|
1120
|
+
initializedRef.current = true;
|
|
1121
|
+
if (storedMessages.length > 0) {
|
|
1122
|
+
setAiMessages(chatMessagesToUiMessages(storedMessages));
|
|
1123
|
+
} else {
|
|
1124
|
+
void loadFromBackend();
|
|
1125
|
+
}
|
|
1126
|
+
}, [loadFromBackend, setAiMessages, storedMessages]);
|
|
1127
|
+
(0, import_react.useEffect)(() => {
|
|
1128
|
+
if (!targetElement) return;
|
|
1129
|
+
const chunks = extractContextChunks(targetElement, containerElement);
|
|
1130
|
+
setContextChunks(chunks);
|
|
1131
|
+
}, [targetElement, containerElement, setContextChunks]);
|
|
1132
|
+
(0, import_react.useEffect)(() => {
|
|
1133
|
+
if (!mergedConfig.showSuggestions) return;
|
|
1134
|
+
if (!contextString) return;
|
|
1135
|
+
if (suggestedPrompts.length > 0) return;
|
|
1136
|
+
let cancelled = false;
|
|
1137
|
+
const fetchSuggestions = async () => {
|
|
1138
|
+
setIsLoadingSuggestions(true);
|
|
1139
|
+
try {
|
|
1140
|
+
const response = await fetch(mergedConfig.endpoint, {
|
|
1141
|
+
method: "POST",
|
|
1142
|
+
headers: { "Content-Type": "application/json" },
|
|
1143
|
+
body: JSON.stringify({
|
|
1144
|
+
action: "suggest",
|
|
1145
|
+
context: contextString,
|
|
1146
|
+
model: mergedConfig.prePassModel
|
|
1147
|
+
})
|
|
1148
|
+
});
|
|
1149
|
+
if (await handleRateLimitResponse(response, mergedConfig.endpoint)) {
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
if (response.ok) {
|
|
1153
|
+
const data = await response.json().catch(() => null);
|
|
1154
|
+
if (data?.suggestions && Array.isArray(data.suggestions)) {
|
|
1155
|
+
if (!cancelled) {
|
|
1156
|
+
setSuggestedPrompts(
|
|
1157
|
+
data.suggestions.map((text, i) => ({
|
|
1158
|
+
id: `suggestion-${i}`,
|
|
1159
|
+
text
|
|
1160
|
+
}))
|
|
1161
|
+
);
|
|
1162
|
+
setIsLoadingSuggestions(false);
|
|
1163
|
+
}
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
} catch (err) {
|
|
1168
|
+
console.error("[useQuickChat] Failed to fetch suggestions:", err);
|
|
1169
|
+
}
|
|
1170
|
+
if (!cancelled) {
|
|
1171
|
+
setSuggestedPrompts([
|
|
1172
|
+
{ id: "s1", text: "What is this element?" },
|
|
1173
|
+
{ id: "s2", text: "How can I style this?" },
|
|
1174
|
+
{ id: "s3", text: "Is this accessible?" }
|
|
1175
|
+
]);
|
|
1176
|
+
setIsLoadingSuggestions(false);
|
|
1177
|
+
}
|
|
1178
|
+
};
|
|
1179
|
+
void fetchSuggestions();
|
|
1180
|
+
return () => {
|
|
1181
|
+
cancelled = true;
|
|
1182
|
+
};
|
|
1183
|
+
}, [
|
|
1184
|
+
contextString,
|
|
1185
|
+
handleRateLimitResponse,
|
|
1186
|
+
mergedConfig.endpoint,
|
|
1187
|
+
mergedConfig.prePassModel,
|
|
1188
|
+
mergedConfig.showSuggestions,
|
|
1189
|
+
setIsLoadingSuggestions,
|
|
1190
|
+
setSuggestedPrompts,
|
|
1191
|
+
suggestedPrompts.length
|
|
1192
|
+
]);
|
|
1193
|
+
const selectSuggestion = (0, import_react.useCallback)(
|
|
1194
|
+
(prompt) => {
|
|
1195
|
+
setInput(prompt.text);
|
|
1196
|
+
},
|
|
1197
|
+
[setInput]
|
|
1198
|
+
);
|
|
1199
|
+
const sendMessage = (0, import_react.useCallback)(
|
|
1200
|
+
async (messageText) => {
|
|
1201
|
+
const text = (messageText || input).trim();
|
|
1202
|
+
if (!text) return;
|
|
1203
|
+
setInput("");
|
|
1204
|
+
setError(null);
|
|
1205
|
+
setManualSending(true);
|
|
1206
|
+
setStoreIsSending(true);
|
|
1207
|
+
setStoreIsStreaming(true);
|
|
1208
|
+
setDebugInfo(null);
|
|
1209
|
+
try {
|
|
1210
|
+
addMessage({
|
|
1211
|
+
role: "user",
|
|
1212
|
+
content: text
|
|
1213
|
+
});
|
|
1214
|
+
await aiSendMessage({ text });
|
|
1215
|
+
} catch (err) {
|
|
1216
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1217
|
+
setError(msg);
|
|
1218
|
+
} finally {
|
|
1219
|
+
setManualSending(false);
|
|
1220
|
+
setStoreIsSending(false);
|
|
1221
|
+
setStoreIsStreaming(false);
|
|
1222
|
+
}
|
|
1223
|
+
},
|
|
1224
|
+
[
|
|
1225
|
+
addMessage,
|
|
1226
|
+
aiSendMessage,
|
|
1227
|
+
input,
|
|
1228
|
+
setError,
|
|
1229
|
+
setInput,
|
|
1230
|
+
setStoreIsSending,
|
|
1231
|
+
setStoreIsStreaming
|
|
1232
|
+
]
|
|
1233
|
+
);
|
|
1234
|
+
const clearMessages = (0, import_react.useCallback)(() => {
|
|
1235
|
+
stop();
|
|
1236
|
+
storeClearMessages();
|
|
1237
|
+
setAiMessages([]);
|
|
1238
|
+
const endpoint = `${mergedConfig.endpoint}/history`;
|
|
1239
|
+
fetch(endpoint, {
|
|
1240
|
+
method: "POST",
|
|
1241
|
+
headers: { "Content-Type": "application/json" },
|
|
1242
|
+
body: JSON.stringify({ action: "clear" })
|
|
1243
|
+
}).then((res) => handleRateLimitResponse(res, endpoint)).catch(
|
|
1244
|
+
(err) => console.error("[useQuickChat] Failed to clear backend history:", err)
|
|
1245
|
+
);
|
|
1246
|
+
}, [
|
|
1247
|
+
handleRateLimitResponse,
|
|
1248
|
+
mergedConfig.endpoint,
|
|
1249
|
+
setAiMessages,
|
|
1250
|
+
stop,
|
|
1251
|
+
storeClearMessages
|
|
1252
|
+
]);
|
|
1253
|
+
(0, import_react.useEffect)(() => {
|
|
1254
|
+
return () => {
|
|
1255
|
+
if (syncTimeoutRef.current) clearTimeout(syncTimeoutRef.current);
|
|
1256
|
+
};
|
|
1257
|
+
}, []);
|
|
1258
|
+
return {
|
|
1259
|
+
input,
|
|
1260
|
+
messages,
|
|
1261
|
+
isLoadingSuggestions,
|
|
1262
|
+
isSending,
|
|
1263
|
+
isStreaming,
|
|
1264
|
+
suggestedPrompts,
|
|
1265
|
+
contextChunks,
|
|
1266
|
+
error,
|
|
1267
|
+
debugInfo,
|
|
1268
|
+
rateLimitNotice,
|
|
1269
|
+
isPinned,
|
|
1270
|
+
lastSyncedAt,
|
|
1271
|
+
config: mergedConfig,
|
|
1272
|
+
setInput,
|
|
1273
|
+
toggleChunk,
|
|
1274
|
+
toggleAllChunks,
|
|
1275
|
+
selectSuggestion,
|
|
1276
|
+
sendMessage,
|
|
1277
|
+
clearMessages,
|
|
1278
|
+
setIsPinned,
|
|
1279
|
+
clearRateLimitNotice: () => setRateLimitNotice(null)
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
// src/QuickChat/QuickChat.tsx
|
|
1284
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1285
|
+
var stylesInjected = false;
|
|
1286
|
+
function injectStyles() {
|
|
1287
|
+
if (stylesInjected || typeof document === "undefined") return;
|
|
1288
|
+
const style = document.createElement("style");
|
|
1289
|
+
style.textContent = quickChatKeyframes;
|
|
1290
|
+
document.head.appendChild(style);
|
|
1291
|
+
stylesInjected = true;
|
|
1292
|
+
}
|
|
1293
|
+
var LoadingDots = import_react3.default.memo(function LoadingDots2() {
|
|
1294
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: quickChatStyles.loadingDots, children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1295
|
+
"div",
|
|
1296
|
+
{
|
|
1297
|
+
style: {
|
|
1298
|
+
...quickChatStyles.loadingDot,
|
|
1299
|
+
animationDelay: `${i * 0.16}s`
|
|
1300
|
+
}
|
|
1301
|
+
},
|
|
1302
|
+
i
|
|
1303
|
+
)) });
|
|
1304
|
+
});
|
|
1305
|
+
function QuickChat({
|
|
1306
|
+
visible,
|
|
1307
|
+
targetElement,
|
|
1308
|
+
containerElement,
|
|
1309
|
+
onClose,
|
|
1310
|
+
onPin,
|
|
1311
|
+
isPinned: isPinnedProp = false,
|
|
1312
|
+
config,
|
|
1313
|
+
style,
|
|
1314
|
+
className,
|
|
1315
|
+
initialInput,
|
|
1316
|
+
onInitialInputConsumed
|
|
1317
|
+
}) {
|
|
1318
|
+
const inputRef = (0, import_react3.useRef)(null);
|
|
1319
|
+
const messagesEndRef = (0, import_react3.useRef)(null);
|
|
1320
|
+
const [inputFocused, setInputFocused] = (0, import_react3.useState)(false);
|
|
1321
|
+
const [showContext, setShowContext] = (0, import_react3.useState)(false);
|
|
1322
|
+
const [hoveredSuggestion, setHoveredSuggestion] = (0, import_react3.useState)(
|
|
1323
|
+
null
|
|
1324
|
+
);
|
|
1325
|
+
const {
|
|
1326
|
+
input,
|
|
1327
|
+
messages,
|
|
1328
|
+
isLoadingSuggestions,
|
|
1329
|
+
isSending,
|
|
1330
|
+
isStreaming,
|
|
1331
|
+
debugInfo,
|
|
1332
|
+
rateLimitNotice,
|
|
1333
|
+
suggestedPrompts,
|
|
1334
|
+
contextChunks,
|
|
1335
|
+
error,
|
|
1336
|
+
isPinned: storePinned,
|
|
1337
|
+
setInput,
|
|
1338
|
+
toggleChunk,
|
|
1339
|
+
toggleAllChunks,
|
|
1340
|
+
selectSuggestion,
|
|
1341
|
+
sendMessage,
|
|
1342
|
+
clearMessages,
|
|
1343
|
+
setIsPinned,
|
|
1344
|
+
clearRateLimitNotice,
|
|
1345
|
+
config: mergedConfig
|
|
1346
|
+
} = useQuickChat(targetElement, containerElement, config);
|
|
1347
|
+
const isPinned = isPinnedProp || storePinned;
|
|
1348
|
+
const handlePinToggle = (0, import_react3.useCallback)(() => {
|
|
1349
|
+
const newPinned = !isPinned;
|
|
1350
|
+
setIsPinned(newPinned);
|
|
1351
|
+
onPin?.(newPinned);
|
|
1352
|
+
}, [isPinned, setIsPinned, onPin]);
|
|
1353
|
+
const handleClose = (0, import_react3.useCallback)(() => {
|
|
1354
|
+
if (isPinned) {
|
|
1355
|
+
setIsPinned(false);
|
|
1356
|
+
onPin?.(false);
|
|
1357
|
+
}
|
|
1358
|
+
onClose();
|
|
1359
|
+
}, [isPinned, setIsPinned, onPin, onClose]);
|
|
1360
|
+
(0, import_react3.useEffect)(() => {
|
|
1361
|
+
injectStyles();
|
|
1362
|
+
}, []);
|
|
1363
|
+
(0, import_react3.useEffect)(() => {
|
|
1364
|
+
if (visible && inputRef.current) {
|
|
1365
|
+
const timer = setTimeout(() => {
|
|
1366
|
+
inputRef.current?.focus();
|
|
1367
|
+
}, 100);
|
|
1368
|
+
return () => clearTimeout(timer);
|
|
1369
|
+
}
|
|
1370
|
+
}, [visible]);
|
|
1371
|
+
(0, import_react3.useEffect)(() => {
|
|
1372
|
+
if (initialInput && visible) {
|
|
1373
|
+
setInput(initialInput);
|
|
1374
|
+
onInitialInputConsumed?.();
|
|
1375
|
+
if (inputRef.current) {
|
|
1376
|
+
inputRef.current.focus();
|
|
1377
|
+
inputRef.current.setSelectionRange(
|
|
1378
|
+
initialInput.length,
|
|
1379
|
+
initialInput.length
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
}, [initialInput, visible, setInput, onInitialInputConsumed]);
|
|
1384
|
+
(0, import_react3.useEffect)(() => {
|
|
1385
|
+
if (messagesEndRef.current) {
|
|
1386
|
+
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
|
|
1387
|
+
}
|
|
1388
|
+
}, [messages]);
|
|
1389
|
+
const handleInputChange = (0, import_react3.useCallback)(
|
|
1390
|
+
(e) => {
|
|
1391
|
+
setInput(e.target.value);
|
|
1392
|
+
const target = e.target;
|
|
1393
|
+
target.style.height = "auto";
|
|
1394
|
+
target.style.height = `${Math.min(target.scrollHeight, 80)}px`;
|
|
1395
|
+
},
|
|
1396
|
+
[setInput]
|
|
1397
|
+
);
|
|
1398
|
+
const handleKeyDown = (0, import_react3.useCallback)(
|
|
1399
|
+
(e) => {
|
|
1400
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
1401
|
+
e.preventDefault();
|
|
1402
|
+
sendMessage();
|
|
1403
|
+
} else if (e.key === "Escape") {
|
|
1404
|
+
onClose();
|
|
1405
|
+
}
|
|
1406
|
+
},
|
|
1407
|
+
[sendMessage, onClose]
|
|
1408
|
+
);
|
|
1409
|
+
const handleSend = (0, import_react3.useCallback)(() => {
|
|
1410
|
+
sendMessage();
|
|
1411
|
+
}, [sendMessage]);
|
|
1412
|
+
const handleSendToT3Chat = (0, import_react3.useCallback)(() => {
|
|
1413
|
+
if (typeof window === "undefined") return;
|
|
1414
|
+
const query = input.trim();
|
|
1415
|
+
const baseUrl = mergedConfig.t3chat?.baseUrl ?? "https://t3.chat";
|
|
1416
|
+
const url = query ? `${baseUrl}/?q=${encodeURIComponent(query)}` : baseUrl;
|
|
1417
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
1418
|
+
}, [input, mergedConfig.t3chat?.baseUrl]);
|
|
1419
|
+
const handleCopy = (0, import_react3.useCallback)((text) => {
|
|
1420
|
+
navigator.clipboard.writeText(text);
|
|
1421
|
+
}, []);
|
|
1422
|
+
const includedCount = (0, import_react3.useMemo)(
|
|
1423
|
+
() => contextChunks.filter((c) => c.included).length,
|
|
1424
|
+
[contextChunks]
|
|
1425
|
+
);
|
|
1426
|
+
const [rateLimitExpanded, setRateLimitExpanded] = (0, import_react3.useState)(false);
|
|
1427
|
+
const [reportStatus, setReportStatus] = (0, import_react3.useState)("idle");
|
|
1428
|
+
const [reportUrl, setReportUrl] = (0, import_react3.useState)(null);
|
|
1429
|
+
const [reportError, setReportError] = (0, import_react3.useState)(null);
|
|
1430
|
+
(0, import_react3.useEffect)(() => {
|
|
1431
|
+
if (rateLimitNotice) {
|
|
1432
|
+
setReportStatus("idle");
|
|
1433
|
+
setReportUrl(null);
|
|
1434
|
+
setReportError(null);
|
|
1435
|
+
setRateLimitExpanded(false);
|
|
1436
|
+
}
|
|
1437
|
+
}, [rateLimitNotice]);
|
|
1438
|
+
const handleReportIssue = (0, import_react3.useCallback)(async () => {
|
|
1439
|
+
if (!rateLimitNotice) return;
|
|
1440
|
+
if (!targetElement) {
|
|
1441
|
+
setReportStatus("error");
|
|
1442
|
+
setReportError("No target element available to report.");
|
|
1443
|
+
return;
|
|
1444
|
+
}
|
|
1445
|
+
setReportStatus("sending");
|
|
1446
|
+
setReportError(null);
|
|
1447
|
+
try {
|
|
1448
|
+
const payload = (0, import_anyclick_core2.buildAnyclickPayload)(targetElement, "issue", {
|
|
1449
|
+
comment: `QuickChat: ${rateLimitNotice.message}`,
|
|
1450
|
+
metadata: {
|
|
1451
|
+
source: "quickchat",
|
|
1452
|
+
kind: "rate_limit",
|
|
1453
|
+
endpoint: rateLimitNotice.endpoint ?? mergedConfig.endpoint,
|
|
1454
|
+
retryAt: rateLimitNotice.retryAt,
|
|
1455
|
+
retryAfterSeconds: rateLimitNotice.retryAfterSeconds,
|
|
1456
|
+
requestId: rateLimitNotice.requestId,
|
|
1457
|
+
debugInfo: debugInfo ?? void 0,
|
|
1458
|
+
raw: rateLimitNotice.raw ?? void 0
|
|
1459
|
+
}
|
|
1460
|
+
});
|
|
1461
|
+
const res = await fetch("/api/feedback", {
|
|
1462
|
+
method: "POST",
|
|
1463
|
+
headers: { "Content-Type": "application/json" },
|
|
1464
|
+
body: JSON.stringify(payload)
|
|
1465
|
+
});
|
|
1466
|
+
const json = await res.json().catch(() => null);
|
|
1467
|
+
if (!res.ok || !json?.success) {
|
|
1468
|
+
const msg = json?.error || (res.status ? `Failed to create issue (${res.status}).` : "Failed to create issue.");
|
|
1469
|
+
throw new Error(msg);
|
|
1470
|
+
}
|
|
1471
|
+
const firstUrl = json.results?.find(
|
|
1472
|
+
(r) => typeof r.url === "string"
|
|
1473
|
+
)?.url;
|
|
1474
|
+
setReportUrl(firstUrl ?? null);
|
|
1475
|
+
setReportStatus("sent");
|
|
1476
|
+
} catch (e) {
|
|
1477
|
+
setReportStatus("error");
|
|
1478
|
+
setReportError(e instanceof Error ? e.message : String(e));
|
|
1479
|
+
}
|
|
1480
|
+
}, [rateLimitNotice, targetElement, mergedConfig.endpoint, debugInfo]);
|
|
1481
|
+
if (!visible) return null;
|
|
1482
|
+
const containerStyles = isPinned ? {
|
|
1483
|
+
...quickChatStyles.pinnedContainer,
|
|
1484
|
+
animation: "slideInFromRight 0.25s ease-out",
|
|
1485
|
+
...style
|
|
1486
|
+
} : {
|
|
1487
|
+
...quickChatStyles.container,
|
|
1488
|
+
animation: "fadeIn 0.15s ease-out",
|
|
1489
|
+
...style
|
|
1490
|
+
};
|
|
1491
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className, style: containerStyles, children: [
|
|
1492
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1493
|
+
"div",
|
|
1494
|
+
{
|
|
1495
|
+
style: {
|
|
1496
|
+
...quickChatStyles.header,
|
|
1497
|
+
padding: isPinned ? "12px 12px 8px 12px" : "6px 8px"
|
|
1498
|
+
},
|
|
1499
|
+
children: [
|
|
1500
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
|
|
1501
|
+
!isPinned && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1502
|
+
"button",
|
|
1503
|
+
{
|
|
1504
|
+
type: "button",
|
|
1505
|
+
onClick: onClose,
|
|
1506
|
+
style: {
|
|
1507
|
+
...quickChatStyles.iconButton,
|
|
1508
|
+
marginLeft: "-4px"
|
|
1509
|
+
},
|
|
1510
|
+
title: "Back to menu",
|
|
1511
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronLeft, { size: 16 })
|
|
1512
|
+
}
|
|
1513
|
+
),
|
|
1514
|
+
mergedConfig.showRedactionUI && contextChunks.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1515
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1516
|
+
"button",
|
|
1517
|
+
{
|
|
1518
|
+
type: "button",
|
|
1519
|
+
onClick: () => setShowContext(!showContext),
|
|
1520
|
+
style: {
|
|
1521
|
+
...quickChatStyles.contextBadge,
|
|
1522
|
+
...showContext ? quickChatStyles.contextBadgeActive : {}
|
|
1523
|
+
},
|
|
1524
|
+
title: "Edit context",
|
|
1525
|
+
children: [
|
|
1526
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
1527
|
+
includedCount,
|
|
1528
|
+
"/",
|
|
1529
|
+
contextChunks.length
|
|
1530
|
+
] }),
|
|
1531
|
+
showContext ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronUp, { size: 10 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronDown, { size: 10 })
|
|
1532
|
+
]
|
|
1533
|
+
}
|
|
1534
|
+
),
|
|
1535
|
+
showContext && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "2px" }, children: [
|
|
1536
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1537
|
+
"button",
|
|
1538
|
+
{
|
|
1539
|
+
type: "button",
|
|
1540
|
+
onClick: () => toggleAllChunks(true),
|
|
1541
|
+
style: quickChatStyles.contextToggleSmall,
|
|
1542
|
+
title: "Include all",
|
|
1543
|
+
children: "All"
|
|
1544
|
+
}
|
|
1545
|
+
),
|
|
1546
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1547
|
+
"button",
|
|
1548
|
+
{
|
|
1549
|
+
type: "button",
|
|
1550
|
+
onClick: () => toggleAllChunks(false),
|
|
1551
|
+
style: quickChatStyles.contextToggleSmall,
|
|
1552
|
+
title: "Exclude all",
|
|
1553
|
+
children: "None"
|
|
1554
|
+
}
|
|
1555
|
+
)
|
|
1556
|
+
] })
|
|
1557
|
+
] })
|
|
1558
|
+
] }),
|
|
1559
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: quickChatStyles.headerActions, children: [
|
|
1560
|
+
messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1561
|
+
"button",
|
|
1562
|
+
{
|
|
1563
|
+
type: "button",
|
|
1564
|
+
onClick: clearMessages,
|
|
1565
|
+
style: quickChatStyles.iconButton,
|
|
1566
|
+
title: "Clear chat",
|
|
1567
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.RefreshCw, { size: 14 })
|
|
1568
|
+
}
|
|
1569
|
+
),
|
|
1570
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1571
|
+
"button",
|
|
1572
|
+
{
|
|
1573
|
+
type: "button",
|
|
1574
|
+
onClick: handlePinToggle,
|
|
1575
|
+
style: {
|
|
1576
|
+
...quickChatStyles.iconButton,
|
|
1577
|
+
...isPinned ? quickChatStyles.iconButtonActive : {}
|
|
1578
|
+
},
|
|
1579
|
+
title: isPinned ? "Unpin (closes with menu)" : "Pin (stays open)",
|
|
1580
|
+
children: isPinned ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.PinOff, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Pin, { size: 14 })
|
|
1581
|
+
}
|
|
1582
|
+
),
|
|
1583
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1584
|
+
"button",
|
|
1585
|
+
{
|
|
1586
|
+
type: "button",
|
|
1587
|
+
onClick: handleClose,
|
|
1588
|
+
style: quickChatStyles.iconButton,
|
|
1589
|
+
title: "Close",
|
|
1590
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { size: 14 })
|
|
1591
|
+
}
|
|
1592
|
+
)
|
|
1593
|
+
] })
|
|
1594
|
+
]
|
|
1595
|
+
}
|
|
1596
|
+
),
|
|
1597
|
+
showContext && contextChunks.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: quickChatStyles.contextDropdown, children: contextChunks.map((chunk) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1598
|
+
"label",
|
|
1599
|
+
{
|
|
1600
|
+
style: {
|
|
1601
|
+
...quickChatStyles.contextChunkCompact,
|
|
1602
|
+
...chunk.included ? {} : quickChatStyles.contextChunkExcluded
|
|
1603
|
+
},
|
|
1604
|
+
children: [
|
|
1605
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1606
|
+
"input",
|
|
1607
|
+
{
|
|
1608
|
+
type: "checkbox",
|
|
1609
|
+
checked: chunk.included,
|
|
1610
|
+
onChange: () => toggleChunk(chunk.id),
|
|
1611
|
+
style: quickChatStyles.contextCheckbox
|
|
1612
|
+
}
|
|
1613
|
+
),
|
|
1614
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: quickChatStyles.contextLabel, children: chunk.label })
|
|
1615
|
+
]
|
|
1616
|
+
},
|
|
1617
|
+
chunk.id
|
|
1618
|
+
)) }),
|
|
1619
|
+
mergedConfig.showSuggestions && messages.length === 0 && suggestedPrompts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: quickChatStyles.suggestionsContainer, children: isLoadingSuggestions ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoadingDots, {}) : suggestedPrompts.map((prompt) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1620
|
+
"button",
|
|
1621
|
+
{
|
|
1622
|
+
type: "button",
|
|
1623
|
+
onClick: () => selectSuggestion(prompt),
|
|
1624
|
+
onMouseEnter: () => setHoveredSuggestion(prompt.id),
|
|
1625
|
+
onMouseLeave: () => setHoveredSuggestion(null),
|
|
1626
|
+
style: {
|
|
1627
|
+
...quickChatStyles.suggestionChip,
|
|
1628
|
+
...hoveredSuggestion === prompt.id ? quickChatStyles.suggestionChipHover : {}
|
|
1629
|
+
},
|
|
1630
|
+
children: prompt.text
|
|
1631
|
+
},
|
|
1632
|
+
prompt.id
|
|
1633
|
+
)) }),
|
|
1634
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1635
|
+
"div",
|
|
1636
|
+
{
|
|
1637
|
+
style: isPinned ? quickChatStyles.pinnedMessagesArea : quickChatStyles.messagesArea,
|
|
1638
|
+
children: [
|
|
1639
|
+
error && !rateLimitNotice && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: quickChatStyles.errorContainer, children: [
|
|
1640
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.AlertCircle, { size: 20, style: quickChatStyles.errorIcon }),
|
|
1641
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: quickChatStyles.errorText, children: error }),
|
|
1642
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1643
|
+
"button",
|
|
1644
|
+
{
|
|
1645
|
+
type: "button",
|
|
1646
|
+
onClick: () => sendMessage(),
|
|
1647
|
+
style: quickChatStyles.errorRetry,
|
|
1648
|
+
children: [
|
|
1649
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.RefreshCw, { size: 10 }),
|
|
1650
|
+
"Retry"
|
|
1651
|
+
]
|
|
1652
|
+
}
|
|
1653
|
+
)
|
|
1654
|
+
] }),
|
|
1655
|
+
debugInfo && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1656
|
+
"div",
|
|
1657
|
+
{
|
|
1658
|
+
style: {
|
|
1659
|
+
backgroundColor: "#0f172a",
|
|
1660
|
+
color: "#e2e8f0",
|
|
1661
|
+
border: "1px solid #334155",
|
|
1662
|
+
borderRadius: "8px",
|
|
1663
|
+
padding: "8px",
|
|
1664
|
+
margin: "0 0 8px",
|
|
1665
|
+
fontSize: "12px",
|
|
1666
|
+
lineHeight: 1.4,
|
|
1667
|
+
wordBreak: "break-word"
|
|
1668
|
+
},
|
|
1669
|
+
children: [
|
|
1670
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1671
|
+
"div",
|
|
1672
|
+
{
|
|
1673
|
+
style: {
|
|
1674
|
+
display: "flex",
|
|
1675
|
+
justifyContent: "space-between",
|
|
1676
|
+
gap: "8px"
|
|
1677
|
+
},
|
|
1678
|
+
children: [
|
|
1679
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
1680
|
+
"Last request: ",
|
|
1681
|
+
debugInfo.status,
|
|
1682
|
+
" ",
|
|
1683
|
+
debugInfo.ok ? "(ok)" : "(error)"
|
|
1684
|
+
] }),
|
|
1685
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { opacity: 0.7 }, children: new Date(debugInfo.timestamp).toLocaleTimeString() })
|
|
1686
|
+
]
|
|
1687
|
+
}
|
|
1688
|
+
),
|
|
1689
|
+
debugInfo.error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { color: "#f87171", marginTop: "4px" }, children: [
|
|
1690
|
+
"Error: ",
|
|
1691
|
+
debugInfo.error
|
|
1692
|
+
] }),
|
|
1693
|
+
debugInfo.contentPreview && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: "4px" }, children: [
|
|
1694
|
+
"Content: ",
|
|
1695
|
+
debugInfo.contentPreview
|
|
1696
|
+
] }),
|
|
1697
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: "4px", opacity: 0.8 }, children: [
|
|
1698
|
+
"Raw: ",
|
|
1699
|
+
debugInfo.rawTextPreview || "(empty)"
|
|
1700
|
+
] })
|
|
1701
|
+
]
|
|
1702
|
+
}
|
|
1703
|
+
),
|
|
1704
|
+
messages.length > 0 && messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1705
|
+
"div",
|
|
1706
|
+
{
|
|
1707
|
+
style: {
|
|
1708
|
+
...quickChatStyles.message,
|
|
1709
|
+
animation: "fadeIn 0.2s ease-out"
|
|
1710
|
+
},
|
|
1711
|
+
children: [
|
|
1712
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1713
|
+
"div",
|
|
1714
|
+
{
|
|
1715
|
+
style: message.role === "user" ? quickChatStyles.messageUser : quickChatStyles.messageAssistant,
|
|
1716
|
+
children: [
|
|
1717
|
+
message.content,
|
|
1718
|
+
message.isStreaming && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: quickChatStyles.streamingIndicator }),
|
|
1719
|
+
message.role === "assistant" && !message.isStreaming && message.content.endsWith("...") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: quickChatStyles.truncated, children: "(truncated)" })
|
|
1720
|
+
]
|
|
1721
|
+
}
|
|
1722
|
+
),
|
|
1723
|
+
message.role === "assistant" && !message.isStreaming && message.content && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: quickChatStyles.messageActions, children: [
|
|
1724
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1725
|
+
"button",
|
|
1726
|
+
{
|
|
1727
|
+
type: "button",
|
|
1728
|
+
onClick: () => handleCopy(message.content),
|
|
1729
|
+
style: quickChatStyles.actionButton,
|
|
1730
|
+
children: [
|
|
1731
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Copy, { size: 10 }),
|
|
1732
|
+
"Copy"
|
|
1733
|
+
]
|
|
1734
|
+
}
|
|
1735
|
+
),
|
|
1736
|
+
message.actions?.map((action) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1737
|
+
"button",
|
|
1738
|
+
{
|
|
1739
|
+
type: "button",
|
|
1740
|
+
onClick: action.onClick,
|
|
1741
|
+
style: quickChatStyles.actionButton,
|
|
1742
|
+
children: [
|
|
1743
|
+
action.icon,
|
|
1744
|
+
action.label
|
|
1745
|
+
]
|
|
1746
|
+
},
|
|
1747
|
+
action.id
|
|
1748
|
+
))
|
|
1749
|
+
] })
|
|
1750
|
+
]
|
|
1751
|
+
},
|
|
1752
|
+
message.id
|
|
1753
|
+
)),
|
|
1754
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: messagesEndRef })
|
|
1755
|
+
]
|
|
1756
|
+
}
|
|
1757
|
+
),
|
|
1758
|
+
rateLimitNotice && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1759
|
+
"div",
|
|
1760
|
+
{
|
|
1761
|
+
style: {
|
|
1762
|
+
borderTop: "1px solid rgba(148, 163, 184, 0.25)",
|
|
1763
|
+
background: "linear-gradient(180deg, rgba(15, 23, 42, 0.92), rgba(15, 23, 42, 0.96))",
|
|
1764
|
+
color: "#e2e8f0",
|
|
1765
|
+
padding: "8px 10px"
|
|
1766
|
+
},
|
|
1767
|
+
children: [
|
|
1768
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1769
|
+
"div",
|
|
1770
|
+
{
|
|
1771
|
+
style: {
|
|
1772
|
+
display: "flex",
|
|
1773
|
+
alignItems: "center",
|
|
1774
|
+
justifyContent: "space-between",
|
|
1775
|
+
gap: "8px"
|
|
1776
|
+
},
|
|
1777
|
+
children: [
|
|
1778
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
1779
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.AlertCircle, { size: 16, style: { color: "#fbbf24" } }),
|
|
1780
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: "13px", lineHeight: 1.2 }, children: rateLimitNotice.message })
|
|
1781
|
+
] }),
|
|
1782
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "6px" }, children: [
|
|
1783
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1784
|
+
"button",
|
|
1785
|
+
{
|
|
1786
|
+
type: "button",
|
|
1787
|
+
onClick: () => setRateLimitExpanded((v) => !v),
|
|
1788
|
+
style: {
|
|
1789
|
+
border: "1px solid rgba(148, 163, 184, 0.25)",
|
|
1790
|
+
background: "rgba(30, 41, 59, 0.6)",
|
|
1791
|
+
color: "#e2e8f0",
|
|
1792
|
+
borderRadius: "6px",
|
|
1793
|
+
padding: "4px 8px",
|
|
1794
|
+
fontSize: "12px",
|
|
1795
|
+
cursor: "pointer"
|
|
1796
|
+
},
|
|
1797
|
+
children: rateLimitExpanded ? "Hide" : "Details"
|
|
1798
|
+
}
|
|
1799
|
+
),
|
|
1800
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1801
|
+
"button",
|
|
1802
|
+
{
|
|
1803
|
+
type: "button",
|
|
1804
|
+
onClick: handleReportIssue,
|
|
1805
|
+
disabled: reportStatus === "sending" || reportStatus === "sent",
|
|
1806
|
+
style: {
|
|
1807
|
+
border: "1px solid rgba(148, 163, 184, 0.25)",
|
|
1808
|
+
background: reportStatus === "sent" ? "rgba(34, 197, 94, 0.22)" : "rgba(30, 41, 59, 0.6)",
|
|
1809
|
+
color: "#e2e8f0",
|
|
1810
|
+
borderRadius: "6px",
|
|
1811
|
+
padding: "4px 8px",
|
|
1812
|
+
fontSize: "12px",
|
|
1813
|
+
cursor: reportStatus === "sending" || reportStatus === "sent" ? "not-allowed" : "pointer",
|
|
1814
|
+
opacity: reportStatus === "sending" ? 0.7 : 1
|
|
1815
|
+
},
|
|
1816
|
+
title: "Create a GitHub issue via /api/feedback",
|
|
1817
|
+
children: reportStatus === "sending" ? "Reporting..." : reportStatus === "sent" ? "Reported" : "Report"
|
|
1818
|
+
}
|
|
1819
|
+
),
|
|
1820
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1821
|
+
"button",
|
|
1822
|
+
{
|
|
1823
|
+
type: "button",
|
|
1824
|
+
onClick: () => {
|
|
1825
|
+
clearRateLimitNotice();
|
|
1826
|
+
setRateLimitExpanded(false);
|
|
1827
|
+
},
|
|
1828
|
+
style: {
|
|
1829
|
+
border: "none",
|
|
1830
|
+
background: "transparent",
|
|
1831
|
+
color: "rgba(226, 232, 240, 0.8)",
|
|
1832
|
+
padding: "4px",
|
|
1833
|
+
cursor: "pointer"
|
|
1834
|
+
},
|
|
1835
|
+
title: "Dismiss",
|
|
1836
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { size: 14 })
|
|
1837
|
+
}
|
|
1838
|
+
)
|
|
1839
|
+
] })
|
|
1840
|
+
]
|
|
1841
|
+
}
|
|
1842
|
+
),
|
|
1843
|
+
reportUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: "6px", fontSize: "12px" }, children: [
|
|
1844
|
+
"Created:",
|
|
1845
|
+
" ",
|
|
1846
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1847
|
+
"a",
|
|
1848
|
+
{
|
|
1849
|
+
href: reportUrl,
|
|
1850
|
+
target: "_blank",
|
|
1851
|
+
rel: "noopener noreferrer",
|
|
1852
|
+
style: { color: "#93c5fd" },
|
|
1853
|
+
children: "Open issue"
|
|
1854
|
+
}
|
|
1855
|
+
)
|
|
1856
|
+
] }),
|
|
1857
|
+
reportError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1858
|
+
"div",
|
|
1859
|
+
{
|
|
1860
|
+
style: { marginTop: "6px", fontSize: "12px", color: "#fca5a5" },
|
|
1861
|
+
children: reportError
|
|
1862
|
+
}
|
|
1863
|
+
),
|
|
1864
|
+
rateLimitExpanded && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1865
|
+
"div",
|
|
1866
|
+
{
|
|
1867
|
+
style: {
|
|
1868
|
+
marginTop: "8px",
|
|
1869
|
+
fontSize: "12px",
|
|
1870
|
+
lineHeight: 1.4,
|
|
1871
|
+
backgroundColor: "rgba(2, 6, 23, 0.55)",
|
|
1872
|
+
border: "1px solid rgba(148, 163, 184, 0.25)",
|
|
1873
|
+
borderRadius: "8px",
|
|
1874
|
+
padding: "8px",
|
|
1875
|
+
wordBreak: "break-word"
|
|
1876
|
+
},
|
|
1877
|
+
children: [
|
|
1878
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { opacity: 0.85 }, children: [
|
|
1879
|
+
"Status: ",
|
|
1880
|
+
rateLimitNotice.status,
|
|
1881
|
+
rateLimitNotice.requestId ? ` \u2022 Request: ${rateLimitNotice.requestId}` : ""
|
|
1882
|
+
] }),
|
|
1883
|
+
rateLimitNotice.endpoint && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { opacity: 0.75, marginTop: "4px" }, children: [
|
|
1884
|
+
"Endpoint: ",
|
|
1885
|
+
rateLimitNotice.endpoint
|
|
1886
|
+
] }),
|
|
1887
|
+
rateLimitNotice.retryAt && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { opacity: 0.75, marginTop: "4px" }, children: [
|
|
1888
|
+
"RetryAt: ",
|
|
1889
|
+
new Date(rateLimitNotice.retryAt).toLocaleString()
|
|
1890
|
+
] }),
|
|
1891
|
+
rateLimitNotice.raw && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: "6px", opacity: 0.85 }, children: [
|
|
1892
|
+
"Raw: ",
|
|
1893
|
+
rateLimitNotice.raw
|
|
1894
|
+
] }),
|
|
1895
|
+
debugInfo && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: "6px", opacity: 0.85 }, children: [
|
|
1896
|
+
"Debug: ",
|
|
1897
|
+
debugInfo.rawTextPreview || "(empty)"
|
|
1898
|
+
] })
|
|
1899
|
+
]
|
|
1900
|
+
}
|
|
1901
|
+
)
|
|
1902
|
+
]
|
|
1903
|
+
}
|
|
1904
|
+
),
|
|
1905
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: quickChatStyles.inputContainer, children: [
|
|
1906
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1907
|
+
"textarea",
|
|
1908
|
+
{
|
|
1909
|
+
ref: inputRef,
|
|
1910
|
+
value: input,
|
|
1911
|
+
onChange: handleInputChange,
|
|
1912
|
+
onKeyDown: handleKeyDown,
|
|
1913
|
+
onFocus: () => setInputFocused(true),
|
|
1914
|
+
onBlur: () => setInputFocused(false),
|
|
1915
|
+
placeholder: mergedConfig.placeholder,
|
|
1916
|
+
disabled: isSending,
|
|
1917
|
+
rows: 1,
|
|
1918
|
+
style: {
|
|
1919
|
+
...quickChatStyles.input,
|
|
1920
|
+
...inputFocused ? quickChatStyles.inputFocused : {}
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
),
|
|
1924
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: "4px" }, children: [
|
|
1925
|
+
mergedConfig.t3chat?.enabled !== false && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1926
|
+
"button",
|
|
1927
|
+
{
|
|
1928
|
+
type: "button",
|
|
1929
|
+
onClick: handleSendToT3Chat,
|
|
1930
|
+
disabled: !input.trim(),
|
|
1931
|
+
title: mergedConfig.t3chat?.label ?? "Ask t3.chat",
|
|
1932
|
+
style: {
|
|
1933
|
+
...quickChatStyles.sendButton,
|
|
1934
|
+
backgroundColor: "#7c3aed",
|
|
1935
|
+
...!input.trim() ? quickChatStyles.sendButtonDisabled : {}
|
|
1936
|
+
},
|
|
1937
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ExternalLink, { size: 14 })
|
|
1938
|
+
}
|
|
1939
|
+
),
|
|
1940
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1941
|
+
"button",
|
|
1942
|
+
{
|
|
1943
|
+
type: "button",
|
|
1944
|
+
onClick: handleSend,
|
|
1945
|
+
disabled: isSending || !input.trim(),
|
|
1946
|
+
style: {
|
|
1947
|
+
...quickChatStyles.sendButton,
|
|
1948
|
+
...isSending || !input.trim() ? quickChatStyles.sendButtonDisabled : {}
|
|
1949
|
+
},
|
|
1950
|
+
children: isSending ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1951
|
+
"div",
|
|
1952
|
+
{
|
|
1953
|
+
style: {
|
|
1954
|
+
width: "14px",
|
|
1955
|
+
height: "14px",
|
|
1956
|
+
border: "2px solid transparent",
|
|
1957
|
+
borderTopColor: "#fff",
|
|
1958
|
+
borderRadius: "50%",
|
|
1959
|
+
animation: "spin 0.8s linear infinite"
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Send, { size: 14 })
|
|
1963
|
+
}
|
|
1964
|
+
)
|
|
1965
|
+
] })
|
|
1966
|
+
] })
|
|
1967
|
+
] });
|
|
1968
|
+
}
|
|
102
1969
|
|
|
103
1970
|
// src/ScreenshotPreview.tsx
|
|
104
|
-
var
|
|
105
|
-
var
|
|
106
|
-
var
|
|
1971
|
+
var import_react4 = __toESM(require("react"));
|
|
1972
|
+
var import_anyclick_core3 = require("@ewjdev/anyclick-core");
|
|
1973
|
+
var import_lucide_react2 = require("lucide-react");
|
|
107
1974
|
|
|
108
1975
|
// src/styles.ts
|
|
109
1976
|
var menuCSSVariables = {
|
|
@@ -578,8 +2445,8 @@ var screenshotPreviewStyles = {
|
|
|
578
2445
|
};
|
|
579
2446
|
|
|
580
2447
|
// src/ScreenshotPreview.tsx
|
|
581
|
-
var
|
|
582
|
-
var ScreenshotPreview =
|
|
2448
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
2449
|
+
var ScreenshotPreview = import_react4.default.memo(function ScreenshotPreview2({
|
|
583
2450
|
isLoading,
|
|
584
2451
|
isSubmitting,
|
|
585
2452
|
onCancel,
|
|
@@ -587,12 +2454,12 @@ var ScreenshotPreview = import_react.default.memo(function ScreenshotPreview2({
|
|
|
587
2454
|
onRetake,
|
|
588
2455
|
screenshots
|
|
589
2456
|
}) {
|
|
590
|
-
const [activeTab, setActiveTab] = (0,
|
|
591
|
-
const [isExpanded, setIsExpanded] = (0,
|
|
2457
|
+
const [activeTab, setActiveTab] = (0, import_react4.useState)("element");
|
|
2458
|
+
const [isExpanded, setIsExpanded] = (0, import_react4.useState)(false);
|
|
592
2459
|
const getError = (key) => {
|
|
593
2460
|
return screenshots?.errors?.[key];
|
|
594
2461
|
};
|
|
595
|
-
const tabs = (0,
|
|
2462
|
+
const tabs = (0, import_react4.useMemo)(() => {
|
|
596
2463
|
if (!screenshots) return [];
|
|
597
2464
|
const allTabs = [
|
|
598
2465
|
{
|
|
@@ -616,29 +2483,29 @@ var ScreenshotPreview = import_react.default.memo(function ScreenshotPreview2({
|
|
|
616
2483
|
];
|
|
617
2484
|
return allTabs.filter((tab) => tab.data || tab.error);
|
|
618
2485
|
}, [screenshots]);
|
|
619
|
-
const totalSize = (0,
|
|
620
|
-
() => screenshots ? (0,
|
|
2486
|
+
const totalSize = (0, import_react4.useMemo)(
|
|
2487
|
+
() => screenshots ? (0, import_anyclick_core3.estimateTotalSize)(screenshots) : 0,
|
|
621
2488
|
[screenshots]
|
|
622
2489
|
);
|
|
623
2490
|
if (isLoading) {
|
|
624
|
-
return /* @__PURE__ */ (0,
|
|
625
|
-
/* @__PURE__ */ (0,
|
|
626
|
-
|
|
2491
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: screenshotPreviewStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: screenshotPreviewStyles.loadingContainer, children: [
|
|
2492
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2493
|
+
import_lucide_react2.Loader2Icon,
|
|
627
2494
|
{
|
|
628
2495
|
className: "w-6 h-6 animate-spin",
|
|
629
2496
|
style: { color: "#3b82f6" }
|
|
630
2497
|
}
|
|
631
2498
|
),
|
|
632
|
-
/* @__PURE__ */ (0,
|
|
2499
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: screenshotPreviewStyles.loadingText, children: "Capturing screenshots..." })
|
|
633
2500
|
] }) });
|
|
634
2501
|
}
|
|
635
2502
|
if (!screenshots) {
|
|
636
|
-
return /* @__PURE__ */ (0,
|
|
637
|
-
/* @__PURE__ */ (0,
|
|
638
|
-
/* @__PURE__ */ (0,
|
|
639
|
-
/* @__PURE__ */ (0,
|
|
640
|
-
/* @__PURE__ */ (0,
|
|
641
|
-
/* @__PURE__ */ (0,
|
|
2503
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: screenshotPreviewStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: screenshotPreviewStyles.emptyContainer, children: [
|
|
2504
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.ImageIcon, { className: "w-8 h-8", style: { color: "#9ca3af" } }),
|
|
2505
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: screenshotPreviewStyles.emptyText, children: "Screenshots unavailable" }),
|
|
2506
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: screenshotPreviewStyles.emptySubtext, children: "Some elements can't be captured (e.g., gradient text)" }),
|
|
2507
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: screenshotPreviewStyles.emptyActions, children: [
|
|
2508
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
642
2509
|
"button",
|
|
643
2510
|
{
|
|
644
2511
|
type: "button",
|
|
@@ -646,12 +2513,12 @@ var ScreenshotPreview = import_react.default.memo(function ScreenshotPreview2({
|
|
|
646
2513
|
onClick: onRetake,
|
|
647
2514
|
style: screenshotPreviewStyles.retakeButtonOutline,
|
|
648
2515
|
children: [
|
|
649
|
-
/* @__PURE__ */ (0,
|
|
2516
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.RefreshCwIcon, { className: "w-4 h-4" }),
|
|
650
2517
|
"Try Again"
|
|
651
2518
|
]
|
|
652
2519
|
}
|
|
653
2520
|
),
|
|
654
|
-
/* @__PURE__ */ (0,
|
|
2521
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
655
2522
|
"button",
|
|
656
2523
|
{
|
|
657
2524
|
type: "button",
|
|
@@ -659,7 +2526,7 @@ var ScreenshotPreview = import_react.default.memo(function ScreenshotPreview2({
|
|
|
659
2526
|
onClick: () => onConfirm({ capturedAt: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
660
2527
|
style: screenshotPreviewStyles.continueButton,
|
|
661
2528
|
children: [
|
|
662
|
-
/* @__PURE__ */ (0,
|
|
2529
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.CheckIcon, { className: "w-4 h-4" }),
|
|
663
2530
|
"Continue Without"
|
|
664
2531
|
]
|
|
665
2532
|
}
|
|
@@ -669,7 +2536,7 @@ var ScreenshotPreview = import_react.default.memo(function ScreenshotPreview2({
|
|
|
669
2536
|
}
|
|
670
2537
|
const activeScreenshot = activeTab === "element" ? screenshots.element : activeTab === "container" ? screenshots.container : screenshots.viewport;
|
|
671
2538
|
const activeError = getError(activeTab);
|
|
672
|
-
return /* @__PURE__ */ (0,
|
|
2539
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
673
2540
|
"div",
|
|
674
2541
|
{
|
|
675
2542
|
style: {
|
|
@@ -678,23 +2545,23 @@ var ScreenshotPreview = import_react.default.memo(function ScreenshotPreview2({
|
|
|
678
2545
|
padding: "8px"
|
|
679
2546
|
},
|
|
680
2547
|
children: [
|
|
681
|
-
/* @__PURE__ */ (0,
|
|
682
|
-
/* @__PURE__ */ (0,
|
|
683
|
-
/* @__PURE__ */ (0,
|
|
684
|
-
/* @__PURE__ */ (0,
|
|
685
|
-
/* @__PURE__ */ (0,
|
|
2548
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: screenshotPreviewStyles.header, children: [
|
|
2549
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: screenshotPreviewStyles.headerTitle, children: "Review Screenshots" }),
|
|
2550
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: screenshotPreviewStyles.headerActions, children: [
|
|
2551
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: screenshotPreviewStyles.sizeLabel, children: (0, import_anyclick_core3.formatBytes)(totalSize) }),
|
|
2552
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
686
2553
|
"button",
|
|
687
2554
|
{
|
|
688
2555
|
type: "button",
|
|
689
2556
|
onClick: () => setIsExpanded(!isExpanded),
|
|
690
2557
|
style: screenshotPreviewStyles.iconButton,
|
|
691
2558
|
title: isExpanded ? "Collapse" : "Expand",
|
|
692
|
-
children: isExpanded ? /* @__PURE__ */ (0,
|
|
2559
|
+
children: isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.ShrinkIcon, { className: "w-4 h-4" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.ExpandIcon, { className: "w-4 h-4" })
|
|
693
2560
|
}
|
|
694
2561
|
)
|
|
695
2562
|
] })
|
|
696
2563
|
] }),
|
|
697
|
-
/* @__PURE__ */ (0,
|
|
2564
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: screenshotPreviewStyles.tabContainer, children: tabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
698
2565
|
"button",
|
|
699
2566
|
{
|
|
700
2567
|
type: "button",
|
|
@@ -705,40 +2572,40 @@ var ScreenshotPreview = import_react.default.memo(function ScreenshotPreview2({
|
|
|
705
2572
|
...tab.error && !tab.data ? screenshotPreviewStyles.tabError : {}
|
|
706
2573
|
},
|
|
707
2574
|
children: [
|
|
708
|
-
tab.error && !tab.data && /* @__PURE__ */ (0,
|
|
709
|
-
|
|
2575
|
+
tab.error && !tab.data && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2576
|
+
import_lucide_react2.AlertCircleIcon,
|
|
710
2577
|
{
|
|
711
2578
|
className: "w-3 h-3",
|
|
712
2579
|
style: { color: "#ef4444" }
|
|
713
2580
|
}
|
|
714
2581
|
),
|
|
715
2582
|
tab.label,
|
|
716
|
-
tab.data && /* @__PURE__ */ (0,
|
|
2583
|
+
tab.data && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: screenshotPreviewStyles.tabSize, children: (0, import_anyclick_core3.formatBytes)(tab.data.sizeBytes) })
|
|
717
2584
|
]
|
|
718
2585
|
},
|
|
719
2586
|
tab.key
|
|
720
2587
|
)) }),
|
|
721
|
-
/* @__PURE__ */ (0,
|
|
2588
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
722
2589
|
"div",
|
|
723
2590
|
{
|
|
724
2591
|
style: {
|
|
725
2592
|
...screenshotPreviewStyles.previewContainer,
|
|
726
2593
|
...isExpanded ? screenshotPreviewStyles.previewContainerExpanded : {}
|
|
727
2594
|
},
|
|
728
|
-
children: activeScreenshot ? /* @__PURE__ */ (0,
|
|
2595
|
+
children: activeScreenshot ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
729
2596
|
"img",
|
|
730
2597
|
{
|
|
731
2598
|
alt: `${activeTab} screenshot`,
|
|
732
2599
|
src: activeScreenshot.dataUrl,
|
|
733
2600
|
style: screenshotPreviewStyles.previewImage
|
|
734
2601
|
}
|
|
735
|
-
) : activeError ? /* @__PURE__ */ (0,
|
|
736
|
-
/* @__PURE__ */ (0,
|
|
737
|
-
/* @__PURE__ */ (0,
|
|
738
|
-
/* @__PURE__ */ (0,
|
|
739
|
-
] }) : /* @__PURE__ */ (0,
|
|
740
|
-
/* @__PURE__ */ (0,
|
|
741
|
-
/* @__PURE__ */ (0,
|
|
2602
|
+
) : activeError ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: screenshotPreviewStyles.errorPreview, children: [
|
|
2603
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.AlertCircleIcon, { className: "w-8 h-8", style: { color: "#ef4444" } }),
|
|
2604
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: screenshotPreviewStyles.errorTitle, children: "Capture Failed" }),
|
|
2605
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: screenshotPreviewStyles.errorMessage, children: activeError.message })
|
|
2606
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: screenshotPreviewStyles.noPreview, children: [
|
|
2607
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.ImageIcon, { className: "w-6 h-6", style: { color: "#9ca3af" } }),
|
|
2608
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
|
|
742
2609
|
"No ",
|
|
743
2610
|
activeTab,
|
|
744
2611
|
" screenshot"
|
|
@@ -746,14 +2613,14 @@ var ScreenshotPreview = import_react.default.memo(function ScreenshotPreview2({
|
|
|
746
2613
|
] })
|
|
747
2614
|
}
|
|
748
2615
|
),
|
|
749
|
-
activeScreenshot && /* @__PURE__ */ (0,
|
|
2616
|
+
activeScreenshot && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: screenshotPreviewStyles.dimensionsInfo, children: [
|
|
750
2617
|
activeScreenshot.width,
|
|
751
2618
|
" \xD7 ",
|
|
752
2619
|
activeScreenshot.height,
|
|
753
2620
|
"px"
|
|
754
2621
|
] }),
|
|
755
|
-
/* @__PURE__ */ (0,
|
|
756
|
-
/* @__PURE__ */ (0,
|
|
2622
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: screenshotPreviewStyles.actions, children: [
|
|
2623
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
757
2624
|
"button",
|
|
758
2625
|
{
|
|
759
2626
|
type: "button",
|
|
@@ -761,13 +2628,13 @@ var ScreenshotPreview = import_react.default.memo(function ScreenshotPreview2({
|
|
|
761
2628
|
onClick: onRetake,
|
|
762
2629
|
style: screenshotPreviewStyles.retakeButtonSmall,
|
|
763
2630
|
children: [
|
|
764
|
-
/* @__PURE__ */ (0,
|
|
2631
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.RefreshCwIcon, { className: "w-3 h-3" }),
|
|
765
2632
|
"Retake"
|
|
766
2633
|
]
|
|
767
2634
|
}
|
|
768
2635
|
),
|
|
769
|
-
/* @__PURE__ */ (0,
|
|
770
|
-
/* @__PURE__ */ (0,
|
|
2636
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: screenshotPreviewStyles.actionsRight, children: [
|
|
2637
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
771
2638
|
"button",
|
|
772
2639
|
{
|
|
773
2640
|
type: "button",
|
|
@@ -776,12 +2643,12 @@ var ScreenshotPreview = import_react.default.memo(function ScreenshotPreview2({
|
|
|
776
2643
|
onClick: onCancel,
|
|
777
2644
|
style: { ...menuStyles.button, ...menuStyles.cancelButton },
|
|
778
2645
|
children: [
|
|
779
|
-
/* @__PURE__ */ (0,
|
|
2646
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.XIcon, { className: "w-3 h-3" }),
|
|
780
2647
|
"Cancel"
|
|
781
2648
|
]
|
|
782
2649
|
}
|
|
783
2650
|
),
|
|
784
|
-
/* @__PURE__ */ (0,
|
|
2651
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
785
2652
|
"button",
|
|
786
2653
|
{
|
|
787
2654
|
type: "button",
|
|
@@ -792,11 +2659,11 @@ var ScreenshotPreview = import_react.default.memo(function ScreenshotPreview2({
|
|
|
792
2659
|
...menuStyles.submitButton,
|
|
793
2660
|
...isSubmitting ? menuStyles.submitButtonDisabled : {}
|
|
794
2661
|
},
|
|
795
|
-
children: isSubmitting ? /* @__PURE__ */ (0,
|
|
796
|
-
/* @__PURE__ */ (0,
|
|
2662
|
+
children: isSubmitting ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2663
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.Loader2Icon, { className: "w-3 h-3 animate-spin" }),
|
|
797
2664
|
"Sending..."
|
|
798
|
-
] }) : /* @__PURE__ */ (0,
|
|
799
|
-
/* @__PURE__ */ (0,
|
|
2665
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
2666
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.CheckIcon, { className: "w-3 h-3" }),
|
|
800
2667
|
"Send"
|
|
801
2668
|
] })
|
|
802
2669
|
}
|
|
@@ -893,7 +2760,7 @@ svg.${HIGHLIGHT_CONTAINER_CLASS},
|
|
|
893
2760
|
}
|
|
894
2761
|
`;
|
|
895
2762
|
}
|
|
896
|
-
function
|
|
2763
|
+
function injectStyles2(colors) {
|
|
897
2764
|
if (typeof document === "undefined") return;
|
|
898
2765
|
const existingStyle = document.getElementById(STYLE_ID);
|
|
899
2766
|
if (existingStyle) {
|
|
@@ -941,12 +2808,12 @@ function findContainerParent(element, config) {
|
|
|
941
2808
|
}
|
|
942
2809
|
function highlightTarget(element, colors) {
|
|
943
2810
|
const mergedColors = { ...defaultHighlightColors, ...colors };
|
|
944
|
-
|
|
2811
|
+
injectStyles2(mergedColors);
|
|
945
2812
|
element.classList.add(HIGHLIGHT_TARGET_CLASS);
|
|
946
2813
|
}
|
|
947
2814
|
function highlightContainer(element, colors) {
|
|
948
2815
|
const mergedColors = { ...defaultHighlightColors, ...colors };
|
|
949
|
-
|
|
2816
|
+
injectStyles2(mergedColors);
|
|
950
2817
|
element.classList.add(HIGHLIGHT_CONTAINER_CLASS);
|
|
951
2818
|
}
|
|
952
2819
|
function clearHighlights() {
|
|
@@ -973,12 +2840,12 @@ function applyHighlights(targetElement, config) {
|
|
|
973
2840
|
}
|
|
974
2841
|
|
|
975
2842
|
// src/ContextMenu.tsx
|
|
976
|
-
var
|
|
2843
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
977
2844
|
var VIEWPORT_PADDING = 10;
|
|
978
2845
|
var defaultIcons = {
|
|
979
|
-
feature: /* @__PURE__ */ (0,
|
|
980
|
-
issue: /* @__PURE__ */ (0,
|
|
981
|
-
like: /* @__PURE__ */ (0,
|
|
2846
|
+
feature: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.PlusIcon, { className: "w-4 h-4" }),
|
|
2847
|
+
issue: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.FlagIcon, { className: "w-4 h-4" }),
|
|
2848
|
+
like: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.ThumbsUpIcon, { className: "w-4 h-4" })
|
|
982
2849
|
};
|
|
983
2850
|
var OFFSCREEN_POSITION = { x: -9999, y: -9999 };
|
|
984
2851
|
var DefaultHeader = ({
|
|
@@ -987,25 +2854,25 @@ var DefaultHeader = ({
|
|
|
987
2854
|
styles,
|
|
988
2855
|
title = "Send Feedback"
|
|
989
2856
|
}) => {
|
|
990
|
-
return /* @__PURE__ */ (0,
|
|
991
|
-
/* @__PURE__ */ (0,
|
|
2857
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: styles, className, children: [
|
|
2858
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: title }),
|
|
992
2859
|
children
|
|
993
2860
|
] });
|
|
994
2861
|
};
|
|
995
|
-
var MenuItem =
|
|
2862
|
+
var MenuItem = import_react5.default.memo(function MenuItem2({
|
|
996
2863
|
disabled,
|
|
997
2864
|
hasChildren,
|
|
998
2865
|
item,
|
|
999
2866
|
onClick
|
|
1000
2867
|
}) {
|
|
1001
|
-
const [isHovered, setIsHovered] = (0,
|
|
1002
|
-
const [isPressed, setIsPressed] = (0,
|
|
2868
|
+
const [isHovered, setIsHovered] = (0, import_react5.useState)(false);
|
|
2869
|
+
const [isPressed, setIsPressed] = (0, import_react5.useState)(false);
|
|
1003
2870
|
const isComingSoon = item.status === "comingSoon";
|
|
1004
2871
|
const badgeLabel = item.badge?.label ?? (isComingSoon ? "Coming soon" : null);
|
|
1005
2872
|
const badgeTone = item.badge?.tone ?? (isComingSoon ? "neutral" : "neutral");
|
|
1006
2873
|
const badgeStyle = badgeLabel ? getBadgeStyle(badgeTone) : void 0;
|
|
1007
2874
|
const iconNode = item.icon ?? defaultIcons[item.type];
|
|
1008
|
-
return /* @__PURE__ */ (0,
|
|
2875
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1009
2876
|
"button",
|
|
1010
2877
|
{
|
|
1011
2878
|
type: "button",
|
|
@@ -1026,22 +2893,22 @@ var MenuItem = import_react2.default.memo(function MenuItem2({
|
|
|
1026
2893
|
...disabled ? menuStyles.itemDisabled : {}
|
|
1027
2894
|
},
|
|
1028
2895
|
children: [
|
|
1029
|
-
iconNode ? /* @__PURE__ */ (0,
|
|
1030
|
-
/* @__PURE__ */ (0,
|
|
2896
|
+
iconNode ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: menuStyles.itemIcon, children: iconNode }) : null,
|
|
2897
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: menuStyles.itemLabel, children: [
|
|
1031
2898
|
item.label,
|
|
1032
|
-
badgeLabel && /* @__PURE__ */ (0,
|
|
2899
|
+
badgeLabel && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: badgeStyle, children: badgeLabel })
|
|
1033
2900
|
] }),
|
|
1034
|
-
hasChildren && /* @__PURE__ */ (0,
|
|
2901
|
+
hasChildren && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.ChevronRightIcon, { className: "w-4 h-4", style: menuStyles.submenuIcon })
|
|
1035
2902
|
]
|
|
1036
2903
|
}
|
|
1037
2904
|
);
|
|
1038
2905
|
});
|
|
1039
|
-
var BackButton =
|
|
2906
|
+
var BackButton = import_react5.default.memo(function BackButton2({
|
|
1040
2907
|
onClick
|
|
1041
2908
|
}) {
|
|
1042
|
-
const [isHovered, setIsHovered] = (0,
|
|
1043
|
-
const [isPressed, setIsPressed] = (0,
|
|
1044
|
-
return /* @__PURE__ */ (0,
|
|
2909
|
+
const [isHovered, setIsHovered] = (0, import_react5.useState)(false);
|
|
2910
|
+
const [isPressed, setIsPressed] = (0, import_react5.useState)(false);
|
|
2911
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1045
2912
|
"button",
|
|
1046
2913
|
{
|
|
1047
2914
|
type: "button",
|
|
@@ -1061,26 +2928,26 @@ var BackButton = import_react2.default.memo(function BackButton2({
|
|
|
1061
2928
|
...isHovered || isPressed ? menuStyles.itemHover : {}
|
|
1062
2929
|
},
|
|
1063
2930
|
children: [
|
|
1064
|
-
/* @__PURE__ */ (0,
|
|
1065
|
-
/* @__PURE__ */ (0,
|
|
2931
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.ChevronLeftIcon, { className: "w-4 h-4", style: { opacity: 0.5 } }),
|
|
2932
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { opacity: 0.7 }, children: "Back" })
|
|
1066
2933
|
]
|
|
1067
2934
|
}
|
|
1068
2935
|
);
|
|
1069
2936
|
});
|
|
1070
|
-
var CommentForm =
|
|
2937
|
+
var CommentForm = import_react5.default.memo(function CommentForm2({
|
|
1071
2938
|
isSubmitting,
|
|
1072
2939
|
onCancel,
|
|
1073
2940
|
onSubmit
|
|
1074
2941
|
}) {
|
|
1075
|
-
const [comment, setComment] = (0,
|
|
1076
|
-
const inputRef = (0,
|
|
1077
|
-
(0,
|
|
2942
|
+
const [comment, setComment] = (0, import_react5.useState)("");
|
|
2943
|
+
const inputRef = (0, import_react5.useRef)(null);
|
|
2944
|
+
(0, import_react5.useEffect)(() => {
|
|
1078
2945
|
inputRef.current?.focus();
|
|
1079
2946
|
}, []);
|
|
1080
|
-
const handleSubmit = (0,
|
|
2947
|
+
const handleSubmit = (0, import_react5.useCallback)(() => {
|
|
1081
2948
|
onSubmit(comment);
|
|
1082
2949
|
}, [comment, onSubmit]);
|
|
1083
|
-
const handleKeyDown = (0,
|
|
2950
|
+
const handleKeyDown = (0, import_react5.useCallback)(
|
|
1084
2951
|
(e) => {
|
|
1085
2952
|
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
1086
2953
|
handleSubmit();
|
|
@@ -1090,8 +2957,8 @@ var CommentForm = import_react2.default.memo(function CommentForm2({
|
|
|
1090
2957
|
},
|
|
1091
2958
|
[handleSubmit, onCancel]
|
|
1092
2959
|
);
|
|
1093
|
-
return /* @__PURE__ */ (0,
|
|
1094
|
-
/* @__PURE__ */ (0,
|
|
2960
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: menuStyles.commentSection, children: [
|
|
2961
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1095
2962
|
"textarea",
|
|
1096
2963
|
{
|
|
1097
2964
|
ref: inputRef,
|
|
@@ -1103,8 +2970,8 @@ var CommentForm = import_react2.default.memo(function CommentForm2({
|
|
|
1103
2970
|
value: comment
|
|
1104
2971
|
}
|
|
1105
2972
|
),
|
|
1106
|
-
/* @__PURE__ */ (0,
|
|
1107
|
-
/* @__PURE__ */ (0,
|
|
2973
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: menuStyles.buttonRow, children: [
|
|
2974
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1108
2975
|
"button",
|
|
1109
2976
|
{
|
|
1110
2977
|
type: "button",
|
|
@@ -1114,7 +2981,7 @@ var CommentForm = import_react2.default.memo(function CommentForm2({
|
|
|
1114
2981
|
children: "Cancel"
|
|
1115
2982
|
}
|
|
1116
2983
|
),
|
|
1117
|
-
/* @__PURE__ */ (0,
|
|
2984
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1118
2985
|
"button",
|
|
1119
2986
|
{
|
|
1120
2987
|
type: "button",
|
|
@@ -1162,39 +3029,48 @@ function ContextMenu({
|
|
|
1162
3029
|
onSelect,
|
|
1163
3030
|
position,
|
|
1164
3031
|
positionMode = "inView",
|
|
3032
|
+
quickChatConfig,
|
|
1165
3033
|
screenshotConfig,
|
|
1166
3034
|
style,
|
|
1167
3035
|
targetElement,
|
|
1168
3036
|
visible
|
|
1169
3037
|
}) {
|
|
1170
|
-
const [selectedType, setSelectedType] = (0,
|
|
1171
|
-
const [currentView, setCurrentView] = (0,
|
|
1172
|
-
const [pendingComment, setPendingComment] = (0,
|
|
1173
|
-
const [submenuStack, setSubmenuStack] = (0,
|
|
1174
|
-
const [screenshots, setScreenshots] = (0,
|
|
1175
|
-
const [isCapturing, setIsCapturing] = (0,
|
|
1176
|
-
const
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
3038
|
+
const [selectedType, setSelectedType] = (0, import_react5.useState)(null);
|
|
3039
|
+
const [currentView, setCurrentView] = (0, import_react5.useState)("menu");
|
|
3040
|
+
const [pendingComment, setPendingComment] = (0, import_react5.useState)();
|
|
3041
|
+
const [submenuStack, setSubmenuStack] = (0, import_react5.useState)([]);
|
|
3042
|
+
const [screenshots, setScreenshots] = (0, import_react5.useState)(null);
|
|
3043
|
+
const [isCapturing, setIsCapturing] = (0, import_react5.useState)(false);
|
|
3044
|
+
const [isQuickChatPinned, setIsQuickChatPinned] = (0, import_react5.useState)(() => {
|
|
3045
|
+
if (typeof window === "undefined") return false;
|
|
3046
|
+
try {
|
|
3047
|
+
return sessionStorage.getItem("anyclick-quick-chat-pinned") === "true";
|
|
3048
|
+
} catch {
|
|
3049
|
+
return false;
|
|
3050
|
+
}
|
|
3051
|
+
});
|
|
3052
|
+
const menuRef = (0, import_react5.useRef)(null);
|
|
3053
|
+
const [adjustedPosition, setAdjustedPosition] = (0, import_react5.useState)(OFFSCREEN_POSITION);
|
|
3054
|
+
const [isDragging, setIsDragging] = (0, import_react5.useState)(false);
|
|
3055
|
+
const [dragOffset, setDragOffset] = (0, import_react5.useState)({
|
|
1180
3056
|
x: 0,
|
|
1181
3057
|
y: 0
|
|
1182
3058
|
});
|
|
1183
|
-
const dragStartRef = (0,
|
|
1184
|
-
const mergedScreenshotConfig =
|
|
3059
|
+
const dragStartRef = (0, import_react5.useRef)(null);
|
|
3060
|
+
const mergedScreenshotConfig = import_react5.default.useMemo(
|
|
1185
3061
|
() => ({
|
|
1186
|
-
...
|
|
3062
|
+
...import_anyclick_core4.DEFAULT_SCREENSHOT_CONFIG,
|
|
1187
3063
|
...screenshotConfig
|
|
1188
3064
|
}),
|
|
1189
3065
|
[screenshotConfig]
|
|
1190
3066
|
);
|
|
1191
|
-
const showPreview = mergedScreenshotConfig.showPreview && (0,
|
|
3067
|
+
const showPreview = mergedScreenshotConfig.showPreview && (0, import_anyclick_core4.isScreenshotSupported)();
|
|
1192
3068
|
const currentItems = submenuStack.length > 0 ? submenuStack[submenuStack.length - 1] : items;
|
|
1193
|
-
const captureScreenshots = (0,
|
|
3069
|
+
const captureScreenshots = (0, import_react5.useCallback)(async () => {
|
|
1194
3070
|
if (!targetElement || !showPreview) return;
|
|
1195
3071
|
setIsCapturing(true);
|
|
1196
3072
|
try {
|
|
1197
|
-
const captured = await (0,
|
|
3073
|
+
const captured = await (0, import_anyclick_core4.captureAllScreenshots)(
|
|
1198
3074
|
targetElement,
|
|
1199
3075
|
containerElement,
|
|
1200
3076
|
mergedScreenshotConfig
|
|
@@ -1207,7 +3083,7 @@ function ContextMenu({
|
|
|
1207
3083
|
setIsCapturing(false);
|
|
1208
3084
|
}
|
|
1209
3085
|
}, [containerElement, mergedScreenshotConfig, showPreview, targetElement]);
|
|
1210
|
-
(0,
|
|
3086
|
+
(0, import_react5.useEffect)(() => {
|
|
1211
3087
|
if (!visible) {
|
|
1212
3088
|
setSelectedType(null);
|
|
1213
3089
|
setCurrentView("menu");
|
|
@@ -1221,7 +3097,7 @@ function ContextMenu({
|
|
|
1221
3097
|
dragStartRef.current = null;
|
|
1222
3098
|
}
|
|
1223
3099
|
}, [visible]);
|
|
1224
|
-
(0,
|
|
3100
|
+
(0, import_react5.useEffect)(() => {
|
|
1225
3101
|
if (visible && targetElement) {
|
|
1226
3102
|
clearHighlights();
|
|
1227
3103
|
applyHighlights(targetElement, highlightConfig);
|
|
@@ -1232,7 +3108,7 @@ function ContextMenu({
|
|
|
1232
3108
|
clearHighlights();
|
|
1233
3109
|
};
|
|
1234
3110
|
}, [highlightConfig, targetElement, visible]);
|
|
1235
|
-
(0,
|
|
3111
|
+
(0, import_react5.useEffect)(() => {
|
|
1236
3112
|
if (!visible) {
|
|
1237
3113
|
return;
|
|
1238
3114
|
}
|
|
@@ -1251,13 +3127,13 @@ function ContextMenu({
|
|
|
1251
3127
|
document.removeEventListener("pointerdown", handlePointerDown);
|
|
1252
3128
|
};
|
|
1253
3129
|
}, [onClose, visible]);
|
|
1254
|
-
(0,
|
|
3130
|
+
(0, import_react5.useEffect)(() => {
|
|
1255
3131
|
if (visible) {
|
|
1256
3132
|
setAdjustedPosition(position);
|
|
1257
3133
|
setDragOffset({ x: 0, y: 0 });
|
|
1258
3134
|
}
|
|
1259
3135
|
}, [position.x, position.y, visible]);
|
|
1260
|
-
(0,
|
|
3136
|
+
(0, import_react5.useEffect)(() => {
|
|
1261
3137
|
if (!visible || !menuRef.current) return;
|
|
1262
3138
|
const updatePosition = () => {
|
|
1263
3139
|
const menuElement = menuRef.current;
|
|
@@ -1281,7 +3157,7 @@ function ContextMenu({
|
|
|
1281
3157
|
window.addEventListener("resize", updatePosition);
|
|
1282
3158
|
return () => window.removeEventListener("resize", updatePosition);
|
|
1283
3159
|
}, [currentView, dragOffset, position, positionMode, visible]);
|
|
1284
|
-
(0,
|
|
3160
|
+
(0, import_react5.useEffect)(() => {
|
|
1285
3161
|
if (!visible || positionMode !== "dynamic") return;
|
|
1286
3162
|
const handlePointerMove = (event) => {
|
|
1287
3163
|
if (!isDragging || !dragStartRef.current) return;
|
|
@@ -1308,7 +3184,7 @@ function ContextMenu({
|
|
|
1308
3184
|
};
|
|
1309
3185
|
}
|
|
1310
3186
|
}, [isDragging, positionMode, visible]);
|
|
1311
|
-
const handleDragStart = (0,
|
|
3187
|
+
const handleDragStart = (0, import_react5.useCallback)(
|
|
1312
3188
|
(event) => {
|
|
1313
3189
|
if (positionMode !== "dynamic") return;
|
|
1314
3190
|
event.preventDefault();
|
|
@@ -1317,7 +3193,8 @@ function ContextMenu({
|
|
|
1317
3193
|
},
|
|
1318
3194
|
[positionMode]
|
|
1319
3195
|
);
|
|
1320
|
-
(0,
|
|
3196
|
+
const [initialChatInput, setInitialChatInput] = (0, import_react5.useState)("");
|
|
3197
|
+
(0, import_react5.useEffect)(() => {
|
|
1321
3198
|
const handleKeyDown = (e) => {
|
|
1322
3199
|
if (e.key === "Escape") {
|
|
1323
3200
|
if (currentView === "screenshot-preview") {
|
|
@@ -1326,19 +3203,38 @@ function ContextMenu({
|
|
|
1326
3203
|
setCurrentView("menu");
|
|
1327
3204
|
setSelectedType(null);
|
|
1328
3205
|
setPendingComment(void 0);
|
|
3206
|
+
} else if (currentView === "quick-chat") {
|
|
3207
|
+
if (!isQuickChatPinned) {
|
|
3208
|
+
setCurrentView("menu");
|
|
3209
|
+
}
|
|
1329
3210
|
} else if (submenuStack.length > 0) {
|
|
1330
3211
|
setSubmenuStack((prev) => prev.slice(0, -1));
|
|
1331
3212
|
} else {
|
|
1332
3213
|
onClose();
|
|
1333
3214
|
}
|
|
3215
|
+
return;
|
|
3216
|
+
}
|
|
3217
|
+
if (quickChatConfig && currentView === "menu" && !isQuickChatPinned && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
3218
|
+
if (e.key.length === 1 && e.key.match(/[a-zA-Z0-9\s.,!?'"]/)) {
|
|
3219
|
+
e.preventDefault();
|
|
3220
|
+
setInitialChatInput(e.key);
|
|
3221
|
+
setCurrentView("quick-chat");
|
|
3222
|
+
}
|
|
1334
3223
|
}
|
|
1335
3224
|
};
|
|
1336
3225
|
if (visible) {
|
|
1337
3226
|
document.addEventListener("keydown", handleKeyDown);
|
|
1338
3227
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
1339
3228
|
}
|
|
1340
|
-
}, [
|
|
1341
|
-
|
|
3229
|
+
}, [
|
|
3230
|
+
currentView,
|
|
3231
|
+
isQuickChatPinned,
|
|
3232
|
+
onClose,
|
|
3233
|
+
quickChatConfig,
|
|
3234
|
+
submenuStack.length,
|
|
3235
|
+
visible
|
|
3236
|
+
]);
|
|
3237
|
+
(0, import_react5.useEffect)(() => {
|
|
1342
3238
|
const menuElement = menuRef.current;
|
|
1343
3239
|
if (!visible || !menuElement) return;
|
|
1344
3240
|
const preventTouchDefault = (e) => {
|
|
@@ -1355,9 +3251,6 @@ function ContextMenu({
|
|
|
1355
3251
|
menuElement.removeEventListener("touchmove", preventTouchDefault);
|
|
1356
3252
|
};
|
|
1357
3253
|
}, [visible]);
|
|
1358
|
-
if (!visible || !targetElement) {
|
|
1359
|
-
return null;
|
|
1360
|
-
}
|
|
1361
3254
|
const handleItemClick = (item) => {
|
|
1362
3255
|
if (item.status === "comingSoon") {
|
|
1363
3256
|
return;
|
|
@@ -1426,100 +3319,181 @@ function ContextMenu({
|
|
|
1426
3319
|
const handleRetakeScreenshots = () => {
|
|
1427
3320
|
captureScreenshots();
|
|
1428
3321
|
};
|
|
1429
|
-
const
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
{
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
3322
|
+
const handleQuickChatToggle = () => {
|
|
3323
|
+
if (currentView === "quick-chat" && !isQuickChatPinned) {
|
|
3324
|
+
setCurrentView("menu");
|
|
3325
|
+
} else {
|
|
3326
|
+
setCurrentView("quick-chat");
|
|
3327
|
+
}
|
|
3328
|
+
};
|
|
3329
|
+
const handleQuickChatPin = (pinned) => {
|
|
3330
|
+
setIsQuickChatPinned(pinned);
|
|
3331
|
+
try {
|
|
3332
|
+
if (pinned) {
|
|
3333
|
+
sessionStorage.setItem("anyclick-quick-chat-pinned", "true");
|
|
3334
|
+
} else {
|
|
3335
|
+
sessionStorage.removeItem("anyclick-quick-chat-pinned");
|
|
3336
|
+
}
|
|
3337
|
+
} catch {
|
|
3338
|
+
}
|
|
3339
|
+
if (pinned) {
|
|
3340
|
+
setCurrentView("menu");
|
|
3341
|
+
}
|
|
3342
|
+
};
|
|
3343
|
+
const handleQuickChatClose = () => {
|
|
3344
|
+
setIsQuickChatPinned(false);
|
|
3345
|
+
try {
|
|
3346
|
+
sessionStorage.removeItem("anyclick-quick-chat-pinned");
|
|
3347
|
+
} catch {
|
|
3348
|
+
}
|
|
3349
|
+
setCurrentView("menu");
|
|
3350
|
+
};
|
|
3351
|
+
const containerWidth = currentView === "screenshot-preview" ? 360 : currentView === "quick-chat" && !isQuickChatPinned ? 320 : void 0;
|
|
3352
|
+
const showPinnedDrawer = isQuickChatPinned && quickChatConfig;
|
|
3353
|
+
const showMenu = visible && targetElement;
|
|
3354
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
3355
|
+
showPinnedDrawer && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3356
|
+
QuickChat,
|
|
3357
|
+
{
|
|
3358
|
+
visible: true,
|
|
3359
|
+
targetElement,
|
|
3360
|
+
containerElement,
|
|
3361
|
+
onClose: handleQuickChatClose,
|
|
3362
|
+
onPin: handleQuickChatPin,
|
|
3363
|
+
isPinned: true,
|
|
3364
|
+
config: quickChatConfig
|
|
3365
|
+
}
|
|
3366
|
+
),
|
|
3367
|
+
showMenu && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3368
|
+
"div",
|
|
3369
|
+
{
|
|
3370
|
+
ref: menuRef,
|
|
3371
|
+
"aria-label": "Feedback options",
|
|
3372
|
+
className,
|
|
3373
|
+
role: "menu",
|
|
3374
|
+
style: {
|
|
3375
|
+
...menuStyles.container,
|
|
3376
|
+
left: adjustedPosition.x,
|
|
3377
|
+
top: adjustedPosition.y,
|
|
3378
|
+
...containerWidth ? { minWidth: containerWidth, width: containerWidth } : {},
|
|
3379
|
+
touchAction: "none",
|
|
3380
|
+
userSelect: "none",
|
|
3381
|
+
WebkitTouchCallout: "none",
|
|
3382
|
+
WebkitUserSelect: "none",
|
|
3383
|
+
...isDragging ? { cursor: "grabbing" } : {},
|
|
3384
|
+
...style
|
|
3385
|
+
},
|
|
3386
|
+
children: [
|
|
3387
|
+
!header && currentView !== "screenshot-preview" && currentView !== "quick-chat" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(DefaultHeader, { styles: menuStyles.header, title: "Send Feedback", children: [
|
|
3388
|
+
positionMode === "dynamic" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3389
|
+
"div",
|
|
3390
|
+
{
|
|
3391
|
+
"data-drag-handle": true,
|
|
3392
|
+
onMouseEnter: (e) => {
|
|
3393
|
+
e.currentTarget.style.opacity = "1";
|
|
3394
|
+
},
|
|
3395
|
+
onMouseLeave: (e) => {
|
|
3396
|
+
e.currentTarget.style.opacity = "0.5";
|
|
3397
|
+
},
|
|
3398
|
+
onPointerDown: handleDragStart,
|
|
3399
|
+
style: {
|
|
3400
|
+
...menuStyles.dragHandle,
|
|
3401
|
+
cursor: isDragging ? "grabbing" : "grab"
|
|
3402
|
+
},
|
|
3403
|
+
title: "Drag to move",
|
|
3404
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.GripVertical, { className: "w-4 h-4" })
|
|
3405
|
+
}
|
|
3406
|
+
),
|
|
3407
|
+
showPreview && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: menuStyles.screenshotIndicator, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.CameraIcon, { className: "w-3 h-3" }) }),
|
|
3408
|
+
quickChatConfig && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3409
|
+
"button",
|
|
3410
|
+
{
|
|
3411
|
+
type: "button",
|
|
3412
|
+
onClick: handleQuickChatToggle,
|
|
3413
|
+
style: {
|
|
3414
|
+
display: "flex",
|
|
3415
|
+
alignItems: "center",
|
|
3416
|
+
justifyContent: "center",
|
|
3417
|
+
width: "24px",
|
|
3418
|
+
height: "24px",
|
|
3419
|
+
border: "none",
|
|
3420
|
+
borderRadius: "4px",
|
|
3421
|
+
backgroundColor: isQuickChatPinned ? "var(--anyclick-menu-accent, #0066cc)" : "transparent",
|
|
3422
|
+
color: isQuickChatPinned ? "#fff" : "var(--anyclick-menu-accent, #0066cc)",
|
|
3423
|
+
cursor: "pointer",
|
|
3424
|
+
transition: "all 0.15s ease"
|
|
3425
|
+
},
|
|
3426
|
+
title: isQuickChatPinned ? "Quick Chat (pinned)" : "Quick Ask AI",
|
|
3427
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.Sparkles, { className: "w-3.5 h-3.5" })
|
|
3428
|
+
}
|
|
3429
|
+
)
|
|
3430
|
+
] }),
|
|
3431
|
+
!!header && header,
|
|
3432
|
+
currentView === "menu" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: menuStyles.itemList, children: [
|
|
3433
|
+
submenuStack.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BackButton, { onClick: handleBack }),
|
|
3434
|
+
currentItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3435
|
+
MenuItem,
|
|
3436
|
+
{
|
|
3437
|
+
disabled: isSubmitting,
|
|
3438
|
+
hasChildren: item.children && item.children.length > 0,
|
|
3439
|
+
item,
|
|
3440
|
+
onClick: () => handleItemClick(item)
|
|
1466
3441
|
},
|
|
1467
|
-
|
|
1468
|
-
|
|
3442
|
+
item.type
|
|
3443
|
+
))
|
|
3444
|
+
] }),
|
|
3445
|
+
currentView === "comment" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3446
|
+
CommentForm,
|
|
3447
|
+
{
|
|
3448
|
+
isSubmitting,
|
|
3449
|
+
onCancel: handleCommentCancel,
|
|
3450
|
+
onSubmit: handleCommentSubmit
|
|
1469
3451
|
}
|
|
1470
|
-
)
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
currentView === "menu" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: menuStyles.itemList, children: [
|
|
1474
|
-
submenuStack.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(BackButton, { onClick: handleBack }),
|
|
1475
|
-
currentItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1476
|
-
MenuItem,
|
|
3452
|
+
),
|
|
3453
|
+
currentView === "screenshot-preview" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3454
|
+
ScreenshotPreview,
|
|
1477
3455
|
{
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
)
|
|
1505
|
-
]
|
|
1506
|
-
}
|
|
1507
|
-
);
|
|
3456
|
+
isLoading: isCapturing,
|
|
3457
|
+
isSubmitting,
|
|
3458
|
+
onCancel: handleScreenshotCancel,
|
|
3459
|
+
onConfirm: handleScreenshotConfirm,
|
|
3460
|
+
onRetake: handleRetakeScreenshots,
|
|
3461
|
+
screenshots
|
|
3462
|
+
}
|
|
3463
|
+
),
|
|
3464
|
+
currentView === "quick-chat" && quickChatConfig && !isQuickChatPinned && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3465
|
+
QuickChat,
|
|
3466
|
+
{
|
|
3467
|
+
visible: true,
|
|
3468
|
+
targetElement,
|
|
3469
|
+
containerElement,
|
|
3470
|
+
onClose: handleQuickChatClose,
|
|
3471
|
+
onPin: handleQuickChatPin,
|
|
3472
|
+
isPinned: false,
|
|
3473
|
+
config: quickChatConfig,
|
|
3474
|
+
initialInput: initialChatInput,
|
|
3475
|
+
onInitialInputConsumed: () => setInitialChatInput("")
|
|
3476
|
+
}
|
|
3477
|
+
)
|
|
3478
|
+
]
|
|
3479
|
+
}
|
|
3480
|
+
)
|
|
3481
|
+
] });
|
|
1508
3482
|
}
|
|
1509
3483
|
|
|
1510
3484
|
// src/context.ts
|
|
1511
|
-
var
|
|
1512
|
-
var AnyclickContext = (0,
|
|
3485
|
+
var import_react6 = require("react");
|
|
3486
|
+
var AnyclickContext = (0, import_react6.createContext)(null);
|
|
1513
3487
|
var FeedbackContext = AnyclickContext;
|
|
1514
3488
|
function useAnyclick() {
|
|
1515
|
-
const context = (0,
|
|
3489
|
+
const context = (0, import_react6.useContext)(AnyclickContext);
|
|
1516
3490
|
if (!context) {
|
|
1517
3491
|
throw new Error("useAnyclick must be used within an AnyclickProvider");
|
|
1518
3492
|
}
|
|
1519
3493
|
return context;
|
|
1520
3494
|
}
|
|
1521
3495
|
function useFeedback() {
|
|
1522
|
-
const context = (0,
|
|
3496
|
+
const context = (0, import_react6.useContext)(AnyclickContext);
|
|
1523
3497
|
if (!context) {
|
|
1524
3498
|
throw new Error("useFeedback must be used within a FeedbackProvider");
|
|
1525
3499
|
}
|
|
@@ -1527,12 +3501,12 @@ function useFeedback() {
|
|
|
1527
3501
|
}
|
|
1528
3502
|
|
|
1529
3503
|
// src/store.ts
|
|
1530
|
-
var
|
|
3504
|
+
var import_zustand2 = require("zustand");
|
|
1531
3505
|
var providerIdCounter = 0;
|
|
1532
3506
|
function generateProviderId() {
|
|
1533
3507
|
return `anyclick-provider-${++providerIdCounter}`;
|
|
1534
3508
|
}
|
|
1535
|
-
var useProviderStore = (0,
|
|
3509
|
+
var useProviderStore = (0, import_zustand2.create)((set, get) => ({
|
|
1536
3510
|
providers: /* @__PURE__ */ new Map(),
|
|
1537
3511
|
findProvidersForElement: (element) => {
|
|
1538
3512
|
const { providers } = get();
|
|
@@ -1688,7 +3662,7 @@ function dispatchContextMenuEvent(event, element) {
|
|
|
1688
3662
|
}
|
|
1689
3663
|
|
|
1690
3664
|
// src/AnyclickProvider.tsx
|
|
1691
|
-
var
|
|
3665
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1692
3666
|
var defaultMenuItems = [
|
|
1693
3667
|
{ label: "Report an issue", showComment: true, type: "issue" },
|
|
1694
3668
|
{ label: "Request a feature", showComment: true, type: "feature" },
|
|
@@ -1711,6 +3685,7 @@ function AnyclickProvider({
|
|
|
1711
3685
|
metadata,
|
|
1712
3686
|
onSubmitError,
|
|
1713
3687
|
onSubmitSuccess,
|
|
3688
|
+
quickChatConfig,
|
|
1714
3689
|
scoped = false,
|
|
1715
3690
|
screenshotConfig,
|
|
1716
3691
|
stripAttributes,
|
|
@@ -1719,18 +3694,18 @@ function AnyclickProvider({
|
|
|
1719
3694
|
touchHoldDurationMs,
|
|
1720
3695
|
touchMoveThreshold
|
|
1721
3696
|
}) {
|
|
1722
|
-
const [isSubmitting, setIsSubmitting] = (0,
|
|
1723
|
-
const [menuVisible, setMenuVisible] = (0,
|
|
1724
|
-
const [menuPosition, setMenuPosition] = (0,
|
|
1725
|
-
const [targetElement, setTargetElement] = (0,
|
|
1726
|
-
const [containerElement, setContainerElement] = (0,
|
|
3697
|
+
const [isSubmitting, setIsSubmitting] = (0, import_react7.useState)(false);
|
|
3698
|
+
const [menuVisible, setMenuVisible] = (0, import_react7.useState)(false);
|
|
3699
|
+
const [menuPosition, setMenuPosition] = (0, import_react7.useState)(OFFSCREEN_POSITION2);
|
|
3700
|
+
const [targetElement, setTargetElement] = (0, import_react7.useState)(null);
|
|
3701
|
+
const [containerElement, setContainerElement] = (0, import_react7.useState)(
|
|
1727
3702
|
null
|
|
1728
3703
|
);
|
|
1729
|
-
const providerId = (0,
|
|
1730
|
-
const containerRef = (0,
|
|
1731
|
-
const [containerReady, setContainerReady] = (0,
|
|
1732
|
-
const clientRef = (0,
|
|
1733
|
-
const setContainerRef = (0,
|
|
3704
|
+
const providerId = (0, import_react7.useId)();
|
|
3705
|
+
const containerRef = (0, import_react7.useRef)(null);
|
|
3706
|
+
const [containerReady, setContainerReady] = (0, import_react7.useState)(!scoped);
|
|
3707
|
+
const clientRef = (0, import_react7.useRef)(null);
|
|
3708
|
+
const setContainerRef = (0, import_react7.useCallback)(
|
|
1734
3709
|
(node) => {
|
|
1735
3710
|
containerRef.current = node;
|
|
1736
3711
|
if (scoped && node) {
|
|
@@ -1759,7 +3734,7 @@ function AnyclickProvider({
|
|
|
1759
3734
|
updateProvider
|
|
1760
3735
|
} = useProviderStore();
|
|
1761
3736
|
const parentId = parentContext?.providerId ?? null;
|
|
1762
|
-
const actualDepth = (0,
|
|
3737
|
+
const actualDepth = (0, import_react7.useMemo)(() => {
|
|
1763
3738
|
if (!parentContext) return 0;
|
|
1764
3739
|
let d = 0;
|
|
1765
3740
|
let currentId = parentId;
|
|
@@ -1773,7 +3748,7 @@ function AnyclickProvider({
|
|
|
1773
3748
|
}, [parentContext, parentId]);
|
|
1774
3749
|
const isDisabledByTheme = theme === null || theme?.disabled === true;
|
|
1775
3750
|
const effectiveDisabled = disabled || isDisabledByTheme;
|
|
1776
|
-
const localTheme = (0,
|
|
3751
|
+
const localTheme = (0, import_react7.useMemo)(() => {
|
|
1777
3752
|
if (theme === null) {
|
|
1778
3753
|
return { disabled: true };
|
|
1779
3754
|
}
|
|
@@ -1788,7 +3763,7 @@ function AnyclickProvider({
|
|
|
1788
3763
|
...theme
|
|
1789
3764
|
};
|
|
1790
3765
|
}, [highlightConfig, menuClassName, menuStyle, screenshotConfig, theme]);
|
|
1791
|
-
const handleContextMenu = (0,
|
|
3766
|
+
const handleContextMenu = (0, import_react7.useCallback)(
|
|
1792
3767
|
(event, element) => {
|
|
1793
3768
|
if (!scoped && isElementInDisabledScope(element)) {
|
|
1794
3769
|
return false;
|
|
@@ -1816,7 +3791,7 @@ function AnyclickProvider({
|
|
|
1816
3791
|
scoped
|
|
1817
3792
|
]
|
|
1818
3793
|
);
|
|
1819
|
-
(0,
|
|
3794
|
+
(0, import_react7.useLayoutEffect)(() => {
|
|
1820
3795
|
const providerInstance = {
|
|
1821
3796
|
containerRef,
|
|
1822
3797
|
depth: actualDepth,
|
|
@@ -1842,7 +3817,7 @@ function AnyclickProvider({
|
|
|
1842
3817
|
scoped,
|
|
1843
3818
|
unregisterProvider
|
|
1844
3819
|
]);
|
|
1845
|
-
(0,
|
|
3820
|
+
(0, import_react7.useEffect)(() => {
|
|
1846
3821
|
updateProvider(providerId, {
|
|
1847
3822
|
disabled: effectiveDisabled,
|
|
1848
3823
|
onContextMenu: handleContextMenu,
|
|
@@ -1855,14 +3830,14 @@ function AnyclickProvider({
|
|
|
1855
3830
|
providerId,
|
|
1856
3831
|
updateProvider
|
|
1857
3832
|
]);
|
|
1858
|
-
(0,
|
|
3833
|
+
(0, import_react7.useEffect)(() => {
|
|
1859
3834
|
if (isDisabledByAncestor(providerId)) {
|
|
1860
3835
|
return;
|
|
1861
3836
|
}
|
|
1862
3837
|
if (scoped && !containerReady) {
|
|
1863
3838
|
return;
|
|
1864
3839
|
}
|
|
1865
|
-
const client = (0,
|
|
3840
|
+
const client = (0, import_anyclick_core5.createAnyclickClient)({
|
|
1866
3841
|
adapter,
|
|
1867
3842
|
container: scoped ? containerRef.current : null,
|
|
1868
3843
|
cooldownMs,
|
|
@@ -1903,7 +3878,7 @@ function AnyclickProvider({
|
|
|
1903
3878
|
touchHoldDurationMs,
|
|
1904
3879
|
touchMoveThreshold
|
|
1905
3880
|
]);
|
|
1906
|
-
const submitAnyclick = (0,
|
|
3881
|
+
const submitAnyclick = (0, import_react7.useCallback)(
|
|
1907
3882
|
async (element, type, comment, screenshots) => {
|
|
1908
3883
|
const client = clientRef.current;
|
|
1909
3884
|
if (!client) return;
|
|
@@ -1924,7 +3899,7 @@ function AnyclickProvider({
|
|
|
1924
3899
|
},
|
|
1925
3900
|
[metadata]
|
|
1926
3901
|
);
|
|
1927
|
-
const openMenu = (0,
|
|
3902
|
+
const openMenu = (0, import_react7.useCallback)(
|
|
1928
3903
|
(element, position) => {
|
|
1929
3904
|
setTargetElement(element);
|
|
1930
3905
|
const mergedTheme2 = getMergedTheme(providerId);
|
|
@@ -1938,13 +3913,13 @@ function AnyclickProvider({
|
|
|
1938
3913
|
},
|
|
1939
3914
|
[getMergedTheme, highlightConfig, providerId]
|
|
1940
3915
|
);
|
|
1941
|
-
const closeMenu = (0,
|
|
3916
|
+
const closeMenu = (0, import_react7.useCallback)(() => {
|
|
1942
3917
|
setMenuVisible(false);
|
|
1943
3918
|
setMenuPosition(OFFSCREEN_POSITION2);
|
|
1944
3919
|
setTargetElement(null);
|
|
1945
3920
|
setContainerElement(null);
|
|
1946
3921
|
}, []);
|
|
1947
|
-
const handleMenuSelect = (0,
|
|
3922
|
+
const handleMenuSelect = (0, import_react7.useCallback)(
|
|
1948
3923
|
(type, comment, screenshots) => {
|
|
1949
3924
|
if (targetElement) {
|
|
1950
3925
|
submitAnyclick(targetElement, type, comment, screenshots);
|
|
@@ -1953,7 +3928,7 @@ function AnyclickProvider({
|
|
|
1953
3928
|
[submitAnyclick, targetElement]
|
|
1954
3929
|
);
|
|
1955
3930
|
const inheritedTheme = getMergedTheme(providerId);
|
|
1956
|
-
const mergedTheme = (0,
|
|
3931
|
+
const mergedTheme = (0, import_react7.useMemo)(
|
|
1957
3932
|
() => ({
|
|
1958
3933
|
...inheritedTheme,
|
|
1959
3934
|
...localTheme,
|
|
@@ -1976,7 +3951,7 @@ function AnyclickProvider({
|
|
|
1976
3951
|
const effectiveMenuClassName = mergedTheme.menuClassName ?? menuClassName;
|
|
1977
3952
|
const effectiveHighlightConfig = mergedTheme.highlightConfig ?? highlightConfig;
|
|
1978
3953
|
const effectiveScreenshotConfig = mergedTheme.screenshotConfig ?? screenshotConfig;
|
|
1979
|
-
const contextValue = (0,
|
|
3954
|
+
const contextValue = (0, import_react7.useMemo)(
|
|
1980
3955
|
() => ({
|
|
1981
3956
|
closeMenu,
|
|
1982
3957
|
isEnabled: !effectiveDisabled && !isDisabledByAncestor(providerId),
|
|
@@ -1999,7 +3974,7 @@ function AnyclickProvider({
|
|
|
1999
3974
|
submitAnyclick
|
|
2000
3975
|
]
|
|
2001
3976
|
);
|
|
2002
|
-
const content = scoped ? /* @__PURE__ */ (0,
|
|
3977
|
+
const content = scoped ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2003
3978
|
"div",
|
|
2004
3979
|
{
|
|
2005
3980
|
ref: setContainerRef,
|
|
@@ -2008,9 +3983,9 @@ function AnyclickProvider({
|
|
|
2008
3983
|
children
|
|
2009
3984
|
}
|
|
2010
3985
|
) : children;
|
|
2011
|
-
return /* @__PURE__ */ (0,
|
|
3986
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AnyclickContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { "data-anyclick-root": true, children: [
|
|
2012
3987
|
content,
|
|
2013
|
-
/* @__PURE__ */ (0,
|
|
3988
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2014
3989
|
ContextMenu,
|
|
2015
3990
|
{
|
|
2016
3991
|
className: effectiveMenuClassName,
|
|
@@ -2022,18 +3997,19 @@ function AnyclickProvider({
|
|
|
2022
3997
|
onClose: closeMenu,
|
|
2023
3998
|
onSelect: handleMenuSelect,
|
|
2024
3999
|
position: menuPosition,
|
|
4000
|
+
quickChatConfig,
|
|
2025
4001
|
screenshotConfig: effectiveScreenshotConfig,
|
|
2026
4002
|
style: effectiveMenuStyle,
|
|
2027
4003
|
targetElement,
|
|
2028
4004
|
visible: menuVisible && !effectiveDisabled
|
|
2029
4005
|
}
|
|
2030
4006
|
)
|
|
2031
|
-
] });
|
|
4007
|
+
] }) });
|
|
2032
4008
|
}
|
|
2033
4009
|
var FeedbackProvider = AnyclickProvider;
|
|
2034
4010
|
|
|
2035
4011
|
// src/FunModeBridge.tsx
|
|
2036
|
-
var
|
|
4012
|
+
var import_react8 = require("react");
|
|
2037
4013
|
var import_anyclick_pointer = require("@ewjdev/anyclick-pointer");
|
|
2038
4014
|
function isFunModeEnabled(theme) {
|
|
2039
4015
|
if (!theme) return false;
|
|
@@ -2080,9 +4056,9 @@ function buildFunConfig(theme, container) {
|
|
|
2080
4056
|
function FunModeBridge() {
|
|
2081
4057
|
const { setConfig } = (0, import_anyclick_pointer.usePointer)();
|
|
2082
4058
|
const providerStore = useProviderStore();
|
|
2083
|
-
const activeProviderRef = (0,
|
|
2084
|
-
const cachedConfigs = (0,
|
|
2085
|
-
const findActiveFunProvider = (0,
|
|
4059
|
+
const activeProviderRef = (0, import_react8.useRef)(null);
|
|
4060
|
+
const cachedConfigs = (0, import_react8.useRef)({});
|
|
4061
|
+
const findActiveFunProvider = (0, import_react8.useMemo)(() => {
|
|
2086
4062
|
return (el) => {
|
|
2087
4063
|
if (!el) return null;
|
|
2088
4064
|
const providers = providerStore.findProvidersForElement(el);
|
|
@@ -2094,7 +4070,7 @@ function FunModeBridge() {
|
|
|
2094
4070
|
return null;
|
|
2095
4071
|
};
|
|
2096
4072
|
}, [providerStore]);
|
|
2097
|
-
(0,
|
|
4073
|
+
(0, import_react8.useEffect)(() => {
|
|
2098
4074
|
const handleMove = (event) => {
|
|
2099
4075
|
const el = document.elementFromPoint(event.clientX, event.clientY);
|
|
2100
4076
|
const provider = findActiveFunProvider(el);
|
|
@@ -2128,13 +4104,73 @@ function FunModeBridge() {
|
|
|
2128
4104
|
return null;
|
|
2129
4105
|
}
|
|
2130
4106
|
|
|
4107
|
+
// src/ui/button.tsx
|
|
4108
|
+
var import_react9 = require("react");
|
|
4109
|
+
|
|
4110
|
+
// src/utils/cn.ts
|
|
4111
|
+
function cn(...classes) {
|
|
4112
|
+
return classes.filter(Boolean).join(" ");
|
|
4113
|
+
}
|
|
4114
|
+
|
|
4115
|
+
// src/ui/button.tsx
|
|
4116
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
4117
|
+
var variantClasses = {
|
|
4118
|
+
default: "ac-bg-accent ac-text-accent-foreground hover:ac-bg-accent-muted ac-border ac-border-border",
|
|
4119
|
+
ghost: "ac-bg-transparent hover:ac-bg-surface-muted ac-text-text",
|
|
4120
|
+
outline: "ac-bg-transparent ac-text-text ac-border ac-border-border hover:ac-bg-surface-muted",
|
|
4121
|
+
destructive: "ac-bg-destructive ac-text-accent-foreground hover:ac-bg-destructive/80"
|
|
4122
|
+
};
|
|
4123
|
+
var sizeClasses = {
|
|
4124
|
+
sm: "ac-h-8 ac-px-3 ac-text-sm",
|
|
4125
|
+
md: "ac-h-10 ac-px-4 ac-text-sm",
|
|
4126
|
+
lg: "ac-h-11 ac-px-5 ac-text-base"
|
|
4127
|
+
};
|
|
4128
|
+
var Button = (0, import_react9.forwardRef)(
|
|
4129
|
+
({ className, variant = "default", size = "md", ...props }, ref) => {
|
|
4130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
4131
|
+
"button",
|
|
4132
|
+
{
|
|
4133
|
+
ref,
|
|
4134
|
+
className: cn(
|
|
4135
|
+
"ac-inline-flex ac-items-center ac-justify-center ac-gap-2 ac-rounded-md ac-font-medium ac-transition-colors focus-visible:ac-outline focus-visible:ac-outline-2 focus-visible:ac-outline-offset-2 focus-visible:ac-outline-accent disabled:ac-opacity-50 disabled:ac-cursor-not-allowed",
|
|
4136
|
+
variantClasses[variant],
|
|
4137
|
+
sizeClasses[size],
|
|
4138
|
+
className
|
|
4139
|
+
),
|
|
4140
|
+
...props
|
|
4141
|
+
}
|
|
4142
|
+
);
|
|
4143
|
+
}
|
|
4144
|
+
);
|
|
4145
|
+
Button.displayName = "Button";
|
|
4146
|
+
|
|
4147
|
+
// src/ui/input.tsx
|
|
4148
|
+
var import_react10 = require("react");
|
|
4149
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
4150
|
+
var Input = (0, import_react10.forwardRef)(
|
|
4151
|
+
({ className, ...props }, ref) => {
|
|
4152
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4153
|
+
"input",
|
|
4154
|
+
{
|
|
4155
|
+
ref,
|
|
4156
|
+
className: cn(
|
|
4157
|
+
"ac-h-10 ac-w-full ac-rounded-md ac-border ac-border-border ac-bg-surface ac-text-text ac-placeholder-text-muted ac-px-3 ac-py-2 ac-text-sm focus-visible:ac-outline focus-visible:ac-outline-2 focus-visible:ac-outline-offset-2 focus-visible:ac-outline-accent disabled:ac-opacity-50 disabled:ac-cursor-not-allowed",
|
|
4158
|
+
className
|
|
4159
|
+
),
|
|
4160
|
+
...props
|
|
4161
|
+
}
|
|
4162
|
+
);
|
|
4163
|
+
}
|
|
4164
|
+
);
|
|
4165
|
+
Input.displayName = "Input";
|
|
4166
|
+
|
|
2131
4167
|
// src/InspectDialog/InspectDialogManager.tsx
|
|
2132
|
-
var
|
|
4168
|
+
var import_react12 = require("react");
|
|
2133
4169
|
|
|
2134
4170
|
// src/InspectDialog/InspectSimple.tsx
|
|
2135
|
-
var
|
|
2136
|
-
var
|
|
2137
|
-
var
|
|
4171
|
+
var import_react11 = require("react");
|
|
4172
|
+
var import_anyclick_core6 = require("@ewjdev/anyclick-core");
|
|
4173
|
+
var import_lucide_react4 = require("lucide-react");
|
|
2138
4174
|
|
|
2139
4175
|
// src/ide.ts
|
|
2140
4176
|
var DEFAULT_IDE_CONFIG = {
|
|
@@ -2236,7 +4272,7 @@ function formatSourceLocation(location) {
|
|
|
2236
4272
|
}
|
|
2237
4273
|
|
|
2238
4274
|
// src/InspectDialog/InspectSimple.tsx
|
|
2239
|
-
var
|
|
4275
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2240
4276
|
var DEFAULT_COMPACT_CONFIG = {
|
|
2241
4277
|
scale: 0.5,
|
|
2242
4278
|
fonts: {
|
|
@@ -2298,8 +4334,8 @@ function downloadDataUrl(dataUrl, filename) {
|
|
|
2298
4334
|
link.click();
|
|
2299
4335
|
}
|
|
2300
4336
|
function useIsMobile() {
|
|
2301
|
-
const [isMobile, setIsMobile] = (0,
|
|
2302
|
-
(0,
|
|
4337
|
+
const [isMobile, setIsMobile] = (0, import_react11.useState)(false);
|
|
4338
|
+
(0, import_react11.useEffect)(() => {
|
|
2303
4339
|
const mq = window.matchMedia("(max-width: 640px)");
|
|
2304
4340
|
setIsMobile(mq.matches);
|
|
2305
4341
|
const handler = (e) => setIsMobile(e.matches);
|
|
@@ -2317,20 +4353,20 @@ function InspectSimple({
|
|
|
2317
4353
|
className,
|
|
2318
4354
|
highlightColors
|
|
2319
4355
|
}) {
|
|
2320
|
-
const [info, setInfo] = (0,
|
|
2321
|
-
const [sourceLocation, setSourceLocation] = (0,
|
|
4356
|
+
const [info, setInfo] = (0, import_react11.useState)(null);
|
|
4357
|
+
const [sourceLocation, setSourceLocation] = (0, import_react11.useState)(
|
|
2322
4358
|
null
|
|
2323
4359
|
);
|
|
2324
|
-
const [status, setStatus] = (0,
|
|
2325
|
-
const [saving, setSaving] = (0,
|
|
2326
|
-
const dialogRef = (0,
|
|
4360
|
+
const [status, setStatus] = (0, import_react11.useState)(null);
|
|
4361
|
+
const [saving, setSaving] = (0, import_react11.useState)(false);
|
|
4362
|
+
const dialogRef = (0, import_react11.useRef)(null);
|
|
2327
4363
|
const isMobile = useIsMobile();
|
|
2328
|
-
(0,
|
|
4364
|
+
(0, import_react11.useEffect)(() => {
|
|
2329
4365
|
if (!status) return;
|
|
2330
4366
|
const timer = setTimeout(() => setStatus(null), 5e3);
|
|
2331
4367
|
return () => clearTimeout(timer);
|
|
2332
4368
|
}, [status]);
|
|
2333
|
-
(0,
|
|
4369
|
+
(0, import_react11.useEffect)(() => {
|
|
2334
4370
|
if (!visible || !targetElement) return;
|
|
2335
4371
|
try {
|
|
2336
4372
|
clearHighlights();
|
|
@@ -2339,7 +4375,7 @@ function InspectSimple({
|
|
|
2339
4375
|
if (container) highlightContainer(container, highlightColors);
|
|
2340
4376
|
} catch {
|
|
2341
4377
|
}
|
|
2342
|
-
const nextInfo = (0,
|
|
4378
|
+
const nextInfo = (0, import_anyclick_core6.getElementInspectInfo)(targetElement);
|
|
2343
4379
|
setInfo(nextInfo);
|
|
2344
4380
|
setSourceLocation(
|
|
2345
4381
|
findSourceLocationInAncestors(targetElement) ?? nextInfo.sourceLocation ?? null
|
|
@@ -2348,7 +4384,7 @@ function InspectSimple({
|
|
|
2348
4384
|
clearHighlights();
|
|
2349
4385
|
};
|
|
2350
4386
|
}, [visible, targetElement, highlightColors]);
|
|
2351
|
-
(0,
|
|
4387
|
+
(0, import_react11.useEffect)(() => {
|
|
2352
4388
|
if (!visible) return;
|
|
2353
4389
|
const handleClickOutside = (e) => {
|
|
2354
4390
|
if (dialogRef.current && !dialogRef.current.contains(e.target)) {
|
|
@@ -2363,7 +4399,7 @@ function InspectSimple({
|
|
|
2363
4399
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
2364
4400
|
};
|
|
2365
4401
|
}, [visible, onClose]);
|
|
2366
|
-
const identityLabel = (0,
|
|
4402
|
+
const identityLabel = (0, import_react11.useMemo)(() => {
|
|
2367
4403
|
if (!info) return "Select an element";
|
|
2368
4404
|
const classes = info.classNames[0] ? `.${info.classNames[0]}` : "";
|
|
2369
4405
|
const id = info.id ? `#${info.id}` : "";
|
|
@@ -2393,7 +4429,7 @@ function InspectSimple({
|
|
|
2393
4429
|
if (!targetElement) return;
|
|
2394
4430
|
setSaving(true);
|
|
2395
4431
|
setStatus("Capturing screenshot\u2026");
|
|
2396
|
-
const result = await (0,
|
|
4432
|
+
const result = await (0, import_anyclick_core6.captureScreenshot)(targetElement, null, "element");
|
|
2397
4433
|
setSaving(false);
|
|
2398
4434
|
if (result.capture?.dataUrl) {
|
|
2399
4435
|
downloadDataUrl(result.capture.dataUrl, "anyclick-inspect.png");
|
|
@@ -2449,8 +4485,8 @@ function InspectSimple({
|
|
|
2449
4485
|
overflow: "hidden",
|
|
2450
4486
|
...style
|
|
2451
4487
|
};
|
|
2452
|
-
return /* @__PURE__ */ (0,
|
|
2453
|
-
/* @__PURE__ */ (0,
|
|
4488
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4489
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2454
4490
|
"div",
|
|
2455
4491
|
{
|
|
2456
4492
|
style: {
|
|
@@ -2465,14 +4501,14 @@ function InspectSimple({
|
|
|
2465
4501
|
role: "presentation"
|
|
2466
4502
|
}
|
|
2467
4503
|
),
|
|
2468
|
-
/* @__PURE__ */ (0,
|
|
4504
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2469
4505
|
"div",
|
|
2470
4506
|
{
|
|
2471
4507
|
ref: dialogRef,
|
|
2472
4508
|
className: `anyclick-tiny-inspect ${className ?? ""}`,
|
|
2473
4509
|
style: dialogStyles,
|
|
2474
4510
|
children: [
|
|
2475
|
-
/* @__PURE__ */ (0,
|
|
4511
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2476
4512
|
"div",
|
|
2477
4513
|
{
|
|
2478
4514
|
style: {
|
|
@@ -2484,7 +4520,7 @@ function InspectSimple({
|
|
|
2484
4520
|
borderBottom: "1px solid #1e293b"
|
|
2485
4521
|
},
|
|
2486
4522
|
children: [
|
|
2487
|
-
isMobile && /* @__PURE__ */ (0,
|
|
4523
|
+
isMobile && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2488
4524
|
"div",
|
|
2489
4525
|
{
|
|
2490
4526
|
style: {
|
|
@@ -2499,8 +4535,8 @@ function InspectSimple({
|
|
|
2499
4535
|
}
|
|
2500
4536
|
}
|
|
2501
4537
|
),
|
|
2502
|
-
/* @__PURE__ */ (0,
|
|
2503
|
-
/* @__PURE__ */ (0,
|
|
4538
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
4539
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2504
4540
|
"span",
|
|
2505
4541
|
{
|
|
2506
4542
|
style: {
|
|
@@ -2515,31 +4551,31 @@ function InspectSimple({
|
|
|
2515
4551
|
children: identityLabel
|
|
2516
4552
|
}
|
|
2517
4553
|
),
|
|
2518
|
-
sourceLocation && /* @__PURE__ */ (0,
|
|
4554
|
+
sourceLocation && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2519
4555
|
"button",
|
|
2520
4556
|
{
|
|
2521
4557
|
type: "button",
|
|
2522
4558
|
onClick: handleOpenIDE,
|
|
2523
4559
|
title: formatSourceLocation(sourceLocation),
|
|
2524
4560
|
style: iconBtnStyle,
|
|
2525
|
-
children: /* @__PURE__ */ (0,
|
|
4561
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.ExternalLink, { size: 14 })
|
|
2526
4562
|
}
|
|
2527
4563
|
)
|
|
2528
4564
|
] }),
|
|
2529
|
-
/* @__PURE__ */ (0,
|
|
4565
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2530
4566
|
"button",
|
|
2531
4567
|
{
|
|
2532
4568
|
type: "button",
|
|
2533
4569
|
onClick: onClose,
|
|
2534
4570
|
style: iconBtnStyle,
|
|
2535
4571
|
"aria-label": "Close inspector",
|
|
2536
|
-
children: /* @__PURE__ */ (0,
|
|
4572
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.X, { size: 16 })
|
|
2537
4573
|
}
|
|
2538
4574
|
)
|
|
2539
4575
|
]
|
|
2540
4576
|
}
|
|
2541
4577
|
),
|
|
2542
|
-
/* @__PURE__ */ (0,
|
|
4578
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2543
4579
|
"div",
|
|
2544
4580
|
{
|
|
2545
4581
|
style: {
|
|
@@ -2549,7 +4585,7 @@ function InspectSimple({
|
|
|
2549
4585
|
gap: 8
|
|
2550
4586
|
},
|
|
2551
4587
|
children: [
|
|
2552
|
-
info?.selector && /* @__PURE__ */ (0,
|
|
4588
|
+
info?.selector && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2553
4589
|
"code",
|
|
2554
4590
|
{
|
|
2555
4591
|
style: {
|
|
@@ -2564,7 +4600,7 @@ function InspectSimple({
|
|
|
2564
4600
|
children: info.selector
|
|
2565
4601
|
}
|
|
2566
4602
|
),
|
|
2567
|
-
status && /* @__PURE__ */ (0,
|
|
4603
|
+
status && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2568
4604
|
"div",
|
|
2569
4605
|
{
|
|
2570
4606
|
style: {
|
|
@@ -2576,7 +4612,7 @@ function InspectSimple({
|
|
|
2576
4612
|
children: status
|
|
2577
4613
|
}
|
|
2578
4614
|
),
|
|
2579
|
-
/* @__PURE__ */ (0,
|
|
4615
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2580
4616
|
"div",
|
|
2581
4617
|
{
|
|
2582
4618
|
style: {
|
|
@@ -2585,7 +4621,7 @@ function InspectSimple({
|
|
|
2585
4621
|
gap: 6
|
|
2586
4622
|
},
|
|
2587
4623
|
children: [
|
|
2588
|
-
/* @__PURE__ */ (0,
|
|
4624
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2589
4625
|
"button",
|
|
2590
4626
|
{
|
|
2591
4627
|
type: "button",
|
|
@@ -2593,10 +4629,10 @@ function InspectSimple({
|
|
|
2593
4629
|
style: iconActionStyle,
|
|
2594
4630
|
title: "Copy CSS selector",
|
|
2595
4631
|
"aria-label": "Copy CSS selector",
|
|
2596
|
-
children: /* @__PURE__ */ (0,
|
|
4632
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.Copy, { size: 15 })
|
|
2597
4633
|
}
|
|
2598
4634
|
),
|
|
2599
|
-
/* @__PURE__ */ (0,
|
|
4635
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2600
4636
|
"button",
|
|
2601
4637
|
{
|
|
2602
4638
|
type: "button",
|
|
@@ -2604,10 +4640,10 @@ function InspectSimple({
|
|
|
2604
4640
|
style: iconActionStyle,
|
|
2605
4641
|
title: "Copy text content",
|
|
2606
4642
|
"aria-label": "Copy text content",
|
|
2607
|
-
children: /* @__PURE__ */ (0,
|
|
4643
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.FileText, { size: 15 })
|
|
2608
4644
|
}
|
|
2609
4645
|
),
|
|
2610
|
-
/* @__PURE__ */ (0,
|
|
4646
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2611
4647
|
"button",
|
|
2612
4648
|
{
|
|
2613
4649
|
type: "button",
|
|
@@ -2615,10 +4651,10 @@ function InspectSimple({
|
|
|
2615
4651
|
style: iconActionStyle,
|
|
2616
4652
|
title: "Copy HTML markup",
|
|
2617
4653
|
"aria-label": "Copy HTML markup",
|
|
2618
|
-
children: /* @__PURE__ */ (0,
|
|
4654
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.Code, { size: 15 })
|
|
2619
4655
|
}
|
|
2620
4656
|
),
|
|
2621
|
-
/* @__PURE__ */ (0,
|
|
4657
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2622
4658
|
"button",
|
|
2623
4659
|
{
|
|
2624
4660
|
type: "button",
|
|
@@ -2630,7 +4666,7 @@ function InspectSimple({
|
|
|
2630
4666
|
disabled: saving,
|
|
2631
4667
|
title: "Save screenshot",
|
|
2632
4668
|
"aria-label": "Save screenshot",
|
|
2633
|
-
children: /* @__PURE__ */ (0,
|
|
4669
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.Camera, { size: 15 })
|
|
2634
4670
|
}
|
|
2635
4671
|
)
|
|
2636
4672
|
]
|
|
@@ -2673,7 +4709,7 @@ var iconActionStyle = {
|
|
|
2673
4709
|
};
|
|
2674
4710
|
|
|
2675
4711
|
// src/InspectDialog/InspectDialogManager.tsx
|
|
2676
|
-
var
|
|
4712
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
2677
4713
|
var INSPECT_DIALOG_EVENT = "anyclick:inspect";
|
|
2678
4714
|
function openInspectDialog(targetElement) {
|
|
2679
4715
|
if (typeof window === "undefined") return;
|
|
@@ -2696,16 +4732,16 @@ function InspectDialogManager({
|
|
|
2696
4732
|
initialPinnedPosition = "floating",
|
|
2697
4733
|
compactConfig
|
|
2698
4734
|
}) {
|
|
2699
|
-
const [visible, setVisible] = (0,
|
|
2700
|
-
const [targetElement, setTargetElement] = (0,
|
|
2701
|
-
const handleClose = (0,
|
|
4735
|
+
const [visible, setVisible] = (0, import_react12.useState)(false);
|
|
4736
|
+
const [targetElement, setTargetElement] = (0, import_react12.useState)(null);
|
|
4737
|
+
const handleClose = (0, import_react12.useCallback)(() => {
|
|
2702
4738
|
setVisible(false);
|
|
2703
4739
|
setTargetElement(null);
|
|
2704
4740
|
}, []);
|
|
2705
|
-
const handleSelectElement = (0,
|
|
4741
|
+
const handleSelectElement = (0, import_react12.useCallback)((element) => {
|
|
2706
4742
|
setTargetElement(element);
|
|
2707
4743
|
}, []);
|
|
2708
|
-
(0,
|
|
4744
|
+
(0, import_react12.useEffect)(() => {
|
|
2709
4745
|
const handleInspectEvent = (event) => {
|
|
2710
4746
|
const customEvent = event;
|
|
2711
4747
|
if (customEvent.detail?.targetElement) {
|
|
@@ -2718,7 +4754,7 @@ function InspectDialogManager({
|
|
|
2718
4754
|
window.removeEventListener(INSPECT_DIALOG_EVENT, handleInspectEvent);
|
|
2719
4755
|
};
|
|
2720
4756
|
}, []);
|
|
2721
|
-
return /* @__PURE__ */ (0,
|
|
4757
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2722
4758
|
InspectSimple,
|
|
2723
4759
|
{
|
|
2724
4760
|
visible,
|
|
@@ -2780,6 +4816,20 @@ var presetDefaults = {
|
|
|
2780
4816
|
showComment: false,
|
|
2781
4817
|
type: "search_google"
|
|
2782
4818
|
},
|
|
4819
|
+
{
|
|
4820
|
+
label: "Ask t3.chat",
|
|
4821
|
+
onClick: ({ closeMenu }) => {
|
|
4822
|
+
closeMenu();
|
|
4823
|
+
if (typeof window === "undefined") return false;
|
|
4824
|
+
const selection = window.getSelection()?.toString().trim();
|
|
4825
|
+
const query = selection && selection.length > 0 ? selection : "";
|
|
4826
|
+
const url = query ? `https://t3.chat/?q=${encodeURIComponent(query)}` : "https://t3.chat";
|
|
4827
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
4828
|
+
return false;
|
|
4829
|
+
},
|
|
4830
|
+
showComment: false,
|
|
4831
|
+
type: "ask_t3chat"
|
|
4832
|
+
},
|
|
2783
4833
|
{
|
|
2784
4834
|
label: "Share\u2026",
|
|
2785
4835
|
onClick: async ({ closeMenu }) => {
|
|
@@ -3049,6 +5099,172 @@ function listPresets() {
|
|
|
3049
5099
|
}))
|
|
3050
5100
|
}));
|
|
3051
5101
|
}
|
|
5102
|
+
function createT3ChatMenuItem(options = {}) {
|
|
5103
|
+
const { label = "Ask t3.chat", baseUrl = "https://t3.chat" } = options;
|
|
5104
|
+
return {
|
|
5105
|
+
label,
|
|
5106
|
+
onClick: ({ closeMenu }) => {
|
|
5107
|
+
closeMenu();
|
|
5108
|
+
if (typeof window === "undefined") return false;
|
|
5109
|
+
const selection = window.getSelection()?.toString().trim();
|
|
5110
|
+
const query = selection && selection.length > 0 ? selection : "";
|
|
5111
|
+
const url = query ? `${baseUrl}/?q=${encodeURIComponent(query)}` : baseUrl;
|
|
5112
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
5113
|
+
return false;
|
|
5114
|
+
},
|
|
5115
|
+
showComment: false,
|
|
5116
|
+
type: "ask_t3chat"
|
|
5117
|
+
};
|
|
5118
|
+
}
|
|
5119
|
+
function getSelectedText() {
|
|
5120
|
+
if (typeof window === "undefined") return "";
|
|
5121
|
+
return window.getSelection()?.toString().trim() ?? "";
|
|
5122
|
+
}
|
|
5123
|
+
function hasTextSelection() {
|
|
5124
|
+
return getSelectedText().length > 0;
|
|
5125
|
+
}
|
|
5126
|
+
function detectImageElement(element) {
|
|
5127
|
+
if (!element) return { isImage: false };
|
|
5128
|
+
if (element.tagName === "IMG") {
|
|
5129
|
+
const img = element;
|
|
5130
|
+
return {
|
|
5131
|
+
isImage: true,
|
|
5132
|
+
src: img.src || img.currentSrc,
|
|
5133
|
+
type: "img"
|
|
5134
|
+
};
|
|
5135
|
+
}
|
|
5136
|
+
if (element.tagName === "PICTURE") {
|
|
5137
|
+
const img = element.querySelector("img");
|
|
5138
|
+
return {
|
|
5139
|
+
isImage: true,
|
|
5140
|
+
src: img?.src || img?.currentSrc,
|
|
5141
|
+
type: "picture"
|
|
5142
|
+
};
|
|
5143
|
+
}
|
|
5144
|
+
if (element.tagName === "SVG" || element.tagName === "svg") {
|
|
5145
|
+
return {
|
|
5146
|
+
isImage: true,
|
|
5147
|
+
type: "svg"
|
|
5148
|
+
};
|
|
5149
|
+
}
|
|
5150
|
+
if (element.tagName === "CANVAS") {
|
|
5151
|
+
return {
|
|
5152
|
+
isImage: true,
|
|
5153
|
+
type: "canvas"
|
|
5154
|
+
};
|
|
5155
|
+
}
|
|
5156
|
+
if (typeof window !== "undefined") {
|
|
5157
|
+
const computedStyle = window.getComputedStyle(element);
|
|
5158
|
+
const backgroundImage = computedStyle.backgroundImage;
|
|
5159
|
+
if (backgroundImage && backgroundImage !== "none") {
|
|
5160
|
+
const urlMatch = backgroundImage.match(/url\(["']?(.+?)["']?\)/);
|
|
5161
|
+
if (urlMatch) {
|
|
5162
|
+
return {
|
|
5163
|
+
isImage: true,
|
|
5164
|
+
src: urlMatch[1],
|
|
5165
|
+
type: "background"
|
|
5166
|
+
};
|
|
5167
|
+
}
|
|
5168
|
+
}
|
|
5169
|
+
}
|
|
5170
|
+
const imgChild = element.querySelector("img");
|
|
5171
|
+
if (imgChild) {
|
|
5172
|
+
return {
|
|
5173
|
+
isImage: true,
|
|
5174
|
+
src: imgChild.src || imgChild.currentSrc,
|
|
5175
|
+
type: "img"
|
|
5176
|
+
};
|
|
5177
|
+
}
|
|
5178
|
+
return { isImage: false };
|
|
5179
|
+
}
|
|
5180
|
+
function createUploadThingMenuItem(options = {}) {
|
|
5181
|
+
const {
|
|
5182
|
+
label = "Upload to UploadThing",
|
|
5183
|
+
endpoint = "/api/uploadthing",
|
|
5184
|
+
onUploadComplete,
|
|
5185
|
+
onUploadError
|
|
5186
|
+
} = options;
|
|
5187
|
+
return {
|
|
5188
|
+
label,
|
|
5189
|
+
onClick: async ({ closeMenu, targetElement }) => {
|
|
5190
|
+
if (!targetElement) {
|
|
5191
|
+
onUploadError?.(new Error("No target element"));
|
|
5192
|
+
return false;
|
|
5193
|
+
}
|
|
5194
|
+
try {
|
|
5195
|
+
const imageInfo = detectImageElement(targetElement);
|
|
5196
|
+
if (imageInfo.isImage && imageInfo.src) {
|
|
5197
|
+
const response = await fetch(imageInfo.src);
|
|
5198
|
+
const blob = await response.blob();
|
|
5199
|
+
const formData = new FormData();
|
|
5200
|
+
const filename = `image-${Date.now()}.${blob.type.split("/")[1] || "png"}`;
|
|
5201
|
+
formData.append("file", blob, filename);
|
|
5202
|
+
const uploadResponse = await fetch(endpoint, {
|
|
5203
|
+
method: "POST",
|
|
5204
|
+
body: formData
|
|
5205
|
+
});
|
|
5206
|
+
if (!uploadResponse.ok) {
|
|
5207
|
+
throw new Error(`Upload failed: ${uploadResponse.status}`);
|
|
5208
|
+
}
|
|
5209
|
+
const result = await uploadResponse.json();
|
|
5210
|
+
onUploadComplete?.(result);
|
|
5211
|
+
} else if (imageInfo.isImage && imageInfo.type === "canvas") {
|
|
5212
|
+
const canvas = targetElement;
|
|
5213
|
+
const dataUrl = canvas.toDataURL("image/png");
|
|
5214
|
+
const response = await fetch(dataUrl);
|
|
5215
|
+
const blob = await response.blob();
|
|
5216
|
+
const formData = new FormData();
|
|
5217
|
+
formData.append("file", blob, `canvas-${Date.now()}.png`);
|
|
5218
|
+
const uploadResponse = await fetch(endpoint, {
|
|
5219
|
+
method: "POST",
|
|
5220
|
+
body: formData
|
|
5221
|
+
});
|
|
5222
|
+
if (!uploadResponse.ok) {
|
|
5223
|
+
throw new Error(`Upload failed: ${uploadResponse.status}`);
|
|
5224
|
+
}
|
|
5225
|
+
const result = await uploadResponse.json();
|
|
5226
|
+
onUploadComplete?.(result);
|
|
5227
|
+
} else {
|
|
5228
|
+
onUploadError?.(
|
|
5229
|
+
new Error(
|
|
5230
|
+
"Element is not an image. Screenshot upload requires anyclick-core."
|
|
5231
|
+
)
|
|
5232
|
+
);
|
|
5233
|
+
}
|
|
5234
|
+
} catch (error) {
|
|
5235
|
+
onUploadError?.(
|
|
5236
|
+
error instanceof Error ? error : new Error(String(error))
|
|
5237
|
+
);
|
|
5238
|
+
}
|
|
5239
|
+
closeMenu();
|
|
5240
|
+
return false;
|
|
5241
|
+
},
|
|
5242
|
+
showComment: false,
|
|
5243
|
+
type: "upload_image"
|
|
5244
|
+
};
|
|
5245
|
+
}
|
|
5246
|
+
function createUploadScreenshotMenuItem(options = {}) {
|
|
5247
|
+
const {
|
|
5248
|
+
label = "Upload Screenshot",
|
|
5249
|
+
endpoint = "/api/uploadthing",
|
|
5250
|
+
onUploadComplete,
|
|
5251
|
+
onUploadError
|
|
5252
|
+
} = options;
|
|
5253
|
+
return {
|
|
5254
|
+
label,
|
|
5255
|
+
badge: { label: "Coming soon", tone: "info" },
|
|
5256
|
+
status: "comingSoon",
|
|
5257
|
+
onClick: async ({ closeMenu }) => {
|
|
5258
|
+
onUploadError?.(
|
|
5259
|
+
new Error("Screenshot upload will be available in a future release")
|
|
5260
|
+
);
|
|
5261
|
+
closeMenu();
|
|
5262
|
+
return false;
|
|
5263
|
+
},
|
|
5264
|
+
showComment: false,
|
|
5265
|
+
type: "upload_screenshot"
|
|
5266
|
+
};
|
|
5267
|
+
}
|
|
3052
5268
|
|
|
3053
5269
|
// src/types.ts
|
|
3054
5270
|
function filterMenuItemsByRole(items, userContext) {
|
|
@@ -3067,10 +5283,10 @@ function filterMenuItemsByRole(items, userContext) {
|
|
|
3067
5283
|
}
|
|
3068
5284
|
|
|
3069
5285
|
// src/index.ts
|
|
3070
|
-
var
|
|
5286
|
+
var import_anyclick_core7 = require("@ewjdev/anyclick-core");
|
|
3071
5287
|
|
|
3072
5288
|
// src/AnyclickLogo.tsx
|
|
3073
|
-
var
|
|
5289
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
3074
5290
|
function AnyclickLogo({
|
|
3075
5291
|
size = 64,
|
|
3076
5292
|
borderWidth = 2,
|
|
@@ -3082,7 +5298,7 @@ function AnyclickLogo({
|
|
|
3082
5298
|
}) {
|
|
3083
5299
|
const cursorSize = size * 0.45;
|
|
3084
5300
|
const cursorStroke = borderWidth;
|
|
3085
|
-
return /* @__PURE__ */ (0,
|
|
5301
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
3086
5302
|
"svg",
|
|
3087
5303
|
{
|
|
3088
5304
|
width: size,
|
|
@@ -3096,7 +5312,7 @@ function AnyclickLogo({
|
|
|
3096
5312
|
role: onClick ? "button" : "img",
|
|
3097
5313
|
"aria-label": "Anyclick Logo",
|
|
3098
5314
|
children: [
|
|
3099
|
-
/* @__PURE__ */ (0,
|
|
5315
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3100
5316
|
"circle",
|
|
3101
5317
|
{
|
|
3102
5318
|
cx: size / 2,
|
|
@@ -3107,11 +5323,11 @@ function AnyclickLogo({
|
|
|
3107
5323
|
strokeWidth: borderWidth
|
|
3108
5324
|
}
|
|
3109
5325
|
),
|
|
3110
|
-
/* @__PURE__ */ (0,
|
|
5326
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3111
5327
|
"g",
|
|
3112
5328
|
{
|
|
3113
5329
|
transform: `translate(${(size - cursorSize) / 2}, ${(size - cursorSize) / 2})`,
|
|
3114
|
-
children: /* @__PURE__ */ (0,
|
|
5330
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
3115
5331
|
"path",
|
|
3116
5332
|
{
|
|
3117
5333
|
d: `
|
|
@@ -3139,24 +5355,28 @@ function AnyclickLogo({
|
|
|
3139
5355
|
}
|
|
3140
5356
|
|
|
3141
5357
|
// src/index.ts
|
|
3142
|
-
var
|
|
5358
|
+
var import_anyclick_core8 = require("@ewjdev/anyclick-core");
|
|
3143
5359
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3144
5360
|
0 && (module.exports = {
|
|
3145
5361
|
ALL_CURATED_PROPERTIES,
|
|
3146
5362
|
AnyclickContext,
|
|
3147
5363
|
AnyclickLogo,
|
|
3148
5364
|
AnyclickProvider,
|
|
5365
|
+
Button,
|
|
3149
5366
|
CURATED_STYLE_PROPERTIES,
|
|
3150
5367
|
ContextMenu,
|
|
3151
5368
|
DEFAULT_COMPACT_CONFIG,
|
|
5369
|
+
DEFAULT_QUICK_CHAT_CONFIG,
|
|
3152
5370
|
DEFAULT_SCREENSHOT_CONFIG,
|
|
3153
5371
|
DEFAULT_SENSITIVE_SELECTORS,
|
|
3154
5372
|
FeedbackContext,
|
|
3155
5373
|
FeedbackProvider,
|
|
3156
5374
|
FunModeBridge,
|
|
3157
5375
|
INSPECT_DIALOG_EVENT,
|
|
5376
|
+
Input,
|
|
3158
5377
|
InspectDialogManager,
|
|
3159
5378
|
InspectSimple,
|
|
5379
|
+
QuickChat,
|
|
3160
5380
|
ScreenshotPreview,
|
|
3161
5381
|
applyHighlights,
|
|
3162
5382
|
buildIDEUrl,
|
|
@@ -3165,9 +5385,13 @@ var import_anyclick_core6 = require("@ewjdev/anyclick-core");
|
|
|
3165
5385
|
clearHighlights,
|
|
3166
5386
|
createIDEOpener,
|
|
3167
5387
|
createPresetMenu,
|
|
5388
|
+
createT3ChatMenuItem,
|
|
5389
|
+
createUploadScreenshotMenuItem,
|
|
5390
|
+
createUploadThingMenuItem,
|
|
3168
5391
|
darkMenuStyles,
|
|
3169
5392
|
defaultContainerSelectors,
|
|
3170
5393
|
defaultHighlightColors,
|
|
5394
|
+
detectImageElement,
|
|
3171
5395
|
detectPreferredIDE,
|
|
3172
5396
|
dispatchContextMenuEvent,
|
|
3173
5397
|
estimateTotalSize,
|
|
@@ -3185,7 +5409,9 @@ var import_anyclick_core6 = require("@ewjdev/anyclick-core");
|
|
|
3185
5409
|
getBoxModelInfo,
|
|
3186
5410
|
getComputedStyles,
|
|
3187
5411
|
getElementInspectInfo,
|
|
5412
|
+
getSelectedText,
|
|
3188
5413
|
getSourceLocationFromElement,
|
|
5414
|
+
hasTextSelection,
|
|
3189
5415
|
highlightContainer,
|
|
3190
5416
|
highlightTarget,
|
|
3191
5417
|
isIDEProtocolSupported,
|
|
@@ -3196,8 +5422,11 @@ var import_anyclick_core6 = require("@ewjdev/anyclick-core");
|
|
|
3196
5422
|
openInIDE,
|
|
3197
5423
|
openInspectDialog,
|
|
3198
5424
|
presetDefaults,
|
|
5425
|
+
quickChatKeyframes,
|
|
5426
|
+
quickChatStyles,
|
|
3199
5427
|
useAnyclick,
|
|
3200
5428
|
useFeedback,
|
|
3201
|
-
useProviderStore
|
|
5429
|
+
useProviderStore,
|
|
5430
|
+
useQuickChat
|
|
3202
5431
|
});
|
|
3203
5432
|
//# sourceMappingURL=index.js.map
|