Add a class to orchestrate all the collapse behaviours

This commit is contained in:
R Midhun Suresh 2026-03-29 19:42:07 +05:30
parent 8348fe8eba
commit bc2dc8c912
No known key found for this signature in database
2 changed files with 146 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";
import { CollapseHandler } from "./CollapseHandler";
import type { BaseCollapseBehaviour } from "./behaviours/BaseCollapseBehaviour";
import { Behaviours } from "./behaviours/behaviours";
/**
* This class orchestrates all the auto-collapse behaviours.
*/
export class AutoCollapse {
private readonly behaviours: BaseCollapseBehaviour[] = [];
private readonly collapseHandler: CollapseHandler;
public constructor(setCollapsed: (collapsed: boolean) => void) {
this.collapseHandler = new CollapseHandler(setCollapsed);
for (const Behaviour of Behaviours) {
this.behaviours.push(new Behaviour(this.collapseHandler));
}
}
/**
* When this returns true, any left panel resized events should be ignored.
*/
public get shouldIgnoreResize(): boolean {
return this.behaviours.some((b) => b.shouldIgnoreResize);
}
/**
* Whether the panel is currently auto-collapsed.
*/
public get isAutoCollapsed(): boolean {
return this.collapseHandler.isAutoCollapsed;
}
/**
* Returns boolean indicating whether the left panel should be collapsed at app start.
*/
public static shouldStartCollapsed(): boolean {
return Behaviours.some((B) => B.shouldStartCollapsed());
}
public dispose = (): void => {
for (const behaviour of this.behaviours) {
behaviour.dispose();
}
};
/**
* 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.collapseHandler.setHandle(handle);
};
/**
* Should be called when the left panel is resized.
*/
public onLeftPanelResized = (): void => {
for (const behaviour of this.behaviours) {
behaviour.onLeftPanelResized();
}
this.collapseHandler.isAutoCollapsed = false;
this.collapseHandler.updateRestoreWidth();
};
}

View File

@ -0,0 +1,74 @@
/*
* 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 { AutoCollapse } from "../../../../src/viewmodels/structures/auto-collapse/AutoCollapse";
import { MockPanelHandle } from "./mocks";
import type { CollapseHandler } from "../../../../src/viewmodels/structures/auto-collapse/CollapseHandler";
import { BaseCollapseBehaviour } from "../../../../src/viewmodels/structures/auto-collapse/behaviours/BaseCollapseBehaviour";
let instances: BaseCollapseBehaviour[] = [];
class MockBehaviour extends BaseCollapseBehaviour {
public constructor(collapseHandler: CollapseHandler) {
super(collapseHandler);
instances.push(this);
}
public onLeftPanelResized = jest.fn();
}
class MockBehaviourWithStartCollapsed extends MockBehaviour {
public static shouldStartCollapsed(): boolean {
return true;
}
}
class MockBehaviourWithIgnoreResize extends MockBehaviour {
public get shouldIgnoreResize(): boolean {
return true;
}
}
jest.mock("../../../../src/viewmodels/structures/auto-collapse/behaviours/behaviours", () => {
return {
// eslint-disable-next-line @typescript-eslint/naming-convention
get Behaviours() {
return [MockBehaviour, MockBehaviour, MockBehaviourWithIgnoreResize, MockBehaviourWithStartCollapsed];
},
};
});
describe("AutoCollapse", () => {
beforeEach(() => {
instances = [];
});
it("should call onLeftPanelResized of each behaviour", () => {
const setCollapsed = jest.fn();
const panelHandle = new MockPanelHandle();
const autoCollapse = new AutoCollapse(setCollapsed);
autoCollapse.setHandle(panelHandle as unknown as PanelImperativeHandle);
autoCollapse.onLeftPanelResized();
for (const behaviour of instances) {
expect(behaviour.onLeftPanelResized).toHaveBeenCalledTimes(1);
}
expect(autoCollapse.isAutoCollapsed).toBe(false);
});
it("should calculate shouldStartCollapsed correctly", () => {
expect(AutoCollapse.shouldStartCollapsed()).toBe(true);
});
it("should calculate shouldIgnoreResize correctly", () => {
const setCollapsed = jest.fn();
const panelHandle = new MockPanelHandle();
const autoCollapse = new AutoCollapse(setCollapsed);
autoCollapse.setHandle(panelHandle as unknown as PanelImperativeHandle);
expect(autoCollapse.shouldIgnoreResize).toBe(true);
});
});