ui icon indicating copy to clipboard operation
ui copied to clipboard

fix: mouse wheel and touch scroll not working over popover

Open pa4080 opened this issue 1 year ago • 6 comments

This PR gracefully resolves #607, also resolves #542. These issues are caused by an issue with Radix-ui/primitives which still open for over a year and a half - it is described here: [Dialog][Popover] Scrolling issue when Popover inside Dialog #1159

The current solution simulates an arrow down/up key press when we use the mouse wheel over the problematic popover primitive component.

pa4080 avatar Dec 17 '23 13:12 pa4080

@pa4080 is attempting to deploy a commit to the shadcn-pro Team on Vercel.

A member of the Team first needs to authorize it.

vercel[bot] avatar Dec 17 '23 13:12 vercel[bot]

Hi! I used your fix in my popover component & it worked. Thanks dude <3 . Much love <3

shrikantkalar023 avatar Jan 19 '24 10:01 shrikantkalar023

Hi! I also have same issue, and solution works well. Thanks, saved my day!

NazariiShvets avatar Jan 24 '24 15:01 NazariiShvets

This solution worked well in my project!

ejscheepers avatar Feb 02 '24 08:02 ejscheepers

Hi, coming back here to add suggestion In our application with this impl we still had problems with scroll, but this time at touch devices

So our final fix is

const useFixScrollForModaledPopovers = () => {
   const touchStartRef = useRef<number | null>(null)

  const onScroll = (event: WheelEvent<HTMLDivElement>) => {
    event.stopPropagation();
    const isScrollingDown = event.deltaY > 0;

    if (isScrollingDown) {
      event.currentTarget.dispatchEvent(
        new KeyboardEvent('keydown', { key: 'ArrowDown' })
      );
    } else {
      event.currentTarget.dispatchEvent(
        new KeyboardEvent('keydown', { key: 'ArrowUp' })
      );
    }
  }
  
  const onTouchStart = (event : TouchEvent<HTMLDivElement>) => {
     touchPosRef.current = event.changedTouches[0]?.clientY ?? null
  } 
  
  const onTouchMove = (event: TouchEvent<HTMLDivElement>) => {
     const touchPos = e.changedTouches[0]?.clientY ?? null;
     if(touchPosRef.current === null || touchPos === null) return;
     
     e.stopPropagation();

     const isScrollingDown = touchPosRef.current < touchPos;

     if (isScrollingDown) {
       e.currentTarget.dispatchEvent(
         new KeyboardEvent('keydown', { key: 'ArrowDown' })
       );
     } else {
       e.currentTarget.dispatchEvent(
         new KeyboardEvent('keydown', { key: 'ArrowUp' })
       );
     }

     touchPosRef.current = touchPos;
  }
  
  return { onWheel, onTouchStart, onTouchMove }
}

NazariiShvets avatar Apr 04 '24 11:04 NazariiShvets

Hi, @NazariiShvets, I've committed your solution to the PR. It works great. Thanks!

pa4080 avatar Apr 10 '24 06:04 pa4080