-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Fix image drop from main editor #8339
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
aae1974
2f5757f
b238659
3675d3b
68e9e6e
f9079ea
4bdca1a
2a04f4e
4a86b55
7e42234
07b0963
07ecdcd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -686,6 +686,18 @@ export class VsCodeMessenger { | |
| }); | ||
| }); | ||
|
|
||
| this.onWebviewOrCore("readFileAsDataUrl", async (msg) => { | ||
| const { filepath } = msg.data; | ||
| const fileUri = vscode.Uri.file(filepath); | ||
| const fileContents = await vscode.workspace.fs.readFile(fileUri); | ||
| const fileType = | ||
| filepath.split(".").pop() === "png" ? "image/png" : "image/jpeg"; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. JPEG fallback will cause various types to fail, could we add a few more common fileTypes here? |
||
| const dataUrl = `data:${fileType};base64,${Buffer.from( | ||
| fileContents, | ||
| ).toString("base64")}`; | ||
| return dataUrl; | ||
| }); | ||
|
|
||
| this.onWebviewOrCore("getIdeSettings", async (msg) => { | ||
| return ide.getIdeSettings(); | ||
| }); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,7 +27,7 @@ import { | |
| getContextProviderDropdownOptions, | ||
| getSlashCommandDropdownOptions, | ||
| } from "./getSuggestion"; | ||
| import { handleImageFile } from "./imageUtils"; | ||
| import { handleImageFile, handleVSCodeResourceFromHtml } from "./imageUtils"; | ||
|
|
||
| export function getPlaceholderText( | ||
| placeholder: TipTapEditorProps["placeholder"], | ||
|
|
@@ -69,8 +69,9 @@ export function createEditorConfig(options: { | |
| props: TipTapEditorProps; | ||
| ideMessenger: IIdeMessenger; | ||
| dispatch: AppDispatch; | ||
| setShowDragOverMsg: (show: boolean) => void; | ||
| }) { | ||
| const { props, ideMessenger, dispatch } = options; | ||
| const { props, ideMessenger, dispatch, setShowDragOverMsg } = options; | ||
|
|
||
| const posthog = usePostHog(); | ||
|
|
||
|
|
@@ -147,6 +148,80 @@ export function createEditorConfig(options: { | |
| const plugin = new Plugin({ | ||
| props: { | ||
| handleDOMEvents: { | ||
| drop(view, event) { | ||
| // Hide drag overlay immediately when drop is handled | ||
| setShowDragOverMsg(false); | ||
|
|
||
| // Get current model and check if it supports images | ||
| const model = defaultModelRef.current; | ||
| if ( | ||
| !model || | ||
| !modelSupportsImages( | ||
| model.provider, | ||
| model.model, | ||
| model.title, | ||
| model.capabilities, | ||
| ) | ||
| ) { | ||
| event.preventDefault(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Preventing default before checking the payload swallows non-image drops; plain-text drag-and-drop now does nothing. Only block the event when you actually handle it, or fall back to the default insertion flow. Prompt for AI agents |
||
| event.stopPropagation(); | ||
| return true; | ||
| } | ||
|
|
||
| event.preventDefault(); | ||
| event.stopPropagation(); | ||
|
|
||
| // Check if dataTransfer exists | ||
| if (!event.dataTransfer) { | ||
| return true; | ||
| } | ||
|
|
||
| // Handle file drop first | ||
| if (event.dataTransfer.files.length > 0) { | ||
| const file = event.dataTransfer.files[0]; | ||
| void handleImageFile(ideMessenger, file).then((result) => { | ||
| if (result) { | ||
| const [_, dataUrl] = result; | ||
| const { schema } = view.state; | ||
| const node = schema.nodes.image.create({ | ||
| src: dataUrl, | ||
| }); | ||
| const tr = view.state.tr.insert(0, node); | ||
| view.dispatch(tr); | ||
| } | ||
| }); | ||
| return true; | ||
| } | ||
|
|
||
| // Handle drop of HTML content (including VS Code resource URLs) | ||
| const html = event.dataTransfer.getData("text/html"); | ||
| if (html) { | ||
| void handleVSCodeResourceFromHtml(ideMessenger, html) | ||
| .then((dataUrl) => { | ||
| if (dataUrl) { | ||
| const { schema } = view.state; | ||
| const node = schema.nodes.image.create({ | ||
| src: dataUrl, | ||
| }); | ||
| const tr = view.state.tr.insert(0, node); | ||
| view.dispatch(tr); | ||
| } | ||
| }) | ||
| .catch((err) => | ||
| console.error( | ||
| "Failed to handle VS Code resource:", | ||
| err, | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| return true; | ||
| }, | ||
| dragover(view, event) { | ||
| // Allow dragover for proper drop handling | ||
| event.preventDefault(); | ||
| return true; | ||
| }, | ||
| paste(view, event) { | ||
| const model = defaultModelRef.current; | ||
| if (!model) return; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can leave this build script out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure will make this changes this weekend.