react-resizable-panels 1.0.6 → 1.0.8
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 +10 -0
- package/README.md +20 -4
- package/dist/declarations/src/Panel.d.ts +6 -6
- package/dist/declarations/src/PanelGroup.d.ts +5 -5
- package/dist/declarations/src/PanelResizeHandle.d.ts +4 -4
- package/dist/declarations/src/utils/dom/calculateAvailablePanelSizeInPixels.d.ts +1 -1
- package/dist/declarations/src/utils/dom/getAvailableGroupSizePixels.d.ts +1 -1
- 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 +82 -59
- package/dist/react-resizable-panels.browser.development.cjs.js +84 -60
- package/dist/react-resizable-panels.browser.development.esm.js +84 -60
- package/dist/react-resizable-panels.browser.esm.js +82 -59
- package/dist/react-resizable-panels.cjs.js +82 -59
- package/dist/react-resizable-panels.development.cjs.js +84 -60
- package/dist/react-resizable-panels.development.esm.js +84 -60
- package/dist/react-resizable-panels.development.node.cjs.js +79 -58
- package/dist/react-resizable-panels.development.node.esm.js +79 -58
- package/dist/react-resizable-panels.esm.js +82 -59
- package/dist/react-resizable-panels.node.cjs.js +77 -57
- package/dist/react-resizable-panels.node.esm.js +77 -57
- package/package.json +1 -1
- package/src/Panel.test.tsx +3 -2
- package/src/Panel.ts +7 -4
- package/src/PanelGroup.test.tsx +3 -2
- package/src/PanelGroup.ts +53 -30
- package/src/PanelGroupContext.ts +4 -2
- package/src/PanelResizeHandle.test.tsx +3 -3
- package/src/PanelResizeHandle.ts +17 -12
- package/src/hooks/useWindowSplitterBehavior.ts +15 -6
- package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +23 -7
- 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/calculateAvailablePanelSizeInPixels.ts +8 -3
- package/src/utils/dom/getAvailableGroupSizePixels.ts +8 -7
- package/src/utils/dom/getPanelElement.ts +6 -3
- package/src/utils/dom/getPanelElementsForGroup.ts +7 -2
- package/src/utils/dom/getPanelGroupElement.ts +15 -3
- package/src/utils/dom/getResizeHandleElement.ts +6 -3
- package/src/utils/dom/getResizeHandleElementIndex.ts +3 -2
- package/src/utils/dom/getResizeHandleElementsForGroup.ts +4 -3
- 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
|
@@ -430,41 +430,48 @@ function adjustLayoutByDelta({
|
|
|
430
430
|
return nextLayout;
|
|
431
431
|
}
|
|
432
432
|
|
|
433
|
-
function getResizeHandleElementsForGroup(groupId) {
|
|
434
|
-
return Array.from(
|
|
433
|
+
function getResizeHandleElementsForGroup(groupId, panelGroupElement) {
|
|
434
|
+
return Array.from(panelGroupElement.querySelectorAll(`[data-panel-resize-handle-id][data-panel-group-id="${groupId}"]`));
|
|
435
435
|
}
|
|
436
436
|
|
|
437
|
-
function getResizeHandleElementIndex(groupId, id) {
|
|
438
|
-
const handles = getResizeHandleElementsForGroup(groupId);
|
|
437
|
+
function getResizeHandleElementIndex(groupId, id, panelGroupElement) {
|
|
438
|
+
const handles = getResizeHandleElementsForGroup(groupId, panelGroupElement);
|
|
439
439
|
const index = handles.findIndex(handle => handle.getAttribute("data-panel-resize-handle-id") === id);
|
|
440
440
|
return index !== null && index !== void 0 ? index : null;
|
|
441
441
|
}
|
|
442
442
|
|
|
443
|
-
function determinePivotIndices(groupId, dragHandleId) {
|
|
444
|
-
const index = getResizeHandleElementIndex(groupId, dragHandleId);
|
|
443
|
+
function determinePivotIndices(groupId, dragHandleId, panelGroupElement) {
|
|
444
|
+
const index = getResizeHandleElementIndex(groupId, dragHandleId, panelGroupElement);
|
|
445
445
|
return index != null ? [index, index + 1] : [-1, -1];
|
|
446
446
|
}
|
|
447
447
|
|
|
448
|
-
function getPanelGroupElement(id) {
|
|
449
|
-
|
|
448
|
+
function getPanelGroupElement(id, rootElement) {
|
|
449
|
+
var _dataset;
|
|
450
|
+
//If the root element is the PanelGroup
|
|
451
|
+
if (rootElement instanceof HTMLElement && (rootElement === null || rootElement === void 0 ? void 0 : (_dataset = rootElement.dataset) === null || _dataset === void 0 ? void 0 : _dataset.panelGroupId) == id) {
|
|
452
|
+
return rootElement;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
//Else query children
|
|
456
|
+
const element = rootElement.querySelector(`[data-panel-group][data-panel-group-id="${id}"]`);
|
|
450
457
|
if (element) {
|
|
451
458
|
return element;
|
|
452
459
|
}
|
|
453
460
|
return null;
|
|
454
461
|
}
|
|
455
462
|
|
|
456
|
-
function getResizeHandleElement(id) {
|
|
457
|
-
const element =
|
|
463
|
+
function getResizeHandleElement(id, panelGroupElement) {
|
|
464
|
+
const element = panelGroupElement.querySelector(`[data-panel-resize-handle-id="${id}"]`);
|
|
458
465
|
if (element) {
|
|
459
466
|
return element;
|
|
460
467
|
}
|
|
461
468
|
return null;
|
|
462
469
|
}
|
|
463
470
|
|
|
464
|
-
function getResizeHandlePanelIds(groupId, handleId, panelsArray) {
|
|
471
|
+
function getResizeHandlePanelIds(groupId, handleId, panelsArray, panelGroupElement) {
|
|
465
472
|
var _panelsArray$index$id, _panelsArray$index, _panelsArray$id, _panelsArray;
|
|
466
|
-
const handle = getResizeHandleElement(handleId);
|
|
467
|
-
const handles = getResizeHandleElementsForGroup(groupId);
|
|
473
|
+
const handle = getResizeHandleElement(handleId, panelGroupElement);
|
|
474
|
+
const handles = getResizeHandleElementsForGroup(groupId, panelGroupElement);
|
|
468
475
|
const index = handle ? handles.indexOf(handle) : -1;
|
|
469
476
|
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
477
|
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 +486,29 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
479
486
|
groupId,
|
|
480
487
|
layout,
|
|
481
488
|
panelDataArray,
|
|
489
|
+
panelGroupElement,
|
|
482
490
|
setLayout
|
|
483
491
|
}) {
|
|
484
492
|
useRef({
|
|
485
493
|
didWarnAboutMissingResizeHandle: false
|
|
486
494
|
});
|
|
487
495
|
useEffect(() => {
|
|
496
|
+
if (!panelGroupElement) {
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
488
499
|
const eagerValues = eagerValuesRef.current;
|
|
489
500
|
assert(eagerValues);
|
|
490
501
|
const {
|
|
491
502
|
panelDataArray
|
|
492
503
|
} = eagerValues;
|
|
493
|
-
const groupElement = getPanelGroupElement(groupId);
|
|
504
|
+
const groupElement = getPanelGroupElement(groupId, panelGroupElement);
|
|
494
505
|
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
495
|
-
const handles = getResizeHandleElementsForGroup(groupId);
|
|
506
|
+
const handles = getResizeHandleElementsForGroup(groupId, panelGroupElement);
|
|
496
507
|
assert(handles);
|
|
497
508
|
const cleanupFunctions = handles.map(handle => {
|
|
498
509
|
const handleId = handle.getAttribute("data-panel-resize-handle-id");
|
|
499
510
|
assert(handleId);
|
|
500
|
-
const [idBefore, idAfter] = getResizeHandlePanelIds(groupId, handleId, panelDataArray);
|
|
511
|
+
const [idBefore, idAfter] = getResizeHandlePanelIds(groupId, handleId, panelDataArray, panelGroupElement);
|
|
501
512
|
if (idBefore == null || idAfter == null) {
|
|
502
513
|
return () => {};
|
|
503
514
|
}
|
|
@@ -524,7 +535,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
524
535
|
delta: fuzzyNumbersEqual(size, collapsedSize) ? minSize - collapsedSize : collapsedSize - size,
|
|
525
536
|
layout,
|
|
526
537
|
panelConstraints: panelDataArray.map(panelData => panelData.constraints),
|
|
527
|
-
pivotIndices: determinePivotIndices(groupId, handleId),
|
|
538
|
+
pivotIndices: determinePivotIndices(groupId, handleId, panelGroupElement),
|
|
528
539
|
trigger: "keyboard"
|
|
529
540
|
});
|
|
530
541
|
if (layout !== nextLayout) {
|
|
@@ -544,7 +555,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
544
555
|
return () => {
|
|
545
556
|
cleanupFunctions.forEach(cleanupFunction => cleanupFunction());
|
|
546
557
|
};
|
|
547
|
-
}, [committedValuesRef, eagerValuesRef, groupId, layout, panelDataArray, setLayout]);
|
|
558
|
+
}, [panelGroupElement, committedValuesRef, eagerValuesRef, groupId, layout, panelDataArray, setLayout]);
|
|
548
559
|
}
|
|
549
560
|
|
|
550
561
|
function areEqual(arrayA, arrayB) {
|
|
@@ -582,9 +593,9 @@ function getResizeEventCursorPosition(direction, event) {
|
|
|
582
593
|
}
|
|
583
594
|
}
|
|
584
595
|
|
|
585
|
-
function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState) {
|
|
596
|
+
function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState, panelGroupElement) {
|
|
586
597
|
const isHorizontal = direction === "horizontal";
|
|
587
|
-
const handleElement = getResizeHandleElement(dragHandleId);
|
|
598
|
+
const handleElement = getResizeHandleElement(dragHandleId, panelGroupElement);
|
|
588
599
|
assert(handleElement);
|
|
589
600
|
const groupId = handleElement.getAttribute("data-panel-group-id");
|
|
590
601
|
assert(groupId);
|
|
@@ -592,7 +603,7 @@ function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDr
|
|
|
592
603
|
initialCursorPosition
|
|
593
604
|
} = initialDragState;
|
|
594
605
|
const cursorPosition = getResizeEventCursorPosition(direction, event);
|
|
595
|
-
const groupElement = getPanelGroupElement(groupId);
|
|
606
|
+
const groupElement = getPanelGroupElement(groupId, panelGroupElement);
|
|
596
607
|
assert(groupElement);
|
|
597
608
|
const groupRect = groupElement.getBoundingClientRect();
|
|
598
609
|
const groupSizeInPixels = isHorizontal ? groupRect.width : groupRect.height;
|
|
@@ -602,7 +613,7 @@ function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDr
|
|
|
602
613
|
}
|
|
603
614
|
|
|
604
615
|
// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX
|
|
605
|
-
function calculateDeltaPercentage(event, dragHandleId, direction, initialDragState, keyboardResizeBy) {
|
|
616
|
+
function calculateDeltaPercentage(event, dragHandleId, direction, initialDragState, keyboardResizeBy, panelGroupElement) {
|
|
606
617
|
if (isKeyDown(event)) {
|
|
607
618
|
const isHorizontal = direction === "horizontal";
|
|
608
619
|
let delta = 0;
|
|
@@ -639,7 +650,7 @@ function calculateDeltaPercentage(event, dragHandleId, direction, initialDragSta
|
|
|
639
650
|
if (initialDragState == null) {
|
|
640
651
|
return 0;
|
|
641
652
|
}
|
|
642
|
-
return calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState);
|
|
653
|
+
return calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState, panelGroupElement);
|
|
643
654
|
}
|
|
644
655
|
}
|
|
645
656
|
|
|
@@ -944,6 +955,7 @@ function PanelGroupWithForwardedRef({
|
|
|
944
955
|
...rest
|
|
945
956
|
}) {
|
|
946
957
|
const groupId = useUniqueId(idFromProps);
|
|
958
|
+
const panelGroupElementRef = useRef(null);
|
|
947
959
|
const [dragState, setDragState] = useState(null);
|
|
948
960
|
const [layout, setLayout] = useState([]);
|
|
949
961
|
const panelIdToLastNotifiedSizeMapRef = useRef({});
|
|
@@ -1004,7 +1016,8 @@ function PanelGroupWithForwardedRef({
|
|
|
1004
1016
|
groupId,
|
|
1005
1017
|
layout,
|
|
1006
1018
|
panelDataArray: eagerValuesRef.current.panelDataArray,
|
|
1007
|
-
setLayout
|
|
1019
|
+
setLayout,
|
|
1020
|
+
panelGroupElement: panelGroupElementRef.current
|
|
1008
1021
|
});
|
|
1009
1022
|
useEffect(() => {
|
|
1010
1023
|
const {
|
|
@@ -1199,6 +1212,10 @@ function PanelGroupWithForwardedRef({
|
|
|
1199
1212
|
const registerResizeHandle = useCallback(dragHandleId => {
|
|
1200
1213
|
return function resizeHandler(event) {
|
|
1201
1214
|
event.preventDefault();
|
|
1215
|
+
const panelGroupElement = panelGroupElementRef.current;
|
|
1216
|
+
if (!panelGroupElement) {
|
|
1217
|
+
return () => null;
|
|
1218
|
+
}
|
|
1202
1219
|
const {
|
|
1203
1220
|
direction,
|
|
1204
1221
|
dragState,
|
|
@@ -1213,8 +1230,8 @@ function PanelGroupWithForwardedRef({
|
|
|
1213
1230
|
const {
|
|
1214
1231
|
initialLayout
|
|
1215
1232
|
} = dragState !== null && dragState !== void 0 ? dragState : {};
|
|
1216
|
-
const pivotIndices = determinePivotIndices(groupId, dragHandleId);
|
|
1217
|
-
let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy);
|
|
1233
|
+
const pivotIndices = determinePivotIndices(groupId, dragHandleId, panelGroupElement);
|
|
1234
|
+
let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy, panelGroupElement);
|
|
1218
1235
|
if (delta === 0) {
|
|
1219
1236
|
return;
|
|
1220
1237
|
}
|
|
@@ -1309,7 +1326,10 @@ function PanelGroupWithForwardedRef({
|
|
|
1309
1326
|
const {
|
|
1310
1327
|
layout
|
|
1311
1328
|
} = eagerValuesRef.current;
|
|
1312
|
-
|
|
1329
|
+
if (!panelGroupElementRef.current) {
|
|
1330
|
+
return;
|
|
1331
|
+
}
|
|
1332
|
+
const handleElement = getResizeHandleElement(dragHandleId, panelGroupElementRef.current);
|
|
1313
1333
|
assert(handleElement);
|
|
1314
1334
|
const initialCursorPosition = getResizeEventCursorPosition(direction, event);
|
|
1315
1335
|
setDragState({
|
|
@@ -1354,7 +1374,8 @@ function PanelGroupWithForwardedRef({
|
|
|
1354
1374
|
resizePanel,
|
|
1355
1375
|
startDragging,
|
|
1356
1376
|
stopDragging,
|
|
1357
|
-
unregisterPanel
|
|
1377
|
+
unregisterPanel,
|
|
1378
|
+
panelGroupElement: panelGroupElementRef.current
|
|
1358
1379
|
}), [collapsePanel, dragState, direction, expandPanel, getPanelSize, getPanelStyle, groupId, isPanelCollapsed, isPanelExpanded, registerPanel, registerResizeHandle, resizePanel, startDragging, stopDragging, unregisterPanel]);
|
|
1359
1380
|
const style = {
|
|
1360
1381
|
display: "flex",
|
|
@@ -1373,6 +1394,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1373
1394
|
...style,
|
|
1374
1395
|
...styleFromProps
|
|
1375
1396
|
},
|
|
1397
|
+
ref: panelGroupElementRef,
|
|
1376
1398
|
// CSS selectors
|
|
1377
1399
|
"data-panel-group": "",
|
|
1378
1400
|
"data-panel-group-direction": direction,
|
|
@@ -1407,13 +1429,14 @@ function panelDataHelper(panelDataArray, panelData, layout) {
|
|
|
1407
1429
|
function useWindowSplitterResizeHandlerBehavior({
|
|
1408
1430
|
disabled,
|
|
1409
1431
|
handleId,
|
|
1410
|
-
resizeHandler
|
|
1432
|
+
resizeHandler,
|
|
1433
|
+
panelGroupElement
|
|
1411
1434
|
}) {
|
|
1412
1435
|
useEffect(() => {
|
|
1413
|
-
if (disabled || resizeHandler == null) {
|
|
1436
|
+
if (disabled || resizeHandler == null || panelGroupElement == null) {
|
|
1414
1437
|
return;
|
|
1415
1438
|
}
|
|
1416
|
-
const handleElement = getResizeHandleElement(handleId);
|
|
1439
|
+
const handleElement = getResizeHandleElement(handleId, panelGroupElement);
|
|
1417
1440
|
if (handleElement == null) {
|
|
1418
1441
|
return;
|
|
1419
1442
|
}
|
|
@@ -1438,8 +1461,8 @@ function useWindowSplitterResizeHandlerBehavior({
|
|
|
1438
1461
|
event.preventDefault();
|
|
1439
1462
|
const groupId = handleElement.getAttribute("data-panel-group-id");
|
|
1440
1463
|
assert(groupId);
|
|
1441
|
-
const handles = getResizeHandleElementsForGroup(groupId);
|
|
1442
|
-
const index = getResizeHandleElementIndex(groupId, handleId);
|
|
1464
|
+
const handles = getResizeHandleElementsForGroup(groupId, panelGroupElement);
|
|
1465
|
+
const index = getResizeHandleElementIndex(groupId, handleId, panelGroupElement);
|
|
1443
1466
|
assert(index !== null);
|
|
1444
1467
|
const nextIndex = event.shiftKey ? index > 0 ? index - 1 : handles.length - 1 : index + 1 < handles.length ? index + 1 : 0;
|
|
1445
1468
|
const nextHandle = handles[nextIndex];
|
|
@@ -1452,7 +1475,7 @@ function useWindowSplitterResizeHandlerBehavior({
|
|
|
1452
1475
|
return () => {
|
|
1453
1476
|
handleElement.removeEventListener("keydown", onKeyDown);
|
|
1454
1477
|
};
|
|
1455
|
-
}, [disabled, handleId, resizeHandler]);
|
|
1478
|
+
}, [panelGroupElement, disabled, handleId, resizeHandler]);
|
|
1456
1479
|
}
|
|
1457
1480
|
|
|
1458
1481
|
function PanelResizeHandle({
|
|
@@ -1466,7 +1489,7 @@ function PanelResizeHandle({
|
|
|
1466
1489
|
tagName: Type = "div",
|
|
1467
1490
|
...rest
|
|
1468
1491
|
}) {
|
|
1469
|
-
const
|
|
1492
|
+
const elementRef = useRef(null);
|
|
1470
1493
|
|
|
1471
1494
|
// Use a ref to guard against users passing inline props
|
|
1472
1495
|
const callbacksRef = useRef({
|
|
@@ -1485,7 +1508,8 @@ function PanelResizeHandle({
|
|
|
1485
1508
|
groupId,
|
|
1486
1509
|
registerResizeHandle,
|
|
1487
1510
|
startDragging,
|
|
1488
|
-
stopDragging
|
|
1511
|
+
stopDragging,
|
|
1512
|
+
panelGroupElement
|
|
1489
1513
|
} = panelGroupContext;
|
|
1490
1514
|
const resizeHandleId = useUniqueId(idFromProps);
|
|
1491
1515
|
const isDragging = (dragState === null || dragState === void 0 ? void 0 : dragState.dragHandleId) === resizeHandleId;
|
|
@@ -1494,9 +1518,9 @@ function PanelResizeHandle({
|
|
|
1494
1518
|
const stopDraggingAndBlur = useCallback(() => {
|
|
1495
1519
|
// Clicking on the drag handle shouldn't leave it focused;
|
|
1496
1520
|
// That would cause the PanelGroup to think it was still active.
|
|
1497
|
-
const
|
|
1498
|
-
assert(
|
|
1499
|
-
|
|
1521
|
+
const element = elementRef.current;
|
|
1522
|
+
assert(element);
|
|
1523
|
+
element.blur();
|
|
1500
1524
|
stopDragging();
|
|
1501
1525
|
const {
|
|
1502
1526
|
onDragging
|
|
@@ -1523,9 +1547,9 @@ function PanelResizeHandle({
|
|
|
1523
1547
|
const onMouseLeave = event => {
|
|
1524
1548
|
resizeHandler(event);
|
|
1525
1549
|
};
|
|
1526
|
-
const
|
|
1527
|
-
assert(
|
|
1528
|
-
const targetDocument =
|
|
1550
|
+
const element = elementRef.current;
|
|
1551
|
+
assert(element);
|
|
1552
|
+
const targetDocument = element.ownerDocument;
|
|
1529
1553
|
targetDocument.body.addEventListener("contextmenu", stopDraggingAndBlur);
|
|
1530
1554
|
targetDocument.body.addEventListener("mousemove", onMove);
|
|
1531
1555
|
targetDocument.body.addEventListener("touchmove", onMove);
|
|
@@ -1544,7 +1568,8 @@ function PanelResizeHandle({
|
|
|
1544
1568
|
useWindowSplitterResizeHandlerBehavior({
|
|
1545
1569
|
disabled,
|
|
1546
1570
|
handleId: resizeHandleId,
|
|
1547
|
-
resizeHandler
|
|
1571
|
+
resizeHandler,
|
|
1572
|
+
panelGroupElement
|
|
1548
1573
|
});
|
|
1549
1574
|
const style = {
|
|
1550
1575
|
cursor: getCursorStyle(direction),
|
|
@@ -1582,7 +1607,7 @@ function PanelResizeHandle({
|
|
|
1582
1607
|
onDragging(true);
|
|
1583
1608
|
}
|
|
1584
1609
|
},
|
|
1585
|
-
ref:
|
|
1610
|
+
ref: elementRef,
|
|
1586
1611
|
role: "separator",
|
|
1587
1612
|
style: {
|
|
1588
1613
|
...style,
|
|
@@ -1600,13 +1625,12 @@ function PanelResizeHandle({
|
|
|
1600
1625
|
}
|
|
1601
1626
|
PanelResizeHandle.displayName = "PanelResizeHandle";
|
|
1602
1627
|
|
|
1603
|
-
function calculateAvailablePanelSizeInPixels(groupId) {
|
|
1604
|
-
const panelGroupElement = getPanelGroupElement(groupId);
|
|
1628
|
+
function calculateAvailablePanelSizeInPixels(groupId, panelGroupElement) {
|
|
1605
1629
|
if (panelGroupElement == null) {
|
|
1606
1630
|
return NaN;
|
|
1607
1631
|
}
|
|
1608
1632
|
const direction = panelGroupElement.getAttribute("data-panel-group-direction");
|
|
1609
|
-
const resizeHandles = getResizeHandleElementsForGroup(groupId);
|
|
1633
|
+
const resizeHandles = getResizeHandleElementsForGroup(groupId, panelGroupElement);
|
|
1610
1634
|
if (direction === "horizontal") {
|
|
1611
1635
|
return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
|
|
1612
1636
|
return accumulated + handle.offsetWidth;
|
|
@@ -1618,13 +1642,9 @@ function calculateAvailablePanelSizeInPixels(groupId) {
|
|
|
1618
1642
|
}
|
|
1619
1643
|
}
|
|
1620
1644
|
|
|
1621
|
-
function getAvailableGroupSizePixels(groupId) {
|
|
1622
|
-
const panelGroupElement = getPanelGroupElement(groupId);
|
|
1623
|
-
if (panelGroupElement == null) {
|
|
1624
|
-
return NaN;
|
|
1625
|
-
}
|
|
1645
|
+
function getAvailableGroupSizePixels(groupId, panelGroupElement) {
|
|
1626
1646
|
const direction = panelGroupElement.getAttribute("data-panel-group-direction");
|
|
1627
|
-
const resizeHandles = getResizeHandleElementsForGroup(groupId);
|
|
1647
|
+
const resizeHandles = getResizeHandleElementsForGroup(groupId, panelGroupElement);
|
|
1628
1648
|
if (direction === "horizontal") {
|
|
1629
1649
|
return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
|
|
1630
1650
|
return accumulated + handle.offsetWidth;
|
|
@@ -1636,16 +1656,16 @@ function getAvailableGroupSizePixels(groupId) {
|
|
|
1636
1656
|
}
|
|
1637
1657
|
}
|
|
1638
1658
|
|
|
1639
|
-
function getPanelElement(id) {
|
|
1640
|
-
const element =
|
|
1659
|
+
function getPanelElement(id, panelGroupElement) {
|
|
1660
|
+
const element = panelGroupElement.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, panelGroupElement) {
|
|
1668
|
+
return Array.from(panelGroupElement.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
|
|
1649
1669
|
}
|
|
1650
1670
|
|
|
1651
1671
|
export { Panel, PanelGroup, PanelResizeHandle, assert, calculateAvailablePanelSizeInPixels, getAvailableGroupSizePixels, 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,7 +259,7 @@ 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");
|
package/src/Panel.ts
CHANGED
|
@@ -4,10 +4,10 @@ import { PanelGroupContext } from "./PanelGroupContext";
|
|
|
4
4
|
import useIsomorphicLayoutEffect from "./hooks/useIsomorphicEffect";
|
|
5
5
|
import useUniqueId from "./hooks/useUniqueId";
|
|
6
6
|
import {
|
|
7
|
-
ElementType,
|
|
8
7
|
ForwardedRef,
|
|
9
8
|
HTMLAttributes,
|
|
10
9
|
PropsWithChildren,
|
|
10
|
+
ReactElement,
|
|
11
11
|
createElement,
|
|
12
12
|
forwardRef,
|
|
13
13
|
useContext,
|
|
@@ -54,7 +54,10 @@ export type ImperativePanelHandle = {
|
|
|
54
54
|
resize: (size: number) => void;
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
-
export type PanelProps = Omit<
|
|
57
|
+
export type PanelProps = Omit<
|
|
58
|
+
HTMLAttributes<keyof HTMLElementTagNameMap>,
|
|
59
|
+
"id" | "onResize"
|
|
60
|
+
> &
|
|
58
61
|
PropsWithChildren<{
|
|
59
62
|
className?: string;
|
|
60
63
|
collapsedSize?: number | undefined;
|
|
@@ -68,7 +71,7 @@ export type PanelProps = Omit<HTMLAttributes<ElementType>, "id" | "onResize"> &
|
|
|
68
71
|
onResize?: PanelOnResize;
|
|
69
72
|
order?: number;
|
|
70
73
|
style?: object;
|
|
71
|
-
tagName?:
|
|
74
|
+
tagName?: keyof HTMLElementTagNameMap;
|
|
72
75
|
}>;
|
|
73
76
|
|
|
74
77
|
export function PanelWithForwardedRef({
|
|
@@ -90,7 +93,7 @@ export function PanelWithForwardedRef({
|
|
|
90
93
|
...rest
|
|
91
94
|
}: PanelProps & {
|
|
92
95
|
forwardedRef: ForwardedRef<ImperativePanelHandle>;
|
|
93
|
-
}) {
|
|
96
|
+
}): ReactElement {
|
|
94
97
|
const context = useContext(PanelGroupContext);
|
|
95
98
|
if (context === null) {
|
|
96
99
|
throw Error(
|
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");
|
package/src/PanelGroup.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { isDevelopment } from "#is-development";
|
|
2
2
|
import { PanelData } from "./Panel";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
DragState,
|
|
5
|
+
PanelGroupContext,
|
|
6
|
+
ResizeEvent,
|
|
7
|
+
TPanelGroupContext,
|
|
8
|
+
} from "./PanelGroupContext";
|
|
4
9
|
import useIsomorphicLayoutEffect from "./hooks/useIsomorphicEffect";
|
|
5
10
|
import useUniqueId from "./hooks/useUniqueId";
|
|
6
11
|
import { useWindowSplitterPanelGroupBehavior } from "./hooks/useWindowSplitterPanelGroupBehavior";
|
|
@@ -28,10 +33,10 @@ import { validatePanelConstraints } from "./utils/validatePanelConstraints";
|
|
|
28
33
|
import { validatePanelGroupLayout } from "./utils/validatePanelGroupLayout";
|
|
29
34
|
import {
|
|
30
35
|
CSSProperties,
|
|
31
|
-
ElementType,
|
|
32
36
|
ForwardedRef,
|
|
33
37
|
HTMLAttributes,
|
|
34
38
|
PropsWithChildren,
|
|
39
|
+
ReactElement,
|
|
35
40
|
createElement,
|
|
36
41
|
forwardRef,
|
|
37
42
|
useCallback,
|
|
@@ -68,7 +73,10 @@ const defaultStorage: PanelGroupStorage = {
|
|
|
68
73
|
},
|
|
69
74
|
};
|
|
70
75
|
|
|
71
|
-
export type PanelGroupProps = Omit<
|
|
76
|
+
export type PanelGroupProps = Omit<
|
|
77
|
+
HTMLAttributes<keyof HTMLElementTagNameMap>,
|
|
78
|
+
"id"
|
|
79
|
+
> &
|
|
72
80
|
PropsWithChildren<{
|
|
73
81
|
autoSaveId?: string | null;
|
|
74
82
|
className?: string;
|
|
@@ -78,7 +86,7 @@ export type PanelGroupProps = Omit<HTMLAttributes<ElementType>, "id"> &
|
|
|
78
86
|
onLayout?: PanelGroupOnLayout | null;
|
|
79
87
|
storage?: PanelGroupStorage;
|
|
80
88
|
style?: CSSProperties;
|
|
81
|
-
tagName?:
|
|
89
|
+
tagName?: keyof HTMLElementTagNameMap;
|
|
82
90
|
}>;
|
|
83
91
|
|
|
84
92
|
const debounceMap: {
|
|
@@ -100,9 +108,9 @@ function PanelGroupWithForwardedRef({
|
|
|
100
108
|
...rest
|
|
101
109
|
}: PanelGroupProps & {
|
|
102
110
|
forwardedRef: ForwardedRef<ImperativePanelGroupHandle>;
|
|
103
|
-
}) {
|
|
111
|
+
}): ReactElement {
|
|
104
112
|
const groupId = useUniqueId(idFromProps);
|
|
105
|
-
|
|
113
|
+
const panelGroupElementRef = useRef<HTMLDivElement | null>(null);
|
|
106
114
|
const [dragState, setDragState] = useState<DragState | null>(null);
|
|
107
115
|
const [layout, setLayout] = useState<number[]>([]);
|
|
108
116
|
|
|
@@ -204,6 +212,7 @@ function PanelGroupWithForwardedRef({
|
|
|
204
212
|
layout,
|
|
205
213
|
panelDataArray: eagerValuesRef.current.panelDataArray,
|
|
206
214
|
setLayout,
|
|
215
|
+
panelGroupElement: panelGroupElementRef.current,
|
|
207
216
|
});
|
|
208
217
|
|
|
209
218
|
useEffect(() => {
|
|
@@ -558,7 +567,10 @@ function PanelGroupWithForwardedRef({
|
|
|
558
567
|
const registerResizeHandle = useCallback((dragHandleId: string) => {
|
|
559
568
|
return function resizeHandler(event: ResizeEvent) {
|
|
560
569
|
event.preventDefault();
|
|
561
|
-
|
|
570
|
+
const panelGroupElement = panelGroupElementRef.current;
|
|
571
|
+
if (!panelGroupElement) {
|
|
572
|
+
return () => null;
|
|
573
|
+
}
|
|
562
574
|
const {
|
|
563
575
|
direction,
|
|
564
576
|
dragState,
|
|
@@ -570,14 +582,19 @@ function PanelGroupWithForwardedRef({
|
|
|
570
582
|
|
|
571
583
|
const { initialLayout } = dragState ?? {};
|
|
572
584
|
|
|
573
|
-
const pivotIndices = determinePivotIndices(
|
|
585
|
+
const pivotIndices = determinePivotIndices(
|
|
586
|
+
groupId,
|
|
587
|
+
dragHandleId,
|
|
588
|
+
panelGroupElement
|
|
589
|
+
);
|
|
574
590
|
|
|
575
591
|
let delta = calculateDeltaPercentage(
|
|
576
592
|
event,
|
|
577
593
|
dragHandleId,
|
|
578
594
|
direction,
|
|
579
595
|
dragState,
|
|
580
|
-
keyboardResizeBy
|
|
596
|
+
keyboardResizeBy,
|
|
597
|
+
panelGroupElement
|
|
581
598
|
);
|
|
582
599
|
if (delta === 0) {
|
|
583
600
|
return;
|
|
@@ -706,8 +723,13 @@ function PanelGroupWithForwardedRef({
|
|
|
706
723
|
(dragHandleId: string, event: ResizeEvent) => {
|
|
707
724
|
const { direction } = committedValuesRef.current;
|
|
708
725
|
const { layout } = eagerValuesRef.current;
|
|
709
|
-
|
|
710
|
-
|
|
726
|
+
if (!panelGroupElementRef.current) {
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
const handleElement = getResizeHandleElement(
|
|
730
|
+
dragHandleId,
|
|
731
|
+
panelGroupElementRef.current
|
|
732
|
+
);
|
|
711
733
|
assert(handleElement);
|
|
712
734
|
|
|
713
735
|
const initialCursorPosition = getResizeEventCursorPosition(
|
|
@@ -748,23 +770,25 @@ function PanelGroupWithForwardedRef({
|
|
|
748
770
|
}, []);
|
|
749
771
|
|
|
750
772
|
const context = useMemo(
|
|
751
|
-
() =>
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
773
|
+
() =>
|
|
774
|
+
({
|
|
775
|
+
collapsePanel,
|
|
776
|
+
direction,
|
|
777
|
+
dragState,
|
|
778
|
+
expandPanel,
|
|
779
|
+
getPanelSize,
|
|
780
|
+
getPanelStyle,
|
|
781
|
+
groupId,
|
|
782
|
+
isPanelCollapsed,
|
|
783
|
+
isPanelExpanded,
|
|
784
|
+
registerPanel,
|
|
785
|
+
registerResizeHandle,
|
|
786
|
+
resizePanel,
|
|
787
|
+
startDragging,
|
|
788
|
+
stopDragging,
|
|
789
|
+
unregisterPanel,
|
|
790
|
+
panelGroupElement: panelGroupElementRef.current,
|
|
791
|
+
}) satisfies TPanelGroupContext,
|
|
768
792
|
[
|
|
769
793
|
collapsePanel,
|
|
770
794
|
dragState,
|
|
@@ -797,14 +821,13 @@ function PanelGroupWithForwardedRef({
|
|
|
797
821
|
{ value: context },
|
|
798
822
|
createElement(Type, {
|
|
799
823
|
...rest,
|
|
800
|
-
|
|
801
824
|
children,
|
|
802
825
|
className: classNameFromProps,
|
|
803
826
|
style: {
|
|
804
827
|
...style,
|
|
805
828
|
...styleFromProps,
|
|
806
829
|
},
|
|
807
|
-
|
|
830
|
+
ref: panelGroupElementRef,
|
|
808
831
|
// CSS selectors
|
|
809
832
|
"data-panel-group": "",
|
|
810
833
|
"data-panel-group-direction": direction,
|
package/src/PanelGroupContext.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type DragState = {
|
|
|
11
11
|
initialLayout: number[];
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
export
|
|
14
|
+
export type TPanelGroupContext = {
|
|
15
15
|
collapsePanel: (panelData: PanelData) => void;
|
|
16
16
|
direction: "horizontal" | "vertical";
|
|
17
17
|
dragState: DragState | null;
|
|
@@ -30,6 +30,8 @@ export const PanelGroupContext = createContext<{
|
|
|
30
30
|
startDragging: (dragHandleId: string, event: ResizeEvent) => void;
|
|
31
31
|
stopDragging: () => void;
|
|
32
32
|
unregisterPanel: (panelData: PanelData) => void;
|
|
33
|
-
|
|
33
|
+
panelGroupElement: ParentNode | null;
|
|
34
|
+
};
|
|
35
|
+
export const PanelGroupContext = createContext<TPanelGroupContext | null>(null);
|
|
34
36
|
|
|
35
37
|
PanelGroupContext.displayName = "PanelGroupContext";
|