Auto Collapse Behaviour - Collapse left panel on window resize (#32964)

* Add functionality to UIStore

- Make it possible to query if the window is currently being resized
- Emit WidthIncreased/WidthDecreased events

* Change resize behaviour of panel

So that the panel does not become smaller when the window is resized.
This is consistent with the old room-list design.

* Introduce a `CollapseHandler` object

This should be used by the collapse behaviours to collapse/expand the
panel. There's a good reason to not have the behaviours depend directly
on the react-resizable-panels API methods: We dont want the collapse/expand
calls to conflict with each other. See the comments in the code for more
information.

* Introduce a base class for collapse behaviour logic

Behaviours should extend this class to describe when the panel should
automatically collapse and expand.

* Add the window resize collapse behaviour

* Create a central file from which to export all behaviours

* Add a class to orchestrate the collapse behaviours

ResizerViewModel will only have a dependency on this class.

* Collapse panel on app start if necessary

For eg, if the app is started with a small window width, the panel should be
collapsed.

* Wire auto collapse code into the viewmodel

* Write jest tests

* Fix e2e tests

* Fix lint error

* Fix e2e test failures

* Expand the panel before taking screenshot

Fixes incorrect narrow screenshots in RTE.spec.ts and CIDER.spec.ts

* Make comments consistent

* Move tests from jest to vitest

* Fix lint errors

* Improve comment

* Remove variable

* Remove mock

* Fix comment formatting
This commit is contained in:
R Midhun Suresh
2026-07-21 16:37:28 +00:00
committed by GitHub
parent 363ef74248
commit 3bff251010
18 changed files with 560 additions and 6 deletions
@@ -16,8 +16,6 @@ import { ResizerViewModel } from "./ResizerViewModel";
import SettingsStore from "../../settings/SettingsStore";
import { SettingLevel } from "../../settings/SettingLevel";
vi.mock("what-input");
describe("LeftPanelResizerViewModel", () => {
afterEach(() => {
localStorage.clear();
@@ -79,6 +77,10 @@ describe("LeftPanelResizerViewModel", () => {
const mockHandle = {
resize: vi.fn(),
isCollapsed: vi.fn().mockReturnValue(true),
getSize: vi.fn().mockReturnValue({
inPixels: 0,
}),
collapse: vi.fn(),
} as unknown as PanelImperativeHandle;
vm.setPanelHandle(mockHandle);
@@ -97,6 +99,7 @@ describe("LeftPanelResizerViewModel", () => {
const mockHandle = {
resize: vi.fn(),
isCollapsed: vi.fn().mockReturnValue(true),
getSize: vi.fn().mockReturnValue(0),
} as unknown as PanelImperativeHandle;
vm.setPanelHandle(mockHandle);
// Simulate click
@@ -110,6 +113,7 @@ describe("LeftPanelResizerViewModel", () => {
const mockHandle = {
resize: vi.fn(),
isCollapsed: vi.fn().mockReturnValue(true),
getSize: vi.fn().mockReturnValue(0),
} as unknown as PanelImperativeHandle;
vm.setPanelHandle(mockHandle);
// Simulate click
@@ -131,14 +135,30 @@ describe("LeftPanelResizerViewModel", () => {
expect(mockHandle.collapse).toHaveBeenCalled();
});
it("should ignore first resized event", () => {
const vm = new ResizerViewModel();
const mockHandle = {
resize: vi.fn(),
getSize: vi.fn().mockReturnValue(0),
} as unknown as PanelImperativeHandle;
vm.setPanelHandle(mockHandle);
vm.onLeftPanelResized(50);
expect(mockHandle.resize).not.toHaveBeenCalled();
});
it("should resize to nearest whole number", () => {
const vm = new ResizerViewModel();
const mockHandle = {
resize: vi.fn(),
getSize: vi.fn().mockReturnValue(0),
} as unknown as PanelImperativeHandle;
vm.setPanelHandle(mockHandle);
// Initial call is ignored
vm.onLeftPanelResized(70);
// This should be processed
vm.onLeftPanelResized(25.515);
expect(mockHandle.resize).toHaveBeenCalledWith("26%");
expect(mockHandle.resize).toHaveBeenLastCalledWith("26%");
});
});