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:
R Midhun Suresh 2026-03-29 19:33:15 +05:30
parent 4f9a0321b5
commit ebe7d5191f
No known key found for this signature in database
2 changed files with 112 additions and 3 deletions

View File

@ -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);
};
}

View 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);
});
});