From 1f86e4e2d2f410d69bc4d5b3ae5cf525d098f583 Mon Sep 17 00:00:00 2001 From: m4air Date: Mon, 31 Aug 2026 22:42:11 -0700 Subject: [PATCH] fix(editor): skip shift-wheel capture when a diff pane cannot scroll sideways Word-wrapped panes never overflow horizontally, so consuming the gesture left it dead instead of reaching the outer combined-diff list. --- .../diff-editor-shift-wheel-scroll.test.ts | 29 +++++++++++++++++-- .../editor/diff-editor-shift-wheel-scroll.ts | 13 +++++++-- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/renderer/src/components/editor/diff-editor-shift-wheel-scroll.test.ts b/src/renderer/src/components/editor/diff-editor-shift-wheel-scroll.test.ts index 73b93cb5a91..8ab9194dc29 100644 --- a/src/renderer/src/components/editor/diff-editor-shift-wheel-scroll.test.ts +++ b/src/renderer/src/components/editor/diff-editor-shift-wheel-scroll.test.ts @@ -9,9 +9,11 @@ type PaneFixture = { setScrollLeft: ReturnType void>> getScrollLeft: () => number getContainerDomNode: () => HTMLElement + getScrollWidth: () => number + getLayoutInfo: () => { contentWidth: number } } -function createPaneFixture(initialScrollLeft = 10): PaneFixture { +function createPaneFixture(initialScrollLeft = 10, scrollWidth = 1000): PaneFixture { const container = document.createElement('div') const input = document.createElement('div') let scrollLeft = initialScrollLeft @@ -26,7 +28,9 @@ function createPaneFixture(initialScrollLeft = 10): PaneFixture { input, setScrollLeft, getScrollLeft: () => scrollLeft, - getContainerDomNode: () => container + getContainerDomNode: () => container, + getScrollWidth: () => scrollWidth, + getLayoutInfo: () => ({ contentWidth: 200 }) } } @@ -93,7 +97,26 @@ describe('installDiffEditorShiftWheelScroll', () => { dispose() }) - it('scrolls the modified pane independently', () => { + it('leaves shift input alone when the pane has no horizontal overflow', () => { + const original = createPaneFixture(0, 200) + const modified = createPaneFixture(0, 200) + const onDownstreamWheel = vi.fn() + original.input.addEventListener('wheel', onDownstreamWheel) + const dispose = installDiffEditorShiftWheelScroll({ + getOriginalEditor: () => original, + getModifiedEditor: () => modified + }) + + const event = dispatchWheel(original.input, { deltaY: 24, shiftKey: true }) + + expect(event.defaultPrevented).toBe(false) + expect(original.setScrollLeft).not.toHaveBeenCalled() + expect(onDownstreamWheel).toHaveBeenCalledTimes(1) + dispose() + }) + + // Monaco syncs pane scroll itself; this covers listener routing, not product-level pane independence. + it('routes the wheel event to the pane under the pointer', () => { const original = createPaneFixture() const modified = createPaneFixture() const dispose = installDiffEditorShiftWheelScroll({ diff --git a/src/renderer/src/components/editor/diff-editor-shift-wheel-scroll.ts b/src/renderer/src/components/editor/diff-editor-shift-wheel-scroll.ts index 185c9615365..7f0b997c1d2 100644 --- a/src/renderer/src/components/editor/diff-editor-shift-wheel-scroll.ts +++ b/src/renderer/src/components/editor/diff-editor-shift-wheel-scroll.ts @@ -4,8 +4,8 @@ const WHEEL_LINE_PIXELS = 16 type HorizontalScrollEditor = Pick< editor.ICodeEditor, - 'getContainerDomNode' | 'getScrollLeft' | 'setScrollLeft' -> + 'getContainerDomNode' | 'getScrollLeft' | 'setScrollLeft' | 'getScrollWidth' +> & { getLayoutInfo: () => Pick } type DiffEditorWithPanes = { getModifiedEditor: () => HorizontalScrollEditor @@ -23,6 +23,10 @@ function getHorizontalWheelPixels(event: WheelEvent, pageWidth: number): number return delta } +function canScrollHorizontally(editor: HorizontalScrollEditor): boolean { + return editor.getScrollWidth() > editor.getLayoutInfo().contentWidth +} + function installPaneShiftWheelScroll(editor: HorizontalScrollEditor): () => void { const container = editor.getContainerDomNode() const handleWheel = (event: WheelEvent): void => { @@ -30,6 +34,11 @@ function installPaneShiftWheelScroll(editor: HorizontalScrollEditor): () => void return } + // Why: a word-wrapped pane never overflows sideways, so leave the gesture to the outer list. + if (!canScrollHorizontally(editor)) { + return + } + const delta = getHorizontalWheelPixels(event, container.clientWidth) if (delta === 0) { return