Add a class to track auto collapse state

- An object of this class can be used by all the behaviours to
  collapse/expand the panel
- Can also query whether the panel is already collapsed
This commit is contained in:
R Midhun Suresh 2026-03-29 19:38:13 +05:30
parent 26dce9ff47
commit 8a6ef20865
No known key found for this signature in database
2 changed files with 127 additions and 0 deletions

View File

@ -0,0 +1,72 @@
/*
* 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 type { PanelImperativeHandle } from "@element-hq/web-shared-components";
/**
* Contains auto-collapsed state and methods to expand/collapse the panel.
* This class is used by the different auto-collapse behaviours.
*/
export class CollapseHandler {
/**
* @param setCollapsed Callback that will be called when the handler changes the collapsed state.
*/
public constructor(private readonly setCollapsed: (collapsed: boolean) => void) {}
/**
* This gives access to the panel's imperative methods.
*/
public panelHandle?: PanelImperativeHandle;
/**
* Whether the left-panel is auto-collapsed.
*/
public isAutoCollapsed: boolean = false;
/**
* Stores the width to which the left-panel should be restored to when the auto-collapsed
* panel is expanded due to the window being resized.
*/
private restoreWidth?: number;
/**
* Make the panel API from react-resizable-panels available to this class.
* @param handle The panel handle to access react-resizable-panels API.
*/
public setHandle = (handle: PanelImperativeHandle): void => {
this.panelHandle = handle;
this.restoreWidth = this.panelHandle?.getSize().inPixels;
};
/**
* Update {@link CollapseHandler#restoreWidth} with the up to date width of the left panel.
*/
public updateRestoreWidth = (): void => {
// Takes a bit of time for the library to update the pixel values.
window.setTimeout(() => {
this.restoreWidth = this.panelHandle?.getSize().inPixels;
}, 500);
};
/**
* Collapse the left panel.
*/
public collapse = (): void => {
this.isAutoCollapsed = true;
this.panelHandle?.collapse();
this.setCollapsed(true);
};
/**
* Expand the left panel.
*/
public expand = (): void => {
this.isAutoCollapsed = false;
this.panelHandle?.resize(this.restoreWidth!);
this.setCollapsed(false);
};
}

View File

@ -0,0 +1,55 @@
/*
* 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 type { PanelImperativeHandle } from "@element-hq/web-shared-components";
import { CollapseHandler } from "../../../../src/viewmodels/structures/auto-collapse/CollapseHandler";
import { MockPanelHandle } from "./mocks";
function setup() {
const setCollapsed = jest.fn();
const panelHandle = new MockPanelHandle();
const collapseHandler = new CollapseHandler(setCollapsed);
collapseHandler.setHandle(panelHandle as unknown as PanelImperativeHandle);
return { collapseHandler, panelHandle, setCollapsed };
}
jest.useFakeTimers();
describe("CollapseHandler", () => {
it("should collapse panel on collapse()", () => {
const { collapseHandler, panelHandle, setCollapsed } = setup();
collapseHandler.collapse();
expect(setCollapsed).toHaveBeenCalledWith(true);
expect(panelHandle.collapse).toHaveBeenCalledTimes(1);
expect(collapseHandler.isAutoCollapsed).toBe(true);
});
it("should expand panel on expand()", () => {
const { collapseHandler, panelHandle, setCollapsed } = setup();
collapseHandler.expand();
expect(setCollapsed).toHaveBeenCalledWith(false);
expect(panelHandle.resize).toHaveBeenCalledTimes(1);
expect(collapseHandler.isAutoCollapsed).toBe(false);
});
it("should update restoreWidth on updateRestoreWidth()", () => {
const { collapseHandler, panelHandle } = setup();
collapseHandler.updateRestoreWidth();
jest.runAllTimers();
expect(panelHandle.getSize).toHaveBeenCalled();
});
it("should update restoreWidth on setHandle", () => {
const setCollapsed = jest.fn();
const panelHandle = new MockPanelHandle();
const collapseHandler = new CollapseHandler(setCollapsed);
expect(collapseHandler.panelHandle).toBeUndefined();
collapseHandler.setHandle(panelHandle as unknown as PanelImperativeHandle);
expect(collapseHandler.panelHandle).toBe(panelHandle);
expect(panelHandle.getSize).toHaveBeenCalled();
});
});