fix(core): sash and scrollbar cannot be dragged inside a popout window#1478
Merged
Merged
Conversation
…s document Splitview registers a sash's pointerdown on the sash element, but registers the follow-up pointermove/pointerup/pointercancel/contextmenu listeners on the global document. An element inside a popout window dispatches its pointer events into that window's document, so those listeners never fire: the drag arms on pointerdown and then nothing moves, and the sash cannot be dragged. Scrollbar repeats the pattern, so the tab-bar overflow scrollbar is affected too. Floating groups render into the main document, which is why the global document happens to be correct for them and only popout groups break. Resolve the owning document from the element instead. It is captured once per drag into a const closed over by both the add and the matching remove, so a listener can never be added on one document and removed from another.
Drives a sash drag on a Splitview built inside a second document (document.implementation.createHTMLDocument), which is the shape a popout window has: the element lives in that window's document, so its pointer events are dispatched there. Fails before the ownerDocument fix — the pointermove never reaches the listener bound to the global document, so the views never resize. The existing sash-drag test dispatches on the global document, where sash.ownerDocument === document, so it passes either way and cannot catch this.
mathuo
self-requested a review
July 16, 2026 18:58
mathuo
approved these changes
Jul 16, 2026
4 tasks
mathuo
added a commit
that referenced
this pull request
Jul 16, 2026
Merge master into v8-branch (reconcile popout sash/scrollbar fix + add PR #1478 regression test)
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.
Description
Fixes #1477.
Inside a popout window (
api.addPopoutGroup), a splitview sash cannot be dragged — the drag arms and then nothing moves, so two groups docked side by side in a popout are stuck at their initial ratio.Scrollbarhas the identical defect, so the tab-bar overflow scrollbar can't be dragged there either.Cause.
Splitviewregisters the sash'spointerdownon the sash element, but registers the follow-up listeners on the globaldocument(splitview.ts~L563):A popout window has its own document.
addPopoutGroupmoves the group's element into it (popoutContainer.appendChild(...), which adopts the node), so a sash living there dispatches pointer events into the popout's document, never the opener's.pointerdownstill fires (it's on the element, which travelled with it), so the drag arms — butpointermove/pointerupnever arrive,resize()is never called andend()never runs.scrollbar.ts(~L100) repeats the pattern.Why it's easy to miss: the symptom discriminates purely on document, and fails silently — no error, no console output.
Floating groups render into the main document, so the global
documenthappens to be right for them. Only popout groups cross a document boundary.Fix. Resolve the owning document from the element —
sash.ownerDocument/this.element.ownerDocument. It's captured once per drag into aconstclosed over by both theaddEventListenerand its matchingremoveEventListener, so a listener can't be added on one document and removed from another (strictly no worse than today, which uses the same global for both).ownerDocumentis correct atpointerdown: cross-documentappendChildadopts the node, so a sash inside the popout container already carries that window's document by the time it can receive a pointer event.Reproduction
api.addPopoutGroup(group)to open a group in its own window.Found against
7.0.2(latest published) and reproduced in currentmaster.Type of change
Affected packages
dockview-coredockview(vanilla JS)dockview-reactdockview-vuedockview-angulardocsNotes
ownerDocumentresolution is duplicated across the two call sites rather than factored out. I have a variant that adds anaddPointerDragListeners(element, { onPointerMove, onEnd, endOnContextMenu })helper todom.ts(wheregetDockviewTheme/isInDocumentalready live): it owns the listener lifecycle and auto-removes on end, so both call sites lose their add/remove bookkeeping (net +83/−29 across three files, with the call sites shrinking), and it makes the invariant structural — the document is resolved once per drag, so the add and the matching remove can't target different documents. Happy to push that instead if you'd prefer it; I led with the minimal fix so the bug fix isn't blocked on a refactor opinion.overlay.tsstill bindspointermove/pointerupto the globalwindowfor floating-group move/resize. Not a bug today (floating groups live in the main window), but it's the same class and would bite if a floating group inside a popout window ever became reachable — left untouched here.Test
splitview.spec.tsgainsdnd: sash drag follows pointer events in the element's own document— it builds aSplitviewinside a second document (document.implementation.createHTMLDocument()), which is the shape a popout window has, and drives a real sash drag from that document.It fails on
master(the views never resize —[200, 200]instead of[220, 180], because thepointermovenever reaches the listener bound to the global document) and passes with the fix.The existing
dnd: pointer events to move sashtest dispatches on the globaldocument, wheresash.ownerDocument === document, so it passes either way and cannot catch this — which is why the bug survived.No real second window is needed: the bug is about which document the listeners land on, and jsdom's second
Documentreproduces that exactly.dockview-core: 1079 tests / 61 suites pass, and the change is prettier-clean.