mirror of
https://github.com/vector-im/element-web.git
synced 2026-05-05 20:26:19 +02:00
Add functionality to UIStore
- Make it possible to query if the window is currently being resized - Emit WidthIncreased/WidthDecreased events
This commit is contained in:
parent
4f9a0321b5
commit
ebe7d5191f
@ -10,6 +10,8 @@ import EventEmitter from "events";
|
||||
|
||||
export enum UI_EVENTS {
|
||||
Resize = "resize",
|
||||
WidthIncreased = "width-increased",
|
||||
WidthDecreased = "width-decreased",
|
||||
}
|
||||
|
||||
export default class UIStore extends EventEmitter {
|
||||
@ -19,9 +21,14 @@ export default class UIStore extends EventEmitter {
|
||||
|
||||
private uiElementDimensions = new Map<string, DOMRectReadOnly>();
|
||||
private trackedUiElements = new Map<Element, string>();
|
||||
private timeoutId: number = 0;
|
||||
|
||||
public windowWidth: number;
|
||||
public windowHeight: number;
|
||||
/**
|
||||
* Whether the window is currently being resized.
|
||||
*/
|
||||
public isWindowBeingResized: boolean = false;
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
@ -38,6 +45,7 @@ export default class UIStore extends EventEmitter {
|
||||
public static get instance(): UIStore {
|
||||
if (!UIStore._instance) {
|
||||
UIStore._instance = new UIStore();
|
||||
window.mxUIStore = UIStore._instance;
|
||||
}
|
||||
return UIStore._instance;
|
||||
}
|
||||
@ -81,7 +89,12 @@ export default class UIStore extends EventEmitter {
|
||||
const windowEntry = entries.find((entry) => entry.target === document.body);
|
||||
|
||||
if (windowEntry) {
|
||||
this.windowWidth = windowEntry.contentRect.width;
|
||||
this.setWindowAsBeingResized();
|
||||
|
||||
const currentWidth = windowEntry.contentRect.width;
|
||||
this.emitWidthChangeEvents(currentWidth);
|
||||
|
||||
this.windowWidth = currentWidth;
|
||||
this.windowHeight = windowEntry.contentRect.height;
|
||||
}
|
||||
|
||||
@ -95,6 +108,29 @@ export default class UIStore extends EventEmitter {
|
||||
|
||||
this.emit(UI_EVENTS.Resize, entries);
|
||||
};
|
||||
}
|
||||
|
||||
window.mxUIStore = UIStore.instance;
|
||||
/**
|
||||
* Emit any necessary {@link UI_EVENTS.WidthIncreased} or {@link UI_EVENTS.WidthDecreased} events.
|
||||
* @param currentWidth The current width of {@link window}
|
||||
*/
|
||||
private emitWidthChangeEvents = (currentWidth: number): void => {
|
||||
if (currentWidth > this.windowWidth) this.emit(UI_EVENTS.WidthIncreased, currentWidth);
|
||||
if (currentWidth < this.windowWidth) this.emit(UI_EVENTS.WidthDecreased, currentWidth);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update {@link UIStore#isWindowBeingResized}.
|
||||
*/
|
||||
private setWindowAsBeingResized = (): void => {
|
||||
// Window is being resized, so set to true.
|
||||
this.isWindowBeingResized = true;
|
||||
// Reset any previous timeout.
|
||||
window.clearTimeout(this.timeoutId);
|
||||
// Set to false after a second.
|
||||
// If the window continues to be resized, this method will be called
|
||||
// again and this setTimeout will be cancelled.
|
||||
this.timeoutId = window.setTimeout(() => {
|
||||
this.isWindowBeingResized = false;
|
||||
}, 1000);
|
||||
};
|
||||
}
|
||||
|
||||
73
apps/web/test/unit-tests/stores/UIStore-test.ts
Normal file
73
apps/web/test/unit-tests/stores/UIStore-test.ts
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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 UIStore, { UI_EVENTS } from "../../../src/stores/UIStore";
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
describe("UIStore", () => {
|
||||
class MockResizeObserver {
|
||||
public static instance: ResizeObserver;
|
||||
public static callback: ResizeObserverCallback;
|
||||
|
||||
public constructor(callback: ResizeObserverCallback) {
|
||||
MockResizeObserver.callback = callback;
|
||||
MockResizeObserver.instance = this;
|
||||
}
|
||||
|
||||
public static changeWidth = (width: number): void => {
|
||||
const entry = {
|
||||
target: document.body,
|
||||
contentRect: {
|
||||
width,
|
||||
height: 1000,
|
||||
},
|
||||
} as unknown as ResizeObserverEntry;
|
||||
MockResizeObserver.callback([entry], MockResizeObserver.instance);
|
||||
};
|
||||
|
||||
public observe = jest.fn();
|
||||
public unobserve = jest.fn();
|
||||
public disconnect = jest.fn();
|
||||
}
|
||||
globalThis.ResizeObserver = MockResizeObserver;
|
||||
|
||||
it("should emit events on width increase/decrease", () => {
|
||||
// eslint-disable-next-line no-restricted-properties
|
||||
window.innerWidth = 500;
|
||||
const store = UIStore.instance;
|
||||
|
||||
const onDecrease = jest.fn();
|
||||
store.on(UI_EVENTS.WidthDecreased, onDecrease);
|
||||
MockResizeObserver.changeWidth(200);
|
||||
expect(onDecrease).toHaveBeenCalledWith(200);
|
||||
|
||||
const onIncrease = jest.fn();
|
||||
store.on(UI_EVENTS.WidthIncreased, onIncrease);
|
||||
MockResizeObserver.changeWidth(700);
|
||||
expect(onIncrease).toHaveBeenCalledWith(700);
|
||||
|
||||
UIStore.destroy();
|
||||
});
|
||||
|
||||
it("should set isWindowBeingResized on resize", () => {
|
||||
// eslint-disable-next-line no-restricted-properties
|
||||
window.innerWidth = 500;
|
||||
const store = UIStore.instance;
|
||||
|
||||
// No resize yet, so expect isWindowBeingResized to be false
|
||||
expect(store.isWindowBeingResized).toBe(false);
|
||||
|
||||
// When resizing the window, expect isWindowBeingResized to be true
|
||||
MockResizeObserver.changeWidth(200);
|
||||
expect(store.isWindowBeingResized).toBe(true);
|
||||
|
||||
// After a second, isWindowBeingResized should again become false
|
||||
jest.runAllTimers();
|
||||
expect(store.isWindowBeingResized).toBe(false);
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user