Skip to content

[VSCode Extension] Fix MacOs drag & drop issue #847

@Ivanruii

Description

@Ivanruii

Dragging a component from the gallery into the canvas had no effect when the QuickMock app was running inside the VS Code extension on macOS. The drag preview followed the cursor correctly, but releasing over the canvas did not insert the shape.

The same flow worked correctly in:

  • A standalone browser on macOS.
  • The VS Code extension on Linux and Windows.

Root cause

The QuickMock editor inside the extension lives in a doubly-nested frame structure.

The drag-and-drop implementation uses pragmatic-drag-and-drop, which relies on the HTML5 native Drag and Drop API (dragover, dragenter, drop).

On macOS, Chromium routes drag events to the <iframe> element in the parent webview shell instead of into the iframe's own document. This means the gallery's dragstart originates inside the iframe, but during the drag operation the inner document never receives any tracking events.

pragmatic-drag-and-drop's drop targets therefore never activate, dropTargets is empty when the drag ends, and the callback that would insert the shape is never invoked.

This is a documented platform issue:

  • microsoft/vscode#193558"Only on macOS, some drag-and-drop interactions fail in webview" (open, labeled bug, help wanted, and webview).
  • microsoft/vscode#147148, microsoft/vscode#139111 — same family of issues, now closed.
  • microsoft/vscode#256444 — related drag interception across webviews.
  • Chromium issues 251718 and 936299 — HTML5 drag events not delivered to cross-origin / nested iframes.
  • electron/electron#... — specific drag handling issues in Electron webviews (CoreDragCreate).

VS Code maintainers have explicitly stated they do not currently plan to fix it, so the workaround has to live on the consumer side.

How the diagnosis was confirmed

We instrumented every layer with capture-phase sniffers:

  • window
  • document
  • document.body
  • The canvas drop target inside the iframe
  • A parallel sniffer in the webview shell

During a failing drag operation on macOS:

  • The iframe's document received no dragover, dragenter, or drop events. Only dragstart and the terminal dragend were observed.
  • The webview shell received the entire stream of dragover events with:
    • target: 'IFRAME'
    • Correct cursor coordinates

This confirmed that the events existed at the OS / shell level but were not being propagated into the iframe's content document.

It also demonstrated that the shell still had access to the drag stream, making it possible to bridge the missing events manually.

Fix

A small message-passing bridge was implemented between the webview shell and the inner iframe, scoped specifically to the gallery → canvas drop flow.

1. Drag lifecycle events

When a drag starts in the gallery, the iframe posts:

{ type: 'qm:drag-start' }

When the drag ends, it posts:

{ type: 'qm:drag-end' }

2. Shell-side drag interception

The shell tracks whether a gallery drag is active.

While active:

  • The shell calls preventDefault() on dragover (required for the browser to emit drop).
  • On drop, the shell posts:
{
  type: 'qm:gallery-drop',
  x,
  y
}

back to the iframe, with coordinates translated relative to the iframe bounds.

3. Iframe-side drop reconstruction

A new hook inside the iframe listens for:

qm:gallery-drop

The hook:

  1. Converts the coordinates using the same logic as the existing pragmatic-drag-and-drop path.
  2. Calls addNewShape(...) directly.

This bypasses the missing native drag propagation while preserving the existing insertion logic and coordinate system.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions