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,81 @@
|
|
|
1
|
+
import { PanelData } from "../Panel";
|
|
2
|
+
import { MixedSizes } from "../types";
|
|
3
|
+
import { calculateAvailablePanelSizeInPixels } from "../utils/dom/calculateAvailablePanelSizeInPixels";
|
|
4
|
+
import { convertPercentageToPixels } from "./convertPercentageToPixels";
|
|
5
|
+
import { getPercentageSizeFromMixedSizes } from "./getPercentageSizeFromMixedSizes";
|
|
6
|
+
|
|
7
|
+
// Layout should be pre-converted into percentages
|
|
8
|
+
export function callPanelCallbacks(
|
|
9
|
+
groupId: string,
|
|
10
|
+
panelsArray: PanelData[],
|
|
11
|
+
layout: number[],
|
|
12
|
+
panelIdToLastNotifiedMixedSizesMap: Record<string, MixedSizes>
|
|
13
|
+
) {
|
|
14
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
15
|
+
|
|
16
|
+
layout.forEach((sizePercentage, index) => {
|
|
17
|
+
const panelData = panelsArray[index];
|
|
18
|
+
if (!panelData) {
|
|
19
|
+
// Handle initial mount (when panels are registered too late to be in the panels array)
|
|
20
|
+
// The subsequent render+effects will handle the resize notification
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { callbacks, constraints, id: panelId } = panelData;
|
|
25
|
+
const { collapsible } = constraints;
|
|
26
|
+
|
|
27
|
+
const mixedSizes: MixedSizes = {
|
|
28
|
+
sizePercentage,
|
|
29
|
+
sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels),
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const lastNotifiedMixedSizes = panelIdToLastNotifiedMixedSizesMap[panelId];
|
|
33
|
+
if (
|
|
34
|
+
lastNotifiedMixedSizes == null ||
|
|
35
|
+
mixedSizes.sizePercentage !== lastNotifiedMixedSizes.sizePercentage ||
|
|
36
|
+
mixedSizes.sizePixels !== lastNotifiedMixedSizes.sizePixels
|
|
37
|
+
) {
|
|
38
|
+
panelIdToLastNotifiedMixedSizesMap[panelId] = mixedSizes;
|
|
39
|
+
|
|
40
|
+
const { onCollapse, onExpand, onResize } = callbacks;
|
|
41
|
+
|
|
42
|
+
if (onResize) {
|
|
43
|
+
onResize(mixedSizes, lastNotifiedMixedSizes);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (collapsible && (onCollapse || onExpand)) {
|
|
47
|
+
const collapsedSize =
|
|
48
|
+
getPercentageSizeFromMixedSizes(
|
|
49
|
+
{
|
|
50
|
+
sizePercentage: constraints.collapsedSizePercentage,
|
|
51
|
+
sizePixels: constraints.collapsedSizePixels,
|
|
52
|
+
},
|
|
53
|
+
groupSizePixels
|
|
54
|
+
) ?? 0;
|
|
55
|
+
|
|
56
|
+
const size = getPercentageSizeFromMixedSizes(
|
|
57
|
+
mixedSizes,
|
|
58
|
+
groupSizePixels
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
if (
|
|
62
|
+
onExpand &&
|
|
63
|
+
(lastNotifiedMixedSizes == null ||
|
|
64
|
+
lastNotifiedMixedSizes.sizePercentage === collapsedSize) &&
|
|
65
|
+
size !== collapsedSize
|
|
66
|
+
) {
|
|
67
|
+
onExpand();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (
|
|
71
|
+
onCollapse &&
|
|
72
|
+
(lastNotifiedMixedSizes == null ||
|
|
73
|
+
lastNotifiedMixedSizes.sizePercentage !== collapsedSize) &&
|
|
74
|
+
size === collapsedSize
|
|
75
|
+
) {
|
|
76
|
+
onCollapse();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { compareLayouts } from "./compareLayouts";
|
|
2
|
+
|
|
3
|
+
describe("compareLayouts", () => {
|
|
4
|
+
it("should work", () => {
|
|
5
|
+
expect(compareLayouts([1, 2], [1])).toBe(false);
|
|
6
|
+
expect(compareLayouts([1], [1, 2])).toBe(false);
|
|
7
|
+
expect(compareLayouts([1, 2, 3], [1, 2, 3])).toBe(true);
|
|
8
|
+
});
|
|
9
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// This method returns a number between 1 and 100 representing
|
|
2
|
+
|
|
3
|
+
import { PanelData } from "../Panel";
|
|
4
|
+
import { DragState } from "../PanelGroupContext";
|
|
5
|
+
import { CSSProperties } from "../vendor/react";
|
|
6
|
+
|
|
7
|
+
// the % of the group's overall space this panel should occupy.
|
|
8
|
+
export function computePanelFlexBoxStyle({
|
|
9
|
+
dragState,
|
|
10
|
+
layout,
|
|
11
|
+
panelData,
|
|
12
|
+
panelIndex,
|
|
13
|
+
precision = 3,
|
|
14
|
+
}: {
|
|
15
|
+
layout: number[];
|
|
16
|
+
dragState: DragState | null;
|
|
17
|
+
panelData: PanelData[];
|
|
18
|
+
panelIndex: number;
|
|
19
|
+
precision?: number;
|
|
20
|
+
}): CSSProperties {
|
|
21
|
+
const size = layout[panelIndex];
|
|
22
|
+
|
|
23
|
+
let flexGrow;
|
|
24
|
+
if (panelData.length === 1) {
|
|
25
|
+
flexGrow = "100";
|
|
26
|
+
} else if (size == null) {
|
|
27
|
+
flexGrow = "0";
|
|
28
|
+
} else {
|
|
29
|
+
flexGrow = size.toPrecision(precision);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
flexBasis: 0,
|
|
34
|
+
flexGrow,
|
|
35
|
+
flexShrink: 1,
|
|
36
|
+
|
|
37
|
+
// Without this, Panel sizes may be unintentionally overridden by their content
|
|
38
|
+
overflow: "hidden",
|
|
39
|
+
|
|
40
|
+
// Disable pointer events inside of a panel during resize
|
|
41
|
+
// This avoid edge cases like nested iframes
|
|
42
|
+
pointerEvents: dragState !== null ? "none" : undefined,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { PanelConstraints } from "../Panel";
|
|
2
|
+
import { computePercentagePanelConstraints } from "./computePercentagePanelConstraints";
|
|
3
|
+
|
|
4
|
+
describe("computePercentagePanelConstraints", () => {
|
|
5
|
+
it("should compute reasonable defaults with no constraints", () => {
|
|
6
|
+
expect(computePercentagePanelConstraints([{}, {}], 0, 100))
|
|
7
|
+
.toMatchInlineSnapshot(`
|
|
8
|
+
{
|
|
9
|
+
"collapsedSizePercentage": 0,
|
|
10
|
+
"defaultSizePercentage": undefined,
|
|
11
|
+
"maxSizePercentage": 100,
|
|
12
|
+
"minSizePercentage": 0,
|
|
13
|
+
}
|
|
14
|
+
`);
|
|
15
|
+
|
|
16
|
+
expect(computePercentagePanelConstraints([{}, {}], 1, 100))
|
|
17
|
+
.toMatchInlineSnapshot(`
|
|
18
|
+
{
|
|
19
|
+
"collapsedSizePercentage": 0,
|
|
20
|
+
"defaultSizePercentage": undefined,
|
|
21
|
+
"maxSizePercentage": 100,
|
|
22
|
+
"minSizePercentage": 0,
|
|
23
|
+
}
|
|
24
|
+
`);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should compute percentage based constraints based on a mix of pixels and percentages", () => {
|
|
28
|
+
const constraints: PanelConstraints[] = [
|
|
29
|
+
{
|
|
30
|
+
maxSizePixels: 20,
|
|
31
|
+
minSizePixels: 10,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
minSizePixels: 10,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
minSizePixels: 10,
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
expect(computePercentagePanelConstraints(constraints, 0, 100))
|
|
42
|
+
.toMatchInlineSnapshot(`
|
|
43
|
+
{
|
|
44
|
+
"collapsedSizePercentage": 0,
|
|
45
|
+
"defaultSizePercentage": undefined,
|
|
46
|
+
"maxSizePercentage": 20,
|
|
47
|
+
"minSizePercentage": 10,
|
|
48
|
+
}
|
|
49
|
+
`);
|
|
50
|
+
|
|
51
|
+
expect(computePercentagePanelConstraints(constraints, 1, 100))
|
|
52
|
+
.toMatchInlineSnapshot(`
|
|
53
|
+
{
|
|
54
|
+
"collapsedSizePercentage": 0,
|
|
55
|
+
"defaultSizePercentage": undefined,
|
|
56
|
+
"maxSizePercentage": 80,
|
|
57
|
+
"minSizePercentage": 10,
|
|
58
|
+
}
|
|
59
|
+
`);
|
|
60
|
+
|
|
61
|
+
expect(computePercentagePanelConstraints(constraints, 2, 100))
|
|
62
|
+
.toMatchInlineSnapshot(`
|
|
63
|
+
{
|
|
64
|
+
"collapsedSizePercentage": 0,
|
|
65
|
+
"defaultSizePercentage": undefined,
|
|
66
|
+
"maxSizePercentage": 80,
|
|
67
|
+
"minSizePercentage": 10,
|
|
68
|
+
}
|
|
69
|
+
`);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("should compute reasonable percentage based constraints from pixels if group size is negative", () => {
|
|
73
|
+
jest.spyOn(console, "warn").mockImplementation(() => {});
|
|
74
|
+
|
|
75
|
+
expect(
|
|
76
|
+
computePercentagePanelConstraints(
|
|
77
|
+
[
|
|
78
|
+
{
|
|
79
|
+
minSizePixels: 25,
|
|
80
|
+
maxSizePixels: 100,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
|
|
84
|
+
0,
|
|
85
|
+
-100
|
|
86
|
+
)
|
|
87
|
+
).toMatchInlineSnapshot(`
|
|
88
|
+
{
|
|
89
|
+
"collapsedSizePercentage": 0,
|
|
90
|
+
"defaultSizePercentage": undefined,
|
|
91
|
+
"maxSizePercentage": 0,
|
|
92
|
+
"minSizePercentage": 0,
|
|
93
|
+
}
|
|
94
|
+
`);
|
|
95
|
+
|
|
96
|
+
expect(console.warn).toHaveBeenCalledTimes(1);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { PanelConstraints } from "../Panel";
|
|
2
|
+
import { convertPixelConstraintsToPercentages } from "./convertPixelConstraintsToPercentages";
|
|
3
|
+
|
|
4
|
+
export function computePercentagePanelConstraints(
|
|
5
|
+
panelConstraintsArray: PanelConstraints[],
|
|
6
|
+
panelIndex: number,
|
|
7
|
+
groupSizePixels: number
|
|
8
|
+
): {
|
|
9
|
+
collapsedSizePercentage: number;
|
|
10
|
+
defaultSizePercentage: number | undefined;
|
|
11
|
+
maxSizePercentage: number;
|
|
12
|
+
minSizePercentage: number;
|
|
13
|
+
} {
|
|
14
|
+
// All panel constraints, excluding the current one
|
|
15
|
+
let totalMinConstraints = 0;
|
|
16
|
+
let totalMaxConstraints = 0;
|
|
17
|
+
|
|
18
|
+
for (let index = 0; index < panelConstraintsArray.length; index++) {
|
|
19
|
+
if (index !== panelIndex) {
|
|
20
|
+
const { collapsible } = panelConstraintsArray[index]!;
|
|
21
|
+
const { collapsedSizePercentage, maxSizePercentage, minSizePercentage } =
|
|
22
|
+
convertPixelConstraintsToPercentages(
|
|
23
|
+
panelConstraintsArray[index]!,
|
|
24
|
+
groupSizePixels
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
totalMaxConstraints += maxSizePercentage;
|
|
28
|
+
totalMinConstraints += collapsible
|
|
29
|
+
? collapsedSizePercentage
|
|
30
|
+
: minSizePercentage;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const {
|
|
35
|
+
collapsedSizePercentage,
|
|
36
|
+
defaultSizePercentage,
|
|
37
|
+
maxSizePercentage,
|
|
38
|
+
minSizePercentage,
|
|
39
|
+
} = convertPixelConstraintsToPercentages(
|
|
40
|
+
panelConstraintsArray[panelIndex]!,
|
|
41
|
+
groupSizePixels
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
collapsedSizePercentage,
|
|
46
|
+
defaultSizePercentage,
|
|
47
|
+
maxSizePercentage:
|
|
48
|
+
panelConstraintsArray.length > 1
|
|
49
|
+
? Math.min(maxSizePercentage, 100 - totalMinConstraints)
|
|
50
|
+
: maxSizePercentage,
|
|
51
|
+
minSizePercentage:
|
|
52
|
+
panelConstraintsArray.length > 1
|
|
53
|
+
? Math.max(minSizePercentage, 100 - totalMaxConstraints)
|
|
54
|
+
: minSizePercentage,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { convertPercentageToPixels } from "./convertPercentageToPixels";
|
|
2
|
+
|
|
3
|
+
describe("convertPercentageToPixels", () => {
|
|
4
|
+
it("should convert percentages to pixels", () => {
|
|
5
|
+
expect(convertPercentageToPixels(0, 100_000)).toBe(0);
|
|
6
|
+
expect(convertPercentageToPixels(50, 100_000)).toBe(50_000);
|
|
7
|
+
expect(convertPercentageToPixels(100, 100_000)).toBe(100_000);
|
|
8
|
+
});
|
|
9
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { convertPixelConstraintsToPercentages } from "./convertPixelConstraintsToPercentages";
|
|
2
|
+
|
|
3
|
+
describe("convertPixelConstraintsToPercentages", () => {
|
|
4
|
+
it("should respect percentage panel constraints if group size is negative", () => {
|
|
5
|
+
jest.spyOn(console, "warn").mockImplementation(() => {});
|
|
6
|
+
|
|
7
|
+
expect(
|
|
8
|
+
convertPixelConstraintsToPercentages(
|
|
9
|
+
{
|
|
10
|
+
minSizePercentage: 25,
|
|
11
|
+
defaultSizePercentage: 50,
|
|
12
|
+
maxSizePercentage: 75,
|
|
13
|
+
},
|
|
14
|
+
-100
|
|
15
|
+
)
|
|
16
|
+
).toEqual({
|
|
17
|
+
collapsedSizePercentage: 0,
|
|
18
|
+
defaultSizePercentage: 50,
|
|
19
|
+
maxSizePercentage: 75,
|
|
20
|
+
minSizePercentage: 25,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
expect(console.warn).toHaveBeenCalledTimes(0);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Edge case test (issues/206)
|
|
27
|
+
it("should ignore pixel panel constraints if group size is negative", () => {
|
|
28
|
+
jest.spyOn(console, "warn").mockImplementation(() => {});
|
|
29
|
+
|
|
30
|
+
expect(
|
|
31
|
+
convertPixelConstraintsToPercentages(
|
|
32
|
+
{
|
|
33
|
+
minSizePixels: 25,
|
|
34
|
+
maxSizePixels: 75,
|
|
35
|
+
},
|
|
36
|
+
-100
|
|
37
|
+
)
|
|
38
|
+
).toEqual({
|
|
39
|
+
collapsedSizePercentage: 0,
|
|
40
|
+
defaultSizePercentage: undefined,
|
|
41
|
+
maxSizePercentage: 0,
|
|
42
|
+
minSizePercentage: 0,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
expect(console.warn).toHaveBeenCalledTimes(1);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { PanelConstraints } from "../Panel";
|
|
2
|
+
import { convertPixelsToPercentage } from "./convertPixelsToPercentage";
|
|
3
|
+
|
|
4
|
+
export function convertPixelConstraintsToPercentages(
|
|
5
|
+
panelConstraints: PanelConstraints,
|
|
6
|
+
groupSizePixels: number
|
|
7
|
+
): {
|
|
8
|
+
collapsedSizePercentage: number;
|
|
9
|
+
defaultSizePercentage: number | undefined;
|
|
10
|
+
maxSizePercentage: number;
|
|
11
|
+
minSizePercentage: number;
|
|
12
|
+
} {
|
|
13
|
+
let {
|
|
14
|
+
collapsedSizePercentage = 0,
|
|
15
|
+
collapsedSizePixels,
|
|
16
|
+
defaultSizePercentage,
|
|
17
|
+
defaultSizePixels,
|
|
18
|
+
maxSizePercentage = 100,
|
|
19
|
+
maxSizePixels,
|
|
20
|
+
minSizePercentage = 0,
|
|
21
|
+
minSizePixels,
|
|
22
|
+
} = panelConstraints;
|
|
23
|
+
|
|
24
|
+
const hasPixelConstraints =
|
|
25
|
+
collapsedSizePixels != null ||
|
|
26
|
+
defaultSizePixels != null ||
|
|
27
|
+
minSizePixels != null ||
|
|
28
|
+
maxSizePixels != null;
|
|
29
|
+
|
|
30
|
+
if (hasPixelConstraints && groupSizePixels <= 0) {
|
|
31
|
+
console.warn(`WARNING: Invalid group size: ${groupSizePixels}px`);
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
collapsedSizePercentage: 0,
|
|
35
|
+
defaultSizePercentage,
|
|
36
|
+
maxSizePercentage: 0,
|
|
37
|
+
minSizePercentage: 0,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (collapsedSizePixels != null) {
|
|
42
|
+
collapsedSizePercentage = convertPixelsToPercentage(
|
|
43
|
+
collapsedSizePixels,
|
|
44
|
+
groupSizePixels
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
if (defaultSizePixels != null) {
|
|
48
|
+
defaultSizePercentage = convertPixelsToPercentage(
|
|
49
|
+
defaultSizePixels,
|
|
50
|
+
groupSizePixels
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
if (minSizePixels != null) {
|
|
54
|
+
minSizePercentage = convertPixelsToPercentage(
|
|
55
|
+
minSizePixels,
|
|
56
|
+
groupSizePixels
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
if (maxSizePixels != null) {
|
|
60
|
+
maxSizePercentage = convertPixelsToPercentage(
|
|
61
|
+
maxSizePixels,
|
|
62
|
+
groupSizePixels
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
collapsedSizePercentage,
|
|
68
|
+
defaultSizePercentage,
|
|
69
|
+
maxSizePercentage,
|
|
70
|
+
minSizePercentage,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { convertPixelsToPercentage } from "./convertPixelsToPercentage";
|
|
2
|
+
|
|
3
|
+
describe("convertPixelsToPercentage", () => {
|
|
4
|
+
it("should convert pixels to percentages", () => {
|
|
5
|
+
expect(convertPixelsToPercentage(0, 100_000)).toBe(0);
|
|
6
|
+
expect(convertPixelsToPercentage(50_000, 100_000)).toBe(50);
|
|
7
|
+
expect(convertPixelsToPercentage(100_000, 100_000)).toBe(100);
|
|
8
|
+
});
|
|
9
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { getResizeHandleElementIndex } from "../utils/dom/getResizeHandleElementIndex";
|
|
2
|
+
|
|
3
|
+
export function determinePivotIndices(
|
|
4
|
+
groupId: string,
|
|
5
|
+
dragHandleId: string
|
|
6
|
+
): [indexBefore: number, indexAfter: number] {
|
|
7
|
+
const index = getResizeHandleElementIndex(groupId, dragHandleId);
|
|
8
|
+
|
|
9
|
+
return index != null ? [index, index + 1] : [-1, -1];
|
|
10
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getPanelGroupElement } from "./getPanelGroupElement";
|
|
2
|
+
import { getResizeHandleElementsForGroup } from "./getResizeHandleElementsForGroup";
|
|
3
|
+
|
|
4
|
+
export function calculateAvailablePanelSizeInPixels(groupId: string): number {
|
|
5
|
+
const panelGroupElement = getPanelGroupElement(groupId);
|
|
6
|
+
if (panelGroupElement == null) {
|
|
7
|
+
return NaN;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const direction = panelGroupElement.getAttribute(
|
|
11
|
+
"data-panel-group-direction"
|
|
12
|
+
);
|
|
13
|
+
const resizeHandles = getResizeHandleElementsForGroup(groupId);
|
|
14
|
+
if (direction === "horizontal") {
|
|
15
|
+
return (
|
|
16
|
+
panelGroupElement.offsetWidth -
|
|
17
|
+
resizeHandles.reduce((accumulated, handle) => {
|
|
18
|
+
return accumulated + handle.offsetWidth;
|
|
19
|
+
}, 0)
|
|
20
|
+
);
|
|
21
|
+
} else {
|
|
22
|
+
return (
|
|
23
|
+
panelGroupElement.offsetHeight -
|
|
24
|
+
resizeHandles.reduce((accumulated, handle) => {
|
|
25
|
+
return accumulated + handle.offsetHeight;
|
|
26
|
+
}, 0)
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getPanelGroupElement } from "./getPanelGroupElement";
|
|
2
|
+
import { getResizeHandleElementsForGroup } from "./getResizeHandleElementsForGroup";
|
|
3
|
+
|
|
4
|
+
export function getAvailableGroupSizePixels(groupId: string): number {
|
|
5
|
+
const panelGroupElement = getPanelGroupElement(groupId);
|
|
6
|
+
if (panelGroupElement == null) {
|
|
7
|
+
return NaN;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const direction = panelGroupElement.getAttribute(
|
|
11
|
+
"data-panel-group-direction"
|
|
12
|
+
);
|
|
13
|
+
const resizeHandles = getResizeHandleElementsForGroup(groupId);
|
|
14
|
+
if (direction === "horizontal") {
|
|
15
|
+
return (
|
|
16
|
+
panelGroupElement.offsetWidth -
|
|
17
|
+
resizeHandles.reduce((accumulated, handle) => {
|
|
18
|
+
return accumulated + handle.offsetWidth;
|
|
19
|
+
}, 0)
|
|
20
|
+
);
|
|
21
|
+
} else {
|
|
22
|
+
return (
|
|
23
|
+
panelGroupElement.offsetHeight -
|
|
24
|
+
resizeHandles.reduce((accumulated, handle) => {
|
|
25
|
+
return accumulated + handle.offsetHeight;
|
|
26
|
+
}, 0)
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { getResizeHandleElementsForGroup } from "./getResizeHandleElementsForGroup";
|
|
2
|
+
|
|
3
|
+
export function getResizeHandleElementIndex(
|
|
4
|
+
groupId: string,
|
|
5
|
+
id: string
|
|
6
|
+
): number | null {
|
|
7
|
+
const handles = getResizeHandleElementsForGroup(groupId);
|
|
8
|
+
const index = handles.findIndex(
|
|
9
|
+
(handle) => handle.getAttribute("data-panel-resize-handle-id") === id
|
|
10
|
+
);
|
|
11
|
+
return index ?? null;
|
|
12
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PanelData } from "../../Panel";
|
|
2
|
+
import { getResizeHandleElement } from "./getResizeHandleElement";
|
|
3
|
+
import { getResizeHandleElementsForGroup } from "./getResizeHandleElementsForGroup";
|
|
4
|
+
|
|
5
|
+
export function getResizeHandlePanelIds(
|
|
6
|
+
groupId: string,
|
|
7
|
+
handleId: string,
|
|
8
|
+
panelsArray: PanelData[]
|
|
9
|
+
): [idBefore: string | null, idAfter: string | null] {
|
|
10
|
+
const handle = getResizeHandleElement(handleId);
|
|
11
|
+
const handles = getResizeHandleElementsForGroup(groupId);
|
|
12
|
+
const index = handle ? handles.indexOf(handle) : -1;
|
|
13
|
+
|
|
14
|
+
const idBefore: string | null = panelsArray[index]?.id ?? null;
|
|
15
|
+
const idAfter: string | null = panelsArray[index + 1]?.id ?? null;
|
|
16
|
+
|
|
17
|
+
return [idBefore, idAfter];
|
|
18
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ResizeEvent } from "../PanelGroupContext";
|
|
2
|
+
|
|
3
|
+
export function isKeyDown(event: ResizeEvent): event is KeyboardEvent {
|
|
4
|
+
return event.type === "keydown";
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function isMouseEvent(event: ResizeEvent): event is MouseEvent {
|
|
8
|
+
return event.type.startsWith("mouse");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function isTouchEvent(event: ResizeEvent): event is TouchEvent {
|
|
12
|
+
return event.type.startsWith("touch");
|
|
13
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getPercentageSizeFromMixedSizes } from "./getPercentageSizeFromMixedSizes";
|
|
2
|
+
|
|
3
|
+
describe("getPercentageSizeFromMixedSizes", () => {
|
|
4
|
+
it("should return percentage sizes as-is", () => {
|
|
5
|
+
expect(
|
|
6
|
+
getPercentageSizeFromMixedSizes(
|
|
7
|
+
{
|
|
8
|
+
sizePercentage: 50,
|
|
9
|
+
},
|
|
10
|
+
100_000
|
|
11
|
+
)
|
|
12
|
+
).toBe(50);
|
|
13
|
+
expect(
|
|
14
|
+
getPercentageSizeFromMixedSizes(
|
|
15
|
+
{
|
|
16
|
+
sizePercentage: 25,
|
|
17
|
+
sizePixels: 100,
|
|
18
|
+
},
|
|
19
|
+
100_000
|
|
20
|
+
)
|
|
21
|
+
).toBe(25);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should convert pixels to percentages", () => {
|
|
25
|
+
expect(
|
|
26
|
+
getPercentageSizeFromMixedSizes(
|
|
27
|
+
{
|
|
28
|
+
sizePixels: 50_000,
|
|
29
|
+
},
|
|
30
|
+
100_000
|
|
31
|
+
)
|
|
32
|
+
).toBe(50);
|
|
33
|
+
expect(
|
|
34
|
+
getPercentageSizeFromMixedSizes(
|
|
35
|
+
{
|
|
36
|
+
sizePercentage: 25,
|
|
37
|
+
sizePixels: 50_000,
|
|
38
|
+
},
|
|
39
|
+
100_000
|
|
40
|
+
)
|
|
41
|
+
).toBe(25);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("should return undefined if neither pixel nor percentage sizes specified", () => {
|
|
45
|
+
expect(getPercentageSizeFromMixedSizes({}, 100_000)).toBeUndefined();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MixedSizes } from "../types";
|
|
2
|
+
import { convertPixelsToPercentage } from "./convertPixelsToPercentage";
|
|
3
|
+
|
|
4
|
+
export function getPercentageSizeFromMixedSizes(
|
|
5
|
+
{ sizePercentage, sizePixels }: Partial<MixedSizes>,
|
|
6
|
+
groupSizePixels: number
|
|
7
|
+
): number | undefined {
|
|
8
|
+
if (sizePercentage != null) {
|
|
9
|
+
return sizePercentage;
|
|
10
|
+
} else if (sizePixels != null) {
|
|
11
|
+
return convertPixelsToPercentage(sizePixels, groupSizePixels);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|