bvaughn/react-resizable-panels

Unstable panel widths with more than three panels

functoria opened this issue · 14 comments

Hi!

When a panel group has more than three panels, when resizing one of the "center" panels, I've noticed the sizes of the preceding panels are not changing smoothly, but seem to "jump around". I suppose this is caused by a rounding error...

Can this be remedied as the visual experience is not great, especially when the panel content is rich and depends on the panel size? Here's a video showing the issue with a horizontal layout:

Screen.Recording.2024-03-20.at.11.06.54.mov

Thank you for the great libraries!

Can you share a repro of this please? I suspect the reason for the “jumping” is that something in your app is slow to render on resize.

Sure, it's actually a simple modification of your example. Just changed direction, some style and added few more panels. Use zoom to notice the effect.

Looks fine for me, even with 6x CPU throttling enabled. 🤷🏼

This is strange, I'm using a MacBook Pro M2, without any throttling, and I can still reproduce the effect in the video below on all my browsers:

Screen.Recording.2024-03-20.at.14.36.34.mov

(I've updated the sandbox.)

Resizing seems smooth for me?

Kapture.2024-03-20.at.09.49.01.mp4

I think I initially misunderstood what you were reporting though. I assumed the "jumping" was because of slow renders and React not keeping up with the resize updates, but I think you're talking about some small changes in percentage sizes that cause the panels to shift a bit unexpectedly during resize.

I haven't noticed that either, personally.

It's definitely noticeable with the right panel content (just tested on other OS/machine as well).

And yes, I think is related to some non-determinism in how the sizes are computed here, probably due to the "fuzzy" number comparisons. When slowly resizing a panel, on my machine, I've noticed some of the panels, which shouldn't change size at all yet, still have their size "jumping" around the "right" value by couple of pixels.

I'm curious if anybody else is able to reproduce the issue; or maybe the effect is so negligible for most of the use cases that nobody really notices it...

Anyway, thank you for the quick response!

Maybe you could record a Replay of this happening?

Does seem like it could be related to the fuzzy number / precision stuff. :(

It's definitely noticeable with the right panel content (just tested on other OS/machine as well).

And yes, I think is related to some non-determinism in how the sizes are computed here, probably due to the "fuzzy" number comparisons. When slowly resizing a panel, on my machine, I've noticed some of the panels, which shouldn't change size at all yet, still have their size "jumping" around the "right" value by couple of pixels.

I'm curious if anybody else is able to reproduce the issue; or maybe the effect is so negligible for most of the use cases that nobody really notices it...

Anyway, thank you for the quick response!

Seems like this is the same problem as in the issue I opened a few days ago. I also put up a sandbox where I was able to duplicate that behavior (You have to play around a bit to notice it, but in some positions of the right bar, it flickers if you resize with the left bar).

Hi, sorry for the late come-back.

Here's the updated sandbox and a recording of the unstable panel width behavior:

Screen.Recording.2024-03-24.at.08.47.03.mov

As you may see, when resizing Panel#1 and Panel#2, the PIXEL widths of Panel#3 and Panel#4 are changing, although they should not (none of the min sizes are reached yet). The percent sizes are indeed stable.

In my usecase I'm "observing" the panel PIXEL widths (with a resize observer) and rendering other (expensive) elements based on those widths. It would definitely help not having pixel widths of unaffected panels changing unnecesarily as in the example above.

I could help by looking at the code, if there is not an obvious immediate solution to fix this.

Thank you!

I think this is just a quirk in how flex box layout works. If you observe the CSS styles for each panel, you'll see that the flex-grow style values don't change for the "flickering" panels.

Kapture.2024-03-24.at.08.49.56.mp4

I don't think I can do anything to fix this, short of maybe a major overhaul in the way this library works, and I don't have the capacity for that. (This is just a pro bono side project.)

If you dig into this and have a proposal, please submit a PR. Otherwise I don't think this is something I can tackle.

If you update your test app to the following, it makes this a bit easier to see I think:

export default function App() {
  return (
    <div className={styles.PanelGroupWrapper}>
      <PanelGroup className={styles.PanelGroup} direction="horizontal">
        <PanelWithDebugInfo />
        <ResizeHandle className={styles.ResizeHandle} />
        <PanelWithDebugInfo />
        <ResizeHandle className={styles.ResizeHandle} />
        <PanelWithDebugInfo />
        <ResizeHandle className={styles.ResizeHandle} />
        <PanelWithDebugInfo />
      </PanelGroup>
    </div>
  );
}

function PanelWithDebugInfo() {
  const ref = useRef<HTMLDivElement>(null);

  useLayoutEffect(() => {
    const element = ref.current;
    if (element) {
      const update = () => {
        const { width } = element.getBoundingClientRect();
        const size = element.parentElement!.style.flexGrow;

        const percentage = element.querySelector(
          '[data-test-name="percentage"]'
        );
        if (percentage) {
          percentage.textContent = `${size}%`;
        }

        const pixels = element.querySelector('[data-test-name="pixels"]');
        if (pixels) {
          pixels.textContent = `${width}px`;
        }
      };

      update();

      const observer = new ResizeObserver(update);
      observer.observe(element);

      return () => {
        observer.disconnect();
      };
    }
  }, []);

  return (
    <Panel className={styles.PanelColumn}>
      <div className={styles.Centered} ref={ref}>
        <center>
          <div data-test-name="percentage">0%</div>
          <div data-test-name="pixels">0px</div>
        </center>
      </div>
    </Panel>
  );
}
Kapture.2024-03-24.at.09.10.49.mp4

I think I may have figured out a way to fix it. Stay tuned.

Okay check out react-resizable-panels@2.0.16. I think it should fix this for you!


❤️ → ☕ givebrian.coffee

Thank you for fixing this!