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.
This commit is contained in:
m4air
2026-08-31 22:42:11 -07:00
parent 04b6d7b29d
commit 1f86e4e2d2
2 changed files with 37 additions and 5 deletions
@@ -9,9 +9,11 @@ type PaneFixture = {
setScrollLeft: ReturnType<typeof vi.fn<(value: number) => 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({
@@ -4,8 +4,8 @@ const WHEEL_LINE_PIXELS = 16
type HorizontalScrollEditor = Pick<
editor.ICodeEditor,
'getContainerDomNode' | 'getScrollLeft' | 'setScrollLeft'
>
'getContainerDomNode' | 'getScrollLeft' | 'setScrollLeft' | 'getScrollWidth'
> & { getLayoutInfo: () => Pick<editor.EditorLayoutInfo, 'contentWidth'> }
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