react-resizable-panels 1.0.7 → 1.0.9
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 +11 -0
- package/README.md +16 -15
- package/dist/declarations/src/Panel.d.ts +3 -3
- package/dist/declarations/src/PanelGroup.d.ts +2 -2
- package/dist/declarations/src/PanelResizeHandle.d.ts +2 -2
- package/dist/declarations/src/index.d.ts +1 -3
- package/dist/declarations/src/utils/dom/getPanelElement.d.ts +1 -1
- package/dist/declarations/src/utils/dom/getPanelElementsForGroup.d.ts +1 -1
- package/dist/declarations/src/utils/dom/getPanelGroupElement.d.ts +1 -1
- package/dist/declarations/src/utils/dom/getResizeHandleElement.d.ts +1 -1
- package/dist/declarations/src/utils/dom/getResizeHandleElementIndex.d.ts +1 -1
- package/dist/declarations/src/utils/dom/getResizeHandleElementsForGroup.d.ts +1 -1
- package/dist/declarations/src/utils/dom/getResizeHandlePanelIds.d.ts +1 -1
- package/dist/declarations/src/vendor/react.d.ts +2 -2
- package/dist/react-resizable-panels.browser.cjs.js +114 -84
- package/dist/react-resizable-panels.browser.cjs.mjs +0 -2
- package/dist/react-resizable-panels.browser.development.cjs.js +116 -85
- package/dist/react-resizable-panels.browser.development.cjs.mjs +0 -2
- package/dist/react-resizable-panels.browser.development.esm.js +117 -84
- package/dist/react-resizable-panels.browser.esm.js +115 -83
- package/dist/react-resizable-panels.cjs.js +114 -84
- package/dist/react-resizable-panels.cjs.mjs +0 -2
- package/dist/react-resizable-panels.development.cjs.js +116 -85
- package/dist/react-resizable-panels.development.cjs.mjs +0 -2
- package/dist/react-resizable-panels.development.esm.js +117 -84
- package/dist/react-resizable-panels.development.node.cjs.js +102 -83
- package/dist/react-resizable-panels.development.node.cjs.mjs +0 -2
- package/dist/react-resizable-panels.development.node.esm.js +103 -82
- package/dist/react-resizable-panels.esm.js +115 -83
- package/dist/react-resizable-panels.node.cjs.js +100 -82
- package/dist/react-resizable-panels.node.cjs.mjs +0 -2
- package/dist/react-resizable-panels.node.esm.js +101 -81
- package/package.json +1 -1
- package/src/Panel.test.tsx +137 -2
- package/src/Panel.ts +16 -2
- package/src/PanelGroup.test.tsx +3 -2
- package/src/PanelGroup.ts +95 -35
- package/src/PanelGroupContext.ts +9 -3
- package/src/PanelResizeHandle.test.tsx +3 -3
- package/src/PanelResizeHandle.ts +4 -2
- package/src/hooks/useWindowSplitterBehavior.ts +14 -5
- package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +23 -7
- package/src/index.ts +0 -4
- package/src/utils/calculateDeltaPercentage.ts +4 -2
- package/src/utils/calculateDragOffsetPercentage.ts +4 -3
- package/src/utils/determinePivotIndices.ts +7 -2
- package/src/utils/dom/getPanelElement.ts +5 -2
- package/src/utils/dom/getPanelElementsForGroup.ts +5 -2
- package/src/utils/dom/getPanelGroupElement.ts +14 -2
- package/src/utils/dom/getResizeHandleElement.ts +5 -4
- package/src/utils/dom/getResizeHandleElementIndex.ts +3 -2
- package/src/utils/dom/getResizeHandleElementsForGroup.ts +3 -2
- package/src/utils/dom/getResizeHandlePanelIds.ts +4 -3
- package/src/utils/validatePanelConstraints.test.ts +45 -0
- package/src/utils/validatePanelConstraints.ts +5 -1
- package/src/vendor/react.ts +2 -0
- package/dist/declarations/src/utils/dom/calculateAvailablePanelSizeInPixels.d.ts +0 -1
- package/dist/declarations/src/utils/dom/getAvailableGroupSizePixels.d.ts +0 -1
- package/src/utils/dom/calculateAvailablePanelSizeInPixels.ts +0 -29
- package/src/utils/dom/getAvailableGroupSizePixels.ts +0 -29
|
@@ -65,6 +65,7 @@ function PanelWithForwardedRef({
|
|
|
65
65
|
getPanelStyle,
|
|
66
66
|
groupId,
|
|
67
67
|
isPanelCollapsed,
|
|
68
|
+
reevaluatePanelConstraints,
|
|
68
69
|
registerPanel,
|
|
69
70
|
resizePanel,
|
|
70
71
|
unregisterPanel
|
|
@@ -430,41 +431,48 @@ function adjustLayoutByDelta({
|
|
|
430
431
|
return nextLayout;
|
|
431
432
|
}
|
|
432
433
|
|
|
433
|
-
function getResizeHandleElementsForGroup(groupId) {
|
|
434
|
-
return Array.from(
|
|
434
|
+
function getResizeHandleElementsForGroup(groupId, scope = document) {
|
|
435
|
+
return Array.from(scope.querySelectorAll(`[data-panel-resize-handle-id][data-panel-group-id="${groupId}"]`));
|
|
435
436
|
}
|
|
436
437
|
|
|
437
|
-
function getResizeHandleElementIndex(groupId, id) {
|
|
438
|
-
const handles = getResizeHandleElementsForGroup(groupId);
|
|
438
|
+
function getResizeHandleElementIndex(groupId, id, scope = document) {
|
|
439
|
+
const handles = getResizeHandleElementsForGroup(groupId, scope);
|
|
439
440
|
const index = handles.findIndex(handle => handle.getAttribute("data-panel-resize-handle-id") === id);
|
|
440
441
|
return index !== null && index !== void 0 ? index : null;
|
|
441
442
|
}
|
|
442
443
|
|
|
443
|
-
function determinePivotIndices(groupId, dragHandleId) {
|
|
444
|
-
const index = getResizeHandleElementIndex(groupId, dragHandleId);
|
|
444
|
+
function determinePivotIndices(groupId, dragHandleId, panelGroupElement) {
|
|
445
|
+
const index = getResizeHandleElementIndex(groupId, dragHandleId, panelGroupElement);
|
|
445
446
|
return index != null ? [index, index + 1] : [-1, -1];
|
|
446
447
|
}
|
|
447
448
|
|
|
448
|
-
function getPanelGroupElement(id) {
|
|
449
|
-
|
|
449
|
+
function getPanelGroupElement(id, rootElement = document) {
|
|
450
|
+
var _dataset;
|
|
451
|
+
//If the root element is the PanelGroup
|
|
452
|
+
if (rootElement instanceof HTMLElement && (rootElement === null || rootElement === void 0 ? void 0 : (_dataset = rootElement.dataset) === null || _dataset === void 0 ? void 0 : _dataset.panelGroupId) == id) {
|
|
453
|
+
return rootElement;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
//Else query children
|
|
457
|
+
const element = rootElement.querySelector(`[data-panel-group][data-panel-group-id="${id}"]`);
|
|
450
458
|
if (element) {
|
|
451
459
|
return element;
|
|
452
460
|
}
|
|
453
461
|
return null;
|
|
454
462
|
}
|
|
455
463
|
|
|
456
|
-
function getResizeHandleElement(id) {
|
|
457
|
-
const element =
|
|
464
|
+
function getResizeHandleElement(id, scope = document) {
|
|
465
|
+
const element = scope.querySelector(`[data-panel-resize-handle-id="${id}"]`);
|
|
458
466
|
if (element) {
|
|
459
467
|
return element;
|
|
460
468
|
}
|
|
461
469
|
return null;
|
|
462
470
|
}
|
|
463
471
|
|
|
464
|
-
function getResizeHandlePanelIds(groupId, handleId, panelsArray) {
|
|
472
|
+
function getResizeHandlePanelIds(groupId, handleId, panelsArray, scope = document) {
|
|
465
473
|
var _panelsArray$index$id, _panelsArray$index, _panelsArray$id, _panelsArray;
|
|
466
|
-
const handle = getResizeHandleElement(handleId);
|
|
467
|
-
const handles = getResizeHandleElementsForGroup(groupId);
|
|
474
|
+
const handle = getResizeHandleElement(handleId, scope);
|
|
475
|
+
const handles = getResizeHandleElementsForGroup(groupId, scope);
|
|
468
476
|
const index = handle ? handles.indexOf(handle) : -1;
|
|
469
477
|
const idBefore = (_panelsArray$index$id = (_panelsArray$index = panelsArray[index]) === null || _panelsArray$index === void 0 ? void 0 : _panelsArray$index.id) !== null && _panelsArray$index$id !== void 0 ? _panelsArray$index$id : null;
|
|
470
478
|
const idAfter = (_panelsArray$id = (_panelsArray = panelsArray[index + 1]) === null || _panelsArray === void 0 ? void 0 : _panelsArray.id) !== null && _panelsArray$id !== void 0 ? _panelsArray$id : null;
|
|
@@ -479,25 +487,29 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
479
487
|
groupId,
|
|
480
488
|
layout,
|
|
481
489
|
panelDataArray,
|
|
490
|
+
panelGroupElement,
|
|
482
491
|
setLayout
|
|
483
492
|
}) {
|
|
484
493
|
useRef({
|
|
485
494
|
didWarnAboutMissingResizeHandle: false
|
|
486
495
|
});
|
|
487
496
|
useEffect(() => {
|
|
497
|
+
if (!panelGroupElement) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
488
500
|
const eagerValues = eagerValuesRef.current;
|
|
489
501
|
assert(eagerValues);
|
|
490
502
|
const {
|
|
491
503
|
panelDataArray
|
|
492
504
|
} = eagerValues;
|
|
493
|
-
const groupElement = getPanelGroupElement(groupId);
|
|
505
|
+
const groupElement = getPanelGroupElement(groupId, panelGroupElement);
|
|
494
506
|
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
495
|
-
const handles = getResizeHandleElementsForGroup(groupId);
|
|
507
|
+
const handles = getResizeHandleElementsForGroup(groupId, panelGroupElement);
|
|
496
508
|
assert(handles);
|
|
497
509
|
const cleanupFunctions = handles.map(handle => {
|
|
498
510
|
const handleId = handle.getAttribute("data-panel-resize-handle-id");
|
|
499
511
|
assert(handleId);
|
|
500
|
-
const [idBefore, idAfter] = getResizeHandlePanelIds(groupId, handleId, panelDataArray);
|
|
512
|
+
const [idBefore, idAfter] = getResizeHandlePanelIds(groupId, handleId, panelDataArray, panelGroupElement);
|
|
501
513
|
if (idBefore == null || idAfter == null) {
|
|
502
514
|
return () => {};
|
|
503
515
|
}
|
|
@@ -524,7 +536,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
524
536
|
delta: fuzzyNumbersEqual(size, collapsedSize) ? minSize - collapsedSize : collapsedSize - size,
|
|
525
537
|
layout,
|
|
526
538
|
panelConstraints: panelDataArray.map(panelData => panelData.constraints),
|
|
527
|
-
pivotIndices: determinePivotIndices(groupId, handleId),
|
|
539
|
+
pivotIndices: determinePivotIndices(groupId, handleId, panelGroupElement),
|
|
528
540
|
trigger: "keyboard"
|
|
529
541
|
});
|
|
530
542
|
if (layout !== nextLayout) {
|
|
@@ -544,7 +556,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
544
556
|
return () => {
|
|
545
557
|
cleanupFunctions.forEach(cleanupFunction => cleanupFunction());
|
|
546
558
|
};
|
|
547
|
-
}, [committedValuesRef, eagerValuesRef, groupId, layout, panelDataArray, setLayout]);
|
|
559
|
+
}, [panelGroupElement, committedValuesRef, eagerValuesRef, groupId, layout, panelDataArray, setLayout]);
|
|
548
560
|
}
|
|
549
561
|
|
|
550
562
|
function areEqual(arrayA, arrayB) {
|
|
@@ -582,9 +594,9 @@ function getResizeEventCursorPosition(direction, event) {
|
|
|
582
594
|
}
|
|
583
595
|
}
|
|
584
596
|
|
|
585
|
-
function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState) {
|
|
597
|
+
function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState, panelGroupElement) {
|
|
586
598
|
const isHorizontal = direction === "horizontal";
|
|
587
|
-
const handleElement = getResizeHandleElement(dragHandleId);
|
|
599
|
+
const handleElement = getResizeHandleElement(dragHandleId, panelGroupElement);
|
|
588
600
|
assert(handleElement);
|
|
589
601
|
const groupId = handleElement.getAttribute("data-panel-group-id");
|
|
590
602
|
assert(groupId);
|
|
@@ -592,7 +604,7 @@ function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDr
|
|
|
592
604
|
initialCursorPosition
|
|
593
605
|
} = initialDragState;
|
|
594
606
|
const cursorPosition = getResizeEventCursorPosition(direction, event);
|
|
595
|
-
const groupElement = getPanelGroupElement(groupId);
|
|
607
|
+
const groupElement = getPanelGroupElement(groupId, panelGroupElement);
|
|
596
608
|
assert(groupElement);
|
|
597
609
|
const groupRect = groupElement.getBoundingClientRect();
|
|
598
610
|
const groupSizeInPixels = isHorizontal ? groupRect.width : groupRect.height;
|
|
@@ -602,7 +614,7 @@ function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDr
|
|
|
602
614
|
}
|
|
603
615
|
|
|
604
616
|
// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX
|
|
605
|
-
function calculateDeltaPercentage(event, dragHandleId, direction, initialDragState, keyboardResizeBy) {
|
|
617
|
+
function calculateDeltaPercentage(event, dragHandleId, direction, initialDragState, keyboardResizeBy, panelGroupElement) {
|
|
606
618
|
if (isKeyDown(event)) {
|
|
607
619
|
const isHorizontal = direction === "horizontal";
|
|
608
620
|
let delta = 0;
|
|
@@ -639,7 +651,7 @@ function calculateDeltaPercentage(event, dragHandleId, direction, initialDragSta
|
|
|
639
651
|
if (initialDragState == null) {
|
|
640
652
|
return 0;
|
|
641
653
|
}
|
|
642
|
-
return calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState);
|
|
654
|
+
return calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState, panelGroupElement);
|
|
643
655
|
}
|
|
644
656
|
}
|
|
645
657
|
|
|
@@ -944,6 +956,7 @@ function PanelGroupWithForwardedRef({
|
|
|
944
956
|
...rest
|
|
945
957
|
}) {
|
|
946
958
|
const groupId = useUniqueId(idFromProps);
|
|
959
|
+
const panelGroupElementRef = useRef(null);
|
|
947
960
|
const [dragState, setDragState] = useState(null);
|
|
948
961
|
const [layout, setLayout] = useState([]);
|
|
949
962
|
const panelIdToLastNotifiedSizeMapRef = useRef({});
|
|
@@ -1004,7 +1017,8 @@ function PanelGroupWithForwardedRef({
|
|
|
1004
1017
|
groupId,
|
|
1005
1018
|
layout,
|
|
1006
1019
|
panelDataArray: eagerValuesRef.current.panelDataArray,
|
|
1007
|
-
setLayout
|
|
1020
|
+
setLayout,
|
|
1021
|
+
panelGroupElement: panelGroupElementRef.current
|
|
1008
1022
|
});
|
|
1009
1023
|
useEffect(() => {
|
|
1010
1024
|
const {
|
|
@@ -1199,6 +1213,10 @@ function PanelGroupWithForwardedRef({
|
|
|
1199
1213
|
const registerResizeHandle = useCallback(dragHandleId => {
|
|
1200
1214
|
return function resizeHandler(event) {
|
|
1201
1215
|
event.preventDefault();
|
|
1216
|
+
const panelGroupElement = panelGroupElementRef.current;
|
|
1217
|
+
if (!panelGroupElement) {
|
|
1218
|
+
return () => null;
|
|
1219
|
+
}
|
|
1202
1220
|
const {
|
|
1203
1221
|
direction,
|
|
1204
1222
|
dragState,
|
|
@@ -1213,8 +1231,8 @@ function PanelGroupWithForwardedRef({
|
|
|
1213
1231
|
const {
|
|
1214
1232
|
initialLayout
|
|
1215
1233
|
} = dragState !== null && dragState !== void 0 ? dragState : {};
|
|
1216
|
-
const pivotIndices = determinePivotIndices(groupId, dragHandleId);
|
|
1217
|
-
let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy);
|
|
1234
|
+
const pivotIndices = determinePivotIndices(groupId, dragHandleId, panelGroupElement);
|
|
1235
|
+
let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy, panelGroupElement);
|
|
1218
1236
|
if (delta === 0) {
|
|
1219
1237
|
return;
|
|
1220
1238
|
}
|
|
@@ -1302,6 +1320,37 @@ function PanelGroupWithForwardedRef({
|
|
|
1302
1320
|
callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
|
|
1303
1321
|
}
|
|
1304
1322
|
}, []);
|
|
1323
|
+
const reevaluatePanelConstraints = useCallback((panelData, prevConstraints) => {
|
|
1324
|
+
const {
|
|
1325
|
+
layout,
|
|
1326
|
+
panelDataArray
|
|
1327
|
+
} = eagerValuesRef.current;
|
|
1328
|
+
const {
|
|
1329
|
+
collapsedSize: prevCollapsedSize = 0,
|
|
1330
|
+
collapsible: prevCollapsible,
|
|
1331
|
+
defaultSize: prevDefaultSize,
|
|
1332
|
+
maxSize: prevMaxSize = 100,
|
|
1333
|
+
minSize: prevMinSize = 0
|
|
1334
|
+
} = prevConstraints;
|
|
1335
|
+
const {
|
|
1336
|
+
collapsedSize: nextCollapsedSize = 0,
|
|
1337
|
+
collapsible: nextCollapsible,
|
|
1338
|
+
defaultSize: nextDefaultSize,
|
|
1339
|
+
maxSize: nextMaxSize = 100,
|
|
1340
|
+
minSize: nextMinSize = 0
|
|
1341
|
+
} = panelData.constraints;
|
|
1342
|
+
const {
|
|
1343
|
+
panelSize: prevPanelSize
|
|
1344
|
+
} = panelDataHelper(panelDataArray, panelData, layout);
|
|
1345
|
+
assert(prevPanelSize != null);
|
|
1346
|
+
if (prevCollapsible && nextCollapsible && prevCollapsedSize !== nextCollapsedSize && prevPanelSize === prevCollapsedSize) {
|
|
1347
|
+
resizePanel(panelData, nextCollapsedSize);
|
|
1348
|
+
} else if (prevPanelSize < nextMinSize) {
|
|
1349
|
+
resizePanel(panelData, nextMinSize);
|
|
1350
|
+
} else if (prevPanelSize > nextMaxSize) {
|
|
1351
|
+
resizePanel(panelData, nextMaxSize);
|
|
1352
|
+
}
|
|
1353
|
+
}, [resizePanel]);
|
|
1305
1354
|
const startDragging = useCallback((dragHandleId, event) => {
|
|
1306
1355
|
const {
|
|
1307
1356
|
direction
|
|
@@ -1309,7 +1358,10 @@ function PanelGroupWithForwardedRef({
|
|
|
1309
1358
|
const {
|
|
1310
1359
|
layout
|
|
1311
1360
|
} = eagerValuesRef.current;
|
|
1312
|
-
|
|
1361
|
+
if (!panelGroupElementRef.current) {
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
const handleElement = getResizeHandleElement(dragHandleId, panelGroupElementRef.current);
|
|
1313
1365
|
assert(handleElement);
|
|
1314
1366
|
const initialCursorPosition = getResizeEventCursorPosition(direction, event);
|
|
1315
1367
|
setDragState({
|
|
@@ -1349,13 +1401,15 @@ function PanelGroupWithForwardedRef({
|
|
|
1349
1401
|
groupId,
|
|
1350
1402
|
isPanelCollapsed,
|
|
1351
1403
|
isPanelExpanded,
|
|
1404
|
+
reevaluatePanelConstraints,
|
|
1352
1405
|
registerPanel,
|
|
1353
1406
|
registerResizeHandle,
|
|
1354
1407
|
resizePanel,
|
|
1355
1408
|
startDragging,
|
|
1356
1409
|
stopDragging,
|
|
1357
|
-
unregisterPanel
|
|
1358
|
-
|
|
1410
|
+
unregisterPanel,
|
|
1411
|
+
panelGroupElement: panelGroupElementRef.current
|
|
1412
|
+
}), [collapsePanel, dragState, direction, expandPanel, getPanelSize, getPanelStyle, groupId, isPanelCollapsed, isPanelExpanded, reevaluatePanelConstraints, registerPanel, registerResizeHandle, resizePanel, startDragging, stopDragging, unregisterPanel]);
|
|
1359
1413
|
const style = {
|
|
1360
1414
|
display: "flex",
|
|
1361
1415
|
flexDirection: direction === "horizontal" ? "row" : "column",
|
|
@@ -1373,6 +1427,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1373
1427
|
...style,
|
|
1374
1428
|
...styleFromProps
|
|
1375
1429
|
},
|
|
1430
|
+
ref: panelGroupElementRef,
|
|
1376
1431
|
// CSS selectors
|
|
1377
1432
|
"data-panel-group": "",
|
|
1378
1433
|
"data-panel-group-direction": direction,
|
|
@@ -1389,14 +1444,12 @@ function findPanelDataIndex(panelDataArray, panelData) {
|
|
|
1389
1444
|
return panelDataArray.findIndex(prevPanelData => prevPanelData === panelData || prevPanelData.id === panelData.id);
|
|
1390
1445
|
}
|
|
1391
1446
|
function panelDataHelper(panelDataArray, panelData, layout) {
|
|
1392
|
-
const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
|
|
1393
1447
|
const panelIndex = findPanelDataIndex(panelDataArray, panelData);
|
|
1394
|
-
const panelConstraints = panelConstraintsArray[panelIndex];
|
|
1395
1448
|
const isLastPanel = panelIndex === panelDataArray.length - 1;
|
|
1396
1449
|
const pivotIndices = isLastPanel ? [panelIndex - 1, panelIndex] : [panelIndex, panelIndex + 1];
|
|
1397
1450
|
const panelSize = layout[panelIndex];
|
|
1398
1451
|
return {
|
|
1399
|
-
...
|
|
1452
|
+
...panelData.constraints,
|
|
1400
1453
|
panelSize,
|
|
1401
1454
|
pivotIndices
|
|
1402
1455
|
};
|
|
@@ -1407,13 +1460,14 @@ function panelDataHelper(panelDataArray, panelData, layout) {
|
|
|
1407
1460
|
function useWindowSplitterResizeHandlerBehavior({
|
|
1408
1461
|
disabled,
|
|
1409
1462
|
handleId,
|
|
1410
|
-
resizeHandler
|
|
1463
|
+
resizeHandler,
|
|
1464
|
+
panelGroupElement
|
|
1411
1465
|
}) {
|
|
1412
1466
|
useEffect(() => {
|
|
1413
|
-
if (disabled || resizeHandler == null) {
|
|
1467
|
+
if (disabled || resizeHandler == null || panelGroupElement == null) {
|
|
1414
1468
|
return;
|
|
1415
1469
|
}
|
|
1416
|
-
const handleElement = getResizeHandleElement(handleId);
|
|
1470
|
+
const handleElement = getResizeHandleElement(handleId, panelGroupElement);
|
|
1417
1471
|
if (handleElement == null) {
|
|
1418
1472
|
return;
|
|
1419
1473
|
}
|
|
@@ -1438,8 +1492,8 @@ function useWindowSplitterResizeHandlerBehavior({
|
|
|
1438
1492
|
event.preventDefault();
|
|
1439
1493
|
const groupId = handleElement.getAttribute("data-panel-group-id");
|
|
1440
1494
|
assert(groupId);
|
|
1441
|
-
const handles = getResizeHandleElementsForGroup(groupId);
|
|
1442
|
-
const index = getResizeHandleElementIndex(groupId, handleId);
|
|
1495
|
+
const handles = getResizeHandleElementsForGroup(groupId, panelGroupElement);
|
|
1496
|
+
const index = getResizeHandleElementIndex(groupId, handleId, panelGroupElement);
|
|
1443
1497
|
assert(index !== null);
|
|
1444
1498
|
const nextIndex = event.shiftKey ? index > 0 ? index - 1 : handles.length - 1 : index + 1 < handles.length ? index + 1 : 0;
|
|
1445
1499
|
const nextHandle = handles[nextIndex];
|
|
@@ -1452,7 +1506,7 @@ function useWindowSplitterResizeHandlerBehavior({
|
|
|
1452
1506
|
return () => {
|
|
1453
1507
|
handleElement.removeEventListener("keydown", onKeyDown);
|
|
1454
1508
|
};
|
|
1455
|
-
}, [disabled, handleId, resizeHandler]);
|
|
1509
|
+
}, [panelGroupElement, disabled, handleId, resizeHandler]);
|
|
1456
1510
|
}
|
|
1457
1511
|
|
|
1458
1512
|
function PanelResizeHandle({
|
|
@@ -1485,7 +1539,8 @@ function PanelResizeHandle({
|
|
|
1485
1539
|
groupId,
|
|
1486
1540
|
registerResizeHandle,
|
|
1487
1541
|
startDragging,
|
|
1488
|
-
stopDragging
|
|
1542
|
+
stopDragging,
|
|
1543
|
+
panelGroupElement
|
|
1489
1544
|
} = panelGroupContext;
|
|
1490
1545
|
const resizeHandleId = useUniqueId(idFromProps);
|
|
1491
1546
|
const isDragging = (dragState === null || dragState === void 0 ? void 0 : dragState.dragHandleId) === resizeHandleId;
|
|
@@ -1544,7 +1599,8 @@ function PanelResizeHandle({
|
|
|
1544
1599
|
useWindowSplitterResizeHandlerBehavior({
|
|
1545
1600
|
disabled,
|
|
1546
1601
|
handleId: resizeHandleId,
|
|
1547
|
-
resizeHandler
|
|
1602
|
+
resizeHandler,
|
|
1603
|
+
panelGroupElement
|
|
1548
1604
|
});
|
|
1549
1605
|
const style = {
|
|
1550
1606
|
cursor: getCursorStyle(direction),
|
|
@@ -1600,52 +1656,16 @@ function PanelResizeHandle({
|
|
|
1600
1656
|
}
|
|
1601
1657
|
PanelResizeHandle.displayName = "PanelResizeHandle";
|
|
1602
1658
|
|
|
1603
|
-
function
|
|
1604
|
-
const
|
|
1605
|
-
if (panelGroupElement == null) {
|
|
1606
|
-
return NaN;
|
|
1607
|
-
}
|
|
1608
|
-
const direction = panelGroupElement.getAttribute("data-panel-group-direction");
|
|
1609
|
-
const resizeHandles = getResizeHandleElementsForGroup(groupId);
|
|
1610
|
-
if (direction === "horizontal") {
|
|
1611
|
-
return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
|
|
1612
|
-
return accumulated + handle.offsetWidth;
|
|
1613
|
-
}, 0);
|
|
1614
|
-
} else {
|
|
1615
|
-
return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
|
|
1616
|
-
return accumulated + handle.offsetHeight;
|
|
1617
|
-
}, 0);
|
|
1618
|
-
}
|
|
1619
|
-
}
|
|
1620
|
-
|
|
1621
|
-
function getAvailableGroupSizePixels(groupId) {
|
|
1622
|
-
const panelGroupElement = getPanelGroupElement(groupId);
|
|
1623
|
-
if (panelGroupElement == null) {
|
|
1624
|
-
return NaN;
|
|
1625
|
-
}
|
|
1626
|
-
const direction = panelGroupElement.getAttribute("data-panel-group-direction");
|
|
1627
|
-
const resizeHandles = getResizeHandleElementsForGroup(groupId);
|
|
1628
|
-
if (direction === "horizontal") {
|
|
1629
|
-
return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
|
|
1630
|
-
return accumulated + handle.offsetWidth;
|
|
1631
|
-
}, 0);
|
|
1632
|
-
} else {
|
|
1633
|
-
return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
|
|
1634
|
-
return accumulated + handle.offsetHeight;
|
|
1635
|
-
}, 0);
|
|
1636
|
-
}
|
|
1637
|
-
}
|
|
1638
|
-
|
|
1639
|
-
function getPanelElement(id) {
|
|
1640
|
-
const element = document.querySelector(`[data-panel-id="${id}"]`);
|
|
1659
|
+
function getPanelElement(id, scope = document) {
|
|
1660
|
+
const element = scope.querySelector(`[data-panel-id="${id}"]`);
|
|
1641
1661
|
if (element) {
|
|
1642
1662
|
return element;
|
|
1643
1663
|
}
|
|
1644
1664
|
return null;
|
|
1645
1665
|
}
|
|
1646
1666
|
|
|
1647
|
-
function getPanelElementsForGroup(groupId) {
|
|
1648
|
-
return Array.from(
|
|
1667
|
+
function getPanelElementsForGroup(groupId, scope = document) {
|
|
1668
|
+
return Array.from(scope.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
|
|
1649
1669
|
}
|
|
1650
1670
|
|
|
1651
|
-
export { Panel, PanelGroup, PanelResizeHandle, assert,
|
|
1671
|
+
export { Panel, PanelGroup, PanelResizeHandle, assert, getPanelElement, getPanelElementsForGroup, getPanelGroupElement, getResizeHandleElement, getResizeHandleElementIndex, getResizeHandleElementsForGroup, getResizeHandlePanelIds };
|
package/package.json
CHANGED
package/src/Panel.test.tsx
CHANGED
|
@@ -12,6 +12,7 @@ import { createRef } from "./vendor/react";
|
|
|
12
12
|
describe("PanelGroup", () => {
|
|
13
13
|
let expectedWarnings: string[] = [];
|
|
14
14
|
let root: Root;
|
|
15
|
+
let container: HTMLElement;
|
|
15
16
|
let uninstallMockOffsetWidthAndHeight: () => void;
|
|
16
17
|
|
|
17
18
|
function expectWarning(expectedMessage: string) {
|
|
@@ -24,7 +25,7 @@ describe("PanelGroup", () => {
|
|
|
24
25
|
|
|
25
26
|
uninstallMockOffsetWidthAndHeight = mockPanelGroupOffsetWidthAndHeight();
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
container = document.createElement("div");
|
|
28
29
|
document.body.appendChild(container);
|
|
29
30
|
|
|
30
31
|
expectedWarnings = [];
|
|
@@ -258,13 +259,147 @@ describe("PanelGroup", () => {
|
|
|
258
259
|
);
|
|
259
260
|
});
|
|
260
261
|
|
|
261
|
-
const element = getPanelElement("panel");
|
|
262
|
+
const element = getPanelElement("panel", container);
|
|
262
263
|
assert(element);
|
|
263
264
|
expect(element.tabIndex).toBe(123);
|
|
264
265
|
expect(element.getAttribute("data-test-name")).toBe("foo");
|
|
265
266
|
expect(element.title).toBe("bar");
|
|
266
267
|
});
|
|
267
268
|
|
|
269
|
+
describe("constraints", () => {
|
|
270
|
+
it("should resize a collapsed panel if the collapsedSize prop changes", () => {
|
|
271
|
+
act(() => {
|
|
272
|
+
root.render(
|
|
273
|
+
<PanelGroup direction="horizontal">
|
|
274
|
+
<Panel
|
|
275
|
+
id="left"
|
|
276
|
+
collapsedSize={10}
|
|
277
|
+
collapsible
|
|
278
|
+
defaultSize={10}
|
|
279
|
+
minSize={25}
|
|
280
|
+
/>
|
|
281
|
+
<PanelResizeHandle />
|
|
282
|
+
<Panel id="middle" />
|
|
283
|
+
<PanelResizeHandle />
|
|
284
|
+
<Panel
|
|
285
|
+
id="right"
|
|
286
|
+
collapsedSize={10}
|
|
287
|
+
collapsible
|
|
288
|
+
defaultSize={10}
|
|
289
|
+
minSize={25}
|
|
290
|
+
/>
|
|
291
|
+
</PanelGroup>
|
|
292
|
+
);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
let leftElement = getPanelElement("left", container);
|
|
296
|
+
let middleElement = getPanelElement("middle", container);
|
|
297
|
+
let rightElement = getPanelElement("right", container);
|
|
298
|
+
assert(leftElement);
|
|
299
|
+
assert(middleElement);
|
|
300
|
+
assert(rightElement);
|
|
301
|
+
expect(leftElement.getAttribute("data-panel-size")).toBe("10.0");
|
|
302
|
+
expect(middleElement.getAttribute("data-panel-size")).toBe("80.0");
|
|
303
|
+
expect(rightElement.getAttribute("data-panel-size")).toBe("10.0");
|
|
304
|
+
|
|
305
|
+
act(() => {
|
|
306
|
+
root.render(
|
|
307
|
+
<PanelGroup direction="horizontal">
|
|
308
|
+
<Panel id="left" collapsedSize={5} collapsible minSize={25} />
|
|
309
|
+
<PanelResizeHandle />
|
|
310
|
+
<Panel id="middle" />
|
|
311
|
+
<PanelResizeHandle />
|
|
312
|
+
<Panel id="right" collapsedSize={5} collapsible minSize={25} />
|
|
313
|
+
</PanelGroup>
|
|
314
|
+
);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
expect(leftElement.getAttribute("data-panel-size")).toBe("5.0");
|
|
318
|
+
expect(middleElement.getAttribute("data-panel-size")).toBe("90.0");
|
|
319
|
+
expect(rightElement.getAttribute("data-panel-size")).toBe("5.0");
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it("should resize a panel if the minSize prop changes", () => {
|
|
323
|
+
act(() => {
|
|
324
|
+
root.render(
|
|
325
|
+
<PanelGroup direction="horizontal">
|
|
326
|
+
<Panel id="left" defaultSize={15} minSize={10} />
|
|
327
|
+
<PanelResizeHandle />
|
|
328
|
+
<Panel id="middle" />
|
|
329
|
+
<PanelResizeHandle />
|
|
330
|
+
<Panel id="right" defaultSize={15} minSize={10} />
|
|
331
|
+
</PanelGroup>
|
|
332
|
+
);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
let leftElement = getPanelElement("left", container);
|
|
336
|
+
let middleElement = getPanelElement("middle", container);
|
|
337
|
+
let rightElement = getPanelElement("right", container);
|
|
338
|
+
assert(leftElement);
|
|
339
|
+
assert(middleElement);
|
|
340
|
+
assert(rightElement);
|
|
341
|
+
expect(leftElement.getAttribute("data-panel-size")).toBe("15.0");
|
|
342
|
+
expect(middleElement.getAttribute("data-panel-size")).toBe("70.0");
|
|
343
|
+
expect(rightElement.getAttribute("data-panel-size")).toBe("15.0");
|
|
344
|
+
|
|
345
|
+
act(() => {
|
|
346
|
+
root.render(
|
|
347
|
+
<PanelGroup direction="horizontal">
|
|
348
|
+
<Panel id="left" minSize={20} />
|
|
349
|
+
<PanelResizeHandle />
|
|
350
|
+
<Panel id="middle" />
|
|
351
|
+
<PanelResizeHandle />
|
|
352
|
+
<Panel id="right" minSize={20} />
|
|
353
|
+
</PanelGroup>
|
|
354
|
+
);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
expect(leftElement.getAttribute("data-panel-size")).toBe("20.0");
|
|
358
|
+
expect(middleElement.getAttribute("data-panel-size")).toBe("60.0");
|
|
359
|
+
expect(rightElement.getAttribute("data-panel-size")).toBe("20.0");
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it("should resize a panel if the maxSize prop changes", () => {
|
|
363
|
+
act(() => {
|
|
364
|
+
root.render(
|
|
365
|
+
<PanelGroup direction="horizontal">
|
|
366
|
+
<Panel id="left" defaultSize={25} maxSize={30} />
|
|
367
|
+
<PanelResizeHandle />
|
|
368
|
+
<Panel id="middle" />
|
|
369
|
+
<PanelResizeHandle />
|
|
370
|
+
<Panel id="right" defaultSize={25} maxSize={30} />
|
|
371
|
+
</PanelGroup>
|
|
372
|
+
);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
let leftElement = getPanelElement("left", container);
|
|
376
|
+
let middleElement = getPanelElement("middle", container);
|
|
377
|
+
let rightElement = getPanelElement("right", container);
|
|
378
|
+
assert(leftElement);
|
|
379
|
+
assert(middleElement);
|
|
380
|
+
assert(rightElement);
|
|
381
|
+
expect(leftElement.getAttribute("data-panel-size")).toBe("25.0");
|
|
382
|
+
expect(middleElement.getAttribute("data-panel-size")).toBe("50.0");
|
|
383
|
+
expect(rightElement.getAttribute("data-panel-size")).toBe("25.0");
|
|
384
|
+
|
|
385
|
+
act(() => {
|
|
386
|
+
root.render(
|
|
387
|
+
<PanelGroup direction="horizontal">
|
|
388
|
+
<Panel id="left" maxSize={20} />
|
|
389
|
+
<PanelResizeHandle />
|
|
390
|
+
<Panel id="middle" />
|
|
391
|
+
<PanelResizeHandle />
|
|
392
|
+
<Panel id="right" maxSize={20} />
|
|
393
|
+
</PanelGroup>
|
|
394
|
+
);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
expect(leftElement.getAttribute("data-panel-size")).toBe("20.0");
|
|
398
|
+
expect(middleElement.getAttribute("data-panel-size")).toBe("60.0");
|
|
399
|
+
expect(rightElement.getAttribute("data-panel-size")).toBe("20.0");
|
|
400
|
+
});
|
|
401
|
+
});
|
|
402
|
+
|
|
268
403
|
describe("callbacks", () => {
|
|
269
404
|
describe("onCollapse", () => {
|
|
270
405
|
it("should be called on mount if a panels initial size is 0", () => {
|
package/src/Panel.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
ForwardedRef,
|
|
8
8
|
HTMLAttributes,
|
|
9
9
|
PropsWithChildren,
|
|
10
|
-
|
|
10
|
+
ReactElement,
|
|
11
11
|
createElement,
|
|
12
12
|
forwardRef,
|
|
13
13
|
useContext,
|
|
@@ -93,7 +93,7 @@ export function PanelWithForwardedRef({
|
|
|
93
93
|
...rest
|
|
94
94
|
}: PanelProps & {
|
|
95
95
|
forwardedRef: ForwardedRef<ImperativePanelHandle>;
|
|
96
|
-
}):
|
|
96
|
+
}): ReactElement {
|
|
97
97
|
const context = useContext(PanelGroupContext);
|
|
98
98
|
if (context === null) {
|
|
99
99
|
throw Error(
|
|
@@ -108,6 +108,7 @@ export function PanelWithForwardedRef({
|
|
|
108
108
|
getPanelStyle,
|
|
109
109
|
groupId,
|
|
110
110
|
isPanelCollapsed,
|
|
111
|
+
reevaluatePanelConstraints,
|
|
111
112
|
registerPanel,
|
|
112
113
|
resizePanel,
|
|
113
114
|
unregisterPanel,
|
|
@@ -155,6 +156,8 @@ export function PanelWithForwardedRef({
|
|
|
155
156
|
useIsomorphicLayoutEffect(() => {
|
|
156
157
|
const { callbacks, constraints } = panelDataRef.current;
|
|
157
158
|
|
|
159
|
+
const prevConstraints = { ...constraints };
|
|
160
|
+
|
|
158
161
|
panelDataRef.current.id = panelId;
|
|
159
162
|
panelDataRef.current.idIsFromProps = idFromProps !== undefined;
|
|
160
163
|
panelDataRef.current.order = order;
|
|
@@ -168,6 +171,17 @@ export function PanelWithForwardedRef({
|
|
|
168
171
|
constraints.defaultSize = defaultSize;
|
|
169
172
|
constraints.maxSize = maxSize;
|
|
170
173
|
constraints.minSize = minSize;
|
|
174
|
+
|
|
175
|
+
// If constraints have changed, we should revisit panel sizes.
|
|
176
|
+
// This is uncommon but may happen if people are trying to implement pixel based constraints.
|
|
177
|
+
if (
|
|
178
|
+
prevConstraints.collapsedSize !== constraints.collapsedSize ||
|
|
179
|
+
prevConstraints.collapsible !== constraints.collapsible ||
|
|
180
|
+
prevConstraints.maxSize !== constraints.maxSize ||
|
|
181
|
+
prevConstraints.minSize !== constraints.minSize
|
|
182
|
+
) {
|
|
183
|
+
reevaluatePanelConstraints(panelDataRef.current, prevConstraints);
|
|
184
|
+
}
|
|
171
185
|
});
|
|
172
186
|
|
|
173
187
|
useIsomorphicLayoutEffect(() => {
|
package/src/PanelGroup.test.tsx
CHANGED
|
@@ -15,6 +15,7 @@ import { createRef } from "./vendor/react";
|
|
|
15
15
|
describe("PanelGroup", () => {
|
|
16
16
|
let expectedWarnings: string[] = [];
|
|
17
17
|
let root: Root;
|
|
18
|
+
let container: HTMLElement;
|
|
18
19
|
let uninstallMockOffsetWidthAndHeight: () => void;
|
|
19
20
|
|
|
20
21
|
function expectWarning(expectedMessage: string) {
|
|
@@ -28,7 +29,7 @@ describe("PanelGroup", () => {
|
|
|
28
29
|
// JSDom doesn't support element sizes
|
|
29
30
|
uninstallMockOffsetWidthAndHeight = mockPanelGroupOffsetWidthAndHeight();
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
container = document.createElement("div");
|
|
32
33
|
document.body.appendChild(container);
|
|
33
34
|
|
|
34
35
|
expectedWarnings = [];
|
|
@@ -124,7 +125,7 @@ describe("PanelGroup", () => {
|
|
|
124
125
|
);
|
|
125
126
|
});
|
|
126
127
|
|
|
127
|
-
const element = getPanelGroupElement("group");
|
|
128
|
+
const element = getPanelGroupElement("group", container);
|
|
128
129
|
assert(element);
|
|
129
130
|
expect(element.tabIndex).toBe(123);
|
|
130
131
|
expect(element.getAttribute("data-test-name")).toBe("foo");
|