bvaughn / react-resizable-panels

https://react-resizable-panels.vercel.app/
MIT License
3.87k stars 135 forks source link

PanelResizeHandle not releasing when mouse click ends when outside of allowed width. #205

Closed Davenporten closed 10 months ago

Davenporten commented 10 months ago

First, thanks for the great lib, saves me a lot of time and trouble!

I have a custom PanelResizeHandle and PanelGroup and looks like the following:

const StyledResizeHandle = styled(PanelResizeHandle)<StyledResizeHandleProps>`
  width: ${({ width }) => width};
  height: ${({ height }) => height};
  display: flex;
  margin: -10px;
  z-index: 9999;
  justify-content: center;
  align-items: center;
  background-image: linear-gradient(
      to bottom,
      transparent 50%,
      ${colors.defaultGray} 50%,
      ${colors.defaultGray} calc(50% + 50px),
      transparent calc(50% + 50px
    )
  );
  background-repeat: no-repeat;
  background-position: center;
`;

...

        <PanelGroup direction="horizontal" units="pixels">
          <Panel order={0} minSize={150}>
            <LeftSideBar />
          </Panel>
          <StyledResizeHandle
            width="5px"
            onDragging={(isDragging) => {
              console.log('isDragging', isDragging);
            }}
          />
          <Panel minSize={1120} order={1}>
            <Preview />
          </Panel>
          <Panel order={2} minSize={250}>
            <RightSideBar />
          </Panel>
        </PanelGroup>

When I clicking and dragging the handle works fine except if shrink the "Preview" panel down to it's min size and the cursor keeps going. When I do this the handle doesn't release and if my cursor moves back over the handle, without selecting it again, it will continue to follow my cursor. The only way to get it to release is to click on the handle again.

An obvious symptom of this is that onDragging is not firing on release in the scenario I described.

image

The isDragging: false is when I clicked on the handle again.

I wasn't able to rule out that the problem is with my custom handle as the components surrounding the PanelGroup make it so that I need the custom handler otherwise I can't see it, but of course it is a possibility that there is some conflict with that.

I was able to reduce it down to

const StyledResizeHandle = styled(PanelResizeHandle)<StyledResizeHandleProps>`
  width: ${({ width }) => width};
  height: ${({ height }) => height};
  z-index: 9999;
`;

but the problem persisted.

Thanks in advance for any help or insight into this!

bvaughn commented 10 months ago

Any chance you could share a Replay of this bug?

If not, then could you recreate a Code Sandbox that reproduces the problem you're describing?

Davenporten commented 10 months ago

I created the sandbox and of course the issue isn't showing up there 😭 so it's something with what's happening in my code. Maybe you can give me some insight though.

After seeing working in the sandbox I wrapped what was in each Panel in a div and while my components' heights got messed up the sticky handle wasn't happening. However, when I set that div to height: "100%" it came back. It's not just 100% it was anytime I set height to anything.

Would you have any insight into why that would be happening? I completely realize that you might not though, I'm working with components I can't share and I don't expect you to debug this for me.

Thanks for the reply!

Davenporten commented 10 months ago

Figured it out. I had messed with negative margins to achieve a particular visual affect, but because of that I think some weirdness happened so that the focus for the release of the handle was on the wrong div.

Thanks again for replying!

bvaughn commented 10 months ago

For sure! Thank you for updating the issue 🙇🏼

Davenporten commented 10 months ago

@bvaughn I removed all the stuff with the margins and then found the problem showing up again. I think it has something to do with the cursor going over an iframe when dragging rather than going beyond the width. I have an idea of how to resolve this using onDragging, but wanted to bring this to your attention.

If I get this worked out I'll come back here with my workaround.

Here is the problem happening in a sandbox: https://codesandbox.io/s/vigilant-elbakyan-lt9nzd?file=/src/App.tsx

Davenporten commented 10 months ago

Not beautiful, but this worked for me

            onDragging={(isDragging) => {
              const previewIframe = document.getElementById('preview') as HTMLIFrameElement;

              if (previewIframe) {
                if (isDragging) {
                  previewIframe.style.pointerEvents = 'none';
                } else {
                  previewIframe.style.pointerEvents = 'auto';
                }
              }
            }}