react-resizable-panels 2.0.8 → 2.0.10

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