react-resizable-panels 0.0.55 → 0.0.56
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 +234 -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 +1241 -1035
- package/dist/react-resizable-panels.browser.cjs.mjs +1 -2
- package/dist/react-resizable-panels.browser.development.cjs.js +1367 -1081
- package/dist/react-resizable-panels.browser.development.cjs.mjs +1 -2
- package/dist/react-resizable-panels.browser.development.esm.js +1368 -1081
- package/dist/react-resizable-panels.browser.esm.js +1242 -1035
- package/dist/react-resizable-panels.cjs.js +1241 -1035
- 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 +1370 -1084
- package/dist/react-resizable-panels.development.cjs.mjs +1 -2
- package/dist/react-resizable-panels.development.esm.js +1371 -1084
- package/dist/react-resizable-panels.development.node.cjs.js +1151 -940
- package/dist/react-resizable-panels.development.node.cjs.mjs +1 -2
- package/dist/react-resizable-panels.development.node.esm.js +1152 -940
- package/dist/react-resizable-panels.esm.js +1242 -1035
- package/dist/react-resizable-panels.esm.js.map +1 -1
- package/dist/react-resizable-panels.node.cjs.js +1049 -912
- package/dist/react-resizable-panels.node.cjs.mjs +1 -2
- package/dist/react-resizable-panels.node.esm.js +1050 -912
- package/jest.config.js +10 -0
- package/package.json +3 -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 -669
- package/src/PanelGroupContext.ts +33 -0
- package/src/PanelResizeHandle.ts +13 -8
- 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 +71 -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.ts +55 -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 +7 -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.ts +41 -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
package/jest.config.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
testEnvironment: "jsdom",
|
|
4
|
+
preset: "ts-jest",
|
|
5
|
+
prettierPath: null,
|
|
6
|
+
testEnvironmentOptions: {
|
|
7
|
+
customExportConditions: ["development"],
|
|
8
|
+
},
|
|
9
|
+
testMatch: ["**/*.test.{ts,tsx}"],
|
|
10
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-resizable-panels",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.56",
|
|
4
4
|
"description": "React components for resizable panel groups/layouts",
|
|
5
5
|
"author": "Brian Vaughn <brian.david.vaughn@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -62,6 +62,8 @@
|
|
|
62
62
|
"types": "dist/react-resizable-panels.cjs.d.ts",
|
|
63
63
|
"scripts": {
|
|
64
64
|
"lint": "eslint \"src/**/*.{ts,tsx}\"",
|
|
65
|
+
"test": "jest --config=jest.config.js",
|
|
66
|
+
"test:watch": "jest --config=jest.config.js --watch",
|
|
65
67
|
"watch": "parcel watch --port=2345"
|
|
66
68
|
},
|
|
67
69
|
"devDependencies": {
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { Root, createRoot } from "react-dom/client";
|
|
2
|
+
import { act } from "react-dom/test-utils";
|
|
3
|
+
import {
|
|
4
|
+
ImperativePanelHandle,
|
|
5
|
+
MixedSizes,
|
|
6
|
+
Panel,
|
|
7
|
+
PanelGroup,
|
|
8
|
+
PanelResizeHandle,
|
|
9
|
+
} from ".";
|
|
10
|
+
import {
|
|
11
|
+
mockPanelGroupOffsetWidthAndHeight,
|
|
12
|
+
verifyExpandedPanelGroupLayout,
|
|
13
|
+
} from "./utils/test-utils";
|
|
14
|
+
import { createRef } from "./vendor/react";
|
|
15
|
+
|
|
16
|
+
describe("PanelGroup", () => {
|
|
17
|
+
let expectedWarnings: string[] = [];
|
|
18
|
+
let root: Root;
|
|
19
|
+
let uninstallMockOffsetWidthAndHeight: () => void;
|
|
20
|
+
|
|
21
|
+
function expectWarning(expectedMessage: string) {
|
|
22
|
+
expectedWarnings.push(expectedMessage);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
// @ts-expect-error
|
|
27
|
+
global.IS_REACT_ACT_ENVIRONMENT = true;
|
|
28
|
+
|
|
29
|
+
uninstallMockOffsetWidthAndHeight = mockPanelGroupOffsetWidthAndHeight();
|
|
30
|
+
|
|
31
|
+
const container = document.createElement("div");
|
|
32
|
+
document.body.appendChild(container);
|
|
33
|
+
|
|
34
|
+
expectedWarnings = [];
|
|
35
|
+
root = createRoot(container);
|
|
36
|
+
|
|
37
|
+
jest.spyOn(console, "warn").mockImplementation((actualMessage: string) => {
|
|
38
|
+
const match = expectedWarnings.findIndex((expectedMessage) => {
|
|
39
|
+
return actualMessage.includes(expectedMessage);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (match >= 0) {
|
|
43
|
+
expectedWarnings.splice(match, 1);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
throw Error(`Unexpected warning: ${actualMessage}`);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
afterEach(() => {
|
|
52
|
+
uninstallMockOffsetWidthAndHeight();
|
|
53
|
+
|
|
54
|
+
jest.clearAllMocks();
|
|
55
|
+
jest.resetModules();
|
|
56
|
+
|
|
57
|
+
act(() => {
|
|
58
|
+
root.unmount();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
expect(expectedWarnings).toHaveLength(0);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("imperative handle API", () => {
|
|
65
|
+
describe("collapse and expand", () => {
|
|
66
|
+
let leftPanelRef = createRef<ImperativePanelHandle>();
|
|
67
|
+
let rightPanelRef = createRef<ImperativePanelHandle>();
|
|
68
|
+
|
|
69
|
+
let mostRecentLayout: MixedSizes[] | null;
|
|
70
|
+
|
|
71
|
+
beforeEach(() => {
|
|
72
|
+
leftPanelRef = createRef<ImperativePanelHandle>();
|
|
73
|
+
rightPanelRef = createRef<ImperativePanelHandle>();
|
|
74
|
+
|
|
75
|
+
mostRecentLayout = null;
|
|
76
|
+
|
|
77
|
+
const onLayout = (layout: MixedSizes[]) => {
|
|
78
|
+
mostRecentLayout = layout;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
act(() => {
|
|
82
|
+
root.render(
|
|
83
|
+
<PanelGroup direction="horizontal" onLayout={onLayout}>
|
|
84
|
+
<Panel
|
|
85
|
+
collapsible
|
|
86
|
+
defaultSizePercentage={50}
|
|
87
|
+
ref={leftPanelRef}
|
|
88
|
+
/>
|
|
89
|
+
<PanelResizeHandle />
|
|
90
|
+
<Panel
|
|
91
|
+
collapsible
|
|
92
|
+
defaultSizePercentage={50}
|
|
93
|
+
ref={rightPanelRef}
|
|
94
|
+
/>
|
|
95
|
+
</PanelGroup>
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("should expand and collapse the first panel in a group", () => {
|
|
101
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [50, 50]);
|
|
102
|
+
act(() => {
|
|
103
|
+
leftPanelRef.current!.collapse();
|
|
104
|
+
});
|
|
105
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [0, 100]);
|
|
106
|
+
act(() => {
|
|
107
|
+
leftPanelRef.current!.expand();
|
|
108
|
+
});
|
|
109
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [50, 50]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("should expand and collapse the last panel in a group", () => {
|
|
113
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [50, 50]);
|
|
114
|
+
act(() => {
|
|
115
|
+
rightPanelRef.current!.collapse();
|
|
116
|
+
});
|
|
117
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [100, 0]);
|
|
118
|
+
act(() => {
|
|
119
|
+
rightPanelRef.current!.expand();
|
|
120
|
+
});
|
|
121
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [50, 50]);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should re-expand to the most recent size before collapsing", () => {
|
|
125
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [50, 50]);
|
|
126
|
+
act(() => {
|
|
127
|
+
leftPanelRef.current!.resize({ sizePercentage: 30 });
|
|
128
|
+
});
|
|
129
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [30, 70]);
|
|
130
|
+
act(() => {
|
|
131
|
+
leftPanelRef.current!.collapse();
|
|
132
|
+
});
|
|
133
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [0, 100]);
|
|
134
|
+
act(() => {
|
|
135
|
+
leftPanelRef.current!.expand();
|
|
136
|
+
});
|
|
137
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [30, 70]);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe("resize", () => {
|
|
142
|
+
let leftPanelRef = createRef<ImperativePanelHandle>();
|
|
143
|
+
let middlePanelRef = createRef<ImperativePanelHandle>();
|
|
144
|
+
let rightPanelRef = createRef<ImperativePanelHandle>();
|
|
145
|
+
|
|
146
|
+
let mostRecentLayout: MixedSizes[] | null;
|
|
147
|
+
|
|
148
|
+
beforeEach(() => {
|
|
149
|
+
leftPanelRef = createRef<ImperativePanelHandle>();
|
|
150
|
+
middlePanelRef = createRef<ImperativePanelHandle>();
|
|
151
|
+
rightPanelRef = createRef<ImperativePanelHandle>();
|
|
152
|
+
|
|
153
|
+
mostRecentLayout = null;
|
|
154
|
+
|
|
155
|
+
const onLayout = (layout: MixedSizes[]) => {
|
|
156
|
+
mostRecentLayout = layout;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
act(() => {
|
|
160
|
+
root.render(
|
|
161
|
+
<PanelGroup direction="horizontal" onLayout={onLayout}>
|
|
162
|
+
<Panel defaultSizePercentage={20} ref={leftPanelRef} />
|
|
163
|
+
<PanelResizeHandle />
|
|
164
|
+
<Panel defaultSizePercentage={60} ref={middlePanelRef} />
|
|
165
|
+
<PanelResizeHandle />
|
|
166
|
+
<Panel defaultSizePercentage={20} ref={rightPanelRef} />
|
|
167
|
+
</PanelGroup>
|
|
168
|
+
);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("should resize the first panel in a group", () => {
|
|
173
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [20, 60, 20]);
|
|
174
|
+
act(() => {
|
|
175
|
+
leftPanelRef.current!.resize({ sizePercentage: 40 });
|
|
176
|
+
});
|
|
177
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [40, 40, 20]);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("should resize the middle panel in a group", () => {
|
|
181
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [20, 60, 20]);
|
|
182
|
+
act(() => {
|
|
183
|
+
middlePanelRef.current!.resize({ sizePercentage: 40 });
|
|
184
|
+
});
|
|
185
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [20, 40, 40]);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("should resize the last panel in a group", () => {
|
|
189
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [20, 60, 20]);
|
|
190
|
+
act(() => {
|
|
191
|
+
rightPanelRef.current!.resize({ sizePercentage: 40 });
|
|
192
|
+
});
|
|
193
|
+
verifyExpandedPanelGroupLayout(mostRecentLayout!, [20, 40, 40]);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe("invariants", () => {
|
|
199
|
+
beforeEach(() => {
|
|
200
|
+
jest.spyOn(console, "error").mockImplementation(() => {
|
|
201
|
+
// Noop
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("should throw if default size is less than 0 or greater than 100", () => {
|
|
206
|
+
expect(() => {
|
|
207
|
+
act(() => {
|
|
208
|
+
root.render(
|
|
209
|
+
<PanelGroup direction="horizontal">
|
|
210
|
+
<Panel defaultSizePercentage={-1} />
|
|
211
|
+
</PanelGroup>
|
|
212
|
+
);
|
|
213
|
+
});
|
|
214
|
+
}).toThrow("Invalid layout");
|
|
215
|
+
|
|
216
|
+
expect(() => {
|
|
217
|
+
act(() => {
|
|
218
|
+
root.render(
|
|
219
|
+
<PanelGroup direction="horizontal">
|
|
220
|
+
<Panel defaultSizePercentage={101} />
|
|
221
|
+
</PanelGroup>
|
|
222
|
+
);
|
|
223
|
+
});
|
|
224
|
+
}).toThrow("Invalid layout");
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it("should throw if rendered outside of a PanelGroup", () => {
|
|
228
|
+
expect(() => {
|
|
229
|
+
act(() => {
|
|
230
|
+
root.render(<Panel />);
|
|
231
|
+
});
|
|
232
|
+
}).toThrow(
|
|
233
|
+
"Panel components must be rendered within a PanelGroup container"
|
|
234
|
+
);
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
describe("DEV warnings", () => {
|
|
239
|
+
it("should warn about server rendered panels with no default size", () => {
|
|
240
|
+
jest.resetModules();
|
|
241
|
+
jest.mock("#is-browser", () => ({ isBrowser: false }));
|
|
242
|
+
|
|
243
|
+
const { TextEncoder } = require("util");
|
|
244
|
+
global.TextEncoder = TextEncoder;
|
|
245
|
+
|
|
246
|
+
const { renderToStaticMarkup } = require("react-dom/server.browser");
|
|
247
|
+
const { act } = require("react-dom/test-utils");
|
|
248
|
+
const Panel = require("./Panel").Panel;
|
|
249
|
+
const PanelGroup = require("./PanelGroup").PanelGroup;
|
|
250
|
+
const PanelResizeHandle =
|
|
251
|
+
require("./PanelResizeHandle").PanelResizeHandle;
|
|
252
|
+
|
|
253
|
+
act(() => {
|
|
254
|
+
// No warning expected if default sizes provided
|
|
255
|
+
renderToStaticMarkup(
|
|
256
|
+
<PanelGroup direction="horizontal">
|
|
257
|
+
<Panel defaultSizePercentage={100} />
|
|
258
|
+
<PanelResizeHandle />
|
|
259
|
+
<Panel defaultSizePixels={1_000} />
|
|
260
|
+
</PanelGroup>
|
|
261
|
+
);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
expectWarning(
|
|
265
|
+
"Panel defaultSizePercentage or defaultSizePixels prop recommended to avoid layout shift after server rendering"
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
act(() => {
|
|
269
|
+
renderToStaticMarkup(
|
|
270
|
+
<PanelGroup direction="horizontal">
|
|
271
|
+
<Panel id="one" />
|
|
272
|
+
</PanelGroup>
|
|
273
|
+
);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it("should warn if both pixel and percentage units are specified", () => {
|
|
278
|
+
// We just spot check this here; validatePanelConstraints() has its own in-depth tests
|
|
279
|
+
expectWarning(
|
|
280
|
+
"should not specify both percentage and pixel units for: min size"
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
expectWarning("Pixel based constraints require ResizeObserver");
|
|
284
|
+
|
|
285
|
+
act(() => {
|
|
286
|
+
root.render(
|
|
287
|
+
<PanelGroup direction="horizontal" key="minSize">
|
|
288
|
+
<Panel minSizePercentage={100} minSizePixels={1_000} />
|
|
289
|
+
</PanelGroup>
|
|
290
|
+
);
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it("should warn if invalid sizes are specified declaratively", () => {
|
|
295
|
+
expectWarning("default size should not be less than 0");
|
|
296
|
+
|
|
297
|
+
act(() => {
|
|
298
|
+
root.render(
|
|
299
|
+
<PanelGroup direction="horizontal" key="collapsedSize">
|
|
300
|
+
<Panel defaultSizePercentage={-1} />
|
|
301
|
+
<PanelResizeHandle />
|
|
302
|
+
<Panel />
|
|
303
|
+
</PanelGroup>
|
|
304
|
+
);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
});
|