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
@@ -85,6 +85,9 @@ test.describe("Composer", () => {
test("renders in narrow viewports", { tag: "@screenshot" }, async ({ page, bot, app }) => {
// Shrink the viewport
await page.setViewportSize({ width: 500, height: 1080 });
// Shrinking the viewport will collapse the left-panel, so manually expand it.
await app.resizeLeftPanel(150);
// Now take the screenshot
await expect(app.getComposer()).toMatchScreenshot("narrow.png");
});
@@ -224,6 +224,9 @@ test.describe("Composer", () => {
test("renders in narrow viewports", { tag: "@screenshot" }, async ({ page, bot, app }) => {
// Shrink the viewport
await page.setViewportSize({ width: 750, height: 1080 });
// Shrinking the viewport will collapse the left-panel, so manually expand it.
await app.resizeLeftPanel(150);
// Now take the screenshot
await expect(page.locator(".mx_MessageComposer_wrapper")).toMatchScreenshot("narrow.png");
});
});
@@ -11,6 +11,10 @@ import { test, expect } from "../../../element-web-test";
import { getRoomListView } from "./utils";
test.describe("Room list panel", () => {
test.use({
displayName: "Eve",
});
test.beforeEach(async ({ page, app, user }) => {
// The toasts are displayed above the search section
await rejectToast(page, "Verify this device");
@@ -36,8 +40,7 @@ test.describe("Room list panel", () => {
test.use({ lockLeftPanelWidth: false });
test("should respond to small screen sizes", { tag: "@screenshot" }, async ({ page }) => {
await page.setViewportSize({ width: 575, height: 600 });
const roomListPanel = getRoomListView(page);
await expect(roomListPanel).toMatchScreenshot("room-list-panel-smallscreen.png");
await expect(page).toMatchScreenshot("room-list-panel-smallscreen.png");
});
});
});
@@ -96,6 +96,13 @@ export class ElementAppPage {
* @param name The exact room name to find and click on/open.
*/
public async viewRoomByName(name: string): Promise<void> {
// Expand the left panel if necessary
const separator = this.page.getByRole("separator", { name: "Click or drag to expand" });
const type = await separator.getAttribute("data-separator-type");
if (type === "bar") {
await separator.click();
}
// Make sure the room list is actually present before we try closing toasts,
// otherwise we may race with page loading
await this.page.getByTestId("room-list").waitFor();
@@ -387,4 +394,22 @@ export class ElementAppPage {
await this.page.mouse.wheel(0, 1000);
} while (await needsScroll());
}
/**
* Resize the left panel by a given number of pixels.
* @param delta The number of pixels to resize by. Negative value makes the panel smaller.
*/
public async resizeLeftPanel(delta: number): Promise<void> {
const separator = this.page.getByRole("separator", { name: "Click or drag to expand" });
const boundingRectangle = await separator.boundingBox();
// Place the cursor in the center of the separator
const centerX = boundingRectangle.x + boundingRectangle.width / 2;
await this.page.mouse.move(centerX, boundingRectangle.y);
// Drag the cursor by delta pixels
await this.page.mouse.down();
await this.page.mouse.move(centerX + delta, boundingRectangle.y);
await this.page.mouse.up();
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 26 KiB