Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 2 additions & 13 deletions lib/global/styles/sizeStyleToPixels.test.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,14 @@
import { afterEach, beforeEach, describe, expect, test } from "vitest";
import { NOOP_FUNCTION } from "../../constants";
import {
mockGetComputedStyle,
setDefaultElementStyle
} from "../../utils/test/mockGetComputedStyle";
import { beforeEach, describe, expect, test } from "vitest";
import { setDefaultElementStyle } from "../../utils/test/mockGetComputedStyle";
import { sizeStyleToPixels } from "./sizeStyleToPixels";

describe("sizeStyleToPixels", () => {
let panelElement: HTMLElement;
let unmockGetComputedStyle = NOOP_FUNCTION;

beforeEach(() => {
unmockGetComputedStyle = mockGetComputedStyle();

panelElement = document.createElement("div");
});

afterEach(() => {
unmockGetComputedStyle();
});

describe("implicit units", () => {
test("% units", () => {
expect(
Expand Down
56 changes: 52 additions & 4 deletions lib/global/utils/getImperativePanelMethods.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import type {
PanelConstraints,
PanelImperativeHandle
} from "../../components/panel/types";
import {
mockGetComputedStyle,
setDefaultElementStyle
} from "../../utils/test/mockGetComputedStyle";
import { mountGroup } from "../mountGroup";
import { subscribeToMountedGroup } from "../mutable-state/groups";
import { mockGroup } from "../test/mockGroup";
Expand Down Expand Up @@ -294,23 +298,67 @@ describe("getImperativePanelMethods", () => {
});

describe("resize", () => {
describe("units", () => {
test("accepts percentage units", () => {
const { panelApis } = init([{}, {}]);
panelApis[0].resize("35%");

expect(onLayoutChange).toHaveBeenCalledTimes(1);
expect(onLayoutChange).toHaveBeenCalledWith([35, 65]);
});

test("accepts pixel units", () => {
// Computed group size is 1,000
const { panelApis } = init([{}, {}]);
panelApis[0].resize(400);

expect(onLayoutChange).toHaveBeenCalledTimes(1);
expect(onLayoutChange).toHaveBeenCalledWith([40, 60]);
});

test("accepts rem units", () => {
setDefaultElementStyle({
fontSize: 16,
writingMode: ""
} as unknown as CSSStyleDeclaration);
mockGetComputedStyle();

const { panelApis } = init([{}, {}]);
panelApis[0].resize("10rem");

expect(onLayoutChange).toHaveBeenCalledTimes(1);
expect(onLayoutChange).toHaveBeenCalledWith([16, 84]);
});

test("accepts viewport units", () => {
window.innerHeight = 2000;
window.innerWidth = 2000;

const { panelApis } = init([{}, {}]);
panelApis[0].resize("15vw");

expect(onLayoutChange).toHaveBeenCalledTimes(1);
expect(onLayoutChange).toHaveBeenCalledWith([30, 70]);
});
});

test("ignores a no-op size update", () => {
const { panelApis } = init([{ defaultSize: 10 }, {}]);
panelApis[0].resize(10);
panelApis[0].resize("10%");

expect(onLayoutChange).not.toHaveBeenCalled();
});

test("ignores an invalid size update", () => {
const { panelApis } = init([{ defaultSize: 10, minSize: 10 }, {}]);
panelApis[0].resize(0);
panelApis[0].resize("0%");

expect(onLayoutChange).not.toHaveBeenCalled();
});

test("validates and updates the panel size", () => {
const { panelApis } = init([{ defaultSize: 25, minSize: 10 }, {}]);
panelApis[0].resize(0);
panelApis[0].resize("0%");

expect(onLayoutChange).toHaveBeenCalledTimes(1);
expect(onLayoutChange).toHaveBeenCalledWith([10, 90]);
Expand All @@ -322,7 +370,7 @@ describe("getImperativePanelMethods", () => {
{}
]);

panelApis[0].resize(0);
panelApis[0].resize("0%");

expect(onLayoutChange).toHaveBeenCalledTimes(1);
expect(onLayoutChange).toHaveBeenCalledWith([10, 90]);
Expand Down
30 changes: 13 additions & 17 deletions lib/global/utils/getImperativePanelMethods.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { PanelImperativeHandle } from "../../components/panel/types";
import { calculateAvailableGroupSize } from "../dom/calculateAvailableGroupSize";
import { getMountedGroups, updateMountedGroup } from "../mutable-state/groups";
import { sizeStyleToPixels } from "../styles/sizeStyleToPixels";
import { adjustLayoutByDelta } from "./adjustLayoutByDelta";
import { formatLayoutNumber } from "./formatLayoutNumber";
import { layoutNumbersEqual } from "./layoutNumbersEqual";
Expand Down Expand Up @@ -164,24 +165,19 @@ export function getImperativePanelMethods({
return collapsible && layoutNumbersEqual(collapsedSize, size);
},
resize: (size: number | string) => {
const prevSize = getPanelSize();
if (prevSize !== size) {
let asPercentage;
switch (typeof size) {
case "number": {
const { group } = find();
const groupSize = calculateAvailableGroupSize({ group });
asPercentage = formatLayoutNumber((size / groupSize) * 100);
break;
}
case "string": {
asPercentage = parseFloat(size);
break;
}
}
const { group } = find();
const { element } = getPanel();
const groupSize = calculateAvailableGroupSize({ group });

setPanelSize(asPercentage);
}
const asPixels = sizeStyleToPixels({
groupSize,
panelElement: element,
styleProp: size
});

const asPercentage = formatLayoutNumber((asPixels / groupSize) * 100);

setPanelSize(asPercentage);
}
} satisfies PanelImperativeHandle;
}
18 changes: 9 additions & 9 deletions lib/utils/test/mockBoundingClientRect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import EventEmitter from "node:events";

type GetDOMRect = (element: HTMLElement) => DOMRectReadOnly | undefined | void;

const originalGetBoundingClientRect =
HTMLElement.prototype.getBoundingClientRect;

export const emitter = new EventEmitter();
emitter.setMaxListeners(100);

Expand Down Expand Up @@ -76,9 +79,6 @@ export function setElementBounds(element: HTMLElement, rect: DOMRect) {
}

export function mockBoundingClientRect() {
const originalGetBoundingClientRect =
HTMLElement.prototype.getBoundingClientRect;

HTMLElement.prototype.getBoundingClientRect =
function getBoundingClientRect() {
if (getDOMRect) {
Expand Down Expand Up @@ -129,13 +129,13 @@ export function mockBoundingClientRect() {
return (this as HTMLElement).getBoundingClientRect().width;
}
});
}

return function unmockBoundingClientRect() {
HTMLElement.prototype.getBoundingClientRect = originalGetBoundingClientRect;
export function unmockBoundingClientRect() {
HTMLElement.prototype.getBoundingClientRect = originalGetBoundingClientRect;

defaultDomRect = new DOMRect(0, 0, 0, 0);
getDOMRect = undefined;
defaultDomRect = new DOMRect(0, 0, 0, 0);
getDOMRect = undefined;

elementToDOMRect.clear();
};
elementToDOMRect.clear();
}
29 changes: 19 additions & 10 deletions lib/utils/test/mockGetComputedStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,29 @@ import { EventEmitter } from "stream";

const elementToStyle = new Map<Element, CSSStyleDeclaration>();

const originalGetComputedStyle = window.getComputedStyle;

let defaultStyle: CSSStyleDeclaration | undefined = undefined;

const emptyStyle = {} as CSSStyleDeclaration;

export const emitter = new EventEmitter();
emitter.setMaxListeners(100);

export function mockGetComputedStyle() {
const originalGetComputedStyle = window.getComputedStyle;

window.getComputedStyle = function getComputedStyle(element: Element) {
return (
elementToStyle.get(element) ??
defaultStyle ??
originalGetComputedStyle(element)
);
};
return new Proxy(emptyStyle, {
get(_, name) {
const key = name as keyof CSSStyleDeclaration;

return () => {
window.getComputedStyle = originalGetComputedStyle;
const mockedStyle =
elementToStyle.get(element) ?? defaultStyle ?? emptyStyle;

const actualStyle = originalGetComputedStyle(element);

return name in mockedStyle ? mockedStyle[key] : actualStyle[key];
}
});
};
}

Expand All @@ -34,3 +39,7 @@ export function setElementStyle(element: Element, style: CSSStyleDeclaration) {

emitter.emit("change", element);
}

export function unmockGetComputedStyle() {
window.getComputedStyle = originalGetComputedStyle;
}
12 changes: 6 additions & 6 deletions lib/utils/test/mockResizeObserver.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { emitter } from "./mockBoundingClientRect";

const originalResizeObserver = window.ResizeObserver;

let disabled: boolean = false;

export function disableResizeObserverForCurrentTest() {
Expand All @@ -14,15 +16,13 @@ export function simulateUnsupportedEnvironmentForTest() {
export function mockResizeObserver() {
disabled = false;

const originalResizeObserver = window.ResizeObserver;

window.ResizeObserver = MockResizeObserver;
}

return function unmockResizeObserver() {
window.ResizeObserver = originalResizeObserver;
export function unmockResizeObserver() {
window.ResizeObserver = originalResizeObserver;

disabled = false;
};
disabled = false;
}

class MockResizeObserver implements ResizeObserver {
Expand Down
32 changes: 18 additions & 14 deletions vitest.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ import { cleanup } from "@testing-library/react";
import { afterAll, afterEach, beforeAll, beforeEach, expect, vi } from "vitest";
import failOnConsole from "vitest-fail-on-console";
import { resetMockGroupIdCounter } from "./lib/global/test/mockGroup";
import { mockBoundingClientRect } from "./lib/utils/test/mockBoundingClientRect";
import { mockResizeObserver } from "./lib/utils/test/mockResizeObserver";

let unmockBoundingClientRect: (() => void) | null = null;
let unmockResizeObserver: (() => void) | null = null;
import {
mockBoundingClientRect,
unmockBoundingClientRect
} from "./lib/utils/test/mockBoundingClientRect";
import {
mockGetComputedStyle,
unmockGetComputedStyle
} from "./lib/utils/test/mockGetComputedStyle";
import {
mockResizeObserver,
unmockResizeObserver
} from "./lib/utils/test/mockResizeObserver";

const PROTOTYPE_PROPS = [
"clientHeight",
Expand Down Expand Up @@ -76,20 +83,17 @@ afterAll(() => {
});

beforeEach(() => {
unmockBoundingClientRect = mockBoundingClientRect();
unmockResizeObserver = mockResizeObserver();
mockBoundingClientRect();
mockGetComputedStyle();
mockResizeObserver();
});

afterEach(() => {
cleanup();

resetMockGroupIdCounter();

if (unmockBoundingClientRect) {
unmockBoundingClientRect();
}

if (unmockResizeObserver) {
unmockResizeObserver();
}
unmockBoundingClientRect();
unmockGetComputedStyle();
unmockResizeObserver();
});
Loading