From b7e05d23e19b5dd127ce67941bb7d7915a52ba2e Mon Sep 17 00:00:00 2001 From: Timur Sufiev Date: Thu, 7 Dec 2023 14:44:37 +0000 Subject: [PATCH] Normalize layouts not totalling to 100% Resolves #227 --- .../utils/validatePanelGroupLayout.test.ts | 37 +++++++++---------- .../src/utils/validatePanelGroupLayout.ts | 18 +++++---- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/packages/react-resizable-panels/src/utils/validatePanelGroupLayout.test.ts b/packages/react-resizable-panels/src/utils/validatePanelGroupLayout.test.ts index d017f539e..fd8eccf04 100644 --- a/packages/react-resizable-panels/src/utils/validatePanelGroupLayout.test.ts +++ b/packages/react-resizable-panels/src/utils/validatePanelGroupLayout.test.ts @@ -12,26 +12,25 @@ describe("validatePanelGroupLayout", () => { ).toEqual([10, 60, 30]); }); - it("should reject layouts that do not total 100%", () => { - verifyExpectedWarnings( - () => - validatePanelGroupLayout({ - groupSizePixels: NaN, - layout: [10, 20, 30], - panelConstraints: [{}, {}, {}], - }), - "Invalid layout total size" - ); + it("should normalize layouts that do not total 100%", () => { + let layout; + verifyExpectedWarnings(() => { + layout = validatePanelGroupLayout({ + groupSizePixels: NaN, + layout: [10, 20, 20], + panelConstraints: [{}, {}, {}], + }); + }, "Invalid layout total size"); + expect(layout).toEqual([20, 40, 40]); - verifyExpectedWarnings( - () => - validatePanelGroupLayout({ - groupSizePixels: NaN, - layout: [50, 100, 150], - panelConstraints: [{}, {}, {}], - }), - "Invalid layout total size" - ); + verifyExpectedWarnings(() => { + layout = validatePanelGroupLayout({ + groupSizePixels: NaN, + layout: [50, 100, 50], + panelConstraints: [{}, {}, {}], + }); + }, "Invalid layout total size"); + expect(layout).toEqual([25, 50, 25]); }); it("should reject layouts that do not match the number of panels", () => { diff --git a/packages/react-resizable-panels/src/utils/validatePanelGroupLayout.ts b/packages/react-resizable-panels/src/utils/validatePanelGroupLayout.ts index 50d4b3168..134db0584 100644 --- a/packages/react-resizable-panels/src/utils/validatePanelGroupLayout.ts +++ b/packages/react-resizable-panels/src/utils/validatePanelGroupLayout.ts @@ -14,6 +14,10 @@ export function validatePanelGroupLayout({ panelConstraints: PanelConstraints[]; }): number[] { const nextLayout = [...prevLayout]; + const nextLayoutTotalSize = nextLayout.reduce( + (accumulated, current) => accumulated + current, + 0 + ); // Validate layout expectations if (nextLayout.length !== panelConstraints.length) { @@ -22,21 +26,21 @@ export function validatePanelGroupLayout({ .map((size) => `${size}%`) .join(", ")}` ); - } else if ( - !fuzzyNumbersEqual( - nextLayout.reduce((accumulated, current) => accumulated + current, 0), - 100 - ) - ) { + } else if (!fuzzyNumbersEqual(nextLayoutTotalSize, 100)) { // This is not ideal so we should warn about it, but it may be recoverable in some cases // (especially if the amount is small) if (isDevelopment) { console.warn( `WARNING: Invalid layout total size: ${nextLayout .map((size) => `${size}%`) - .join(", ")}` + .join(", ")}. Layout normalization will be applied.` ); } + for (let index = 0; index < panelConstraints.length; index++) { + const unsafeSize = nextLayout[index]!; + const safeSize = (100 / nextLayoutTotalSize) * unsafeSize; + nextLayout[index] = safeSize; + } } let remainingSize = 0;