@ewjdev/anyclick-react 3.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 +55 -18
- package/dist/index.d.ts +55 -18
- package/dist/index.js +1077 -485
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +942 -352
- 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 +16 -5
package/dist/index.js
CHANGED
|
@@ -31,28 +31,30 @@ 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
|
DEFAULT_QUICK_CHAT_CONFIG: () => DEFAULT_QUICK_CHAT_CONFIG,
|
|
42
|
-
DEFAULT_SCREENSHOT_CONFIG: () =>
|
|
43
|
-
DEFAULT_SENSITIVE_SELECTORS: () =>
|
|
43
|
+
DEFAULT_SCREENSHOT_CONFIG: () => import_anyclick_core7.DEFAULT_SCREENSHOT_CONFIG,
|
|
44
|
+
DEFAULT_SENSITIVE_SELECTORS: () => import_anyclick_core7.DEFAULT_SENSITIVE_SELECTORS,
|
|
44
45
|
FeedbackContext: () => FeedbackContext,
|
|
45
46
|
FeedbackProvider: () => FeedbackProvider,
|
|
46
47
|
FunModeBridge: () => FunModeBridge,
|
|
47
48
|
INSPECT_DIALOG_EVENT: () => INSPECT_DIALOG_EVENT,
|
|
49
|
+
Input: () => Input,
|
|
48
50
|
InspectDialogManager: () => InspectDialogManager,
|
|
49
51
|
InspectSimple: () => InspectSimple,
|
|
50
52
|
QuickChat: () => QuickChat,
|
|
51
53
|
ScreenshotPreview: () => ScreenshotPreview,
|
|
52
54
|
applyHighlights: () => applyHighlights,
|
|
53
55
|
buildIDEUrl: () => buildIDEUrl,
|
|
54
|
-
captureAllScreenshots: () =>
|
|
55
|
-
captureScreenshot: () =>
|
|
56
|
+
captureAllScreenshots: () => import_anyclick_core7.captureAllScreenshots,
|
|
57
|
+
captureScreenshot: () => import_anyclick_core7.captureScreenshot,
|
|
56
58
|
clearHighlights: () => clearHighlights,
|
|
57
59
|
createIDEOpener: () => createIDEOpener,
|
|
58
60
|
createPresetMenu: () => createPresetMenu,
|
|
@@ -65,28 +67,28 @@ __export(index_exports, {
|
|
|
65
67
|
detectImageElement: () => detectImageElement,
|
|
66
68
|
detectPreferredIDE: () => detectPreferredIDE,
|
|
67
69
|
dispatchContextMenuEvent: () => dispatchContextMenuEvent,
|
|
68
|
-
estimateTotalSize: () =>
|
|
70
|
+
estimateTotalSize: () => import_anyclick_core7.estimateTotalSize,
|
|
69
71
|
filterMenuItemsByRole: () => filterMenuItemsByRole,
|
|
70
72
|
findContainerParent: () => findContainerParent,
|
|
71
73
|
findSourceLocationInAncestors: () => findSourceLocationInAncestors,
|
|
72
|
-
formatBoxModel: () =>
|
|
73
|
-
formatBytes: () =>
|
|
74
|
+
formatBoxModel: () => import_anyclick_core8.formatBoxModel,
|
|
75
|
+
formatBytes: () => import_anyclick_core7.formatBytes,
|
|
74
76
|
formatSourceLocation: () => formatSourceLocation,
|
|
75
|
-
formatStylesAsCSS: () =>
|
|
77
|
+
formatStylesAsCSS: () => import_anyclick_core8.formatStylesAsCSS,
|
|
76
78
|
generateProviderId: () => generateProviderId,
|
|
77
|
-
getAccessibilityInfo: () =>
|
|
78
|
-
getAttributes: () =>
|
|
79
|
+
getAccessibilityInfo: () => import_anyclick_core8.getAccessibilityInfo,
|
|
80
|
+
getAttributes: () => import_anyclick_core8.getAttributes,
|
|
79
81
|
getBadgeStyle: () => getBadgeStyle,
|
|
80
|
-
getBoxModelInfo: () =>
|
|
81
|
-
getComputedStyles: () =>
|
|
82
|
-
getElementInspectInfo: () =>
|
|
82
|
+
getBoxModelInfo: () => import_anyclick_core8.getBoxModelInfo,
|
|
83
|
+
getComputedStyles: () => import_anyclick_core8.getComputedStyles,
|
|
84
|
+
getElementInspectInfo: () => import_anyclick_core8.getElementInspectInfo,
|
|
83
85
|
getSelectedText: () => getSelectedText,
|
|
84
86
|
getSourceLocationFromElement: () => getSourceLocationFromElement,
|
|
85
87
|
hasTextSelection: () => hasTextSelection,
|
|
86
88
|
highlightContainer: () => highlightContainer,
|
|
87
89
|
highlightTarget: () => highlightTarget,
|
|
88
90
|
isIDEProtocolSupported: () => isIDEProtocolSupported,
|
|
89
|
-
isScreenshotSupported: () =>
|
|
91
|
+
isScreenshotSupported: () => import_anyclick_core7.isScreenshotSupported,
|
|
90
92
|
listPresets: () => listPresets,
|
|
91
93
|
menuCSSVariables: () => menuCSSVariables,
|
|
92
94
|
menuStyles: () => menuStyles,
|
|
@@ -103,16 +105,17 @@ __export(index_exports, {
|
|
|
103
105
|
module.exports = __toCommonJS(index_exports);
|
|
104
106
|
|
|
105
107
|
// src/AnyclickProvider.tsx
|
|
106
|
-
var
|
|
107
|
-
var
|
|
108
|
+
var import_react7 = require("react");
|
|
109
|
+
var import_anyclick_core5 = require("@ewjdev/anyclick-core");
|
|
108
110
|
|
|
109
111
|
// src/ContextMenu.tsx
|
|
110
|
-
var
|
|
111
|
-
var
|
|
112
|
+
var import_react5 = __toESM(require("react"));
|
|
113
|
+
var import_anyclick_core4 = require("@ewjdev/anyclick-core");
|
|
112
114
|
var import_lucide_react3 = require("lucide-react");
|
|
113
115
|
|
|
114
116
|
// src/QuickChat/QuickChat.tsx
|
|
115
|
-
var
|
|
117
|
+
var import_react3 = __toESM(require("react"));
|
|
118
|
+
var import_anyclick_core2 = require("@ewjdev/anyclick-core");
|
|
116
119
|
var import_lucide_react = require("lucide-react");
|
|
117
120
|
|
|
118
121
|
// src/QuickChat/styles.ts
|
|
@@ -294,6 +297,7 @@ var quickChatStyles = {
|
|
|
294
297
|
// Suggestions - compact horizontal scroll
|
|
295
298
|
suggestionsContainer: {
|
|
296
299
|
display: "flex",
|
|
300
|
+
flexDirection: "column",
|
|
297
301
|
gap: "6px",
|
|
298
302
|
padding: "6px 8px",
|
|
299
303
|
overflowX: "auto",
|
|
@@ -557,7 +561,130 @@ var quickChatKeyframes = `
|
|
|
557
561
|
|
|
558
562
|
// src/QuickChat/useQuickChat.ts
|
|
559
563
|
var import_react = require("react");
|
|
560
|
-
var
|
|
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
|
+
}
|
|
561
688
|
|
|
562
689
|
// src/QuickChat/types.ts
|
|
563
690
|
var DEFAULT_T3CHAT_CONFIG = {
|
|
@@ -567,9 +694,9 @@ var DEFAULT_T3CHAT_CONFIG = {
|
|
|
567
694
|
};
|
|
568
695
|
var DEFAULT_QUICK_CHAT_CONFIG = {
|
|
569
696
|
endpoint: "/api/anyclick/chat",
|
|
570
|
-
model: "gpt-5-
|
|
697
|
+
model: "gpt-5-nano",
|
|
571
698
|
prePassModel: "gpt-5-nano",
|
|
572
|
-
maxResponseLength:
|
|
699
|
+
maxResponseLength: 1e4,
|
|
573
700
|
showRedactionUI: true,
|
|
574
701
|
showSuggestions: true,
|
|
575
702
|
systemPrompt: "You are a helpful assistant that provides quick, concise answers about web elements and UI. Keep responses brief and actionable.",
|
|
@@ -578,57 +705,9 @@ var DEFAULT_QUICK_CHAT_CONFIG = {
|
|
|
578
705
|
t3chat: DEFAULT_T3CHAT_CONFIG
|
|
579
706
|
};
|
|
580
707
|
|
|
581
|
-
// src/QuickChat/useQuickChat.ts
|
|
582
|
-
var
|
|
583
|
-
|
|
584
|
-
function generateId() {
|
|
585
|
-
return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
586
|
-
}
|
|
587
|
-
function getPinnedState() {
|
|
588
|
-
if (typeof window === "undefined") return false;
|
|
589
|
-
try {
|
|
590
|
-
return sessionStorage.getItem(PINNED_STATE_KEY) === "true";
|
|
591
|
-
} catch {
|
|
592
|
-
return false;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
function getChatHistory() {
|
|
596
|
-
if (typeof window === "undefined") return [];
|
|
597
|
-
try {
|
|
598
|
-
const stored = sessionStorage.getItem(CHAT_HISTORY_KEY);
|
|
599
|
-
if (stored) {
|
|
600
|
-
const parsed = JSON.parse(stored);
|
|
601
|
-
return parsed.map((msg) => ({
|
|
602
|
-
...msg,
|
|
603
|
-
isStreaming: false,
|
|
604
|
-
actions: void 0
|
|
605
|
-
}));
|
|
606
|
-
}
|
|
607
|
-
} catch {
|
|
608
|
-
}
|
|
609
|
-
return [];
|
|
610
|
-
}
|
|
611
|
-
function saveChatHistory(messages) {
|
|
612
|
-
if (typeof window === "undefined") return;
|
|
613
|
-
try {
|
|
614
|
-
const toStore = messages.slice(-10).map((msg) => ({
|
|
615
|
-
id: msg.id,
|
|
616
|
-
role: msg.role,
|
|
617
|
-
content: msg.content,
|
|
618
|
-
timestamp: msg.timestamp
|
|
619
|
-
}));
|
|
620
|
-
sessionStorage.setItem(CHAT_HISTORY_KEY, JSON.stringify(toStore));
|
|
621
|
-
} catch {
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
function clearChatHistory() {
|
|
625
|
-
if (typeof window === "undefined") return;
|
|
626
|
-
try {
|
|
627
|
-
sessionStorage.removeItem(CHAT_HISTORY_KEY);
|
|
628
|
-
} catch {
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
function extractContextChunks(targetElement, containerElement) {
|
|
708
|
+
// src/QuickChat/useQuickChat.context.ts
|
|
709
|
+
var import_anyclick_core = require("@ewjdev/anyclick-core");
|
|
710
|
+
function extractContextChunks(targetElement, _containerElement) {
|
|
632
711
|
const chunks = [];
|
|
633
712
|
if (!targetElement) return chunks;
|
|
634
713
|
try {
|
|
@@ -655,7 +734,7 @@ function extractContextChunks(targetElement, containerElement) {
|
|
|
655
734
|
}
|
|
656
735
|
if (info.computedStyles) {
|
|
657
736
|
const styleEntries = [];
|
|
658
|
-
for (const [
|
|
737
|
+
for (const [, styles] of Object.entries(info.computedStyles)) {
|
|
659
738
|
if (styles && typeof styles === "object") {
|
|
660
739
|
const entries = Object.entries(styles).slice(0, 2);
|
|
661
740
|
for (const [k, v] of entries) {
|
|
@@ -693,7 +772,9 @@ function extractContextChunks(targetElement, containerElement) {
|
|
|
693
772
|
}
|
|
694
773
|
}
|
|
695
774
|
if (info.boxModel) {
|
|
696
|
-
const boxContent = `${Math.round(info.boxModel.content.width)}x${Math.round(
|
|
775
|
+
const boxContent = `${Math.round(info.boxModel.content.width)}x${Math.round(
|
|
776
|
+
info.boxModel.content.height
|
|
777
|
+
)}px`;
|
|
697
778
|
chunks.push({
|
|
698
779
|
id: "element-dimensions",
|
|
699
780
|
label: "Dimensions",
|
|
@@ -704,54 +785,358 @@ function extractContextChunks(targetElement, containerElement) {
|
|
|
704
785
|
});
|
|
705
786
|
}
|
|
706
787
|
} catch (error) {
|
|
707
|
-
console.error("Failed to extract context:", error);
|
|
788
|
+
console.error("[useQuickChat] Failed to extract context:", error);
|
|
708
789
|
}
|
|
709
790
|
return chunks;
|
|
710
791
|
}
|
|
711
792
|
function buildContextString(chunks) {
|
|
712
|
-
const
|
|
713
|
-
if (
|
|
714
|
-
return
|
|
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;
|
|
715
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
|
|
716
946
|
function useQuickChat(targetElement, containerElement, config = {}) {
|
|
947
|
+
console.count("useQuickChat");
|
|
717
948
|
const mergedConfig = { ...DEFAULT_QUICK_CHAT_CONFIG, ...config };
|
|
718
|
-
const abortControllerRef = (0, import_react.useRef)(null);
|
|
719
949
|
const initializedRef = (0, import_react.useRef)(false);
|
|
720
|
-
const
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
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
|
+
}
|
|
729
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;
|
|
730
1118
|
(0, import_react.useEffect)(() => {
|
|
731
1119
|
if (initializedRef.current) return;
|
|
732
1120
|
initializedRef.current = true;
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
setState((prev) => ({ ...prev, messages: history }));
|
|
738
|
-
}
|
|
1121
|
+
if (storedMessages.length > 0) {
|
|
1122
|
+
setAiMessages(chatMessagesToUiMessages(storedMessages));
|
|
1123
|
+
} else {
|
|
1124
|
+
void loadFromBackend();
|
|
739
1125
|
}
|
|
740
|
-
}, []);
|
|
1126
|
+
}, [loadFromBackend, setAiMessages, storedMessages]);
|
|
741
1127
|
(0, import_react.useEffect)(() => {
|
|
742
|
-
if (targetElement)
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
}, [targetElement, containerElement]);
|
|
1128
|
+
if (!targetElement) return;
|
|
1129
|
+
const chunks = extractContextChunks(targetElement, containerElement);
|
|
1130
|
+
setContextChunks(chunks);
|
|
1131
|
+
}, [targetElement, containerElement, setContextChunks]);
|
|
747
1132
|
(0, import_react.useEffect)(() => {
|
|
748
|
-
if (!mergedConfig.showSuggestions
|
|
749
|
-
|
|
750
|
-
|
|
1133
|
+
if (!mergedConfig.showSuggestions) return;
|
|
1134
|
+
if (!contextString) return;
|
|
1135
|
+
if (suggestedPrompts.length > 0) return;
|
|
1136
|
+
let cancelled = false;
|
|
751
1137
|
const fetchSuggestions = async () => {
|
|
752
|
-
|
|
1138
|
+
setIsLoadingSuggestions(true);
|
|
753
1139
|
try {
|
|
754
|
-
const contextString = buildContextString(state.contextChunks);
|
|
755
1140
|
const response = await fetch(mergedConfig.endpoint, {
|
|
756
1141
|
method: "POST",
|
|
757
1142
|
headers: { "Content-Type": "application/json" },
|
|
@@ -761,250 +1146,142 @@ function useQuickChat(targetElement, containerElement, config = {}) {
|
|
|
761
1146
|
model: mergedConfig.prePassModel
|
|
762
1147
|
})
|
|
763
1148
|
});
|
|
1149
|
+
if (await handleRateLimitResponse(response, mergedConfig.endpoint)) {
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
764
1152
|
if (response.ok) {
|
|
765
|
-
const data = await response.json();
|
|
766
|
-
if (data
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
(text, i) => ({
|
|
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) => ({
|
|
771
1158
|
id: `suggestion-${i}`,
|
|
772
1159
|
text
|
|
773
|
-
})
|
|
774
|
-
)
|
|
775
|
-
|
|
776
|
-
}
|
|
1160
|
+
}))
|
|
1161
|
+
);
|
|
1162
|
+
setIsLoadingSuggestions(false);
|
|
1163
|
+
}
|
|
777
1164
|
return;
|
|
778
1165
|
}
|
|
779
1166
|
}
|
|
780
|
-
} catch (
|
|
781
|
-
console.error("Failed to fetch suggestions:",
|
|
1167
|
+
} catch (err) {
|
|
1168
|
+
console.error("[useQuickChat] Failed to fetch suggestions:", err);
|
|
782
1169
|
}
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
suggestedPrompts: [
|
|
1170
|
+
if (!cancelled) {
|
|
1171
|
+
setSuggestedPrompts([
|
|
786
1172
|
{ id: "s1", text: "What is this element?" },
|
|
787
1173
|
{ id: "s2", text: "How can I style this?" },
|
|
788
1174
|
{ id: "s3", text: "Is this accessible?" }
|
|
789
|
-
]
|
|
790
|
-
|
|
791
|
-
}
|
|
1175
|
+
]);
|
|
1176
|
+
setIsLoadingSuggestions(false);
|
|
1177
|
+
}
|
|
1178
|
+
};
|
|
1179
|
+
void fetchSuggestions();
|
|
1180
|
+
return () => {
|
|
1181
|
+
cancelled = true;
|
|
792
1182
|
};
|
|
793
|
-
fetchSuggestions();
|
|
794
1183
|
}, [
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
mergedConfig.showSuggestions,
|
|
1184
|
+
contextString,
|
|
1185
|
+
handleRateLimitResponse,
|
|
798
1186
|
mergedConfig.endpoint,
|
|
799
|
-
mergedConfig.prePassModel
|
|
1187
|
+
mergedConfig.prePassModel,
|
|
1188
|
+
mergedConfig.showSuggestions,
|
|
1189
|
+
setIsLoadingSuggestions,
|
|
1190
|
+
setSuggestedPrompts,
|
|
1191
|
+
suggestedPrompts.length
|
|
800
1192
|
]);
|
|
801
|
-
const
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
contextChunks: prev.contextChunks.map(
|
|
808
|
-
(chunk) => chunk.id === chunkId ? { ...chunk, included: !chunk.included } : chunk
|
|
809
|
-
)
|
|
810
|
-
}));
|
|
811
|
-
}, []);
|
|
812
|
-
const toggleAllChunks = (0, import_react.useCallback)((included) => {
|
|
813
|
-
setState((prev) => ({
|
|
814
|
-
...prev,
|
|
815
|
-
contextChunks: prev.contextChunks.map((chunk) => ({
|
|
816
|
-
...chunk,
|
|
817
|
-
included
|
|
818
|
-
}))
|
|
819
|
-
}));
|
|
820
|
-
}, []);
|
|
821
|
-
const selectSuggestion = (0, import_react.useCallback)((prompt) => {
|
|
822
|
-
setState((prev) => ({ ...prev, input: prompt.text }));
|
|
823
|
-
}, []);
|
|
1193
|
+
const selectSuggestion = (0, import_react.useCallback)(
|
|
1194
|
+
(prompt) => {
|
|
1195
|
+
setInput(prompt.text);
|
|
1196
|
+
},
|
|
1197
|
+
[setInput]
|
|
1198
|
+
);
|
|
824
1199
|
const sendMessage = (0, import_react.useCallback)(
|
|
825
1200
|
async (messageText) => {
|
|
826
|
-
const text = (messageText ||
|
|
1201
|
+
const text = (messageText || input).trim();
|
|
827
1202
|
if (!text) return;
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
role: "user",
|
|
835
|
-
content: text,
|
|
836
|
-
timestamp: Date.now()
|
|
837
|
-
};
|
|
838
|
-
const assistantMessageId = generateId();
|
|
839
|
-
const assistantMessage = {
|
|
840
|
-
id: assistantMessageId,
|
|
841
|
-
role: "assistant",
|
|
842
|
-
content: "",
|
|
843
|
-
timestamp: Date.now(),
|
|
844
|
-
isStreaming: true
|
|
845
|
-
};
|
|
846
|
-
setState((prev) => ({
|
|
847
|
-
...prev,
|
|
848
|
-
input: "",
|
|
849
|
-
messages: [...prev.messages, userMessage, assistantMessage],
|
|
850
|
-
isSending: true,
|
|
851
|
-
isStreaming: true,
|
|
852
|
-
error: null
|
|
853
|
-
}));
|
|
1203
|
+
setInput("");
|
|
1204
|
+
setError(null);
|
|
1205
|
+
setManualSending(true);
|
|
1206
|
+
setStoreIsSending(true);
|
|
1207
|
+
setStoreIsStreaming(true);
|
|
1208
|
+
setDebugInfo(null);
|
|
854
1209
|
try {
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
headers: { "Content-Type": "application/json" },
|
|
859
|
-
body: JSON.stringify({
|
|
860
|
-
action: "chat",
|
|
861
|
-
message: text,
|
|
862
|
-
context: contextString,
|
|
863
|
-
model: mergedConfig.model,
|
|
864
|
-
systemPrompt: mergedConfig.systemPrompt,
|
|
865
|
-
maxLength: mergedConfig.maxResponseLength
|
|
866
|
-
}),
|
|
867
|
-
signal: abortControllerRef.current.signal
|
|
1210
|
+
addMessage({
|
|
1211
|
+
role: "user",
|
|
1212
|
+
content: text
|
|
868
1213
|
});
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
let fullContent = "";
|
|
878
|
-
while (true) {
|
|
879
|
-
const { done, value } = await reader.read();
|
|
880
|
-
if (done) break;
|
|
881
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
882
|
-
fullContent += chunk;
|
|
883
|
-
if (fullContent.length > mergedConfig.maxResponseLength) {
|
|
884
|
-
fullContent = fullContent.slice(0, mergedConfig.maxResponseLength) + "...";
|
|
885
|
-
}
|
|
886
|
-
setState((prev) => ({
|
|
887
|
-
...prev,
|
|
888
|
-
messages: prev.messages.map(
|
|
889
|
-
(msg) => msg.id === assistantMessageId ? { ...msg, content: fullContent } : msg
|
|
890
|
-
)
|
|
891
|
-
}));
|
|
892
|
-
}
|
|
893
|
-
setState((prev) => ({
|
|
894
|
-
...prev,
|
|
895
|
-
messages: prev.messages.map(
|
|
896
|
-
(msg) => msg.id === assistantMessageId ? {
|
|
897
|
-
...msg,
|
|
898
|
-
content: fullContent,
|
|
899
|
-
isStreaming: false,
|
|
900
|
-
actions: [
|
|
901
|
-
{
|
|
902
|
-
id: "copy",
|
|
903
|
-
label: "Copy",
|
|
904
|
-
onClick: () => {
|
|
905
|
-
navigator.clipboard.writeText(fullContent);
|
|
906
|
-
}
|
|
907
|
-
},
|
|
908
|
-
{
|
|
909
|
-
id: "research",
|
|
910
|
-
label: "Research more",
|
|
911
|
-
onClick: () => {
|
|
912
|
-
setState((p) => ({
|
|
913
|
-
...p,
|
|
914
|
-
input: `Tell me more about: ${text}`
|
|
915
|
-
}));
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
]
|
|
919
|
-
} : msg
|
|
920
|
-
),
|
|
921
|
-
isSending: false,
|
|
922
|
-
isStreaming: false
|
|
923
|
-
}));
|
|
924
|
-
} catch (error) {
|
|
925
|
-
if (error.name === "AbortError") {
|
|
926
|
-
return;
|
|
927
|
-
}
|
|
928
|
-
console.error("Chat error:", error);
|
|
929
|
-
setState((prev) => ({
|
|
930
|
-
...prev,
|
|
931
|
-
messages: prev.messages.map(
|
|
932
|
-
(msg) => msg.id === assistantMessageId ? {
|
|
933
|
-
...msg,
|
|
934
|
-
content: "Sorry, I couldn't process your request. Please try again.",
|
|
935
|
-
isStreaming: false
|
|
936
|
-
} : msg
|
|
937
|
-
),
|
|
938
|
-
isSending: false,
|
|
939
|
-
isStreaming: false,
|
|
940
|
-
error: error.message
|
|
941
|
-
}));
|
|
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);
|
|
942
1222
|
}
|
|
943
1223
|
},
|
|
944
|
-
[
|
|
1224
|
+
[
|
|
1225
|
+
addMessage,
|
|
1226
|
+
aiSendMessage,
|
|
1227
|
+
input,
|
|
1228
|
+
setError,
|
|
1229
|
+
setInput,
|
|
1230
|
+
setStoreIsSending,
|
|
1231
|
+
setStoreIsStreaming
|
|
1232
|
+
]
|
|
945
1233
|
);
|
|
946
1234
|
const clearMessages = (0, import_react.useCallback)(() => {
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
}))
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
}
|
|
966
|
-
}, [state.messages]);
|
|
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
|
+
]);
|
|
967
1253
|
(0, import_react.useEffect)(() => {
|
|
968
1254
|
return () => {
|
|
969
|
-
if (
|
|
970
|
-
abortControllerRef.current.abort();
|
|
971
|
-
}
|
|
1255
|
+
if (syncTimeoutRef.current) clearTimeout(syncTimeoutRef.current);
|
|
972
1256
|
};
|
|
973
1257
|
}, []);
|
|
974
1258
|
return {
|
|
975
|
-
|
|
1259
|
+
input,
|
|
1260
|
+
messages,
|
|
1261
|
+
isLoadingSuggestions,
|
|
1262
|
+
isSending,
|
|
1263
|
+
isStreaming,
|
|
1264
|
+
suggestedPrompts,
|
|
1265
|
+
contextChunks,
|
|
1266
|
+
error,
|
|
1267
|
+
debugInfo,
|
|
1268
|
+
rateLimitNotice,
|
|
1269
|
+
isPinned,
|
|
1270
|
+
lastSyncedAt,
|
|
976
1271
|
config: mergedConfig,
|
|
977
1272
|
setInput,
|
|
978
1273
|
toggleChunk,
|
|
979
1274
|
toggleAllChunks,
|
|
980
1275
|
selectSuggestion,
|
|
981
1276
|
sendMessage,
|
|
982
|
-
clearMessages
|
|
1277
|
+
clearMessages,
|
|
1278
|
+
setIsPinned,
|
|
1279
|
+
clearRateLimitNotice: () => setRateLimitNotice(null)
|
|
983
1280
|
};
|
|
984
1281
|
}
|
|
985
1282
|
|
|
986
1283
|
// src/QuickChat/QuickChat.tsx
|
|
987
1284
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
988
|
-
var PINNED_STATE_KEY2 = "anyclick-quick-chat-pinned";
|
|
989
|
-
function getStoredPinnedState() {
|
|
990
|
-
if (typeof window === "undefined") return false;
|
|
991
|
-
try {
|
|
992
|
-
return sessionStorage.getItem(PINNED_STATE_KEY2) === "true";
|
|
993
|
-
} catch {
|
|
994
|
-
return false;
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
function setStoredPinnedState(pinned) {
|
|
998
|
-
if (typeof window === "undefined") return;
|
|
999
|
-
try {
|
|
1000
|
-
if (pinned) {
|
|
1001
|
-
sessionStorage.setItem(PINNED_STATE_KEY2, "true");
|
|
1002
|
-
} else {
|
|
1003
|
-
sessionStorage.removeItem(PINNED_STATE_KEY2);
|
|
1004
|
-
}
|
|
1005
|
-
} catch {
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
1285
|
var stylesInjected = false;
|
|
1009
1286
|
function injectStyles() {
|
|
1010
1287
|
if (stylesInjected || typeof document === "undefined") return;
|
|
@@ -1013,7 +1290,7 @@ function injectStyles() {
|
|
|
1013
1290
|
document.head.appendChild(style);
|
|
1014
1291
|
stylesInjected = true;
|
|
1015
1292
|
}
|
|
1016
|
-
var LoadingDots =
|
|
1293
|
+
var LoadingDots = import_react3.default.memo(function LoadingDots2() {
|
|
1017
1294
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: quickChatStyles.loadingDots, children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1018
1295
|
"div",
|
|
1019
1296
|
{
|
|
@@ -1038,50 +1315,52 @@ function QuickChat({
|
|
|
1038
1315
|
initialInput,
|
|
1039
1316
|
onInitialInputConsumed
|
|
1040
1317
|
}) {
|
|
1041
|
-
const inputRef = (0,
|
|
1042
|
-
const messagesEndRef = (0,
|
|
1043
|
-
const [inputFocused, setInputFocused] = (0,
|
|
1044
|
-
const [showContext, setShowContext] = (0,
|
|
1045
|
-
const [hoveredSuggestion, setHoveredSuggestion] = (0,
|
|
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)(
|
|
1046
1323
|
null
|
|
1047
1324
|
);
|
|
1048
|
-
const [localPinned, setLocalPinned] = (0, import_react2.useState)(() => getStoredPinnedState());
|
|
1049
|
-
const isPinned = isPinnedProp || localPinned;
|
|
1050
|
-
const handlePinToggle = (0, import_react2.useCallback)(() => {
|
|
1051
|
-
const newPinned = !isPinned;
|
|
1052
|
-
setLocalPinned(newPinned);
|
|
1053
|
-
setStoredPinnedState(newPinned);
|
|
1054
|
-
onPin?.(newPinned);
|
|
1055
|
-
}, [isPinned, onPin]);
|
|
1056
|
-
const handleClose = (0, import_react2.useCallback)(() => {
|
|
1057
|
-
if (isPinned) {
|
|
1058
|
-
setLocalPinned(false);
|
|
1059
|
-
setStoredPinnedState(false);
|
|
1060
|
-
onPin?.(false);
|
|
1061
|
-
}
|
|
1062
|
-
onClose();
|
|
1063
|
-
}, [isPinned, onPin, onClose]);
|
|
1064
1325
|
const {
|
|
1065
1326
|
input,
|
|
1066
1327
|
messages,
|
|
1067
1328
|
isLoadingSuggestions,
|
|
1068
1329
|
isSending,
|
|
1069
1330
|
isStreaming,
|
|
1331
|
+
debugInfo,
|
|
1332
|
+
rateLimitNotice,
|
|
1070
1333
|
suggestedPrompts,
|
|
1071
1334
|
contextChunks,
|
|
1072
1335
|
error,
|
|
1336
|
+
isPinned: storePinned,
|
|
1073
1337
|
setInput,
|
|
1074
1338
|
toggleChunk,
|
|
1075
1339
|
toggleAllChunks,
|
|
1076
1340
|
selectSuggestion,
|
|
1077
1341
|
sendMessage,
|
|
1078
1342
|
clearMessages,
|
|
1343
|
+
setIsPinned,
|
|
1344
|
+
clearRateLimitNotice,
|
|
1079
1345
|
config: mergedConfig
|
|
1080
1346
|
} = useQuickChat(targetElement, containerElement, config);
|
|
1081
|
-
|
|
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)(() => {
|
|
1082
1361
|
injectStyles();
|
|
1083
1362
|
}, []);
|
|
1084
|
-
(0,
|
|
1363
|
+
(0, import_react3.useEffect)(() => {
|
|
1085
1364
|
if (visible && inputRef.current) {
|
|
1086
1365
|
const timer = setTimeout(() => {
|
|
1087
1366
|
inputRef.current?.focus();
|
|
@@ -1089,7 +1368,7 @@ function QuickChat({
|
|
|
1089
1368
|
return () => clearTimeout(timer);
|
|
1090
1369
|
}
|
|
1091
1370
|
}, [visible]);
|
|
1092
|
-
(0,
|
|
1371
|
+
(0, import_react3.useEffect)(() => {
|
|
1093
1372
|
if (initialInput && visible) {
|
|
1094
1373
|
setInput(initialInput);
|
|
1095
1374
|
onInitialInputConsumed?.();
|
|
@@ -1102,12 +1381,12 @@ function QuickChat({
|
|
|
1102
1381
|
}
|
|
1103
1382
|
}
|
|
1104
1383
|
}, [initialInput, visible, setInput, onInitialInputConsumed]);
|
|
1105
|
-
(0,
|
|
1384
|
+
(0, import_react3.useEffect)(() => {
|
|
1106
1385
|
if (messagesEndRef.current) {
|
|
1107
1386
|
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
|
|
1108
1387
|
}
|
|
1109
1388
|
}, [messages]);
|
|
1110
|
-
const handleInputChange = (0,
|
|
1389
|
+
const handleInputChange = (0, import_react3.useCallback)(
|
|
1111
1390
|
(e) => {
|
|
1112
1391
|
setInput(e.target.value);
|
|
1113
1392
|
const target = e.target;
|
|
@@ -1116,7 +1395,7 @@ function QuickChat({
|
|
|
1116
1395
|
},
|
|
1117
1396
|
[setInput]
|
|
1118
1397
|
);
|
|
1119
|
-
const handleKeyDown = (0,
|
|
1398
|
+
const handleKeyDown = (0, import_react3.useCallback)(
|
|
1120
1399
|
(e) => {
|
|
1121
1400
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
1122
1401
|
e.preventDefault();
|
|
@@ -1127,23 +1406,78 @@ function QuickChat({
|
|
|
1127
1406
|
},
|
|
1128
1407
|
[sendMessage, onClose]
|
|
1129
1408
|
);
|
|
1130
|
-
const handleSend = (0,
|
|
1409
|
+
const handleSend = (0, import_react3.useCallback)(() => {
|
|
1131
1410
|
sendMessage();
|
|
1132
1411
|
}, [sendMessage]);
|
|
1133
|
-
const handleSendToT3Chat = (0,
|
|
1412
|
+
const handleSendToT3Chat = (0, import_react3.useCallback)(() => {
|
|
1134
1413
|
if (typeof window === "undefined") return;
|
|
1135
1414
|
const query = input.trim();
|
|
1136
1415
|
const baseUrl = mergedConfig.t3chat?.baseUrl ?? "https://t3.chat";
|
|
1137
1416
|
const url = query ? `${baseUrl}/?q=${encodeURIComponent(query)}` : baseUrl;
|
|
1138
1417
|
window.open(url, "_blank", "noopener,noreferrer");
|
|
1139
1418
|
}, [input, mergedConfig.t3chat?.baseUrl]);
|
|
1140
|
-
const handleCopy = (0,
|
|
1419
|
+
const handleCopy = (0, import_react3.useCallback)((text) => {
|
|
1141
1420
|
navigator.clipboard.writeText(text);
|
|
1142
1421
|
}, []);
|
|
1143
|
-
const includedCount = (0,
|
|
1422
|
+
const includedCount = (0, import_react3.useMemo)(
|
|
1144
1423
|
() => contextChunks.filter((c) => c.included).length,
|
|
1145
1424
|
[contextChunks]
|
|
1146
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]);
|
|
1147
1481
|
if (!visible) return null;
|
|
1148
1482
|
const containerStyles = isPinned ? {
|
|
1149
1483
|
...quickChatStyles.pinnedContainer,
|
|
@@ -1302,7 +1636,7 @@ function QuickChat({
|
|
|
1302
1636
|
{
|
|
1303
1637
|
style: isPinned ? quickChatStyles.pinnedMessagesArea : quickChatStyles.messagesArea,
|
|
1304
1638
|
children: [
|
|
1305
|
-
error && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: quickChatStyles.errorContainer, children: [
|
|
1639
|
+
error && !rateLimitNotice && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: quickChatStyles.errorContainer, children: [
|
|
1306
1640
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.AlertCircle, { size: 20, style: quickChatStyles.errorIcon }),
|
|
1307
1641
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: quickChatStyles.errorText, children: error }),
|
|
1308
1642
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
@@ -1318,6 +1652,55 @@ function QuickChat({
|
|
|
1318
1652
|
}
|
|
1319
1653
|
)
|
|
1320
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
|
+
),
|
|
1321
1704
|
messages.length > 0 && messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1322
1705
|
"div",
|
|
1323
1706
|
{
|
|
@@ -1372,6 +1755,153 @@ function QuickChat({
|
|
|
1372
1755
|
]
|
|
1373
1756
|
}
|
|
1374
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
|
+
),
|
|
1375
1905
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: quickChatStyles.inputContainer, children: [
|
|
1376
1906
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1377
1907
|
"textarea",
|
|
@@ -1438,8 +1968,8 @@ function QuickChat({
|
|
|
1438
1968
|
}
|
|
1439
1969
|
|
|
1440
1970
|
// src/ScreenshotPreview.tsx
|
|
1441
|
-
var
|
|
1442
|
-
var
|
|
1971
|
+
var import_react4 = __toESM(require("react"));
|
|
1972
|
+
var import_anyclick_core3 = require("@ewjdev/anyclick-core");
|
|
1443
1973
|
var import_lucide_react2 = require("lucide-react");
|
|
1444
1974
|
|
|
1445
1975
|
// src/styles.ts
|
|
@@ -1916,7 +2446,7 @@ var screenshotPreviewStyles = {
|
|
|
1916
2446
|
|
|
1917
2447
|
// src/ScreenshotPreview.tsx
|
|
1918
2448
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1919
|
-
var ScreenshotPreview =
|
|
2449
|
+
var ScreenshotPreview = import_react4.default.memo(function ScreenshotPreview2({
|
|
1920
2450
|
isLoading,
|
|
1921
2451
|
isSubmitting,
|
|
1922
2452
|
onCancel,
|
|
@@ -1924,12 +2454,12 @@ var ScreenshotPreview = import_react3.default.memo(function ScreenshotPreview2({
|
|
|
1924
2454
|
onRetake,
|
|
1925
2455
|
screenshots
|
|
1926
2456
|
}) {
|
|
1927
|
-
const [activeTab, setActiveTab] = (0,
|
|
1928
|
-
const [isExpanded, setIsExpanded] = (0,
|
|
2457
|
+
const [activeTab, setActiveTab] = (0, import_react4.useState)("element");
|
|
2458
|
+
const [isExpanded, setIsExpanded] = (0, import_react4.useState)(false);
|
|
1929
2459
|
const getError = (key) => {
|
|
1930
2460
|
return screenshots?.errors?.[key];
|
|
1931
2461
|
};
|
|
1932
|
-
const tabs = (0,
|
|
2462
|
+
const tabs = (0, import_react4.useMemo)(() => {
|
|
1933
2463
|
if (!screenshots) return [];
|
|
1934
2464
|
const allTabs = [
|
|
1935
2465
|
{
|
|
@@ -1953,8 +2483,8 @@ var ScreenshotPreview = import_react3.default.memo(function ScreenshotPreview2({
|
|
|
1953
2483
|
];
|
|
1954
2484
|
return allTabs.filter((tab) => tab.data || tab.error);
|
|
1955
2485
|
}, [screenshots]);
|
|
1956
|
-
const totalSize = (0,
|
|
1957
|
-
() => screenshots ? (0,
|
|
2486
|
+
const totalSize = (0, import_react4.useMemo)(
|
|
2487
|
+
() => screenshots ? (0, import_anyclick_core3.estimateTotalSize)(screenshots) : 0,
|
|
1958
2488
|
[screenshots]
|
|
1959
2489
|
);
|
|
1960
2490
|
if (isLoading) {
|
|
@@ -2018,7 +2548,7 @@ var ScreenshotPreview = import_react3.default.memo(function ScreenshotPreview2({
|
|
|
2018
2548
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: screenshotPreviewStyles.header, children: [
|
|
2019
2549
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: screenshotPreviewStyles.headerTitle, children: "Review Screenshots" }),
|
|
2020
2550
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: screenshotPreviewStyles.headerActions, children: [
|
|
2021
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: screenshotPreviewStyles.sizeLabel, children: (0,
|
|
2551
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: screenshotPreviewStyles.sizeLabel, children: (0, import_anyclick_core3.formatBytes)(totalSize) }),
|
|
2022
2552
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2023
2553
|
"button",
|
|
2024
2554
|
{
|
|
@@ -2050,7 +2580,7 @@ var ScreenshotPreview = import_react3.default.memo(function ScreenshotPreview2({
|
|
|
2050
2580
|
}
|
|
2051
2581
|
),
|
|
2052
2582
|
tab.label,
|
|
2053
|
-
tab.data && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: screenshotPreviewStyles.tabSize, children: (0,
|
|
2583
|
+
tab.data && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: screenshotPreviewStyles.tabSize, children: (0, import_anyclick_core3.formatBytes)(tab.data.sizeBytes) })
|
|
2054
2584
|
]
|
|
2055
2585
|
},
|
|
2056
2586
|
tab.key
|
|
@@ -2329,14 +2859,14 @@ var DefaultHeader = ({
|
|
|
2329
2859
|
children
|
|
2330
2860
|
] });
|
|
2331
2861
|
};
|
|
2332
|
-
var MenuItem =
|
|
2862
|
+
var MenuItem = import_react5.default.memo(function MenuItem2({
|
|
2333
2863
|
disabled,
|
|
2334
2864
|
hasChildren,
|
|
2335
2865
|
item,
|
|
2336
2866
|
onClick
|
|
2337
2867
|
}) {
|
|
2338
|
-
const [isHovered, setIsHovered] = (0,
|
|
2339
|
-
const [isPressed, setIsPressed] = (0,
|
|
2868
|
+
const [isHovered, setIsHovered] = (0, import_react5.useState)(false);
|
|
2869
|
+
const [isPressed, setIsPressed] = (0, import_react5.useState)(false);
|
|
2340
2870
|
const isComingSoon = item.status === "comingSoon";
|
|
2341
2871
|
const badgeLabel = item.badge?.label ?? (isComingSoon ? "Coming soon" : null);
|
|
2342
2872
|
const badgeTone = item.badge?.tone ?? (isComingSoon ? "neutral" : "neutral");
|
|
@@ -2373,11 +2903,11 @@ var MenuItem = import_react4.default.memo(function MenuItem2({
|
|
|
2373
2903
|
}
|
|
2374
2904
|
);
|
|
2375
2905
|
});
|
|
2376
|
-
var BackButton =
|
|
2906
|
+
var BackButton = import_react5.default.memo(function BackButton2({
|
|
2377
2907
|
onClick
|
|
2378
2908
|
}) {
|
|
2379
|
-
const [isHovered, setIsHovered] = (0,
|
|
2380
|
-
const [isPressed, setIsPressed] = (0,
|
|
2909
|
+
const [isHovered, setIsHovered] = (0, import_react5.useState)(false);
|
|
2910
|
+
const [isPressed, setIsPressed] = (0, import_react5.useState)(false);
|
|
2381
2911
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2382
2912
|
"button",
|
|
2383
2913
|
{
|
|
@@ -2404,20 +2934,20 @@ var BackButton = import_react4.default.memo(function BackButton2({
|
|
|
2404
2934
|
}
|
|
2405
2935
|
);
|
|
2406
2936
|
});
|
|
2407
|
-
var CommentForm =
|
|
2937
|
+
var CommentForm = import_react5.default.memo(function CommentForm2({
|
|
2408
2938
|
isSubmitting,
|
|
2409
2939
|
onCancel,
|
|
2410
2940
|
onSubmit
|
|
2411
2941
|
}) {
|
|
2412
|
-
const [comment, setComment] = (0,
|
|
2413
|
-
const inputRef = (0,
|
|
2414
|
-
(0,
|
|
2942
|
+
const [comment, setComment] = (0, import_react5.useState)("");
|
|
2943
|
+
const inputRef = (0, import_react5.useRef)(null);
|
|
2944
|
+
(0, import_react5.useEffect)(() => {
|
|
2415
2945
|
inputRef.current?.focus();
|
|
2416
2946
|
}, []);
|
|
2417
|
-
const handleSubmit = (0,
|
|
2947
|
+
const handleSubmit = (0, import_react5.useCallback)(() => {
|
|
2418
2948
|
onSubmit(comment);
|
|
2419
2949
|
}, [comment, onSubmit]);
|
|
2420
|
-
const handleKeyDown = (0,
|
|
2950
|
+
const handleKeyDown = (0, import_react5.useCallback)(
|
|
2421
2951
|
(e) => {
|
|
2422
2952
|
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
2423
2953
|
handleSubmit();
|
|
@@ -2505,13 +3035,13 @@ function ContextMenu({
|
|
|
2505
3035
|
targetElement,
|
|
2506
3036
|
visible
|
|
2507
3037
|
}) {
|
|
2508
|
-
const [selectedType, setSelectedType] = (0,
|
|
2509
|
-
const [currentView, setCurrentView] = (0,
|
|
2510
|
-
const [pendingComment, setPendingComment] = (0,
|
|
2511
|
-
const [submenuStack, setSubmenuStack] = (0,
|
|
2512
|
-
const [screenshots, setScreenshots] = (0,
|
|
2513
|
-
const [isCapturing, setIsCapturing] = (0,
|
|
2514
|
-
const [isQuickChatPinned, setIsQuickChatPinned] = (0,
|
|
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)(() => {
|
|
2515
3045
|
if (typeof window === "undefined") return false;
|
|
2516
3046
|
try {
|
|
2517
3047
|
return sessionStorage.getItem("anyclick-quick-chat-pinned") === "true";
|
|
@@ -2519,28 +3049,28 @@ function ContextMenu({
|
|
|
2519
3049
|
return false;
|
|
2520
3050
|
}
|
|
2521
3051
|
});
|
|
2522
|
-
const menuRef = (0,
|
|
2523
|
-
const [adjustedPosition, setAdjustedPosition] = (0,
|
|
2524
|
-
const [isDragging, setIsDragging] = (0,
|
|
2525
|
-
const [dragOffset, setDragOffset] = (0,
|
|
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)({
|
|
2526
3056
|
x: 0,
|
|
2527
3057
|
y: 0
|
|
2528
3058
|
});
|
|
2529
|
-
const dragStartRef = (0,
|
|
2530
|
-
const mergedScreenshotConfig =
|
|
3059
|
+
const dragStartRef = (0, import_react5.useRef)(null);
|
|
3060
|
+
const mergedScreenshotConfig = import_react5.default.useMemo(
|
|
2531
3061
|
() => ({
|
|
2532
|
-
...
|
|
3062
|
+
...import_anyclick_core4.DEFAULT_SCREENSHOT_CONFIG,
|
|
2533
3063
|
...screenshotConfig
|
|
2534
3064
|
}),
|
|
2535
3065
|
[screenshotConfig]
|
|
2536
3066
|
);
|
|
2537
|
-
const showPreview = mergedScreenshotConfig.showPreview && (0,
|
|
3067
|
+
const showPreview = mergedScreenshotConfig.showPreview && (0, import_anyclick_core4.isScreenshotSupported)();
|
|
2538
3068
|
const currentItems = submenuStack.length > 0 ? submenuStack[submenuStack.length - 1] : items;
|
|
2539
|
-
const captureScreenshots = (0,
|
|
3069
|
+
const captureScreenshots = (0, import_react5.useCallback)(async () => {
|
|
2540
3070
|
if (!targetElement || !showPreview) return;
|
|
2541
3071
|
setIsCapturing(true);
|
|
2542
3072
|
try {
|
|
2543
|
-
const captured = await (0,
|
|
3073
|
+
const captured = await (0, import_anyclick_core4.captureAllScreenshots)(
|
|
2544
3074
|
targetElement,
|
|
2545
3075
|
containerElement,
|
|
2546
3076
|
mergedScreenshotConfig
|
|
@@ -2553,7 +3083,7 @@ function ContextMenu({
|
|
|
2553
3083
|
setIsCapturing(false);
|
|
2554
3084
|
}
|
|
2555
3085
|
}, [containerElement, mergedScreenshotConfig, showPreview, targetElement]);
|
|
2556
|
-
(0,
|
|
3086
|
+
(0, import_react5.useEffect)(() => {
|
|
2557
3087
|
if (!visible) {
|
|
2558
3088
|
setSelectedType(null);
|
|
2559
3089
|
setCurrentView("menu");
|
|
@@ -2567,7 +3097,7 @@ function ContextMenu({
|
|
|
2567
3097
|
dragStartRef.current = null;
|
|
2568
3098
|
}
|
|
2569
3099
|
}, [visible]);
|
|
2570
|
-
(0,
|
|
3100
|
+
(0, import_react5.useEffect)(() => {
|
|
2571
3101
|
if (visible && targetElement) {
|
|
2572
3102
|
clearHighlights();
|
|
2573
3103
|
applyHighlights(targetElement, highlightConfig);
|
|
@@ -2578,7 +3108,7 @@ function ContextMenu({
|
|
|
2578
3108
|
clearHighlights();
|
|
2579
3109
|
};
|
|
2580
3110
|
}, [highlightConfig, targetElement, visible]);
|
|
2581
|
-
(0,
|
|
3111
|
+
(0, import_react5.useEffect)(() => {
|
|
2582
3112
|
if (!visible) {
|
|
2583
3113
|
return;
|
|
2584
3114
|
}
|
|
@@ -2597,13 +3127,13 @@ function ContextMenu({
|
|
|
2597
3127
|
document.removeEventListener("pointerdown", handlePointerDown);
|
|
2598
3128
|
};
|
|
2599
3129
|
}, [onClose, visible]);
|
|
2600
|
-
(0,
|
|
3130
|
+
(0, import_react5.useEffect)(() => {
|
|
2601
3131
|
if (visible) {
|
|
2602
3132
|
setAdjustedPosition(position);
|
|
2603
3133
|
setDragOffset({ x: 0, y: 0 });
|
|
2604
3134
|
}
|
|
2605
3135
|
}, [position.x, position.y, visible]);
|
|
2606
|
-
(0,
|
|
3136
|
+
(0, import_react5.useEffect)(() => {
|
|
2607
3137
|
if (!visible || !menuRef.current) return;
|
|
2608
3138
|
const updatePosition = () => {
|
|
2609
3139
|
const menuElement = menuRef.current;
|
|
@@ -2627,7 +3157,7 @@ function ContextMenu({
|
|
|
2627
3157
|
window.addEventListener("resize", updatePosition);
|
|
2628
3158
|
return () => window.removeEventListener("resize", updatePosition);
|
|
2629
3159
|
}, [currentView, dragOffset, position, positionMode, visible]);
|
|
2630
|
-
(0,
|
|
3160
|
+
(0, import_react5.useEffect)(() => {
|
|
2631
3161
|
if (!visible || positionMode !== "dynamic") return;
|
|
2632
3162
|
const handlePointerMove = (event) => {
|
|
2633
3163
|
if (!isDragging || !dragStartRef.current) return;
|
|
@@ -2654,7 +3184,7 @@ function ContextMenu({
|
|
|
2654
3184
|
};
|
|
2655
3185
|
}
|
|
2656
3186
|
}, [isDragging, positionMode, visible]);
|
|
2657
|
-
const handleDragStart = (0,
|
|
3187
|
+
const handleDragStart = (0, import_react5.useCallback)(
|
|
2658
3188
|
(event) => {
|
|
2659
3189
|
if (positionMode !== "dynamic") return;
|
|
2660
3190
|
event.preventDefault();
|
|
@@ -2663,8 +3193,8 @@ function ContextMenu({
|
|
|
2663
3193
|
},
|
|
2664
3194
|
[positionMode]
|
|
2665
3195
|
);
|
|
2666
|
-
const [initialChatInput, setInitialChatInput] = (0,
|
|
2667
|
-
(0,
|
|
3196
|
+
const [initialChatInput, setInitialChatInput] = (0, import_react5.useState)("");
|
|
3197
|
+
(0, import_react5.useEffect)(() => {
|
|
2668
3198
|
const handleKeyDown = (e) => {
|
|
2669
3199
|
if (e.key === "Escape") {
|
|
2670
3200
|
if (currentView === "screenshot-preview") {
|
|
@@ -2704,7 +3234,7 @@ function ContextMenu({
|
|
|
2704
3234
|
submenuStack.length,
|
|
2705
3235
|
visible
|
|
2706
3236
|
]);
|
|
2707
|
-
(0,
|
|
3237
|
+
(0, import_react5.useEffect)(() => {
|
|
2708
3238
|
const menuElement = menuRef.current;
|
|
2709
3239
|
if (!visible || !menuElement) return;
|
|
2710
3240
|
const preventTouchDefault = (e) => {
|
|
@@ -2952,18 +3482,18 @@ function ContextMenu({
|
|
|
2952
3482
|
}
|
|
2953
3483
|
|
|
2954
3484
|
// src/context.ts
|
|
2955
|
-
var
|
|
2956
|
-
var AnyclickContext = (0,
|
|
3485
|
+
var import_react6 = require("react");
|
|
3486
|
+
var AnyclickContext = (0, import_react6.createContext)(null);
|
|
2957
3487
|
var FeedbackContext = AnyclickContext;
|
|
2958
3488
|
function useAnyclick() {
|
|
2959
|
-
const context = (0,
|
|
3489
|
+
const context = (0, import_react6.useContext)(AnyclickContext);
|
|
2960
3490
|
if (!context) {
|
|
2961
3491
|
throw new Error("useAnyclick must be used within an AnyclickProvider");
|
|
2962
3492
|
}
|
|
2963
3493
|
return context;
|
|
2964
3494
|
}
|
|
2965
3495
|
function useFeedback() {
|
|
2966
|
-
const context = (0,
|
|
3496
|
+
const context = (0, import_react6.useContext)(AnyclickContext);
|
|
2967
3497
|
if (!context) {
|
|
2968
3498
|
throw new Error("useFeedback must be used within a FeedbackProvider");
|
|
2969
3499
|
}
|
|
@@ -2971,12 +3501,12 @@ function useFeedback() {
|
|
|
2971
3501
|
}
|
|
2972
3502
|
|
|
2973
3503
|
// src/store.ts
|
|
2974
|
-
var
|
|
3504
|
+
var import_zustand2 = require("zustand");
|
|
2975
3505
|
var providerIdCounter = 0;
|
|
2976
3506
|
function generateProviderId() {
|
|
2977
3507
|
return `anyclick-provider-${++providerIdCounter}`;
|
|
2978
3508
|
}
|
|
2979
|
-
var useProviderStore = (0,
|
|
3509
|
+
var useProviderStore = (0, import_zustand2.create)((set, get) => ({
|
|
2980
3510
|
providers: /* @__PURE__ */ new Map(),
|
|
2981
3511
|
findProvidersForElement: (element) => {
|
|
2982
3512
|
const { providers } = get();
|
|
@@ -3164,18 +3694,18 @@ function AnyclickProvider({
|
|
|
3164
3694
|
touchHoldDurationMs,
|
|
3165
3695
|
touchMoveThreshold
|
|
3166
3696
|
}) {
|
|
3167
|
-
const [isSubmitting, setIsSubmitting] = (0,
|
|
3168
|
-
const [menuVisible, setMenuVisible] = (0,
|
|
3169
|
-
const [menuPosition, setMenuPosition] = (0,
|
|
3170
|
-
const [targetElement, setTargetElement] = (0,
|
|
3171
|
-
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)(
|
|
3172
3702
|
null
|
|
3173
3703
|
);
|
|
3174
|
-
const providerId = (0,
|
|
3175
|
-
const containerRef = (0,
|
|
3176
|
-
const [containerReady, setContainerReady] = (0,
|
|
3177
|
-
const clientRef = (0,
|
|
3178
|
-
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)(
|
|
3179
3709
|
(node) => {
|
|
3180
3710
|
containerRef.current = node;
|
|
3181
3711
|
if (scoped && node) {
|
|
@@ -3204,7 +3734,7 @@ function AnyclickProvider({
|
|
|
3204
3734
|
updateProvider
|
|
3205
3735
|
} = useProviderStore();
|
|
3206
3736
|
const parentId = parentContext?.providerId ?? null;
|
|
3207
|
-
const actualDepth = (0,
|
|
3737
|
+
const actualDepth = (0, import_react7.useMemo)(() => {
|
|
3208
3738
|
if (!parentContext) return 0;
|
|
3209
3739
|
let d = 0;
|
|
3210
3740
|
let currentId = parentId;
|
|
@@ -3218,7 +3748,7 @@ function AnyclickProvider({
|
|
|
3218
3748
|
}, [parentContext, parentId]);
|
|
3219
3749
|
const isDisabledByTheme = theme === null || theme?.disabled === true;
|
|
3220
3750
|
const effectiveDisabled = disabled || isDisabledByTheme;
|
|
3221
|
-
const localTheme = (0,
|
|
3751
|
+
const localTheme = (0, import_react7.useMemo)(() => {
|
|
3222
3752
|
if (theme === null) {
|
|
3223
3753
|
return { disabled: true };
|
|
3224
3754
|
}
|
|
@@ -3233,7 +3763,7 @@ function AnyclickProvider({
|
|
|
3233
3763
|
...theme
|
|
3234
3764
|
};
|
|
3235
3765
|
}, [highlightConfig, menuClassName, menuStyle, screenshotConfig, theme]);
|
|
3236
|
-
const handleContextMenu = (0,
|
|
3766
|
+
const handleContextMenu = (0, import_react7.useCallback)(
|
|
3237
3767
|
(event, element) => {
|
|
3238
3768
|
if (!scoped && isElementInDisabledScope(element)) {
|
|
3239
3769
|
return false;
|
|
@@ -3261,7 +3791,7 @@ function AnyclickProvider({
|
|
|
3261
3791
|
scoped
|
|
3262
3792
|
]
|
|
3263
3793
|
);
|
|
3264
|
-
(0,
|
|
3794
|
+
(0, import_react7.useLayoutEffect)(() => {
|
|
3265
3795
|
const providerInstance = {
|
|
3266
3796
|
containerRef,
|
|
3267
3797
|
depth: actualDepth,
|
|
@@ -3287,7 +3817,7 @@ function AnyclickProvider({
|
|
|
3287
3817
|
scoped,
|
|
3288
3818
|
unregisterProvider
|
|
3289
3819
|
]);
|
|
3290
|
-
(0,
|
|
3820
|
+
(0, import_react7.useEffect)(() => {
|
|
3291
3821
|
updateProvider(providerId, {
|
|
3292
3822
|
disabled: effectiveDisabled,
|
|
3293
3823
|
onContextMenu: handleContextMenu,
|
|
@@ -3300,14 +3830,14 @@ function AnyclickProvider({
|
|
|
3300
3830
|
providerId,
|
|
3301
3831
|
updateProvider
|
|
3302
3832
|
]);
|
|
3303
|
-
(0,
|
|
3833
|
+
(0, import_react7.useEffect)(() => {
|
|
3304
3834
|
if (isDisabledByAncestor(providerId)) {
|
|
3305
3835
|
return;
|
|
3306
3836
|
}
|
|
3307
3837
|
if (scoped && !containerReady) {
|
|
3308
3838
|
return;
|
|
3309
3839
|
}
|
|
3310
|
-
const client = (0,
|
|
3840
|
+
const client = (0, import_anyclick_core5.createAnyclickClient)({
|
|
3311
3841
|
adapter,
|
|
3312
3842
|
container: scoped ? containerRef.current : null,
|
|
3313
3843
|
cooldownMs,
|
|
@@ -3348,7 +3878,7 @@ function AnyclickProvider({
|
|
|
3348
3878
|
touchHoldDurationMs,
|
|
3349
3879
|
touchMoveThreshold
|
|
3350
3880
|
]);
|
|
3351
|
-
const submitAnyclick = (0,
|
|
3881
|
+
const submitAnyclick = (0, import_react7.useCallback)(
|
|
3352
3882
|
async (element, type, comment, screenshots) => {
|
|
3353
3883
|
const client = clientRef.current;
|
|
3354
3884
|
if (!client) return;
|
|
@@ -3369,7 +3899,7 @@ function AnyclickProvider({
|
|
|
3369
3899
|
},
|
|
3370
3900
|
[metadata]
|
|
3371
3901
|
);
|
|
3372
|
-
const openMenu = (0,
|
|
3902
|
+
const openMenu = (0, import_react7.useCallback)(
|
|
3373
3903
|
(element, position) => {
|
|
3374
3904
|
setTargetElement(element);
|
|
3375
3905
|
const mergedTheme2 = getMergedTheme(providerId);
|
|
@@ -3383,13 +3913,13 @@ function AnyclickProvider({
|
|
|
3383
3913
|
},
|
|
3384
3914
|
[getMergedTheme, highlightConfig, providerId]
|
|
3385
3915
|
);
|
|
3386
|
-
const closeMenu = (0,
|
|
3916
|
+
const closeMenu = (0, import_react7.useCallback)(() => {
|
|
3387
3917
|
setMenuVisible(false);
|
|
3388
3918
|
setMenuPosition(OFFSCREEN_POSITION2);
|
|
3389
3919
|
setTargetElement(null);
|
|
3390
3920
|
setContainerElement(null);
|
|
3391
3921
|
}, []);
|
|
3392
|
-
const handleMenuSelect = (0,
|
|
3922
|
+
const handleMenuSelect = (0, import_react7.useCallback)(
|
|
3393
3923
|
(type, comment, screenshots) => {
|
|
3394
3924
|
if (targetElement) {
|
|
3395
3925
|
submitAnyclick(targetElement, type, comment, screenshots);
|
|
@@ -3398,7 +3928,7 @@ function AnyclickProvider({
|
|
|
3398
3928
|
[submitAnyclick, targetElement]
|
|
3399
3929
|
);
|
|
3400
3930
|
const inheritedTheme = getMergedTheme(providerId);
|
|
3401
|
-
const mergedTheme = (0,
|
|
3931
|
+
const mergedTheme = (0, import_react7.useMemo)(
|
|
3402
3932
|
() => ({
|
|
3403
3933
|
...inheritedTheme,
|
|
3404
3934
|
...localTheme,
|
|
@@ -3421,7 +3951,7 @@ function AnyclickProvider({
|
|
|
3421
3951
|
const effectiveMenuClassName = mergedTheme.menuClassName ?? menuClassName;
|
|
3422
3952
|
const effectiveHighlightConfig = mergedTheme.highlightConfig ?? highlightConfig;
|
|
3423
3953
|
const effectiveScreenshotConfig = mergedTheme.screenshotConfig ?? screenshotConfig;
|
|
3424
|
-
const contextValue = (0,
|
|
3954
|
+
const contextValue = (0, import_react7.useMemo)(
|
|
3425
3955
|
() => ({
|
|
3426
3956
|
closeMenu,
|
|
3427
3957
|
isEnabled: !effectiveDisabled && !isDisabledByAncestor(providerId),
|
|
@@ -3453,7 +3983,7 @@ function AnyclickProvider({
|
|
|
3453
3983
|
children
|
|
3454
3984
|
}
|
|
3455
3985
|
) : children;
|
|
3456
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.
|
|
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: [
|
|
3457
3987
|
content,
|
|
3458
3988
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3459
3989
|
ContextMenu,
|
|
@@ -3474,12 +4004,12 @@ function AnyclickProvider({
|
|
|
3474
4004
|
visible: menuVisible && !effectiveDisabled
|
|
3475
4005
|
}
|
|
3476
4006
|
)
|
|
3477
|
-
] });
|
|
4007
|
+
] }) });
|
|
3478
4008
|
}
|
|
3479
4009
|
var FeedbackProvider = AnyclickProvider;
|
|
3480
4010
|
|
|
3481
4011
|
// src/FunModeBridge.tsx
|
|
3482
|
-
var
|
|
4012
|
+
var import_react8 = require("react");
|
|
3483
4013
|
var import_anyclick_pointer = require("@ewjdev/anyclick-pointer");
|
|
3484
4014
|
function isFunModeEnabled(theme) {
|
|
3485
4015
|
if (!theme) return false;
|
|
@@ -3526,9 +4056,9 @@ function buildFunConfig(theme, container) {
|
|
|
3526
4056
|
function FunModeBridge() {
|
|
3527
4057
|
const { setConfig } = (0, import_anyclick_pointer.usePointer)();
|
|
3528
4058
|
const providerStore = useProviderStore();
|
|
3529
|
-
const activeProviderRef = (0,
|
|
3530
|
-
const cachedConfigs = (0,
|
|
3531
|
-
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)(() => {
|
|
3532
4062
|
return (el) => {
|
|
3533
4063
|
if (!el) return null;
|
|
3534
4064
|
const providers = providerStore.findProvidersForElement(el);
|
|
@@ -3540,7 +4070,7 @@ function FunModeBridge() {
|
|
|
3540
4070
|
return null;
|
|
3541
4071
|
};
|
|
3542
4072
|
}, [providerStore]);
|
|
3543
|
-
(0,
|
|
4073
|
+
(0, import_react8.useEffect)(() => {
|
|
3544
4074
|
const handleMove = (event) => {
|
|
3545
4075
|
const el = document.elementFromPoint(event.clientX, event.clientY);
|
|
3546
4076
|
const provider = findActiveFunProvider(el);
|
|
@@ -3574,12 +4104,72 @@ function FunModeBridge() {
|
|
|
3574
4104
|
return null;
|
|
3575
4105
|
}
|
|
3576
4106
|
|
|
3577
|
-
// src/
|
|
4107
|
+
// src/ui/button.tsx
|
|
3578
4108
|
var import_react9 = require("react");
|
|
3579
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
|
+
|
|
4167
|
+
// src/InspectDialog/InspectDialogManager.tsx
|
|
4168
|
+
var import_react12 = require("react");
|
|
4169
|
+
|
|
3580
4170
|
// src/InspectDialog/InspectSimple.tsx
|
|
3581
|
-
var
|
|
3582
|
-
var
|
|
4171
|
+
var import_react11 = require("react");
|
|
4172
|
+
var import_anyclick_core6 = require("@ewjdev/anyclick-core");
|
|
3583
4173
|
var import_lucide_react4 = require("lucide-react");
|
|
3584
4174
|
|
|
3585
4175
|
// src/ide.ts
|
|
@@ -3682,7 +4272,7 @@ function formatSourceLocation(location) {
|
|
|
3682
4272
|
}
|
|
3683
4273
|
|
|
3684
4274
|
// src/InspectDialog/InspectSimple.tsx
|
|
3685
|
-
var
|
|
4275
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
3686
4276
|
var DEFAULT_COMPACT_CONFIG = {
|
|
3687
4277
|
scale: 0.5,
|
|
3688
4278
|
fonts: {
|
|
@@ -3744,8 +4334,8 @@ function downloadDataUrl(dataUrl, filename) {
|
|
|
3744
4334
|
link.click();
|
|
3745
4335
|
}
|
|
3746
4336
|
function useIsMobile() {
|
|
3747
|
-
const [isMobile, setIsMobile] = (0,
|
|
3748
|
-
(0,
|
|
4337
|
+
const [isMobile, setIsMobile] = (0, import_react11.useState)(false);
|
|
4338
|
+
(0, import_react11.useEffect)(() => {
|
|
3749
4339
|
const mq = window.matchMedia("(max-width: 640px)");
|
|
3750
4340
|
setIsMobile(mq.matches);
|
|
3751
4341
|
const handler = (e) => setIsMobile(e.matches);
|
|
@@ -3763,20 +4353,20 @@ function InspectSimple({
|
|
|
3763
4353
|
className,
|
|
3764
4354
|
highlightColors
|
|
3765
4355
|
}) {
|
|
3766
|
-
const [info, setInfo] = (0,
|
|
3767
|
-
const [sourceLocation, setSourceLocation] = (0,
|
|
4356
|
+
const [info, setInfo] = (0, import_react11.useState)(null);
|
|
4357
|
+
const [sourceLocation, setSourceLocation] = (0, import_react11.useState)(
|
|
3768
4358
|
null
|
|
3769
4359
|
);
|
|
3770
|
-
const [status, setStatus] = (0,
|
|
3771
|
-
const [saving, setSaving] = (0,
|
|
3772
|
-
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);
|
|
3773
4363
|
const isMobile = useIsMobile();
|
|
3774
|
-
(0,
|
|
4364
|
+
(0, import_react11.useEffect)(() => {
|
|
3775
4365
|
if (!status) return;
|
|
3776
4366
|
const timer = setTimeout(() => setStatus(null), 5e3);
|
|
3777
4367
|
return () => clearTimeout(timer);
|
|
3778
4368
|
}, [status]);
|
|
3779
|
-
(0,
|
|
4369
|
+
(0, import_react11.useEffect)(() => {
|
|
3780
4370
|
if (!visible || !targetElement) return;
|
|
3781
4371
|
try {
|
|
3782
4372
|
clearHighlights();
|
|
@@ -3785,7 +4375,7 @@ function InspectSimple({
|
|
|
3785
4375
|
if (container) highlightContainer(container, highlightColors);
|
|
3786
4376
|
} catch {
|
|
3787
4377
|
}
|
|
3788
|
-
const nextInfo = (0,
|
|
4378
|
+
const nextInfo = (0, import_anyclick_core6.getElementInspectInfo)(targetElement);
|
|
3789
4379
|
setInfo(nextInfo);
|
|
3790
4380
|
setSourceLocation(
|
|
3791
4381
|
findSourceLocationInAncestors(targetElement) ?? nextInfo.sourceLocation ?? null
|
|
@@ -3794,7 +4384,7 @@ function InspectSimple({
|
|
|
3794
4384
|
clearHighlights();
|
|
3795
4385
|
};
|
|
3796
4386
|
}, [visible, targetElement, highlightColors]);
|
|
3797
|
-
(0,
|
|
4387
|
+
(0, import_react11.useEffect)(() => {
|
|
3798
4388
|
if (!visible) return;
|
|
3799
4389
|
const handleClickOutside = (e) => {
|
|
3800
4390
|
if (dialogRef.current && !dialogRef.current.contains(e.target)) {
|
|
@@ -3809,7 +4399,7 @@ function InspectSimple({
|
|
|
3809
4399
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
3810
4400
|
};
|
|
3811
4401
|
}, [visible, onClose]);
|
|
3812
|
-
const identityLabel = (0,
|
|
4402
|
+
const identityLabel = (0, import_react11.useMemo)(() => {
|
|
3813
4403
|
if (!info) return "Select an element";
|
|
3814
4404
|
const classes = info.classNames[0] ? `.${info.classNames[0]}` : "";
|
|
3815
4405
|
const id = info.id ? `#${info.id}` : "";
|
|
@@ -3839,7 +4429,7 @@ function InspectSimple({
|
|
|
3839
4429
|
if (!targetElement) return;
|
|
3840
4430
|
setSaving(true);
|
|
3841
4431
|
setStatus("Capturing screenshot\u2026");
|
|
3842
|
-
const result = await (0,
|
|
4432
|
+
const result = await (0, import_anyclick_core6.captureScreenshot)(targetElement, null, "element");
|
|
3843
4433
|
setSaving(false);
|
|
3844
4434
|
if (result.capture?.dataUrl) {
|
|
3845
4435
|
downloadDataUrl(result.capture.dataUrl, "anyclick-inspect.png");
|
|
@@ -3895,8 +4485,8 @@ function InspectSimple({
|
|
|
3895
4485
|
overflow: "hidden",
|
|
3896
4486
|
...style
|
|
3897
4487
|
};
|
|
3898
|
-
return /* @__PURE__ */ (0,
|
|
3899
|
-
/* @__PURE__ */ (0,
|
|
4488
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
4489
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3900
4490
|
"div",
|
|
3901
4491
|
{
|
|
3902
4492
|
style: {
|
|
@@ -3911,14 +4501,14 @@ function InspectSimple({
|
|
|
3911
4501
|
role: "presentation"
|
|
3912
4502
|
}
|
|
3913
4503
|
),
|
|
3914
|
-
/* @__PURE__ */ (0,
|
|
4504
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3915
4505
|
"div",
|
|
3916
4506
|
{
|
|
3917
4507
|
ref: dialogRef,
|
|
3918
4508
|
className: `anyclick-tiny-inspect ${className ?? ""}`,
|
|
3919
4509
|
style: dialogStyles,
|
|
3920
4510
|
children: [
|
|
3921
|
-
/* @__PURE__ */ (0,
|
|
4511
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3922
4512
|
"div",
|
|
3923
4513
|
{
|
|
3924
4514
|
style: {
|
|
@@ -3930,7 +4520,7 @@ function InspectSimple({
|
|
|
3930
4520
|
borderBottom: "1px solid #1e293b"
|
|
3931
4521
|
},
|
|
3932
4522
|
children: [
|
|
3933
|
-
isMobile && /* @__PURE__ */ (0,
|
|
4523
|
+
isMobile && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3934
4524
|
"div",
|
|
3935
4525
|
{
|
|
3936
4526
|
style: {
|
|
@@ -3945,8 +4535,8 @@ function InspectSimple({
|
|
|
3945
4535
|
}
|
|
3946
4536
|
}
|
|
3947
4537
|
),
|
|
3948
|
-
/* @__PURE__ */ (0,
|
|
3949
|
-
/* @__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)(
|
|
3950
4540
|
"span",
|
|
3951
4541
|
{
|
|
3952
4542
|
style: {
|
|
@@ -3961,31 +4551,31 @@ function InspectSimple({
|
|
|
3961
4551
|
children: identityLabel
|
|
3962
4552
|
}
|
|
3963
4553
|
),
|
|
3964
|
-
sourceLocation && /* @__PURE__ */ (0,
|
|
4554
|
+
sourceLocation && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3965
4555
|
"button",
|
|
3966
4556
|
{
|
|
3967
4557
|
type: "button",
|
|
3968
4558
|
onClick: handleOpenIDE,
|
|
3969
4559
|
title: formatSourceLocation(sourceLocation),
|
|
3970
4560
|
style: iconBtnStyle,
|
|
3971
|
-
children: /* @__PURE__ */ (0,
|
|
4561
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.ExternalLink, { size: 14 })
|
|
3972
4562
|
}
|
|
3973
4563
|
)
|
|
3974
4564
|
] }),
|
|
3975
|
-
/* @__PURE__ */ (0,
|
|
4565
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3976
4566
|
"button",
|
|
3977
4567
|
{
|
|
3978
4568
|
type: "button",
|
|
3979
4569
|
onClick: onClose,
|
|
3980
4570
|
style: iconBtnStyle,
|
|
3981
4571
|
"aria-label": "Close inspector",
|
|
3982
|
-
children: /* @__PURE__ */ (0,
|
|
4572
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.X, { size: 16 })
|
|
3983
4573
|
}
|
|
3984
4574
|
)
|
|
3985
4575
|
]
|
|
3986
4576
|
}
|
|
3987
4577
|
),
|
|
3988
|
-
/* @__PURE__ */ (0,
|
|
4578
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3989
4579
|
"div",
|
|
3990
4580
|
{
|
|
3991
4581
|
style: {
|
|
@@ -3995,7 +4585,7 @@ function InspectSimple({
|
|
|
3995
4585
|
gap: 8
|
|
3996
4586
|
},
|
|
3997
4587
|
children: [
|
|
3998
|
-
info?.selector && /* @__PURE__ */ (0,
|
|
4588
|
+
info?.selector && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3999
4589
|
"code",
|
|
4000
4590
|
{
|
|
4001
4591
|
style: {
|
|
@@ -4010,7 +4600,7 @@ function InspectSimple({
|
|
|
4010
4600
|
children: info.selector
|
|
4011
4601
|
}
|
|
4012
4602
|
),
|
|
4013
|
-
status && /* @__PURE__ */ (0,
|
|
4603
|
+
status && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4014
4604
|
"div",
|
|
4015
4605
|
{
|
|
4016
4606
|
style: {
|
|
@@ -4022,7 +4612,7 @@ function InspectSimple({
|
|
|
4022
4612
|
children: status
|
|
4023
4613
|
}
|
|
4024
4614
|
),
|
|
4025
|
-
/* @__PURE__ */ (0,
|
|
4615
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
4026
4616
|
"div",
|
|
4027
4617
|
{
|
|
4028
4618
|
style: {
|
|
@@ -4031,7 +4621,7 @@ function InspectSimple({
|
|
|
4031
4621
|
gap: 6
|
|
4032
4622
|
},
|
|
4033
4623
|
children: [
|
|
4034
|
-
/* @__PURE__ */ (0,
|
|
4624
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4035
4625
|
"button",
|
|
4036
4626
|
{
|
|
4037
4627
|
type: "button",
|
|
@@ -4039,10 +4629,10 @@ function InspectSimple({
|
|
|
4039
4629
|
style: iconActionStyle,
|
|
4040
4630
|
title: "Copy CSS selector",
|
|
4041
4631
|
"aria-label": "Copy CSS selector",
|
|
4042
|
-
children: /* @__PURE__ */ (0,
|
|
4632
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.Copy, { size: 15 })
|
|
4043
4633
|
}
|
|
4044
4634
|
),
|
|
4045
|
-
/* @__PURE__ */ (0,
|
|
4635
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4046
4636
|
"button",
|
|
4047
4637
|
{
|
|
4048
4638
|
type: "button",
|
|
@@ -4050,10 +4640,10 @@ function InspectSimple({
|
|
|
4050
4640
|
style: iconActionStyle,
|
|
4051
4641
|
title: "Copy text content",
|
|
4052
4642
|
"aria-label": "Copy text content",
|
|
4053
|
-
children: /* @__PURE__ */ (0,
|
|
4643
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.FileText, { size: 15 })
|
|
4054
4644
|
}
|
|
4055
4645
|
),
|
|
4056
|
-
/* @__PURE__ */ (0,
|
|
4646
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4057
4647
|
"button",
|
|
4058
4648
|
{
|
|
4059
4649
|
type: "button",
|
|
@@ -4061,10 +4651,10 @@ function InspectSimple({
|
|
|
4061
4651
|
style: iconActionStyle,
|
|
4062
4652
|
title: "Copy HTML markup",
|
|
4063
4653
|
"aria-label": "Copy HTML markup",
|
|
4064
|
-
children: /* @__PURE__ */ (0,
|
|
4654
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.Code, { size: 15 })
|
|
4065
4655
|
}
|
|
4066
4656
|
),
|
|
4067
|
-
/* @__PURE__ */ (0,
|
|
4657
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
4068
4658
|
"button",
|
|
4069
4659
|
{
|
|
4070
4660
|
type: "button",
|
|
@@ -4076,7 +4666,7 @@ function InspectSimple({
|
|
|
4076
4666
|
disabled: saving,
|
|
4077
4667
|
title: "Save screenshot",
|
|
4078
4668
|
"aria-label": "Save screenshot",
|
|
4079
|
-
children: /* @__PURE__ */ (0,
|
|
4669
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react4.Camera, { size: 15 })
|
|
4080
4670
|
}
|
|
4081
4671
|
)
|
|
4082
4672
|
]
|
|
@@ -4119,7 +4709,7 @@ var iconActionStyle = {
|
|
|
4119
4709
|
};
|
|
4120
4710
|
|
|
4121
4711
|
// src/InspectDialog/InspectDialogManager.tsx
|
|
4122
|
-
var
|
|
4712
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
4123
4713
|
var INSPECT_DIALOG_EVENT = "anyclick:inspect";
|
|
4124
4714
|
function openInspectDialog(targetElement) {
|
|
4125
4715
|
if (typeof window === "undefined") return;
|
|
@@ -4142,16 +4732,16 @@ function InspectDialogManager({
|
|
|
4142
4732
|
initialPinnedPosition = "floating",
|
|
4143
4733
|
compactConfig
|
|
4144
4734
|
}) {
|
|
4145
|
-
const [visible, setVisible] = (0,
|
|
4146
|
-
const [targetElement, setTargetElement] = (0,
|
|
4147
|
-
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)(() => {
|
|
4148
4738
|
setVisible(false);
|
|
4149
4739
|
setTargetElement(null);
|
|
4150
4740
|
}, []);
|
|
4151
|
-
const handleSelectElement = (0,
|
|
4741
|
+
const handleSelectElement = (0, import_react12.useCallback)((element) => {
|
|
4152
4742
|
setTargetElement(element);
|
|
4153
4743
|
}, []);
|
|
4154
|
-
(0,
|
|
4744
|
+
(0, import_react12.useEffect)(() => {
|
|
4155
4745
|
const handleInspectEvent = (event) => {
|
|
4156
4746
|
const customEvent = event;
|
|
4157
4747
|
if (customEvent.detail?.targetElement) {
|
|
@@ -4164,7 +4754,7 @@ function InspectDialogManager({
|
|
|
4164
4754
|
window.removeEventListener(INSPECT_DIALOG_EVENT, handleInspectEvent);
|
|
4165
4755
|
};
|
|
4166
4756
|
}, []);
|
|
4167
|
-
return /* @__PURE__ */ (0,
|
|
4757
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
4168
4758
|
InspectSimple,
|
|
4169
4759
|
{
|
|
4170
4760
|
visible,
|
|
@@ -4693,10 +5283,10 @@ function filterMenuItemsByRole(items, userContext) {
|
|
|
4693
5283
|
}
|
|
4694
5284
|
|
|
4695
5285
|
// src/index.ts
|
|
4696
|
-
var
|
|
5286
|
+
var import_anyclick_core7 = require("@ewjdev/anyclick-core");
|
|
4697
5287
|
|
|
4698
5288
|
// src/AnyclickLogo.tsx
|
|
4699
|
-
var
|
|
5289
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
4700
5290
|
function AnyclickLogo({
|
|
4701
5291
|
size = 64,
|
|
4702
5292
|
borderWidth = 2,
|
|
@@ -4708,7 +5298,7 @@ function AnyclickLogo({
|
|
|
4708
5298
|
}) {
|
|
4709
5299
|
const cursorSize = size * 0.45;
|
|
4710
5300
|
const cursorStroke = borderWidth;
|
|
4711
|
-
return /* @__PURE__ */ (0,
|
|
5301
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
4712
5302
|
"svg",
|
|
4713
5303
|
{
|
|
4714
5304
|
width: size,
|
|
@@ -4722,7 +5312,7 @@ function AnyclickLogo({
|
|
|
4722
5312
|
role: onClick ? "button" : "img",
|
|
4723
5313
|
"aria-label": "Anyclick Logo",
|
|
4724
5314
|
children: [
|
|
4725
|
-
/* @__PURE__ */ (0,
|
|
5315
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4726
5316
|
"circle",
|
|
4727
5317
|
{
|
|
4728
5318
|
cx: size / 2,
|
|
@@ -4733,11 +5323,11 @@ function AnyclickLogo({
|
|
|
4733
5323
|
strokeWidth: borderWidth
|
|
4734
5324
|
}
|
|
4735
5325
|
),
|
|
4736
|
-
/* @__PURE__ */ (0,
|
|
5326
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4737
5327
|
"g",
|
|
4738
5328
|
{
|
|
4739
5329
|
transform: `translate(${(size - cursorSize) / 2}, ${(size - cursorSize) / 2})`,
|
|
4740
|
-
children: /* @__PURE__ */ (0,
|
|
5330
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
4741
5331
|
"path",
|
|
4742
5332
|
{
|
|
4743
5333
|
d: `
|
|
@@ -4765,13 +5355,14 @@ function AnyclickLogo({
|
|
|
4765
5355
|
}
|
|
4766
5356
|
|
|
4767
5357
|
// src/index.ts
|
|
4768
|
-
var
|
|
5358
|
+
var import_anyclick_core8 = require("@ewjdev/anyclick-core");
|
|
4769
5359
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4770
5360
|
0 && (module.exports = {
|
|
4771
5361
|
ALL_CURATED_PROPERTIES,
|
|
4772
5362
|
AnyclickContext,
|
|
4773
5363
|
AnyclickLogo,
|
|
4774
5364
|
AnyclickProvider,
|
|
5365
|
+
Button,
|
|
4775
5366
|
CURATED_STYLE_PROPERTIES,
|
|
4776
5367
|
ContextMenu,
|
|
4777
5368
|
DEFAULT_COMPACT_CONFIG,
|
|
@@ -4782,6 +5373,7 @@ var import_anyclick_core7 = require("@ewjdev/anyclick-core");
|
|
|
4782
5373
|
FeedbackProvider,
|
|
4783
5374
|
FunModeBridge,
|
|
4784
5375
|
INSPECT_DIALOG_EVENT,
|
|
5376
|
+
Input,
|
|
4785
5377
|
InspectDialogManager,
|
|
4786
5378
|
InspectSimple,
|
|
4787
5379
|
QuickChat,
|