Skip to content

Commit 2c11f91

Browse files
committed
fix(files): keep the vertical component of a diagonal wheel pan
Cancelling a wheel event is all-or-nothing, so applying only `scrollLeft` after `preventDefault` dropped a diagonal trackpad pan's `deltaY` entirely. Apply the vertical component too, except under Shift, which remaps `deltaY` onto the horizontal axis and so has none left to spend.
1 parent b019698 commit 2c11f91

2 files changed

Lines changed: 38 additions & 3 deletions

File tree

apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/preview-wheel-zoom.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,27 @@ describe('bindPreviewHorizontalWheel', () => {
5050
expect(event.defaultPrevented).toBe(true)
5151
})
5252

53+
/**
54+
* Cancelling a wheel event is all-or-nothing, so a diagonal trackpad pan must have its
55+
* vertical movement re-applied by hand — otherwise `preventDefault` silently eats it.
56+
*/
57+
it('keeps the vertical movement of a diagonal pan', () => {
58+
Object.defineProperty(container, 'scrollHeight', { value: 5000, configurable: true })
59+
Object.defineProperty(container, 'clientHeight', { value: 500, configurable: true })
60+
61+
wheel(container, { deltaX: 40, deltaY: 90 })
62+
63+
expect(container.scrollLeft).toBe(40)
64+
expect(container.scrollTop).toBe(90)
65+
})
66+
67+
it('does not also spend a shift gesture vertically', () => {
68+
wheel(container, { deltaX: 0, deltaY: 120, shiftKey: true })
69+
70+
expect(container.scrollLeft).toBe(120)
71+
expect(container.scrollTop).toBe(0)
72+
})
73+
5374
it('leaves a plain vertical wheel alone so the container still scrolls down', () => {
5475
const event = wheel(container, { deltaX: 0, deltaY: 120 })
5576

apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/preview-wheel-zoom.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,30 @@ function horizontalDeltaOf(event: WheelEvent): number {
1818
}
1919

2020
/**
21-
* Scroll `container` horizontally for a wheel gesture. No-op when the gesture carries
22-
* no horizontal component or the container has nothing to scroll, leaving the event to
23-
* scroll vertically as usual.
21+
* Vertical component still owed to the container once the horizontal one is taken.
22+
* Shift *remaps* `deltaY` onto the horizontal axis, so that gesture has no vertical
23+
* component left to spend; an ordinary diagonal trackpad pan does.
24+
*/
25+
function verticalDeltaOf(event: WheelEvent): number {
26+
return event.deltaX !== 0 ? event.deltaY : 0
27+
}
28+
29+
/**
30+
* Scroll `container` for a wheel gesture carrying a horizontal component. No-op when the
31+
* gesture is purely vertical or the container has nothing to scroll sideways, leaving the
32+
* event to scroll natively.
33+
*
34+
* Cancelling a wheel event is all-or-nothing, so once `preventDefault` is called this owes
35+
* the container *both* axes — a diagonal pan that only had its `deltaX` applied would lose
36+
* its vertical movement entirely.
2437
*/
2538
function applyHorizontalWheel(container: HTMLElement, event: WheelEvent): void {
2639
const horizontalDelta = horizontalDeltaOf(event)
2740
if (horizontalDelta === 0 || container.scrollWidth <= container.clientWidth) return
2841

2942
event.preventDefault()
3043
container.scrollLeft += horizontalDelta
44+
container.scrollTop += verticalDeltaOf(event)
3145
}
3246

3347
/**

0 commit comments

Comments
 (0)