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.
Files changed (52) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +20 -4
  3. package/dist/declarations/src/Panel.d.ts +6 -6
  4. package/dist/declarations/src/PanelGroup.d.ts +5 -5
  5. package/dist/declarations/src/PanelResizeHandle.d.ts +4 -4
  6. package/dist/declarations/src/utils/dom/calculateAvailablePanelSizeInPixels.d.ts +1 -1
  7. package/dist/declarations/src/utils/dom/getAvailableGroupSizePixels.d.ts +1 -1
  8. package/dist/declarations/src/utils/dom/getPanelElement.d.ts +1 -1
  9. package/dist/declarations/src/utils/dom/getPanelElementsForGroup.d.ts +1 -1
  10. package/dist/declarations/src/utils/dom/getPanelGroupElement.d.ts +1 -1
  11. package/dist/declarations/src/utils/dom/getResizeHandleElement.d.ts +1 -1
  12. package/dist/declarations/src/utils/dom/getResizeHandleElementIndex.d.ts +1 -1
  13. package/dist/declarations/src/utils/dom/getResizeHandleElementsForGroup.d.ts +1 -1
  14. package/dist/declarations/src/utils/dom/getResizeHandlePanelIds.d.ts +1 -1
  15. package/dist/declarations/src/vendor/react.d.ts +2 -2
  16. package/dist/react-resizable-panels.browser.cjs.js +82 -59
  17. package/dist/react-resizable-panels.browser.development.cjs.js +84 -60
  18. package/dist/react-resizable-panels.browser.development.esm.js +84 -60
  19. package/dist/react-resizable-panels.browser.esm.js +82 -59
  20. package/dist/react-resizable-panels.cjs.js +82 -59
  21. package/dist/react-resizable-panels.development.cjs.js +84 -60
  22. package/dist/react-resizable-panels.development.esm.js +84 -60
  23. package/dist/react-resizable-panels.development.node.cjs.js +79 -58
  24. package/dist/react-resizable-panels.development.node.esm.js +79 -58
  25. package/dist/react-resizable-panels.esm.js +82 -59
  26. package/dist/react-resizable-panels.node.cjs.js +77 -57
  27. package/dist/react-resizable-panels.node.esm.js +77 -57
  28. package/package.json +1 -1
  29. package/src/Panel.test.tsx +3 -2
  30. package/src/Panel.ts +7 -4
  31. package/src/PanelGroup.test.tsx +3 -2
  32. package/src/PanelGroup.ts +53 -30
  33. package/src/PanelGroupContext.ts +4 -2
  34. package/src/PanelResizeHandle.test.tsx +3 -3
  35. package/src/PanelResizeHandle.ts +17 -12
  36. package/src/hooks/useWindowSplitterBehavior.ts +15 -6
  37. package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +23 -7
  38. package/src/utils/calculateDeltaPercentage.ts +4 -2
  39. package/src/utils/calculateDragOffsetPercentage.ts +4 -3
  40. package/src/utils/determinePivotIndices.ts +7 -2
  41. package/src/utils/dom/calculateAvailablePanelSizeInPixels.ts +8 -3
  42. package/src/utils/dom/getAvailableGroupSizePixels.ts +8 -7
  43. package/src/utils/dom/getPanelElement.ts +6 -3
  44. package/src/utils/dom/getPanelElementsForGroup.ts +7 -2
  45. package/src/utils/dom/getPanelGroupElement.ts +15 -3
  46. package/src/utils/dom/getResizeHandleElement.ts +6 -3
  47. package/src/utils/dom/getResizeHandleElementIndex.ts +3 -2
  48. package/src/utils/dom/getResizeHandleElementsForGroup.ts +4 -3
  49. package/src/utils/dom/getResizeHandlePanelIds.ts +4 -3
  50. package/src/utils/validatePanelConstraints.test.ts +45 -0
  51. package/src/utils/validatePanelConstraints.ts +5 -1
  52. 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(document.querySelectorAll(`[data-panel-resize-handle-id][data-panel-group-id="${groupId}"]`));
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
- const element = document.querySelector(`[data-panel-group][data-panel-group-id="${id}"]`);
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 = document.querySelector(`[data-panel-resize-handle-id="${id}"]`);
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
- const handleElement = getResizeHandleElement(dragHandleId);
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 divElementRef = useRef(null);
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 divElement = divElementRef.current;
1498
- assert(divElement);
1499
- divElement.blur();
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 divElement = divElementRef.current;
1527
- assert(divElement);
1528
- const targetDocument = divElement.ownerDocument;
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: divElementRef,
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 = document.querySelector(`[data-panel-id="${id}"]`);
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(document.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-resizable-panels",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "React components for resizable panel groups/layouts",
5
5
  "author": "Brian Vaughn <brian.david.vaughn@gmail.com>",
6
6
  "license": "MIT",
@@ -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
- const container = document.createElement("div");
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<HTMLAttributes<ElementType>, "id" | "onResize"> &
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?: ElementType;
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(
@@ -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
- const container = document.createElement("div");
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 { DragState, PanelGroupContext, ResizeEvent } from "./PanelGroupContext";
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<HTMLAttributes<ElementType>, "id"> &
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?: ElementType;
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(groupId, dragHandleId);
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
- const handleElement = getResizeHandleElement(dragHandleId);
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
- collapsePanel,
753
- direction,
754
- dragState,
755
- expandPanel,
756
- getPanelSize,
757
- getPanelStyle,
758
- groupId,
759
- isPanelCollapsed,
760
- isPanelExpanded,
761
- registerPanel,
762
- registerResizeHandle,
763
- resizePanel,
764
- startDragging,
765
- stopDragging,
766
- unregisterPanel,
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,
@@ -11,7 +11,7 @@ export type DragState = {
11
11
  initialLayout: number[];
12
12
  };
13
13
 
14
- export const PanelGroupContext = createContext<{
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
- } | null>(null);
33
+ panelGroupElement: ParentNode | null;
34
+ };
35
+ export const PanelGroupContext = createContext<TPanelGroupContext | null>(null);
34
36
 
35
37
  PanelGroupContext.displayName = "PanelGroupContext";