diff --git a/packages/react-resizable-panels/src/utils/computePercentagePanelConstraints.test.ts b/packages/react-resizable-panels/src/utils/computePercentagePanelConstraints.test.ts index 8be84c2c4..0c8d485e6 100644 --- a/packages/react-resizable-panels/src/utils/computePercentagePanelConstraints.test.ts +++ b/packages/react-resizable-panels/src/utils/computePercentagePanelConstraints.test.ts @@ -68,4 +68,31 @@ describe("computePercentagePanelConstraints", () => { } `); }); + + it("should compute reasonable percentage based constraints from pixels if group size is negative", () => { + jest.spyOn(console, "warn").mockImplementation(() => {}); + + expect( + computePercentagePanelConstraints( + [ + { + minSizePixels: 25, + maxSizePixels: 100, + }, + ], + + 0, + -100 + ) + ).toMatchInlineSnapshot(` +{ + "collapsedSizePercentage": 0, + "defaultSizePercentage": undefined, + "maxSizePercentage": 0, + "minSizePercentage": 0, +} +`); + + expect(console.warn).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/react-resizable-panels/src/utils/convertPixelConstraintsToPercentages.test.ts b/packages/react-resizable-panels/src/utils/convertPixelConstraintsToPercentages.test.ts new file mode 100644 index 000000000..1065e577c --- /dev/null +++ b/packages/react-resizable-panels/src/utils/convertPixelConstraintsToPercentages.test.ts @@ -0,0 +1,47 @@ +import { convertPixelConstraintsToPercentages } from "./convertPixelConstraintsToPercentages"; + +describe("convertPixelConstraintsToPercentages", () => { + it("should respect percentage panel constraints if group size is negative", () => { + jest.spyOn(console, "warn").mockImplementation(() => {}); + + expect( + convertPixelConstraintsToPercentages( + { + minSizePercentage: 25, + defaultSizePercentage: 50, + maxSizePercentage: 75, + }, + -100 + ) + ).toEqual({ + collapsedSizePercentage: 0, + defaultSizePercentage: 50, + maxSizePercentage: 75, + minSizePercentage: 25, + }); + + expect(console.warn).toHaveBeenCalledTimes(0); + }); + + // Edge case test (issues/206) + it("should ignore pixel panel constraints if group size is negative", () => { + jest.spyOn(console, "warn").mockImplementation(() => {}); + + expect( + convertPixelConstraintsToPercentages( + { + minSizePixels: 25, + maxSizePixels: 75, + }, + -100 + ) + ).toEqual({ + collapsedSizePercentage: 0, + defaultSizePercentage: undefined, + maxSizePercentage: 0, + minSizePercentage: 0, + }); + + expect(console.warn).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/react-resizable-panels/src/utils/convertPixelConstraintsToPercentages.ts b/packages/react-resizable-panels/src/utils/convertPixelConstraintsToPercentages.ts index d4348f3ff..ce682370b 100644 --- a/packages/react-resizable-panels/src/utils/convertPixelConstraintsToPercentages.ts +++ b/packages/react-resizable-panels/src/utils/convertPixelConstraintsToPercentages.ts @@ -21,6 +21,23 @@ export function convertPixelConstraintsToPercentages( minSizePixels, } = panelConstraints; + const hasPixelConstraints = + collapsedSizePixels != null || + defaultSizePixels != null || + minSizePixels != null || + maxSizePixels != null; + + if (hasPixelConstraints && groupSizePixels <= 0) { + console.warn(`WARNING: Invalid group size: ${groupSizePixels}px`); + + return { + collapsedSizePercentage: 0, + defaultSizePercentage, + maxSizePercentage: 0, + minSizePercentage: 0, + }; + } + if (collapsedSizePixels != null) { collapsedSizePercentage = convertPixelsToPercentage( collapsedSizePixels, diff --git a/packages/react-resizable-panels/src/utils/resizePanel.test.ts b/packages/react-resizable-panels/src/utils/resizePanel.test.ts new file mode 100644 index 000000000..907a0c21e --- /dev/null +++ b/packages/react-resizable-panels/src/utils/resizePanel.test.ts @@ -0,0 +1,45 @@ +import { resizePanel } from "./resizePanel"; + +describe("resizePanel", () => { + // Edge case test (issues/206) + fit("should respect percentage panel constraints if group size is negative", () => { + jest.spyOn(console, "warn").mockImplementation(() => {}); + + expect( + resizePanel({ + groupSizePixels: -100, + panelConstraints: [ + { + minSizePercentage: 25, + maxSizePercentage: 75, + }, + ], + panelIndex: 0, + size: 50, + }) + ).toBe(50); + + expect(console.warn).toHaveBeenCalledTimes(0); + }); + + // Edge case test (issues/206) + it("should handle pixel panel constraints if group size is negative", () => { + jest.spyOn(console, "warn").mockImplementation(() => {}); + + expect( + resizePanel({ + groupSizePixels: -100, + panelConstraints: [ + { + minSizePixels: 25, + maxSizePixels: 75, + }, + ], + panelIndex: 0, + size: 50, + }) + ).toBe(0); + + expect(console.warn).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/react-resizable-panels/src/utils/resizePanel.ts b/packages/react-resizable-panels/src/utils/resizePanel.ts index c8bc51789..2d526cb59 100644 --- a/packages/react-resizable-panels/src/utils/resizePanel.ts +++ b/packages/react-resizable-panels/src/utils/resizePanel.ts @@ -5,7 +5,7 @@ import { fuzzyCompareNumbers } from "./numbers/fuzzyCompareNumbers"; // Panel size must be in percentages; pixel values should be pre-converted export function resizePanel({ groupSizePixels, - panelConstraints, + panelConstraints: panelConstraintsArray, panelIndex, size, }: { @@ -14,14 +14,39 @@ export function resizePanel({ panelIndex: number; size: number; }) { - let { collapsible } = panelConstraints[panelIndex]!; - - const { collapsedSizePercentage, maxSizePercentage, minSizePercentage } = - computePercentagePanelConstraints( - panelConstraints, - panelIndex, - groupSizePixels - ); + const hasPixelConstraints = panelConstraintsArray.some( + ({ + collapsedSizePixels, + defaultSizePixels, + minSizePixels, + maxSizePixels, + }) => + collapsedSizePixels != null || + defaultSizePixels != null || + minSizePixels != null || + maxSizePixels != null + ); + + if (hasPixelConstraints && groupSizePixels <= 0) { + console.warn(`WARNING: Invalid group size: ${groupSizePixels}px`); + + return 0; + } + + const panelConstraints = panelConstraintsArray[panelIndex]!; + let { collapsible } = panelConstraints; + + const { + collapsedSizePercentage = 0, + maxSizePercentage, + minSizePercentage, + } = hasPixelConstraints + ? computePercentagePanelConstraints( + panelConstraintsArray, + panelIndex, + groupSizePixels + ) + : panelConstraints; if (minSizePercentage != null) { if (fuzzyCompareNumbers(size, minSizePercentage) < 0) {