From 6359942a155ef701c14749fe7fc002a32fc87c9c Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 2 Feb 2026 20:26:29 -0500 Subject: [PATCH 1/3] Add e2e test for click-swallowing issue --- .../tests/src/components/Clickable.tsx | 33 ++++++++++++++--- .../tests/tests/pointer-interactions.spec.tsx | 36 +++++++++++++++++++ 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/integrations/tests/src/components/Clickable.tsx b/integrations/tests/src/components/Clickable.tsx index 672498f67..7a2a2499f 100644 --- a/integrations/tests/src/components/Clickable.tsx +++ b/integrations/tests/src/components/Clickable.tsx @@ -2,10 +2,19 @@ import { useState } from "react"; -export type ClickableProps = { className?: string; id?: string }; +export type ClickableProps = { + className?: string; + id?: string; + ignoredDefaultPrevented?: boolean; +}; -export function Clickable({ className = "", id }: ClickableProps) { +export function Clickable({ + className = "", + id, + ignoredDefaultPrevented +}: ClickableProps) { const [counts, setCounts] = useState({ + click: 0, pointerDown: 0, pointerUp: 0 }); @@ -16,28 +25,42 @@ export function Clickable({ className = "", id }: ClickableProps) {
 {
-        if (event.defaultPrevented) {
+        if (event.defaultPrevented && !ignoredDefaultPrevented) {
           return;
         }
 
         setCounts({
+          click: counts.click,
           pointerDown: counts.pointerDown + 1,
           pointerUp: counts.pointerUp
         });
       }}
       onPointerUp={(event) => {
-        if (event.defaultPrevented) {
+        if (event.defaultPrevented && !ignoredDefaultPrevented) {
           return;
         }
 
         setCounts({
+          click: counts.click,
           pointerDown: counts.pointerDown,
           pointerUp: counts.pointerUp + 1
         });
       }}
+      onClick={(event) => {
+        if (event.defaultPrevented && !ignoredDefaultPrevented) {
+          return;
+        }
+
+        setCounts({
+          click: counts.click + 1,
+          pointerDown: counts.pointerDown,
+          pointerUp: counts.pointerUp
+        });
+      }}
     >
       
-        {label} down:{counts.pointerDown} up:{counts.pointerUp}
+        {label} down:{counts.pointerDown} up:{counts.pointerUp} click:
+        {counts.click}
       
     
); diff --git a/integrations/tests/tests/pointer-interactions.spec.tsx b/integrations/tests/tests/pointer-interactions.spec.tsx index d9f87cff8..14e7837c5 100644 --- a/integrations/tests/tests/pointer-interactions.spec.tsx +++ b/integrations/tests/tests/pointer-interactions.spec.tsx @@ -534,4 +534,40 @@ test.describe("pointer interactions", () => { await page.mouse.move(x - 25, y); await expect(separator).toHaveAttribute("data-separator", "inactive"); }); + + test("should not prevent click events if no drag occurs", async ({ + page: mainPage + }) => { + const page = await goToUrl( + mainPage, + + + + + + + + ); + + const separator = page.getByRole("separator"); + const hitAreaBox = await separator.boundingBox(); + const { x, y } = getCenterCoordinates(hitAreaBox!); + + const panel = page.getByText("click"); + await expect(panel).toContainText("click:0"); + + // A click that does not resize should not be blocked + await page.mouse.move(x - 2, y); + await page.mouse.down(); + await page.mouse.up(); + // await page.mouse.click(x - 2, y); + await expect(panel).toContainText("click:1"); + + // A click that resizes should be blocked + await page.mouse.move(x - 2, y); + await page.mouse.down(); + await page.mouse.move(x - 3, y); + await page.mouse.up(); + await expect(panel).toContainText("click:1"); + }); }); From 5cc60a5695ac37a26baa411953e0b2c6095f451c Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 2 Feb 2026 20:32:47 -0500 Subject: [PATCH 2/3] Add another unit test for panel collapse/expand --- lib/global/utils/adjustLayoutByDelta.test.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/global/utils/adjustLayoutByDelta.test.ts b/lib/global/utils/adjustLayoutByDelta.test.ts index fa58ec32b..3d9b1efaf 100644 --- a/lib/global/utils/adjustLayoutByDelta.test.ts +++ b/lib/global/utils/adjustLayoutByDelta.test.ts @@ -2245,9 +2245,13 @@ describe("adjustLayoutByDelta", () => { ( [ [-4, c([collapsible, {}]), l([46, 54])], + [-6, c([collapsible, {}]), l([44, 56])], [-4, c([{}, collapsible]), l([46, 54])], + [-6, c([{}, collapsible]), l([44, 56])], [4, c([collapsible, {}]), l([54, 46])], - [4, c([{}, collapsible]), l([54, 46])] + [6, c([collapsible, {}]), l([56, 44])], + [4, c([{}, collapsible]), l([54, 46])], + [6, c([{}, collapsible]), l([56, 44])] ] satisfies [number, PanelConstraints[], Layout][] ).forEach(([delta, panelConstraints, expectedLayout]) => { expect( From 0c9b5d335243bd19663e8c8d90d07213d1f9befa Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 2 Feb 2026 20:33:04 -0500 Subject: [PATCH 3/3] 4.5.8 -> 4.5.9 --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de12bac9a..51dd5de3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## Unreleased +## 4.5.9 - [649](https://github.com/bvaughn/react-resizable-panels/pull/649): Optimization: Replace `useForceUpdate` with `useSyncExternalStore` to avoid side effect of swallowing "click" events in certain cases - [654](https://github.com/bvaughn/react-resizable-panels/pull/654): **Bugfix** Imperative `Group` method `setLayout` persists layout to in-memory cache diff --git a/package.json b/package.json index c56ddb47e..d03bd57ed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-resizable-panels", - "version": "4.5.9-alpha.0", + "version": "4.5.9", "type": "module", "author": "Brian Vaughn (https://github.com/bvaughn/)", "contributors": [