fix(tab-split): drop editor tabs onto browser-tab panes#1006
Open
brennanb2025 wants to merge 4 commits intomainfrom
Open
fix(tab-split): drop editor tabs onto browser-tab panes#1006brennanb2025 wants to merge 4 commits intomainfrom
brennanb2025 wants to merge 4 commits intomainfrom
Conversation
Root cause: Electron `<webview>` guests run in a separate Chromium process and capture pointerup off the host renderer's event loop. During a dnd-kit tab drag, the drag-over overlay appeared (blue rectangle), but pointerup landed in the guest instead of document, so onDragEnd never fired and the drop silently did nothing. Flip `pointer-events: none` on every registered webview for the duration of an active tab drag so the host's PointerSensor sees the release. HTML5-drag listeners in BrowserPane keep their original purpose (drag-out of images/text); dnd-kit pointer drags now toggle the same passthrough via a useEffect keyed on activeDrag, and cleanup restores input even if the hook unmounts mid-drag. - New `webview-drag-passthrough.ts` owns the webview set + toggle helper so useTabDragSplit can call it without importing BrowserPane. - BrowserPane registers each created webview and unregisters on destroy.
Vite HMR reloads `webview-drag-passthrough.ts` in isolation, replacing the module-level `registry` Set with a fresh empty one. But the live `<webview>` elements are registered once from BrowserPane's "create new webview" branch (not on every mount), so after HMR the reloaded module has no record of them and tab-drag pointer passthrough silently stops working until a full reload. Stash the Set on `window` under a well-known key so the reloaded module instance re-adopts existing registrations. Mirrors the DRAG_LISTENER_KEY pattern already used in BrowserPane.tsx. Falls back to a module-local Set in non-DOM contexts (tests).
The prior pointer-passthrough fix made drops onto a browser pane *work* (pointerup reached the host and onDragEnd fired), but the blue `.tab-drop-overlay` hitbox was still invisible during the drag. Electron `<webview>` guests paint in their own GPU compositor layer above normal DOM regardless of CSS z-index, so the overlay element (z-index 9999) rendered at the correct coords but was occluded by the webview's composite. Flip `visibility: hidden` alongside `pointer-events: none` while a tab drag is active, restored on drag end. Using `visibility` (not `display: none`) preserves layout so the overlay's computed rect still matches the pane body. Verified in a running dev build: pre-fix the overlay DOM appeared at the expected rect but no blue rendered; post-fix the hitbox is visible and the drop still completes correctly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
<webview>guests run in a separate Chromium process and capturepointerupoff the host renderer's event loop, so dnd-kit'sonDragEndnever fired even though the blue drop overlay appeared.webview-drag-passthrough.tsowns a registry of live webview elements and togglespointer-events: noneon them for the duration of an active dnd-kit tab drag.useTabDragSplitflips the toggle via auseEffectkeyed onactiveDrag, and cleanup restores input even if the hook unmounts mid-drag. HTML5-drag listeners inBrowserPaneare untouched — they still handle drag-out of images/text.window(webviews are registered once on creation, not on every mount, so a fresh module instance would otherwise lose them). Mirrors the existingDRAG_LISTENER_KEYpattern inBrowserPane.tsx.Test plan
webview-drag-passthrough.tswith the dev server running; after HMR, tab-drag passthrough still works without a full reload.