Implement collapsible panels for the new room list (#32742)
* Add `react-resizable-panels` library * Implement a custom SeparatorView * Add a `LeftResizablePanelView` * Add a custom `GroupView` * Export everything from shared-components * Make it possible to track width/collapse state through settings * Add a view model to drive the views * Render views without disrupting the old room list * Fix lint error * Disable user interaction on collapsed panel * Prevent widgets fron hijacking pointer events * Expand to full width on separator click * Separator should be shown when focused via keyboard * Update tests * Use data-attribute for hover * Write stories for SeperatorView * Write vite tests for SeparatorView * Write tests for LeftResizablePanelView * More tests * Fix lint errors * Fix flakey border on the roomlst * Fix storybook axe violation * Update snapshots * Fix playwright tests * Fix sonarcloud issues * Use translated string * Add better js-doc comments * Rename `ResizerSnapshot` to `ResizerViewSnapshot` * Externalize react-resizable-panels * Link figma designs to stories * Write playwright tests * Update screenshots * Fix lint errors * Update more screenshots * Update more screenshots * Fix flaky toast test * Update apps/web/playwright/e2e/crypto/toasts.spec.ts Co-authored-by: Andy Balaam <andy.balaam@matrix.org> * Fix indentation --------- Co-authored-by: Andy Balaam <andy.balaam@matrix.org>
This commit is contained in:
co-authored by
Andy Balaam
parent
89261bbe00
commit
99e6ede9f1
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { waitFor } from "jest-matrix-react";
|
||||
import { type PanelImperativeHandle } from "@element-hq/web-shared-components";
|
||||
import whatInput from "what-input";
|
||||
|
||||
import { ResizerViewModel } from "../../../src/viewmodels/structures/ResizerViewModel";
|
||||
import SettingsStore from "../../../src/settings/SettingsStore";
|
||||
import { SettingLevel } from "../../../src/settings/SettingLevel";
|
||||
|
||||
jest.mock("what-input");
|
||||
|
||||
describe("LeftPanelResizerViewModel", () => {
|
||||
afterEach(() => {
|
||||
SettingsStore.reset();
|
||||
});
|
||||
|
||||
describe("Initial state is correct", () => {
|
||||
it("should have correct initial state when panel was previously collapsed", () => {
|
||||
SettingsStore.setValue("RoomList.isPanelCollapsed", null, SettingLevel.DEVICE, true);
|
||||
const vm = new ResizerViewModel();
|
||||
expect(vm.getSnapshot()).toStrictEqual({
|
||||
isCollapsed: true,
|
||||
initialSize: 0,
|
||||
isFocusedViaKeyboard: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("should have correct initial state when panel was previously resized", () => {
|
||||
SettingsStore.setValue("RoomList.panelSize", null, SettingLevel.DEVICE, 34);
|
||||
const vm = new ResizerViewModel();
|
||||
expect(vm.getSnapshot()).toStrictEqual({
|
||||
isCollapsed: false,
|
||||
initialSize: 34,
|
||||
isFocusedViaKeyboard: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("should have correct initial state when panel was neither resized nor collapsed", () => {
|
||||
const vm = new ResizerViewModel();
|
||||
expect(vm.getSnapshot()).toStrictEqual({
|
||||
isCollapsed: false,
|
||||
initialSize: undefined,
|
||||
isFocusedViaKeyboard: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should update isCollapsed on onLeftPanelResized()", async () => {
|
||||
const vm = new ResizerViewModel();
|
||||
vm.onLeftPanelResize({ inPixels: 100, asPercentage: 6 });
|
||||
await waitFor(() => {
|
||||
expect(vm.getSnapshot().isCollapsed).toStrictEqual(false);
|
||||
});
|
||||
vm.onLeftPanelResize({ inPixels: 0, asPercentage: 6 });
|
||||
await waitFor(() => {
|
||||
expect(vm.getSnapshot().isCollapsed).toStrictEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("should noop on onSeparatorClick() when handle is not yet set", () => {
|
||||
const vm = new ResizerViewModel();
|
||||
expect(() => vm.onSeparatorClick()).not.toThrow();
|
||||
});
|
||||
|
||||
it("should expand panel on onSeparatorClick()", () => {
|
||||
const vm = new ResizerViewModel();
|
||||
const mockHandle = {
|
||||
resize: jest.fn(),
|
||||
isCollapsed: jest.fn().mockReturnValue(true),
|
||||
} as unknown as PanelImperativeHandle;
|
||||
vm.setPanelHandle(mockHandle);
|
||||
|
||||
vm.onSeparatorClick();
|
||||
|
||||
expect(mockHandle.resize).toHaveBeenCalledWith("100%");
|
||||
});
|
||||
|
||||
it("should set isFocusedViaKeyboard state correctly", () => {
|
||||
whatInput.ask = jest.fn().mockReturnValue("keyboard");
|
||||
const vm = new ResizerViewModel();
|
||||
vm.onFocus();
|
||||
expect(vm.getSnapshot().isFocusedViaKeyboard).toStrictEqual(true);
|
||||
vm.onBlur();
|
||||
expect(vm.getSnapshot().isFocusedViaKeyboard).toStrictEqual(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user