react-resizable-panels 0.0.55 → 0.0.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +26 -0
- package/CHANGELOG.md +238 -90
- package/README.md +55 -49
- package/dist/declarations/src/Panel.d.ts +75 -20
- package/dist/declarations/src/PanelGroup.d.ts +29 -25
- package/dist/declarations/src/PanelResizeHandle.d.ts +1 -1
- package/dist/declarations/src/index.d.ts +5 -6
- package/dist/declarations/src/types.d.ts +3 -26
- package/dist/declarations/src/vendor/react.d.ts +4 -4
- package/dist/react-resizable-panels.browser.cjs.js +1276 -1043
- package/dist/react-resizable-panels.browser.cjs.mjs +1 -2
- package/dist/react-resizable-panels.browser.development.cjs.js +1410 -1097
- package/dist/react-resizable-panels.browser.development.cjs.mjs +1 -2
- package/dist/react-resizable-panels.browser.development.esm.js +1411 -1097
- package/dist/react-resizable-panels.browser.esm.js +1277 -1043
- package/dist/react-resizable-panels.cjs.js +1276 -1043
- package/dist/react-resizable-panels.cjs.js.map +1 -1
- package/dist/react-resizable-panels.cjs.mjs +1 -2
- package/dist/react-resizable-panels.development.cjs.js +1415 -1102
- package/dist/react-resizable-panels.development.cjs.mjs +1 -2
- package/dist/react-resizable-panels.development.esm.js +1416 -1102
- package/dist/react-resizable-panels.development.node.cjs.js +1179 -947
- package/dist/react-resizable-panels.development.node.cjs.mjs +1 -2
- package/dist/react-resizable-panels.development.node.esm.js +1180 -947
- package/dist/react-resizable-panels.esm.js +1277 -1043
- package/dist/react-resizable-panels.esm.js.map +1 -1
- package/dist/react-resizable-panels.node.cjs.js +1068 -910
- package/dist/react-resizable-panels.node.cjs.mjs +1 -2
- package/dist/react-resizable-panels.node.esm.js +1069 -910
- package/jest.config.js +10 -0
- package/package.json +5 -1
- package/src/Panel.test.tsx +308 -0
- package/src/Panel.ts +175 -123
- package/src/PanelGroup.test.tsx +210 -0
- package/src/PanelGroup.ts +730 -667
- package/src/PanelGroupContext.ts +33 -0
- package/src/PanelResizeHandle.ts +21 -17
- package/src/hooks/useUniqueId.ts +1 -1
- package/src/hooks/useWindowSplitterBehavior.ts +9 -164
- package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +185 -0
- package/src/index.ts +19 -14
- package/src/types.ts +3 -30
- package/src/utils/adjustLayoutByDelta.test.ts +1808 -0
- package/src/utils/adjustLayoutByDelta.ts +211 -0
- package/src/utils/calculateAriaValues.test.ts +111 -0
- package/src/utils/calculateAriaValues.ts +67 -0
- package/src/utils/calculateDeltaPercentage.ts +68 -0
- package/src/utils/calculateDragOffsetPercentage.ts +30 -0
- package/src/utils/calculateUnsafeDefaultLayout.test.ts +92 -0
- package/src/utils/calculateUnsafeDefaultLayout.ts +55 -0
- package/src/utils/callPanelCallbacks.ts +81 -0
- package/src/utils/compareLayouts.test.ts +9 -0
- package/src/utils/compareLayouts.ts +12 -0
- package/src/utils/computePanelFlexBoxStyle.ts +44 -0
- package/src/utils/computePercentagePanelConstraints.test.ts +98 -0
- package/src/utils/computePercentagePanelConstraints.ts +56 -0
- package/src/utils/convertPercentageToPixels.test.ts +9 -0
- package/src/utils/convertPercentageToPixels.ts +6 -0
- package/src/utils/convertPixelConstraintsToPercentages.test.ts +47 -0
- package/src/utils/convertPixelConstraintsToPercentages.ts +72 -0
- package/src/utils/convertPixelsToPercentage.test.ts +9 -0
- package/src/utils/convertPixelsToPercentage.ts +6 -0
- package/src/utils/determinePivotIndices.ts +10 -0
- package/src/utils/dom/calculateAvailablePanelSizeInPixels.ts +29 -0
- package/src/utils/dom/getAvailableGroupSizePixels.ts +29 -0
- package/src/utils/dom/getPanelElement.ts +7 -0
- package/src/utils/dom/getPanelGroupElement.ts +9 -0
- package/src/utils/dom/getResizeHandleElement.ts +9 -0
- package/src/utils/dom/getResizeHandleElementIndex.ts +12 -0
- package/src/utils/dom/getResizeHandleElementsForGroup.ts +9 -0
- package/src/utils/dom/getResizeHandlePanelIds.ts +18 -0
- package/src/utils/events.ts +13 -0
- package/src/utils/getPercentageSizeFromMixedSizes.test.ts +47 -0
- package/src/utils/getPercentageSizeFromMixedSizes.ts +15 -0
- package/src/utils/getResizeEventCursorPosition.ts +19 -0
- package/src/utils/initializeDefaultStorage.ts +26 -0
- package/src/utils/numbers/fuzzyCompareNumbers.test.ts +16 -0
- package/src/utils/numbers/fuzzyCompareNumbers.ts +17 -0
- package/src/utils/numbers/fuzzyNumbersEqual.ts +9 -0
- package/src/utils/resizePanel.test.ts +45 -0
- package/src/utils/resizePanel.ts +60 -0
- package/src/utils/serialization.ts +9 -4
- package/src/utils/shouldMonitorPixelBasedConstraints.test.ts +23 -0
- package/src/utils/shouldMonitorPixelBasedConstraints.ts +13 -0
- package/src/utils/test-utils.ts +136 -0
- package/src/utils/validatePanelConstraints.test.ts +151 -0
- package/src/utils/validatePanelConstraints.ts +103 -0
- package/src/utils/validatePanelGroupLayout.test.ts +233 -0
- package/src/utils/validatePanelGroupLayout.ts +88 -0
- package/src/vendor/react.ts +4 -0
- package/.eslintrc.json +0 -22
- package/dist/declarations/src/utils/group.d.ts +0 -29
- package/src/PanelContexts.ts +0 -22
- package/src/utils/coordinates.ts +0 -149
- package/src/utils/group.ts +0 -614
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ResizeEvent } from "../PanelGroupContext";
|
|
2
|
+
import { Direction } from "../types";
|
|
3
|
+
import { isMouseEvent, isTouchEvent } from "./events";
|
|
4
|
+
|
|
5
|
+
export function getResizeEventCursorPosition(
|
|
6
|
+
direction: Direction,
|
|
7
|
+
event: ResizeEvent
|
|
8
|
+
): number {
|
|
9
|
+
const isHorizontal = direction === "horizontal";
|
|
10
|
+
|
|
11
|
+
if (isMouseEvent(event)) {
|
|
12
|
+
return isHorizontal ? event.clientX : event.clientY;
|
|
13
|
+
} else if (isTouchEvent(event)) {
|
|
14
|
+
const firstTouch = event.touches[0];
|
|
15
|
+
return isHorizontal ? firstTouch.screenX : firstTouch.screenY;
|
|
16
|
+
} else {
|
|
17
|
+
throw Error(`Unsupported event type "${event.type}"`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { PanelGroupStorage } from "../PanelGroup";
|
|
2
|
+
|
|
3
|
+
// PanelGroup might be rendering in a server-side environment where localStorage is not available
|
|
4
|
+
// or on a browser with cookies/storage disabled.
|
|
5
|
+
// In either case, this function avoids accessing localStorage until needed,
|
|
6
|
+
// and avoids throwing user-visible errors.
|
|
7
|
+
export function initializeDefaultStorage(storageObject: PanelGroupStorage) {
|
|
8
|
+
try {
|
|
9
|
+
if (typeof localStorage !== "undefined") {
|
|
10
|
+
// Bypass this check for future calls
|
|
11
|
+
storageObject.getItem = (name: string) => {
|
|
12
|
+
return localStorage.getItem(name);
|
|
13
|
+
};
|
|
14
|
+
storageObject.setItem = (name: string, value: string) => {
|
|
15
|
+
localStorage.setItem(name, value);
|
|
16
|
+
};
|
|
17
|
+
} else {
|
|
18
|
+
throw new Error("localStorage not supported in this environment");
|
|
19
|
+
}
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error(error);
|
|
22
|
+
|
|
23
|
+
storageObject.getItem = () => null;
|
|
24
|
+
storageObject.setItem = () => {};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { fuzzyCompareNumbers } from "./fuzzyCompareNumbers";
|
|
2
|
+
|
|
3
|
+
describe("fuzzyCompareNumbers", () => {
|
|
4
|
+
it("should return 0 when numbers are equal", () => {
|
|
5
|
+
expect(fuzzyCompareNumbers(10.123, 10.123, 5)).toBe(0);
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it("should return 0 when numbers are fuzzy equal", () => {
|
|
9
|
+
expect(fuzzyCompareNumbers(0.000001, 0.000002, 5)).toBe(0);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("should return a delta when numbers are not unequal", () => {
|
|
13
|
+
expect(fuzzyCompareNumbers(0.000001, 0.000002, 6)).toBe(-1);
|
|
14
|
+
expect(fuzzyCompareNumbers(0.000005, 0.000002, 6)).toBe(1);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { PRECISION } from "../../constants";
|
|
2
|
+
|
|
3
|
+
export function fuzzyCompareNumbers(
|
|
4
|
+
actual: number,
|
|
5
|
+
expected: number,
|
|
6
|
+
fractionDigits: number = PRECISION
|
|
7
|
+
): number {
|
|
8
|
+
actual = parseFloat(actual.toFixed(fractionDigits));
|
|
9
|
+
expected = parseFloat(expected.toFixed(fractionDigits));
|
|
10
|
+
|
|
11
|
+
const delta = actual - expected;
|
|
12
|
+
if (delta === 0) {
|
|
13
|
+
return 0;
|
|
14
|
+
} else {
|
|
15
|
+
return delta > 0 ? 1 : -1;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { resizePanel } from "./resizePanel";
|
|
2
|
+
|
|
3
|
+
describe("resizePanel", () => {
|
|
4
|
+
// Edge case test (issues/206)
|
|
5
|
+
fit("should respect percentage panel constraints if group size is negative", () => {
|
|
6
|
+
jest.spyOn(console, "warn").mockImplementation(() => {});
|
|
7
|
+
|
|
8
|
+
expect(
|
|
9
|
+
resizePanel({
|
|
10
|
+
groupSizePixels: -100,
|
|
11
|
+
panelConstraints: [
|
|
12
|
+
{
|
|
13
|
+
minSizePercentage: 25,
|
|
14
|
+
maxSizePercentage: 75,
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
panelIndex: 0,
|
|
18
|
+
size: 50,
|
|
19
|
+
})
|
|
20
|
+
).toBe(50);
|
|
21
|
+
|
|
22
|
+
expect(console.warn).toHaveBeenCalledTimes(0);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Edge case test (issues/206)
|
|
26
|
+
it("should handle pixel panel constraints if group size is negative", () => {
|
|
27
|
+
jest.spyOn(console, "warn").mockImplementation(() => {});
|
|
28
|
+
|
|
29
|
+
expect(
|
|
30
|
+
resizePanel({
|
|
31
|
+
groupSizePixels: -100,
|
|
32
|
+
panelConstraints: [
|
|
33
|
+
{
|
|
34
|
+
minSizePixels: 25,
|
|
35
|
+
maxSizePixels: 75,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
panelIndex: 0,
|
|
39
|
+
size: 50,
|
|
40
|
+
})
|
|
41
|
+
).toBe(0);
|
|
42
|
+
|
|
43
|
+
expect(console.warn).toHaveBeenCalledTimes(1);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { PanelConstraints } from "../Panel";
|
|
2
|
+
import { computePercentagePanelConstraints } from "./computePercentagePanelConstraints";
|
|
3
|
+
import { fuzzyCompareNumbers } from "./numbers/fuzzyCompareNumbers";
|
|
4
|
+
|
|
5
|
+
// Panel size must be in percentages; pixel values should be pre-converted
|
|
6
|
+
export function resizePanel({
|
|
7
|
+
groupSizePixels,
|
|
8
|
+
panelConstraints,
|
|
9
|
+
panelIndex,
|
|
10
|
+
size,
|
|
11
|
+
}: {
|
|
12
|
+
groupSizePixels: number;
|
|
13
|
+
panelConstraints: PanelConstraints[];
|
|
14
|
+
panelIndex: number;
|
|
15
|
+
size: number;
|
|
16
|
+
}) {
|
|
17
|
+
const hasPixelConstraints = panelConstraints.some(
|
|
18
|
+
({
|
|
19
|
+
collapsedSizePixels,
|
|
20
|
+
defaultSizePixels,
|
|
21
|
+
minSizePixels,
|
|
22
|
+
maxSizePixels,
|
|
23
|
+
}) =>
|
|
24
|
+
collapsedSizePixels != null ||
|
|
25
|
+
defaultSizePixels != null ||
|
|
26
|
+
minSizePixels != null ||
|
|
27
|
+
maxSizePixels != null
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
if (hasPixelConstraints && groupSizePixels <= 0) {
|
|
31
|
+
console.warn(`WARNING: Invalid group size: ${groupSizePixels}px`);
|
|
32
|
+
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let { collapsible } = panelConstraints[panelIndex]!;
|
|
37
|
+
|
|
38
|
+
const { collapsedSizePercentage, maxSizePercentage, minSizePercentage } =
|
|
39
|
+
computePercentagePanelConstraints(
|
|
40
|
+
panelConstraints,
|
|
41
|
+
panelIndex,
|
|
42
|
+
groupSizePixels
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
if (minSizePercentage != null) {
|
|
46
|
+
if (fuzzyCompareNumbers(size, minSizePercentage) < 0) {
|
|
47
|
+
if (collapsible) {
|
|
48
|
+
size = collapsedSizePercentage;
|
|
49
|
+
} else {
|
|
50
|
+
size = minSizePercentage;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (maxSizePercentage != null) {
|
|
56
|
+
size = Math.min(maxSizePercentage, size);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return size;
|
|
60
|
+
}
|
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
import { PanelData
|
|
1
|
+
import { PanelData } from "../Panel";
|
|
2
|
+
import { PanelGroupStorage } from "../PanelGroup";
|
|
2
3
|
|
|
3
4
|
type SerializedPanelGroupState = { [panelIds: string]: number[] };
|
|
4
5
|
|
|
5
6
|
// Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
|
|
6
7
|
// so they should not be used as part of the serialization key.
|
|
7
|
-
// Using
|
|
8
|
+
// Using the min/max size attributes should work well enough as a backup.
|
|
8
9
|
// Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
|
|
9
10
|
function getSerializationKey(panels: PanelData[]): string {
|
|
10
11
|
return panels
|
|
11
12
|
.map((panel) => {
|
|
12
|
-
const {
|
|
13
|
-
|
|
13
|
+
const { constraints, id, idIsFromProps, order } = panel;
|
|
14
|
+
if (idIsFromProps) {
|
|
15
|
+
return id;
|
|
16
|
+
} else {
|
|
17
|
+
return `${order}:${JSON.stringify(constraints)}`;
|
|
18
|
+
}
|
|
14
19
|
})
|
|
15
20
|
.sort((a, b) => a.localeCompare(b))
|
|
16
21
|
.join(",");
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { shouldMonitorPixelBasedConstraints } from "./shouldMonitorPixelBasedConstraints";
|
|
2
|
+
|
|
3
|
+
describe("shouldMonitorPixelBasedConstraints", () => {
|
|
4
|
+
it("should identify min, max, or collapsed size pixel constraints", () => {
|
|
5
|
+
expect(
|
|
6
|
+
shouldMonitorPixelBasedConstraints([{}, { collapsedSizePixels: 100 }, {}])
|
|
7
|
+
).toBe(true);
|
|
8
|
+
|
|
9
|
+
expect(
|
|
10
|
+
shouldMonitorPixelBasedConstraints([{ minSizePixels: 100 }, {}, {}])
|
|
11
|
+
).toBe(true);
|
|
12
|
+
|
|
13
|
+
expect(
|
|
14
|
+
shouldMonitorPixelBasedConstraints([{}, {}, { maxSizePixels: 100 }])
|
|
15
|
+
).toBe(true);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should ignore default size constraints", () => {
|
|
19
|
+
expect(
|
|
20
|
+
shouldMonitorPixelBasedConstraints([{ defaultSizePixels: 100 }])
|
|
21
|
+
).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PanelConstraints } from "../Panel";
|
|
2
|
+
|
|
3
|
+
export function shouldMonitorPixelBasedConstraints(
|
|
4
|
+
constraints: PanelConstraints[]
|
|
5
|
+
): boolean {
|
|
6
|
+
return constraints.some((constraints) => {
|
|
7
|
+
return (
|
|
8
|
+
constraints.collapsedSizePixels !== undefined ||
|
|
9
|
+
constraints.maxSizePixels !== undefined ||
|
|
10
|
+
constraints.minSizePixels !== undefined
|
|
11
|
+
);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { MixedSizes } from "../types";
|
|
2
|
+
|
|
3
|
+
const util = require("util");
|
|
4
|
+
|
|
5
|
+
export function expectToBeCloseToArray(
|
|
6
|
+
actualNumbers: number[],
|
|
7
|
+
expectedNumbers: number[]
|
|
8
|
+
) {
|
|
9
|
+
expect(actualNumbers.length).toBe(expectedNumbers.length);
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
actualNumbers.forEach((actualNumber, index) => {
|
|
13
|
+
const expectedNumber = expectedNumbers[index];
|
|
14
|
+
expect(actualNumber).toBeCloseTo(expectedNumber, 1);
|
|
15
|
+
});
|
|
16
|
+
} catch (error) {
|
|
17
|
+
expect(actualNumbers).toEqual(expectedNumbers);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function mockPanelGroupOffsetWidthAndHeight(
|
|
22
|
+
mockWidth = 1_000,
|
|
23
|
+
mockHeight = 1_000
|
|
24
|
+
) {
|
|
25
|
+
const offsetHeightPropertyDescriptor = Object.getOwnPropertyDescriptor(
|
|
26
|
+
HTMLElement.prototype,
|
|
27
|
+
"offsetHeight"
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const offsetWidthPropertyDescriptor = Object.getOwnPropertyDescriptor(
|
|
31
|
+
HTMLElement.prototype,
|
|
32
|
+
"offsetWidth"
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
Object.defineProperty(HTMLElement.prototype, "offsetHeight", {
|
|
36
|
+
configurable: true,
|
|
37
|
+
get: function () {
|
|
38
|
+
if (this.hasAttribute("data-resize-handle")) {
|
|
39
|
+
return 0;
|
|
40
|
+
} else if (this.hasAttribute("data-panel-group")) {
|
|
41
|
+
return mockHeight;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
Object.defineProperty(HTMLElement.prototype, "offsetWidth", {
|
|
47
|
+
configurable: true,
|
|
48
|
+
get: function () {
|
|
49
|
+
if (this.hasAttribute("data-resize-handle")) {
|
|
50
|
+
return 0;
|
|
51
|
+
} else if (this.hasAttribute("data-panel-group")) {
|
|
52
|
+
return mockWidth;
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return function uninstallMocks() {
|
|
58
|
+
if (offsetHeightPropertyDescriptor) {
|
|
59
|
+
Object.defineProperty(
|
|
60
|
+
HTMLElement.prototype,
|
|
61
|
+
"offsetHeight",
|
|
62
|
+
offsetHeightPropertyDescriptor
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (offsetWidthPropertyDescriptor) {
|
|
67
|
+
Object.defineProperty(
|
|
68
|
+
HTMLElement.prototype,
|
|
69
|
+
"offsetWidth",
|
|
70
|
+
offsetWidthPropertyDescriptor
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function verifyExpandedPanelGroupLayout(
|
|
77
|
+
actualLayout: MixedSizes[],
|
|
78
|
+
expectedPercentages: number[]
|
|
79
|
+
) {
|
|
80
|
+
expect(actualLayout).toHaveLength(expectedPercentages.length);
|
|
81
|
+
expect(actualLayout.map(({ sizePercentage }) => sizePercentage)).toEqual(
|
|
82
|
+
expectedPercentages
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function verifyExpectedWarnings(
|
|
87
|
+
callback: Function,
|
|
88
|
+
...expectedMessages: string[]
|
|
89
|
+
) {
|
|
90
|
+
const consoleSpy = (format: any, ...args: any[]) => {
|
|
91
|
+
const message = util.format(format, ...args);
|
|
92
|
+
|
|
93
|
+
for (let index = 0; index < expectedMessages.length; index++) {
|
|
94
|
+
const expectedMessage = expectedMessages[index];
|
|
95
|
+
if (message.includes(expectedMessage)) {
|
|
96
|
+
expectedMessages.splice(index, 1);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (expectedMessages.length === 0) {
|
|
102
|
+
throw new Error(`Unexpected message recorded:\n\n${message}`);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const originalError = console.error;
|
|
107
|
+
const originalWarn = console.warn;
|
|
108
|
+
|
|
109
|
+
console.error = consoleSpy;
|
|
110
|
+
console.warn = consoleSpy;
|
|
111
|
+
|
|
112
|
+
let caughtError;
|
|
113
|
+
let didCatch = false;
|
|
114
|
+
try {
|
|
115
|
+
callback();
|
|
116
|
+
} catch (error) {
|
|
117
|
+
caughtError = error;
|
|
118
|
+
didCatch = true;
|
|
119
|
+
} finally {
|
|
120
|
+
console.error = originalError;
|
|
121
|
+
console.warn = originalWarn;
|
|
122
|
+
|
|
123
|
+
if (didCatch) {
|
|
124
|
+
throw caughtError;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Any remaining messages indicate a failed expectations.
|
|
128
|
+
if (expectedMessages.length > 0) {
|
|
129
|
+
throw Error(
|
|
130
|
+
`Expected message(s) not recorded:\n\n${expectedMessages.join("\n")}`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return { pass: true };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { verifyExpectedWarnings } from "./test-utils";
|
|
2
|
+
import { validatePanelConstraints } from "./validatePanelConstraints";
|
|
3
|
+
|
|
4
|
+
describe("validatePanelConstraints", () => {
|
|
5
|
+
it("should not warn if there are no validation errors", () => {
|
|
6
|
+
verifyExpectedWarnings(() => {
|
|
7
|
+
validatePanelConstraints({
|
|
8
|
+
groupSizePixels: 100_000,
|
|
9
|
+
panelConstraints: [{}],
|
|
10
|
+
panelIndex: 0,
|
|
11
|
+
panelId: "test",
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should warn about conflicting percentages and pixels", () => {
|
|
17
|
+
verifyExpectedWarnings(() => {
|
|
18
|
+
validatePanelConstraints({
|
|
19
|
+
groupSizePixels: 100_000,
|
|
20
|
+
panelConstraints: [
|
|
21
|
+
{
|
|
22
|
+
collapsedSizePercentage: 5,
|
|
23
|
+
collapsedSizePixels: 10,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
panelIndex: 0,
|
|
27
|
+
panelId: "test",
|
|
28
|
+
});
|
|
29
|
+
}, "should not specify both percentage and pixel units for: collapsed size");
|
|
30
|
+
|
|
31
|
+
verifyExpectedWarnings(() => {
|
|
32
|
+
validatePanelConstraints({
|
|
33
|
+
groupSizePixels: 100_000,
|
|
34
|
+
panelConstraints: [
|
|
35
|
+
{
|
|
36
|
+
maxSizePercentage: 5,
|
|
37
|
+
maxSizePixels: 10,
|
|
38
|
+
minSizePercentage: 5,
|
|
39
|
+
minSizePixels: 10,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
panelIndex: 0,
|
|
43
|
+
panelId: "test",
|
|
44
|
+
});
|
|
45
|
+
}, "should not specify both percentage and pixel units for: max size, min size");
|
|
46
|
+
|
|
47
|
+
verifyExpectedWarnings(() => {
|
|
48
|
+
validatePanelConstraints({
|
|
49
|
+
groupSizePixels: 100_000,
|
|
50
|
+
panelConstraints: [
|
|
51
|
+
{
|
|
52
|
+
defaultSizePercentage: 5,
|
|
53
|
+
defaultSizePixels: 10,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
panelIndex: 0,
|
|
57
|
+
panelId: "test",
|
|
58
|
+
});
|
|
59
|
+
}, "should not specify both percentage and pixel units for: default size");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should warn about conflicting min/max sizes", () => {
|
|
63
|
+
verifyExpectedWarnings(() => {
|
|
64
|
+
validatePanelConstraints({
|
|
65
|
+
groupSizePixels: 100_000,
|
|
66
|
+
panelConstraints: [
|
|
67
|
+
{
|
|
68
|
+
maxSizePercentage: 5,
|
|
69
|
+
minSizePercentage: 10,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
panelIndex: 0,
|
|
73
|
+
panelId: "test",
|
|
74
|
+
});
|
|
75
|
+
}, "min size (10%) should not be greater than max size (5%)");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("should warn about conflicting collapsed and min sizes", () => {
|
|
79
|
+
verifyExpectedWarnings(() => {
|
|
80
|
+
validatePanelConstraints({
|
|
81
|
+
groupSizePixels: 100_000,
|
|
82
|
+
panelConstraints: [
|
|
83
|
+
{
|
|
84
|
+
collapsedSizePercentage: 15,
|
|
85
|
+
minSizePercentage: 10,
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
panelIndex: 0,
|
|
89
|
+
panelId: "test",
|
|
90
|
+
});
|
|
91
|
+
}, "collapsed size should not be greater than min size");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("should warn about conflicting default and min/max sizes", () => {
|
|
95
|
+
verifyExpectedWarnings(() => {
|
|
96
|
+
validatePanelConstraints({
|
|
97
|
+
groupSizePixels: 100_000,
|
|
98
|
+
panelConstraints: [
|
|
99
|
+
{
|
|
100
|
+
defaultSizePercentage: -1,
|
|
101
|
+
minSizePercentage: 10,
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
panelIndex: 0,
|
|
105
|
+
panelId: "test",
|
|
106
|
+
});
|
|
107
|
+
}, "default size should not be less than 0");
|
|
108
|
+
|
|
109
|
+
verifyExpectedWarnings(() => {
|
|
110
|
+
validatePanelConstraints({
|
|
111
|
+
groupSizePixels: 100_000,
|
|
112
|
+
panelConstraints: [
|
|
113
|
+
{
|
|
114
|
+
defaultSizePercentage: 5,
|
|
115
|
+
minSizePercentage: 10,
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
panelIndex: 0,
|
|
119
|
+
panelId: "test",
|
|
120
|
+
});
|
|
121
|
+
}, "default size should not be less than min size");
|
|
122
|
+
|
|
123
|
+
verifyExpectedWarnings(() => {
|
|
124
|
+
validatePanelConstraints({
|
|
125
|
+
groupSizePixels: 100_000,
|
|
126
|
+
panelConstraints: [
|
|
127
|
+
{
|
|
128
|
+
defaultSizePercentage: 101,
|
|
129
|
+
maxSizePercentage: 10,
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
panelIndex: 0,
|
|
133
|
+
panelId: "test",
|
|
134
|
+
});
|
|
135
|
+
}, "default size should not be greater than 100");
|
|
136
|
+
|
|
137
|
+
verifyExpectedWarnings(() => {
|
|
138
|
+
validatePanelConstraints({
|
|
139
|
+
groupSizePixels: 100_000,
|
|
140
|
+
panelConstraints: [
|
|
141
|
+
{
|
|
142
|
+
defaultSizePercentage: 15,
|
|
143
|
+
maxSizePercentage: 10,
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
panelIndex: 0,
|
|
147
|
+
panelId: "test",
|
|
148
|
+
});
|
|
149
|
+
}, "default size should not be greater than max size");
|
|
150
|
+
});
|
|
151
|
+
});
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { isDevelopment } from "#is-development";
|
|
2
|
+
import { PanelConstraints } from "../Panel";
|
|
3
|
+
import { computePercentagePanelConstraints } from "./computePercentagePanelConstraints";
|
|
4
|
+
|
|
5
|
+
export function validatePanelConstraints({
|
|
6
|
+
groupSizePixels,
|
|
7
|
+
panelConstraints,
|
|
8
|
+
panelId,
|
|
9
|
+
panelIndex,
|
|
10
|
+
}: {
|
|
11
|
+
groupSizePixels: number;
|
|
12
|
+
panelConstraints: PanelConstraints[];
|
|
13
|
+
panelId: string | undefined;
|
|
14
|
+
panelIndex: number;
|
|
15
|
+
}): boolean {
|
|
16
|
+
if (isDevelopment) {
|
|
17
|
+
const warnings = [];
|
|
18
|
+
|
|
19
|
+
{
|
|
20
|
+
const {
|
|
21
|
+
collapsedSizePercentage,
|
|
22
|
+
collapsedSizePixels,
|
|
23
|
+
defaultSizePercentage,
|
|
24
|
+
defaultSizePixels,
|
|
25
|
+
maxSizePercentage,
|
|
26
|
+
maxSizePixels,
|
|
27
|
+
minSizePercentage,
|
|
28
|
+
minSizePixels,
|
|
29
|
+
} = panelConstraints[panelIndex]!;
|
|
30
|
+
|
|
31
|
+
const conflictingUnits: string[] = [];
|
|
32
|
+
|
|
33
|
+
if (collapsedSizePercentage != null && collapsedSizePixels != null) {
|
|
34
|
+
conflictingUnits.push("collapsed size");
|
|
35
|
+
}
|
|
36
|
+
if (defaultSizePercentage != null && defaultSizePixels != null) {
|
|
37
|
+
conflictingUnits.push("default size");
|
|
38
|
+
}
|
|
39
|
+
if (maxSizePercentage != null && maxSizePixels != null) {
|
|
40
|
+
conflictingUnits.push("max size");
|
|
41
|
+
}
|
|
42
|
+
if (minSizePercentage != null && minSizePixels != null) {
|
|
43
|
+
conflictingUnits.push("min size");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (conflictingUnits.length > 0) {
|
|
47
|
+
warnings.push(
|
|
48
|
+
`should not specify both percentage and pixel units for: ${conflictingUnits.join(
|
|
49
|
+
", "
|
|
50
|
+
)}`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
{
|
|
56
|
+
const {
|
|
57
|
+
collapsedSizePercentage,
|
|
58
|
+
defaultSizePercentage,
|
|
59
|
+
maxSizePercentage,
|
|
60
|
+
minSizePercentage,
|
|
61
|
+
} = computePercentagePanelConstraints(
|
|
62
|
+
panelConstraints,
|
|
63
|
+
panelIndex,
|
|
64
|
+
groupSizePixels
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
if (minSizePercentage > maxSizePercentage) {
|
|
68
|
+
warnings.push(
|
|
69
|
+
`min size (${minSizePercentage}%) should not be greater than max size (${maxSizePercentage}%)`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (defaultSizePercentage != null) {
|
|
74
|
+
if (defaultSizePercentage < 0) {
|
|
75
|
+
warnings.push("default size should not be less than 0");
|
|
76
|
+
} else if (defaultSizePercentage < minSizePercentage) {
|
|
77
|
+
warnings.push("default size should not be less than min size");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (defaultSizePercentage > 100) {
|
|
81
|
+
warnings.push("default size should not be greater than 100");
|
|
82
|
+
} else if (defaultSizePercentage > maxSizePercentage) {
|
|
83
|
+
warnings.push("default size should not be greater than max size");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (collapsedSizePercentage > minSizePercentage) {
|
|
88
|
+
warnings.push("collapsed size should not be greater than min size");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (warnings.length > 0) {
|
|
93
|
+
const name = panelId != null ? `Panel "${panelId}"` : "Panel";
|
|
94
|
+
console.warn(
|
|
95
|
+
`${name} has an invalid configuration:\n\n${warnings.join("\n")}`
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return true;
|
|
103
|
+
}
|