From 34b7d08ba5ccbce13591cc69b4829f02cf3197ab Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sat, 16 May 2026 16:34:16 -0700 Subject: [PATCH] Fix workspace board shift wheel drag scroll (#2126) --- .../sidebar/WorkspaceKanbanDrawer.tsx | 2 +- ...use-workspace-kanban-shift-wheel-scroll.ts | 39 ++++++++++++++++--- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.tsx b/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.tsx index 85292f75f..f9153de9f 100644 --- a/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.tsx +++ b/src/renderer/src/components/sidebar/WorkspaceKanbanDrawer.tsx @@ -333,7 +333,7 @@ export default function WorkspaceKanbanDrawer({ left: drawerLeftCss, top: 36, height: 'calc(100% - 36px)', - width: `min(calc(100vw - ${drawerLeftCss}), 1320px)`, + width: `min(calc(100vw - ${drawerLeftCss}), 1294px)`, opacity: workspaceBoardOpacity } as React.CSSProperties } diff --git a/src/renderer/src/components/sidebar/use-workspace-kanban-shift-wheel-scroll.ts b/src/renderer/src/components/sidebar/use-workspace-kanban-shift-wheel-scroll.ts index 3645a1488..4ff756c1f 100644 --- a/src/renderer/src/components/sidebar/use-workspace-kanban-shift-wheel-scroll.ts +++ b/src/renderer/src/components/sidebar/use-workspace-kanban-shift-wheel-scroll.ts @@ -24,6 +24,19 @@ function isEventInsideElement(event: WheelEvent, element: HTMLElement): boolean ) } +function pointIsInsideElement( + point: { x: number; y: number } | null, + element: HTMLElement +): boolean { + if (!point) { + return false + } + const rect = element.getBoundingClientRect() + return ( + point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.bottom + ) +} + export function useWorkspaceKanbanShiftWheelScroll( boardRef: React.RefObject, scrollerRef: React.RefObject, @@ -35,13 +48,23 @@ export function useWorkspaceKanbanShiftWheelScroll( } let isWorkspaceDragActive = false + let lastDragPoint: { x: number; y: number } | null = null const stopTrackingDrag = (): void => { isWorkspaceDragActive = false + lastDragPoint = null } const handleDragStart = (event: DragEvent): void => { isWorkspaceDragActive = event.dataTransfer ? hasWorkspaceDragData(event.dataTransfer) : false + lastDragPoint = isWorkspaceDragActive ? { x: event.clientX, y: event.clientY } : null + } + + const handleDragOver = (event: DragEvent): void => { + if (!isWorkspaceDragActive) { + return + } + lastDragPoint = { x: event.clientX, y: event.clientY } } const handleWheel = (event: WheelEvent): void => { @@ -52,7 +75,7 @@ export function useWorkspaceKanbanShiftWheelScroll( !isWorkspaceDragActive || !board || !scroller || - !isEventInsideElement(event, board) + (!isEventInsideElement(event, board) && !pointIsInsideElement(lastDragPoint, board)) ) { return } @@ -62,20 +85,26 @@ export function useWorkspaceKanbanShiftWheelScroll( return } event.preventDefault() + event.stopPropagation() + event.stopImmediatePropagation() scroller.scrollLeft += delta } - document.addEventListener('dragstart', handleDragStart) + document.addEventListener('dragstart', handleDragStart, true) + document.addEventListener('dragover', handleDragOver, true) document.addEventListener('drop', stopTrackingDrag, true) document.addEventListener('dragend', stopTrackingDrag, true) window.addEventListener('blur', stopTrackingDrag) - document.addEventListener('wheel', handleWheel, { passive: false }) + // Why: Chromium can cancel the native drag if Shift+wheel reaches default + // scrolling first, so intercept before bubble listeners see the event. + document.addEventListener('wheel', handleWheel, { capture: true, passive: false }) return () => { - document.removeEventListener('dragstart', handleDragStart) + document.removeEventListener('dragstart', handleDragStart, true) + document.removeEventListener('dragover', handleDragOver, true) document.removeEventListener('drop', stopTrackingDrag, true) document.removeEventListener('dragend', stopTrackingDrag, true) window.removeEventListener('blur', stopTrackingDrag) - document.removeEventListener('wheel', handleWheel) + document.removeEventListener('wheel', handleWheel, true) } }, [boardRef, enabled, scrollerRef]) }