react-resizable-panels 2.0.8 → 2.0.10
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/CHANGELOG.md +9 -0
- package/dist/declarations/src/utils/assert.d.ts +1 -1
- package/dist/react-resizable-panels.browser.cjs.js +158 -53
- package/dist/react-resizable-panels.browser.development.cjs.js +160 -55
- package/dist/react-resizable-panels.browser.development.esm.js +159 -54
- package/dist/react-resizable-panels.browser.esm.js +157 -52
- package/dist/react-resizable-panels.cjs.js +158 -53
- package/dist/react-resizable-panels.development.cjs.js +160 -55
- package/dist/react-resizable-panels.development.esm.js +159 -54
- package/dist/react-resizable-panels.development.node.cjs.js +156 -51
- package/dist/react-resizable-panels.development.node.esm.js +155 -50
- package/dist/react-resizable-panels.esm.js +157 -52
- package/dist/react-resizable-panels.node.cjs.js +154 -49
- package/dist/react-resizable-panels.node.esm.js +153 -48
- package/package.json +1 -4
- package/src/Panel.test.tsx +23 -23
- package/src/PanelGroup.test.tsx +32 -3
- package/src/PanelGroup.ts +25 -7
- package/src/PanelResizeHandle.test.tsx +3 -3
- package/src/PanelResizeHandle.ts +1 -1
- package/src/PanelResizeHandleRegistry.ts +2 -2
- package/src/hooks/useWindowSplitterBehavior.ts +5 -2
- package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +5 -5
- package/src/utils/adjustLayoutByDelta.ts +47 -20
- package/src/utils/assert.ts +1 -1
- package/src/utils/calculateAriaValues.ts +1 -1
- package/src/utils/calculateDragOffsetPercentage.ts +6 -3
- package/src/utils/calculateUnsafeDefaultLayout.ts +2 -2
- package/src/utils/callPanelCallbacks.ts +1 -1
- package/src/utils/resizePanel.ts +4 -1
- package/src/utils/test-utils.ts +1 -1
- package/src/utils/validatePanelConstraints.ts +4 -1
- package/src/utils/validatePanelGroupLayout.ts +3 -3
- package/src/vendor/stacking-order.ts +133 -0
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { compare } from 'stacking-order';
|
|
3
2
|
|
|
4
3
|
// This module exists to work around Webpack issue https://github.com/webpack/webpack/issues/14814
|
|
5
4
|
|
|
@@ -244,6 +243,114 @@ function intersects(rectOne, rectTwo, strict) {
|
|
|
244
243
|
}
|
|
245
244
|
}
|
|
246
245
|
|
|
246
|
+
// Forked from NPM stacking-order@2.0.0
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Determine which of two nodes appears in front of the other —
|
|
250
|
+
* if `a` is in front, returns 1, otherwise returns -1
|
|
251
|
+
* @param {HTMLElement} a
|
|
252
|
+
* @param {HTMLElement} b
|
|
253
|
+
*/
|
|
254
|
+
function compare(a, b) {
|
|
255
|
+
if (a === b) throw new Error("Cannot compare node with itself");
|
|
256
|
+
const ancestors = {
|
|
257
|
+
a: get_ancestors(a),
|
|
258
|
+
b: get_ancestors(b)
|
|
259
|
+
};
|
|
260
|
+
let common_ancestor;
|
|
261
|
+
|
|
262
|
+
// remove shared ancestors
|
|
263
|
+
while (ancestors.a.at(-1) === ancestors.b.at(-1)) {
|
|
264
|
+
a = ancestors.a.pop();
|
|
265
|
+
b = ancestors.b.pop();
|
|
266
|
+
common_ancestor = a;
|
|
267
|
+
}
|
|
268
|
+
assert(common_ancestor, "Stacking order can only be calculated for elements with a common ancestor");
|
|
269
|
+
const z_indexes = {
|
|
270
|
+
a: get_z_index(find_stacking_context(ancestors.a)),
|
|
271
|
+
b: get_z_index(find_stacking_context(ancestors.b))
|
|
272
|
+
};
|
|
273
|
+
if (z_indexes.a === z_indexes.b) {
|
|
274
|
+
const children = common_ancestor.childNodes;
|
|
275
|
+
const furthest_ancestors = {
|
|
276
|
+
a: ancestors.a.at(-1),
|
|
277
|
+
b: ancestors.b.at(-1)
|
|
278
|
+
};
|
|
279
|
+
let i = children.length;
|
|
280
|
+
while (i--) {
|
|
281
|
+
const child = children[i];
|
|
282
|
+
if (child === furthest_ancestors.a) return 1;
|
|
283
|
+
if (child === furthest_ancestors.b) return -1;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return Math.sign(z_indexes.a - z_indexes.b);
|
|
287
|
+
}
|
|
288
|
+
const props = /\b(?:position|zIndex|opacity|transform|webkitTransform|mixBlendMode|filter|webkitFilter|isolation)\b/;
|
|
289
|
+
|
|
290
|
+
/** @param {HTMLElement} node */
|
|
291
|
+
function is_flex_item(node) {
|
|
292
|
+
const display = getComputedStyle(get_parent(node)).display;
|
|
293
|
+
return display === "flex" || display === "inline-flex";
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/** @param {HTMLElement} node */
|
|
297
|
+
function creates_stacking_context(node) {
|
|
298
|
+
const style = getComputedStyle(node);
|
|
299
|
+
|
|
300
|
+
// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
|
|
301
|
+
if (style.position === "fixed") return true;
|
|
302
|
+
// Forked to fix upstream bug https://github.com/Rich-Harris/stacking-order/issues/3
|
|
303
|
+
// if (
|
|
304
|
+
// (style.zIndex !== "auto" && style.position !== "static") ||
|
|
305
|
+
// is_flex_item(node)
|
|
306
|
+
// )
|
|
307
|
+
if (style.zIndex !== "auto" && (style.position !== "static" || is_flex_item(node))) return true;
|
|
308
|
+
if (+style.opacity < 1) return true;
|
|
309
|
+
if ("transform" in style && style.transform !== "none") return true;
|
|
310
|
+
if ("webkitTransform" in style && style.webkitTransform !== "none") return true;
|
|
311
|
+
if ("mixBlendMode" in style && style.mixBlendMode !== "normal") return true;
|
|
312
|
+
if ("filter" in style && style.filter !== "none") return true;
|
|
313
|
+
if ("webkitFilter" in style && style.webkitFilter !== "none") return true;
|
|
314
|
+
if ("isolation" in style && style.isolation === "isolate") return true;
|
|
315
|
+
if (props.test(style.willChange)) return true;
|
|
316
|
+
// @ts-expect-error
|
|
317
|
+
if (style.webkitOverflowScrolling === "touch") return true;
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/** @param {HTMLElement[]} nodes */
|
|
322
|
+
function find_stacking_context(nodes) {
|
|
323
|
+
let i = nodes.length;
|
|
324
|
+
while (i--) {
|
|
325
|
+
const node = nodes[i];
|
|
326
|
+
assert(node, "Missing node");
|
|
327
|
+
if (creates_stacking_context(node)) return node;
|
|
328
|
+
}
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** @param {HTMLElement} node */
|
|
333
|
+
function get_z_index(node) {
|
|
334
|
+
return node && Number(getComputedStyle(node).zIndex) || 0;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/** @param {HTMLElement} node */
|
|
338
|
+
function get_ancestors(node) {
|
|
339
|
+
const ancestors = [];
|
|
340
|
+
while (node) {
|
|
341
|
+
ancestors.push(node);
|
|
342
|
+
node = get_parent(node);
|
|
343
|
+
}
|
|
344
|
+
return ancestors; // [ node, ... <body>, <html>, document ]
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/** @param {HTMLElement} node */
|
|
348
|
+
function get_parent(node) {
|
|
349
|
+
var _node$parentNode;
|
|
350
|
+
// @ts-ignore
|
|
351
|
+
return ((_node$parentNode = node.parentNode) === null || _node$parentNode === void 0 ? void 0 : _node$parentNode.host) || node.parentNode;
|
|
352
|
+
}
|
|
353
|
+
|
|
247
354
|
const EXCEEDED_HORIZONTAL_MIN = 0b0001;
|
|
248
355
|
const EXCEEDED_HORIZONTAL_MAX = 0b0010;
|
|
249
356
|
const EXCEEDED_VERTICAL_MIN = 0b0100;
|
|
@@ -456,7 +563,7 @@ function updateListeners() {
|
|
|
456
563
|
window.removeEventListener("mouseup", handlePointerUp);
|
|
457
564
|
window.removeEventListener("touchcancel", handlePointerUp);
|
|
458
565
|
window.removeEventListener("touchend", handlePointerUp);
|
|
459
|
-
if (
|
|
566
|
+
if (registeredResizeHandlers.size > 0) {
|
|
460
567
|
if (isPointerDown) {
|
|
461
568
|
if (intersectingHandles.length > 0) {
|
|
462
569
|
ownerDocumentCounts.forEach((count, ownerDocument) => {
|
|
@@ -503,7 +610,7 @@ function updateResizeHandlerStates(action, event) {
|
|
|
503
610
|
});
|
|
504
611
|
}
|
|
505
612
|
|
|
506
|
-
function assert(expectedCondition, message
|
|
613
|
+
function assert(expectedCondition, message) {
|
|
507
614
|
if (!expectedCondition) {
|
|
508
615
|
console.error(message);
|
|
509
616
|
throw Error(message);
|
|
@@ -534,7 +641,7 @@ function resizePanel({
|
|
|
534
641
|
size
|
|
535
642
|
}) {
|
|
536
643
|
const panelConstraints = panelConstraintsArray[panelIndex];
|
|
537
|
-
assert(panelConstraints != null);
|
|
644
|
+
assert(panelConstraints != null, `Panel constraints not found for index ${panelIndex}`);
|
|
538
645
|
let {
|
|
539
646
|
collapsedSize = 0,
|
|
540
647
|
collapsible,
|
|
@@ -572,8 +679,8 @@ function adjustLayoutByDelta({
|
|
|
572
679
|
}
|
|
573
680
|
const nextLayout = [...prevLayout];
|
|
574
681
|
const [firstPivotIndex, secondPivotIndex] = pivotIndices;
|
|
575
|
-
assert(firstPivotIndex != null);
|
|
576
|
-
assert(secondPivotIndex != null);
|
|
682
|
+
assert(firstPivotIndex != null, "Invalid first pivot index");
|
|
683
|
+
assert(secondPivotIndex != null, "Invalid second pivot index");
|
|
577
684
|
let deltaApplied = 0;
|
|
578
685
|
|
|
579
686
|
//const DEBUG = [];
|
|
@@ -599,19 +706,18 @@ function adjustLayoutByDelta({
|
|
|
599
706
|
// Check if we should expand a collapsed panel
|
|
600
707
|
const index = delta < 0 ? secondPivotIndex : firstPivotIndex;
|
|
601
708
|
const panelConstraints = panelConstraintsArray[index];
|
|
602
|
-
assert(panelConstraints);
|
|
709
|
+
assert(panelConstraints, `Panel constraints not found for index ${index}`);
|
|
710
|
+
const {
|
|
711
|
+
collapsedSize = 0,
|
|
712
|
+
collapsible,
|
|
713
|
+
minSize = 0
|
|
714
|
+
} = panelConstraints;
|
|
603
715
|
|
|
604
716
|
//DEBUG.push(`edge case check 1: ${index}`);
|
|
605
717
|
//DEBUG.push(` -> collapsible? ${constraints.collapsible}`);
|
|
606
|
-
if (
|
|
718
|
+
if (collapsible) {
|
|
607
719
|
const prevSize = prevLayout[index];
|
|
608
|
-
assert(prevSize != null);
|
|
609
|
-
const panelConstraints = panelConstraintsArray[index];
|
|
610
|
-
assert(panelConstraints);
|
|
611
|
-
const {
|
|
612
|
-
collapsedSize = 0,
|
|
613
|
-
minSize = 0
|
|
614
|
-
} = panelConstraints;
|
|
720
|
+
assert(prevSize != null, `Previous layout not found for panel index ${index}`);
|
|
615
721
|
if (fuzzyNumbersEqual(prevSize, collapsedSize)) {
|
|
616
722
|
const localDelta = minSize - prevSize;
|
|
617
723
|
//DEBUG.push(` -> expand delta: ${localDelta}`);
|
|
@@ -628,22 +734,18 @@ function adjustLayoutByDelta({
|
|
|
628
734
|
// Check if we should collapse a panel at its minimum size
|
|
629
735
|
const index = delta < 0 ? firstPivotIndex : secondPivotIndex;
|
|
630
736
|
const panelConstraints = panelConstraintsArray[index];
|
|
631
|
-
assert(panelConstraints);
|
|
737
|
+
assert(panelConstraints, `No panel constraints found for index ${index}`);
|
|
632
738
|
const {
|
|
633
|
-
|
|
739
|
+
collapsedSize = 0,
|
|
740
|
+
collapsible,
|
|
741
|
+
minSize = 0
|
|
634
742
|
} = panelConstraints;
|
|
635
743
|
|
|
636
744
|
//DEBUG.push(`edge case check 2: ${index}`);
|
|
637
745
|
//DEBUG.push(` -> collapsible? ${collapsible}`);
|
|
638
746
|
if (collapsible) {
|
|
639
747
|
const prevSize = prevLayout[index];
|
|
640
|
-
assert(prevSize != null);
|
|
641
|
-
const panelConstraints = panelConstraintsArray[index];
|
|
642
|
-
assert(panelConstraints);
|
|
643
|
-
const {
|
|
644
|
-
collapsedSize = 0,
|
|
645
|
-
minSize = 0
|
|
646
|
-
} = panelConstraints;
|
|
748
|
+
assert(prevSize != null, `Previous layout not found for panel index ${index}`);
|
|
647
749
|
if (fuzzyNumbersEqual(prevSize, minSize)) {
|
|
648
750
|
const localDelta = prevSize - collapsedSize;
|
|
649
751
|
//DEBUG.push(` -> expand delta: ${localDelta}`);
|
|
@@ -673,7 +775,7 @@ function adjustLayoutByDelta({
|
|
|
673
775
|
//DEBUG.push("pre calc...");
|
|
674
776
|
while (true) {
|
|
675
777
|
const prevSize = prevLayout[index];
|
|
676
|
-
assert(prevSize != null);
|
|
778
|
+
assert(prevSize != null, `Previous layout not found for panel index ${index}`);
|
|
677
779
|
const maxSafeSize = resizePanel({
|
|
678
780
|
panelConstraints: panelConstraintsArray,
|
|
679
781
|
panelIndex: index,
|
|
@@ -704,7 +806,7 @@ function adjustLayoutByDelta({
|
|
|
704
806
|
while (index >= 0 && index < panelConstraintsArray.length) {
|
|
705
807
|
const deltaRemaining = Math.abs(delta) - Math.abs(deltaApplied);
|
|
706
808
|
const prevSize = prevLayout[index];
|
|
707
|
-
assert(prevSize != null);
|
|
809
|
+
assert(prevSize != null, `Previous layout not found for panel index ${index}`);
|
|
708
810
|
const unsafeSize = prevSize - deltaRemaining;
|
|
709
811
|
const safeSize = resizePanel({
|
|
710
812
|
panelConstraints: panelConstraintsArray,
|
|
@@ -741,7 +843,7 @@ function adjustLayoutByDelta({
|
|
|
741
843
|
// Now distribute the applied delta to the panels in the other direction
|
|
742
844
|
const pivotIndex = delta < 0 ? secondPivotIndex : firstPivotIndex;
|
|
743
845
|
const prevSize = prevLayout[pivotIndex];
|
|
744
|
-
assert(prevSize != null);
|
|
846
|
+
assert(prevSize != null, `Previous layout not found for panel index ${pivotIndex}`);
|
|
745
847
|
const unsafeSize = prevSize + deltaApplied;
|
|
746
848
|
const safeSize = resizePanel({
|
|
747
849
|
panelConstraints: panelConstraintsArray,
|
|
@@ -759,7 +861,7 @@ function adjustLayoutByDelta({
|
|
|
759
861
|
let index = pivotIndex;
|
|
760
862
|
while (index >= 0 && index < panelConstraintsArray.length) {
|
|
761
863
|
const prevSize = nextLayout[index];
|
|
762
|
-
assert(prevSize != null);
|
|
864
|
+
assert(prevSize != null, `Previous layout not found for panel index ${index}`);
|
|
763
865
|
const unsafeSize = prevSize + deltaRemaining;
|
|
764
866
|
const safeSize = resizePanel({
|
|
765
867
|
panelConstraints: panelConstraintsArray,
|
|
@@ -862,17 +964,17 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
862
964
|
return;
|
|
863
965
|
}
|
|
864
966
|
const eagerValues = eagerValuesRef.current;
|
|
865
|
-
assert(eagerValues);
|
|
967
|
+
assert(eagerValues, `Eager values not found`);
|
|
866
968
|
const {
|
|
867
969
|
panelDataArray
|
|
868
970
|
} = eagerValues;
|
|
869
971
|
const groupElement = getPanelGroupElement(groupId, panelGroupElement);
|
|
870
972
|
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
871
973
|
const handles = getResizeHandleElementsForGroup(groupId, panelGroupElement);
|
|
872
|
-
assert(handles);
|
|
974
|
+
assert(handles, `No resize handles found for group id "${groupId}"`);
|
|
873
975
|
const cleanupFunctions = handles.map(handle => {
|
|
874
976
|
const handleId = handle.getAttribute("data-panel-resize-handle-id");
|
|
875
|
-
assert(handleId);
|
|
977
|
+
assert(handleId, `Resize handle element has no handle id attribute`);
|
|
876
978
|
const [idBefore, idAfter] = getResizeHandlePanelIds(groupId, handleId, panelDataArray, panelGroupElement);
|
|
877
979
|
if (idBefore == null || idAfter == null) {
|
|
878
980
|
return () => {};
|
|
@@ -888,7 +990,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
888
990
|
const index = panelDataArray.findIndex(panelData => panelData.id === idBefore);
|
|
889
991
|
if (index >= 0) {
|
|
890
992
|
const panelData = panelDataArray[index];
|
|
891
|
-
assert(panelData);
|
|
993
|
+
assert(panelData, `No panel data found for index ${index}`);
|
|
892
994
|
const size = layout[index];
|
|
893
995
|
const {
|
|
894
996
|
collapsedSize = 0,
|
|
@@ -947,15 +1049,15 @@ function getResizeEventCursorPosition(direction, event) {
|
|
|
947
1049
|
function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState, panelGroupElement) {
|
|
948
1050
|
const isHorizontal = direction === "horizontal";
|
|
949
1051
|
const handleElement = getResizeHandleElement(dragHandleId, panelGroupElement);
|
|
950
|
-
assert(handleElement);
|
|
1052
|
+
assert(handleElement, `No resize handle element found for id "${dragHandleId}"`);
|
|
951
1053
|
const groupId = handleElement.getAttribute("data-panel-group-id");
|
|
952
|
-
assert(groupId);
|
|
1054
|
+
assert(groupId, `Resize handle element has no group id attribute`);
|
|
953
1055
|
let {
|
|
954
1056
|
initialCursorPosition
|
|
955
1057
|
} = initialDragState;
|
|
956
1058
|
const cursorPosition = getResizeEventCursorPosition(direction, event);
|
|
957
1059
|
const groupElement = getPanelGroupElement(groupId, panelGroupElement);
|
|
958
|
-
assert(groupElement);
|
|
1060
|
+
assert(groupElement, `No group element found for id "${groupId}"`);
|
|
959
1061
|
const groupRect = groupElement.getBoundingClientRect();
|
|
960
1062
|
const groupSizeInPixels = isHorizontal ? groupRect.width : groupRect.height;
|
|
961
1063
|
const offsetPixels = cursorPosition - initialCursorPosition;
|
|
@@ -1009,7 +1111,7 @@ function calculateDeltaPercentage(event, dragHandleId, direction, initialDragSta
|
|
|
1009
1111
|
function callPanelCallbacks(panelsArray, layout, panelIdToLastNotifiedSizeMap) {
|
|
1010
1112
|
layout.forEach((size, index) => {
|
|
1011
1113
|
const panelData = panelsArray[index];
|
|
1012
|
-
assert(panelData);
|
|
1114
|
+
assert(panelData, `Panel data not found for index ${index}`);
|
|
1013
1115
|
const {
|
|
1014
1116
|
callbacks,
|
|
1015
1117
|
constraints,
|
|
@@ -1193,7 +1295,7 @@ function validatePanelGroupLayout({
|
|
|
1193
1295
|
} else if (!fuzzyNumbersEqual(nextLayoutTotalSize, 100)) {
|
|
1194
1296
|
for (let index = 0; index < panelConstraints.length; index++) {
|
|
1195
1297
|
const unsafeSize = nextLayout[index];
|
|
1196
|
-
assert(unsafeSize != null);
|
|
1298
|
+
assert(unsafeSize != null, `No layout data found for index ${index}`);
|
|
1197
1299
|
const safeSize = 100 / nextLayoutTotalSize * unsafeSize;
|
|
1198
1300
|
nextLayout[index] = safeSize;
|
|
1199
1301
|
}
|
|
@@ -1203,7 +1305,7 @@ function validatePanelGroupLayout({
|
|
|
1203
1305
|
// First pass: Validate the proposed layout given each panel's constraints
|
|
1204
1306
|
for (let index = 0; index < panelConstraints.length; index++) {
|
|
1205
1307
|
const unsafeSize = nextLayout[index];
|
|
1206
|
-
assert(unsafeSize != null);
|
|
1308
|
+
assert(unsafeSize != null, `No layout data found for index ${index}`);
|
|
1207
1309
|
const safeSize = resizePanel({
|
|
1208
1310
|
panelConstraints,
|
|
1209
1311
|
panelIndex: index,
|
|
@@ -1220,7 +1322,7 @@ function validatePanelGroupLayout({
|
|
|
1220
1322
|
if (!fuzzyNumbersEqual(remainingSize, 0)) {
|
|
1221
1323
|
for (let index = 0; index < panelConstraints.length; index++) {
|
|
1222
1324
|
const prevSize = nextLayout[index];
|
|
1223
|
-
assert(prevSize != null);
|
|
1325
|
+
assert(prevSize != null, `No layout data found for index ${index}`);
|
|
1224
1326
|
const unsafeSize = prevSize + remainingSize;
|
|
1225
1327
|
const safeSize = resizePanel({
|
|
1226
1328
|
panelConstraints,
|
|
@@ -1378,7 +1480,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1378
1480
|
panelSize,
|
|
1379
1481
|
pivotIndices
|
|
1380
1482
|
} = panelDataHelper(panelDataArray, panelData, prevLayout);
|
|
1381
|
-
assert(panelSize != null);
|
|
1483
|
+
assert(panelSize != null, `Panel size not found for panel "${panelData.id}"`);
|
|
1382
1484
|
if (panelSize !== collapsedSize) {
|
|
1383
1485
|
// Store size before collapse;
|
|
1384
1486
|
// This is the size that gets restored if the expand() API is used.
|
|
@@ -1455,7 +1557,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1455
1557
|
const {
|
|
1456
1558
|
panelSize
|
|
1457
1559
|
} = panelDataHelper(panelDataArray, panelData, layout);
|
|
1458
|
-
assert(panelSize != null);
|
|
1560
|
+
assert(panelSize != null, `Panel size not found for panel "${panelData.id}"`);
|
|
1459
1561
|
return panelSize;
|
|
1460
1562
|
}, []);
|
|
1461
1563
|
|
|
@@ -1499,7 +1601,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1499
1601
|
collapsible,
|
|
1500
1602
|
panelSize
|
|
1501
1603
|
} = panelDataHelper(panelDataArray, panelData, layout);
|
|
1502
|
-
assert(panelSize != null);
|
|
1604
|
+
assert(panelSize != null, `Panel size not found for panel "${panelData.id}"`);
|
|
1503
1605
|
return !collapsible || panelSize > collapsedSize;
|
|
1504
1606
|
}, []);
|
|
1505
1607
|
const registerPanel = useCallback(panelData => {
|
|
@@ -1610,7 +1712,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1610
1712
|
panelSize,
|
|
1611
1713
|
pivotIndices
|
|
1612
1714
|
} = panelDataHelper(panelDataArray, panelData, prevLayout);
|
|
1613
|
-
assert(panelSize != null);
|
|
1715
|
+
assert(panelSize != null, `Panel size not found for panel "${panelData.id}"`);
|
|
1614
1716
|
const isLastPanel = findPanelDataIndex(panelDataArray, panelData) === panelDataArray.length - 1;
|
|
1615
1717
|
const delta = isLastPanel ? panelSize - unsafePanelSize : unsafePanelSize - panelSize;
|
|
1616
1718
|
const nextLayout = adjustLayoutByDelta({
|
|
@@ -1647,7 +1749,10 @@ function PanelGroupWithForwardedRef({
|
|
|
1647
1749
|
const {
|
|
1648
1750
|
panelSize: prevPanelSize
|
|
1649
1751
|
} = panelDataHelper(panelDataArray, panelData, layout);
|
|
1650
|
-
|
|
1752
|
+
if (prevPanelSize == null) {
|
|
1753
|
+
// It's possible that the panels in this group have changed since the last render
|
|
1754
|
+
return;
|
|
1755
|
+
}
|
|
1651
1756
|
if (prevCollapsible && nextCollapsible && prevPanelSize === prevCollapsedSize) {
|
|
1652
1757
|
if (prevCollapsedSize !== nextCollapsedSize) {
|
|
1653
1758
|
resizePanel(panelData, nextCollapsedSize);
|
|
@@ -1669,7 +1774,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1669
1774
|
return;
|
|
1670
1775
|
}
|
|
1671
1776
|
const handleElement = getResizeHandleElement(dragHandleId, panelGroupElementRef.current);
|
|
1672
|
-
assert(handleElement);
|
|
1777
|
+
assert(handleElement, `Drag handle element not found for id "${dragHandleId}"`);
|
|
1673
1778
|
const initialCursorPosition = getResizeEventCursorPosition(direction, event);
|
|
1674
1779
|
setDragState({
|
|
1675
1780
|
dragHandleId,
|
|
@@ -1798,10 +1903,10 @@ function useWindowSplitterResizeHandlerBehavior({
|
|
|
1798
1903
|
{
|
|
1799
1904
|
event.preventDefault();
|
|
1800
1905
|
const groupId = handleElement.getAttribute("data-panel-group-id");
|
|
1801
|
-
assert(groupId);
|
|
1906
|
+
assert(groupId, `No group element found for id "${groupId}"`);
|
|
1802
1907
|
const handles = getResizeHandleElementsForGroup(groupId, panelGroupElement);
|
|
1803
1908
|
const index = getResizeHandleElementIndex(groupId, handleId, panelGroupElement);
|
|
1804
|
-
assert(index !== null);
|
|
1909
|
+
assert(index !== null, `No resize element found for id "${handleId}"`);
|
|
1805
1910
|
const nextIndex = event.shiftKey ? index > 0 ? index - 1 : handles.length - 1 : index + 1 < handles.length ? index + 1 : 0;
|
|
1806
1911
|
const nextHandle = handles[nextIndex];
|
|
1807
1912
|
nextHandle.focus();
|
|
@@ -1870,7 +1975,7 @@ function PanelResizeHandle({
|
|
|
1870
1975
|
return;
|
|
1871
1976
|
}
|
|
1872
1977
|
const element = elementRef.current;
|
|
1873
|
-
assert(element);
|
|
1978
|
+
assert(element, "Element ref not attached");
|
|
1874
1979
|
const setResizeHandlerState = (action, isActive, event) => {
|
|
1875
1980
|
if (isActive) {
|
|
1876
1981
|
switch (action) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-resizable-panels",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.10",
|
|
4
4
|
"description": "React components for resizable panel groups/layouts",
|
|
5
5
|
"author": "Brian Vaughn <brian.david.vaughn@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -66,9 +66,6 @@
|
|
|
66
66
|
"test:watch": "jest --config=jest.config.js --watch",
|
|
67
67
|
"watch": "parcel watch --port=2345"
|
|
68
68
|
},
|
|
69
|
-
"dependencies": {
|
|
70
|
-
"stacking-order": "^1"
|
|
71
|
-
},
|
|
72
69
|
"devDependencies": {
|
|
73
70
|
"@babel/plugin-proposal-nullish-coalescing-operator": "7.18.6",
|
|
74
71
|
"@babel/plugin-proposal-optional-chaining": "7.21.0",
|
package/src/Panel.test.tsx
CHANGED
|
@@ -88,7 +88,7 @@ describe("PanelGroup", () => {
|
|
|
88
88
|
});
|
|
89
89
|
|
|
90
90
|
it("should expand and collapse the first panel in a group", () => {
|
|
91
|
-
assert(mostRecentLayout);
|
|
91
|
+
assert(mostRecentLayout, "");
|
|
92
92
|
|
|
93
93
|
verifyExpandedPanelGroupLayout(mostRecentLayout, [50, 50]);
|
|
94
94
|
expect(leftPanelRef.current?.isCollapsed()).toBe(false);
|
|
@@ -108,7 +108,7 @@ describe("PanelGroup", () => {
|
|
|
108
108
|
});
|
|
109
109
|
|
|
110
110
|
it("should expand and collapse the last panel in a group", () => {
|
|
111
|
-
assert(mostRecentLayout);
|
|
111
|
+
assert(mostRecentLayout, "");
|
|
112
112
|
|
|
113
113
|
verifyExpandedPanelGroupLayout(mostRecentLayout, [50, 50]);
|
|
114
114
|
expect(leftPanelRef.current?.isCollapsed()).toBe(false);
|
|
@@ -128,7 +128,7 @@ describe("PanelGroup", () => {
|
|
|
128
128
|
});
|
|
129
129
|
|
|
130
130
|
it("should re-expand to the most recent size before collapsing", () => {
|
|
131
|
-
assert(mostRecentLayout);
|
|
131
|
+
assert(mostRecentLayout, "");
|
|
132
132
|
|
|
133
133
|
verifyExpandedPanelGroupLayout(mostRecentLayout, [50, 50]);
|
|
134
134
|
act(() => {
|
|
@@ -178,7 +178,7 @@ describe("PanelGroup", () => {
|
|
|
178
178
|
});
|
|
179
179
|
|
|
180
180
|
it("should resize the first panel in a group", () => {
|
|
181
|
-
assert(mostRecentLayout);
|
|
181
|
+
assert(mostRecentLayout, "");
|
|
182
182
|
|
|
183
183
|
verifyExpandedPanelGroupLayout(mostRecentLayout, [20, 60, 20]);
|
|
184
184
|
act(() => {
|
|
@@ -188,7 +188,7 @@ describe("PanelGroup", () => {
|
|
|
188
188
|
});
|
|
189
189
|
|
|
190
190
|
it("should resize the middle panel in a group", () => {
|
|
191
|
-
assert(mostRecentLayout);
|
|
191
|
+
assert(mostRecentLayout, "");
|
|
192
192
|
|
|
193
193
|
verifyExpandedPanelGroupLayout(mostRecentLayout, [20, 60, 20]);
|
|
194
194
|
act(() => {
|
|
@@ -198,7 +198,7 @@ describe("PanelGroup", () => {
|
|
|
198
198
|
});
|
|
199
199
|
|
|
200
200
|
it("should resize the last panel in a group", () => {
|
|
201
|
-
assert(mostRecentLayout);
|
|
201
|
+
assert(mostRecentLayout, "");
|
|
202
202
|
|
|
203
203
|
verifyExpandedPanelGroupLayout(mostRecentLayout, [20, 60, 20]);
|
|
204
204
|
act(() => {
|
|
@@ -261,7 +261,7 @@ describe("PanelGroup", () => {
|
|
|
261
261
|
});
|
|
262
262
|
|
|
263
263
|
const element = getPanelElement("panel", container);
|
|
264
|
-
assert(element);
|
|
264
|
+
assert(element, "");
|
|
265
265
|
expect(element.tabIndex).toBe(123);
|
|
266
266
|
expect(element.getAttribute("data-test-name")).toBe("foo");
|
|
267
267
|
expect(element.title).toBe("bar");
|
|
@@ -296,9 +296,9 @@ describe("PanelGroup", () => {
|
|
|
296
296
|
let leftElement = getPanelElement("left", container);
|
|
297
297
|
let middleElement = getPanelElement("middle", container);
|
|
298
298
|
let rightElement = getPanelElement("right", container);
|
|
299
|
-
assert(leftElement);
|
|
300
|
-
assert(middleElement);
|
|
301
|
-
assert(rightElement);
|
|
299
|
+
assert(leftElement, "");
|
|
300
|
+
assert(middleElement, "");
|
|
301
|
+
assert(rightElement, "");
|
|
302
302
|
expect(leftElement.getAttribute("data-panel-size")).toBe("10.0");
|
|
303
303
|
expect(middleElement.getAttribute("data-panel-size")).toBe("80.0");
|
|
304
304
|
expect(rightElement.getAttribute("data-panel-size")).toBe("10.0");
|
|
@@ -348,9 +348,9 @@ describe("PanelGroup", () => {
|
|
|
348
348
|
let leftElement = getPanelElement("left", container);
|
|
349
349
|
let middleElement = getPanelElement("middle", container);
|
|
350
350
|
let rightElement = getPanelElement("right", container);
|
|
351
|
-
assert(leftElement);
|
|
352
|
-
assert(middleElement);
|
|
353
|
-
assert(rightElement);
|
|
351
|
+
assert(leftElement, "");
|
|
352
|
+
assert(middleElement, "");
|
|
353
|
+
assert(rightElement, "");
|
|
354
354
|
expect(leftElement.getAttribute("data-panel-size")).toBe("10.0");
|
|
355
355
|
expect(middleElement.getAttribute("data-panel-size")).toBe("80.0");
|
|
356
356
|
expect(rightElement.getAttribute("data-panel-size")).toBe("10.0");
|
|
@@ -388,9 +388,9 @@ describe("PanelGroup", () => {
|
|
|
388
388
|
let leftElement = getPanelElement("left", container);
|
|
389
389
|
let middleElement = getPanelElement("middle", container);
|
|
390
390
|
let rightElement = getPanelElement("right", container);
|
|
391
|
-
assert(leftElement);
|
|
392
|
-
assert(middleElement);
|
|
393
|
-
assert(rightElement);
|
|
391
|
+
assert(leftElement, "");
|
|
392
|
+
assert(middleElement, "");
|
|
393
|
+
assert(rightElement, "");
|
|
394
394
|
expect(leftElement.getAttribute("data-panel-size")).toBe("15.0");
|
|
395
395
|
expect(middleElement.getAttribute("data-panel-size")).toBe("70.0");
|
|
396
396
|
expect(rightElement.getAttribute("data-panel-size")).toBe("15.0");
|
|
@@ -428,9 +428,9 @@ describe("PanelGroup", () => {
|
|
|
428
428
|
let leftElement = getPanelElement("left", container);
|
|
429
429
|
let middleElement = getPanelElement("middle", container);
|
|
430
430
|
let rightElement = getPanelElement("right", container);
|
|
431
|
-
assert(leftElement);
|
|
432
|
-
assert(middleElement);
|
|
433
|
-
assert(rightElement);
|
|
431
|
+
assert(leftElement, "");
|
|
432
|
+
assert(middleElement, "");
|
|
433
|
+
assert(rightElement, "");
|
|
434
434
|
expect(leftElement.getAttribute("data-panel-size")).toBe("25.0");
|
|
435
435
|
expect(middleElement.getAttribute("data-panel-size")).toBe("50.0");
|
|
436
436
|
expect(rightElement.getAttribute("data-panel-size")).toBe("25.0");
|
|
@@ -691,8 +691,8 @@ describe("PanelGroup", () => {
|
|
|
691
691
|
const leftElement = getPanelElement("left-panel", container);
|
|
692
692
|
const rightElement = getPanelElement("right-panel", container);
|
|
693
693
|
|
|
694
|
-
assert(leftElement);
|
|
695
|
-
assert(rightElement);
|
|
694
|
+
assert(leftElement, "");
|
|
695
|
+
assert(rightElement, "");
|
|
696
696
|
|
|
697
697
|
verifyAttribute(leftElement, "data-panel", "");
|
|
698
698
|
verifyAttribute(leftElement, "data-panel-id", "left-panel");
|
|
@@ -723,8 +723,8 @@ describe("PanelGroup", () => {
|
|
|
723
723
|
const leftElement = getPanelElement("left-panel", container);
|
|
724
724
|
const rightElement = getPanelElement("right-panel", container);
|
|
725
725
|
|
|
726
|
-
assert(leftElement);
|
|
727
|
-
assert(rightElement);
|
|
726
|
+
assert(leftElement, "");
|
|
727
|
+
assert(rightElement, "");
|
|
728
728
|
|
|
729
729
|
verifyAttribute(leftElement, "data-panel-size", "75.0");
|
|
730
730
|
verifyAttribute(rightElement, "data-panel-size", "25.0");
|
package/src/PanelGroup.test.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-expect-error This is an experimental API
|
|
2
2
|
// eslint-disable-next-line no-restricted-imports
|
|
3
|
-
import { unstable_Activity as Activity } from "react";
|
|
3
|
+
import { unstable_Activity as Activity, Fragment } from "react";
|
|
4
4
|
import { Root, createRoot } from "react-dom/client";
|
|
5
5
|
import { act } from "react-dom/test-utils";
|
|
6
6
|
import {
|
|
@@ -130,6 +130,35 @@ describe("PanelGroup", () => {
|
|
|
130
130
|
expect(rightPanelElement?.getAttribute("data-panel-size")).toBe("40.0");
|
|
131
131
|
});
|
|
132
132
|
|
|
133
|
+
// github.com/bvaughn/react-resizable-panels/issues/303
|
|
134
|
+
it("should recalculate layout after panels are changed", () => {
|
|
135
|
+
let mostRecentLayout: number[] | null = null;
|
|
136
|
+
|
|
137
|
+
const onLayout = (layout: number[]) => {
|
|
138
|
+
mostRecentLayout = layout;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
act(() => {
|
|
142
|
+
root.render(
|
|
143
|
+
<PanelGroup direction="vertical" onLayout={onLayout}>
|
|
144
|
+
<Panel id="foo" minSize={30} order={0} />
|
|
145
|
+
<PanelResizeHandle />
|
|
146
|
+
<Panel id="bar" minSize={70} order={1} />
|
|
147
|
+
</PanelGroup>
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
expect(mostRecentLayout).toEqual([30, 70]);
|
|
151
|
+
|
|
152
|
+
act(() => {
|
|
153
|
+
root.render(
|
|
154
|
+
<PanelGroup direction="vertical" onLayout={onLayout}>
|
|
155
|
+
<Panel id="bar" minSize={70} order={0} />
|
|
156
|
+
</PanelGroup>
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
expect(mostRecentLayout).toEqual([100]);
|
|
160
|
+
});
|
|
161
|
+
|
|
133
162
|
describe("imperative handle API", () => {
|
|
134
163
|
it("should report the most recently rendered group id", () => {
|
|
135
164
|
const ref = createRef<ImperativePanelGroupHandle>();
|
|
@@ -194,7 +223,7 @@ describe("PanelGroup", () => {
|
|
|
194
223
|
});
|
|
195
224
|
|
|
196
225
|
const element = getPanelGroupElement("group", container);
|
|
197
|
-
assert(element);
|
|
226
|
+
assert(element, "");
|
|
198
227
|
expect(element.tabIndex).toBe(123);
|
|
199
228
|
expect(element.getAttribute("data-test-name")).toBe("foo");
|
|
200
229
|
expect(element.title).toBe("bar");
|
|
@@ -268,7 +297,7 @@ describe("PanelGroup", () => {
|
|
|
268
297
|
});
|
|
269
298
|
|
|
270
299
|
const element = getPanelGroupElement("test-group", container);
|
|
271
|
-
assert(element);
|
|
300
|
+
assert(element, "");
|
|
272
301
|
|
|
273
302
|
verifyAttribute(element, "data-panel-group", "");
|
|
274
303
|
verifyAttribute(element, "data-panel-group-direction", "horizontal");
|