react-resizable-panels 0.0.58 → 0.0.60
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 +12 -0
- package/dist/declarations/src/PanelGroup.d.ts +2 -2
- package/dist/react-resizable-panels.browser.cjs.js +189 -98
- package/dist/react-resizable-panels.browser.development.cjs.js +192 -101
- package/dist/react-resizable-panels.browser.development.esm.js +192 -101
- package/dist/react-resizable-panels.browser.esm.js +189 -98
- package/dist/react-resizable-panels.cjs.js +189 -98
- package/dist/react-resizable-panels.cjs.js.map +1 -1
- package/dist/react-resizable-panels.development.cjs.js +192 -101
- package/dist/react-resizable-panels.development.esm.js +192 -101
- package/dist/react-resizable-panels.development.node.cjs.js +237 -49
- package/dist/react-resizable-panels.development.node.esm.js +237 -49
- package/dist/react-resizable-panels.esm.js +189 -98
- package/dist/react-resizable-panels.esm.js.map +1 -1
- package/dist/react-resizable-panels.node.cjs.js +234 -46
- package/dist/react-resizable-panels.node.esm.js +234 -46
- package/package.json +1 -1
- package/src/Panel.ts +2 -0
- package/src/PanelGroup.ts +221 -97
- package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +15 -15
- package/src/utils/dom/getPanelElementsForGroup.ts +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.0.60
|
|
4
|
+
|
|
5
|
+
- Better support imperative API usage from mount effects.
|
|
6
|
+
- Better support strict effects mode.
|
|
7
|
+
- Better checks not to call `onResize` or `onLayout` more than once.
|
|
8
|
+
|
|
9
|
+
## 0.0.59
|
|
10
|
+
|
|
11
|
+
- Support imperative panel API usage on-mount.
|
|
12
|
+
- Made PanelGroup bailout condition smarter (don't bailout for empty groups unless pixel constraints are used).
|
|
13
|
+
- Improved window splitter compatibility by better handling "Enter" key.
|
|
14
|
+
|
|
3
15
|
## 0.0.58
|
|
4
16
|
|
|
5
17
|
- Change group layout to more thoroughly distribute resize delta to support more flexible group size configurations.
|
|
@@ -11,7 +11,7 @@ export type PanelGroupStorage = {
|
|
|
11
11
|
};
|
|
12
12
|
export type PanelGroupOnLayout = (layout: MixedSizes[]) => void;
|
|
13
13
|
export type PanelGroupProps = PropsWithChildren<{
|
|
14
|
-
autoSaveId?: string;
|
|
14
|
+
autoSaveId?: string | null;
|
|
15
15
|
className?: string;
|
|
16
16
|
dataAttributes?: DataAttributes;
|
|
17
17
|
direction: Direction;
|
|
@@ -24,7 +24,7 @@ export type PanelGroupProps = PropsWithChildren<{
|
|
|
24
24
|
tagName?: ElementType;
|
|
25
25
|
}>;
|
|
26
26
|
export declare const PanelGroup: import("react").ForwardRefExoticComponent<{
|
|
27
|
-
autoSaveId?: string | undefined;
|
|
27
|
+
autoSaveId?: string | null | undefined;
|
|
28
28
|
className?: string | undefined;
|
|
29
29
|
dataAttributes?: DataAttributes | undefined;
|
|
30
30
|
direction: Direction;
|
|
@@ -93,6 +93,7 @@ function PanelWithForwardedRef({
|
|
|
93
93
|
expandPanel,
|
|
94
94
|
getPanelSize,
|
|
95
95
|
getPanelStyle,
|
|
96
|
+
groupId,
|
|
96
97
|
isPanelCollapsed,
|
|
97
98
|
registerPanel,
|
|
98
99
|
resizePanel,
|
|
@@ -186,6 +187,7 @@ function PanelWithForwardedRef({
|
|
|
186
187
|
// CSS selectors
|
|
187
188
|
"data-panel": "",
|
|
188
189
|
"data-panel-id": panelId,
|
|
190
|
+
"data-panel-group-id": groupId,
|
|
189
191
|
// e2e test attributes
|
|
190
192
|
"data-panel-collapsible": undefined,
|
|
191
193
|
"data-panel-size": undefined
|
|
@@ -198,8 +200,6 @@ const Panel = forwardRef((props, ref) => createElement(PanelWithForwardedRef, {
|
|
|
198
200
|
PanelWithForwardedRef.displayName = "Panel";
|
|
199
201
|
Panel.displayName = "forwardRef(Panel)";
|
|
200
202
|
|
|
201
|
-
const PRECISION = 10;
|
|
202
|
-
|
|
203
203
|
function convertPixelsToPercentage(pixels, groupSizePixels) {
|
|
204
204
|
return pixels / groupSizePixels * 100;
|
|
205
205
|
}
|
|
@@ -277,6 +277,8 @@ function computePercentagePanelConstraints(panelConstraintsArray, panelIndex, gr
|
|
|
277
277
|
};
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
+
const PRECISION = 10;
|
|
281
|
+
|
|
280
282
|
function fuzzyCompareNumbers(actual, expected, fractionDigits = PRECISION) {
|
|
281
283
|
actual = parseFloat(actual.toFixed(fractionDigits));
|
|
282
284
|
expected = parseFloat(expected.toFixed(fractionDigits));
|
|
@@ -750,15 +752,10 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
750
752
|
}, [groupId, layout, panelDataArray]);
|
|
751
753
|
useEffect(() => {
|
|
752
754
|
const {
|
|
753
|
-
direction,
|
|
754
755
|
panelDataArray
|
|
755
756
|
} = committedValuesRef.current;
|
|
756
757
|
const groupElement = getPanelGroupElement(groupId);
|
|
757
758
|
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
758
|
-
const {
|
|
759
|
-
height,
|
|
760
|
-
width
|
|
761
|
-
} = groupElement.getBoundingClientRect();
|
|
762
759
|
const handles = getResizeHandleElementsForGroup(groupId);
|
|
763
760
|
const cleanupFunctions = handles.map(handle => {
|
|
764
761
|
const handleId = handle.getAttribute("data-panel-resize-handle-id");
|
|
@@ -778,21 +775,19 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
778
775
|
if (index >= 0) {
|
|
779
776
|
const panelData = panelDataArray[index];
|
|
780
777
|
const size = layout[index];
|
|
781
|
-
if (size != null) {
|
|
782
|
-
var _getPercentageSizeFro;
|
|
778
|
+
if (size != null && panelData.constraints.collapsible) {
|
|
779
|
+
var _getPercentageSizeFro, _getPercentageSizeFro2;
|
|
783
780
|
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
784
|
-
const
|
|
781
|
+
const collapsedSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
|
|
782
|
+
sizePercentage: panelData.constraints.collapsedSizePercentage,
|
|
783
|
+
sizePixels: panelData.constraints.collapsedSizePixels
|
|
784
|
+
}, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
|
|
785
|
+
const minSize = (_getPercentageSizeFro2 = getPercentageSizeFromMixedSizes({
|
|
785
786
|
sizePercentage: panelData.constraints.minSizePercentage,
|
|
786
787
|
sizePixels: panelData.constraints.minSizePixels
|
|
787
|
-
}, groupSizePixels)) !== null &&
|
|
788
|
-
let delta = 0;
|
|
789
|
-
if (size.toPrecision(PRECISION) <= minSize.toPrecision(PRECISION)) {
|
|
790
|
-
delta = direction === "horizontal" ? width : height;
|
|
791
|
-
} else {
|
|
792
|
-
delta = -(direction === "horizontal" ? width : height);
|
|
793
|
-
}
|
|
788
|
+
}, groupSizePixels)) !== null && _getPercentageSizeFro2 !== void 0 ? _getPercentageSizeFro2 : 0;
|
|
794
789
|
const nextLayout = adjustLayoutByDelta({
|
|
795
|
-
delta,
|
|
790
|
+
delta: fuzzyNumbersEqual(size, collapsedSize) ? minSize - collapsedSize : collapsedSize - size,
|
|
796
791
|
groupSizePixels,
|
|
797
792
|
layout,
|
|
798
793
|
panelConstraints: panelDataArray.map(panelData => panelData.constraints),
|
|
@@ -1101,6 +1096,10 @@ function debounce(callback, durationMs = 10) {
|
|
|
1101
1096
|
return callable;
|
|
1102
1097
|
}
|
|
1103
1098
|
|
|
1099
|
+
function getPanelElementsForGroup(groupId) {
|
|
1100
|
+
return Array.from(document.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1104
1103
|
// PanelGroup might be rendering in a server-side environment where localStorage is not available
|
|
1105
1104
|
// or on a browser with cookies/storage disabled.
|
|
1106
1105
|
// In either case, this function avoids accessing localStorage until needed,
|
|
@@ -1250,7 +1249,7 @@ const defaultStorage = {
|
|
|
1250
1249
|
};
|
|
1251
1250
|
const debounceMap = {};
|
|
1252
1251
|
function PanelGroupWithForwardedRef({
|
|
1253
|
-
autoSaveId,
|
|
1252
|
+
autoSaveId = null,
|
|
1254
1253
|
children,
|
|
1255
1254
|
className: classNameFromProps = "",
|
|
1256
1255
|
dataAttributes,
|
|
@@ -1267,11 +1266,11 @@ function PanelGroupWithForwardedRef({
|
|
|
1267
1266
|
const groupId = useUniqueId(idFromProps);
|
|
1268
1267
|
const [dragState, setDragState] = useState(null);
|
|
1269
1268
|
const [layout, setLayout] = useState([]);
|
|
1270
|
-
const [panelDataArray, setPanelDataArray] = useState([]);
|
|
1271
1269
|
const panelIdToLastNotifiedMixedSizesMapRef = useRef({});
|
|
1272
1270
|
const panelSizeBeforeCollapseRef = useRef(new Map());
|
|
1273
1271
|
const prevDeltaRef = useRef(0);
|
|
1274
1272
|
const committedValuesRef = useRef({
|
|
1273
|
+
autoSaveId,
|
|
1275
1274
|
direction,
|
|
1276
1275
|
dragState,
|
|
1277
1276
|
id: groupId,
|
|
@@ -1279,7 +1278,8 @@ function PanelGroupWithForwardedRef({
|
|
|
1279
1278
|
keyboardResizeByPixels,
|
|
1280
1279
|
layout,
|
|
1281
1280
|
onLayout,
|
|
1282
|
-
panelDataArray
|
|
1281
|
+
panelDataArray: [],
|
|
1282
|
+
storage
|
|
1283
1283
|
});
|
|
1284
1284
|
useRef({
|
|
1285
1285
|
didLogIdAndOrderWarning: false,
|
|
@@ -1317,6 +1317,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1317
1317
|
});
|
|
1318
1318
|
if (!areEqual(prevLayout, safeLayout)) {
|
|
1319
1319
|
setLayout(safeLayout);
|
|
1320
|
+
committedValuesRef.current.layout = safeLayout;
|
|
1320
1321
|
if (onLayout) {
|
|
1321
1322
|
onLayout(safeLayout.map(sizePercentage => ({
|
|
1322
1323
|
sizePercentage,
|
|
@@ -1328,21 +1329,29 @@ function PanelGroupWithForwardedRef({
|
|
|
1328
1329
|
}
|
|
1329
1330
|
}), []);
|
|
1330
1331
|
useIsomorphicLayoutEffect(() => {
|
|
1332
|
+
committedValuesRef.current.autoSaveId = autoSaveId;
|
|
1331
1333
|
committedValuesRef.current.direction = direction;
|
|
1332
1334
|
committedValuesRef.current.dragState = dragState;
|
|
1333
1335
|
committedValuesRef.current.id = groupId;
|
|
1334
|
-
committedValuesRef.current.layout = layout;
|
|
1335
1336
|
committedValuesRef.current.onLayout = onLayout;
|
|
1336
|
-
committedValuesRef.current.
|
|
1337
|
+
committedValuesRef.current.storage = storage;
|
|
1338
|
+
|
|
1339
|
+
// panelDataArray and layout are updated in-sync with scheduled state updates.
|
|
1340
|
+
// TODO [217] Move these values into a separate ref
|
|
1337
1341
|
});
|
|
1342
|
+
|
|
1338
1343
|
useWindowSplitterPanelGroupBehavior({
|
|
1339
1344
|
committedValuesRef,
|
|
1340
1345
|
groupId,
|
|
1341
1346
|
layout,
|
|
1342
|
-
panelDataArray,
|
|
1347
|
+
panelDataArray: committedValuesRef.current.panelDataArray,
|
|
1343
1348
|
setLayout
|
|
1344
1349
|
});
|
|
1345
1350
|
useEffect(() => {
|
|
1351
|
+
const {
|
|
1352
|
+
panelDataArray
|
|
1353
|
+
} = committedValuesRef.current;
|
|
1354
|
+
|
|
1346
1355
|
// If this panel has been configured to persist sizing information, save sizes to local storage.
|
|
1347
1356
|
if (autoSaveId) {
|
|
1348
1357
|
if (layout.length === 0 || layout.length !== panelDataArray.length) {
|
|
@@ -1355,59 +1364,11 @@ function PanelGroupWithForwardedRef({
|
|
|
1355
1364
|
}
|
|
1356
1365
|
debounceMap[autoSaveId](autoSaveId, panelDataArray, layout, storage);
|
|
1357
1366
|
}
|
|
1358
|
-
}, [autoSaveId, layout,
|
|
1359
|
-
|
|
1360
|
-
// Once all panels have registered themselves,
|
|
1361
|
-
// Compute the initial sizes based on default weights.
|
|
1362
|
-
// This assumes that panels register during initial mount (no conditional rendering)!
|
|
1367
|
+
}, [autoSaveId, layout, storage]);
|
|
1363
1368
|
useIsomorphicLayoutEffect(() => {
|
|
1364
1369
|
const {
|
|
1365
|
-
|
|
1366
|
-
layout,
|
|
1367
|
-
onLayout
|
|
1370
|
+
panelDataArray
|
|
1368
1371
|
} = committedValuesRef.current;
|
|
1369
|
-
if (layout.length === panelDataArray.length) {
|
|
1370
|
-
// Only compute (or restore) default layout once per panel configuration.
|
|
1371
|
-
return;
|
|
1372
|
-
}
|
|
1373
|
-
|
|
1374
|
-
// If this panel has been configured to persist sizing information,
|
|
1375
|
-
// default size should be restored from local storage if possible.
|
|
1376
|
-
let unsafeLayout = null;
|
|
1377
|
-
if (autoSaveId) {
|
|
1378
|
-
unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
|
|
1379
|
-
}
|
|
1380
|
-
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1381
|
-
if (groupSizePixels <= 0) {
|
|
1382
|
-
// Wait until the group has rendered a non-zero size before computing layout.
|
|
1383
|
-
return;
|
|
1384
|
-
}
|
|
1385
|
-
if (unsafeLayout == null) {
|
|
1386
|
-
unsafeLayout = calculateUnsafeDefaultLayout({
|
|
1387
|
-
groupSizePixels,
|
|
1388
|
-
panelDataArray
|
|
1389
|
-
});
|
|
1390
|
-
}
|
|
1391
|
-
|
|
1392
|
-
// Validate even saved layouts in case something has changed since last render
|
|
1393
|
-
// e.g. for pixel groups, this could be the size of the window
|
|
1394
|
-
const validatedLayout = validatePanelGroupLayout({
|
|
1395
|
-
groupSizePixels,
|
|
1396
|
-
layout: unsafeLayout,
|
|
1397
|
-
panelConstraints: panelDataArray.map(panelData => panelData.constraints)
|
|
1398
|
-
});
|
|
1399
|
-
if (!areEqual(layout, validatedLayout)) {
|
|
1400
|
-
setLayout(validatedLayout);
|
|
1401
|
-
}
|
|
1402
|
-
if (onLayout) {
|
|
1403
|
-
onLayout(validatedLayout.map(sizePercentage => ({
|
|
1404
|
-
sizePercentage,
|
|
1405
|
-
sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
|
|
1406
|
-
})));
|
|
1407
|
-
}
|
|
1408
|
-
callPanelCallbacks(groupId, panelDataArray, validatedLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
|
|
1409
|
-
}, [autoSaveId, layout, panelDataArray, storage]);
|
|
1410
|
-
useIsomorphicLayoutEffect(() => {
|
|
1411
1372
|
const constraints = panelDataArray.map(({
|
|
1412
1373
|
constraints
|
|
1413
1374
|
}) => constraints);
|
|
@@ -1431,6 +1392,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1431
1392
|
});
|
|
1432
1393
|
if (!areEqual(prevLayout, nextLayout)) {
|
|
1433
1394
|
setLayout(nextLayout);
|
|
1395
|
+
committedValuesRef.current.layout = nextLayout;
|
|
1434
1396
|
if (onLayout) {
|
|
1435
1397
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1436
1398
|
sizePercentage,
|
|
@@ -1445,7 +1407,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1445
1407
|
resizeObserver.disconnect();
|
|
1446
1408
|
};
|
|
1447
1409
|
}
|
|
1448
|
-
}, [groupId
|
|
1410
|
+
}, [groupId]);
|
|
1449
1411
|
|
|
1450
1412
|
// DEV warnings
|
|
1451
1413
|
useEffect(() => {
|
|
@@ -1482,6 +1444,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1482
1444
|
});
|
|
1483
1445
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
1484
1446
|
setLayout(nextLayout);
|
|
1447
|
+
committedValuesRef.current.layout = nextLayout;
|
|
1485
1448
|
if (onLayout) {
|
|
1486
1449
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1487
1450
|
sizePercentage,
|
|
@@ -1526,6 +1489,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1526
1489
|
});
|
|
1527
1490
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
1528
1491
|
setLayout(nextLayout);
|
|
1492
|
+
committedValuesRef.current.layout = nextLayout;
|
|
1529
1493
|
if (onLayout) {
|
|
1530
1494
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1531
1495
|
sizePercentage,
|
|
@@ -1556,6 +1520,9 @@ function PanelGroupWithForwardedRef({
|
|
|
1556
1520
|
|
|
1557
1521
|
// This API should never read from committedValuesRef
|
|
1558
1522
|
const getPanelStyle = useCallback(panelData => {
|
|
1523
|
+
const {
|
|
1524
|
+
panelDataArray
|
|
1525
|
+
} = committedValuesRef.current;
|
|
1559
1526
|
const panelIndex = panelDataArray.indexOf(panelData);
|
|
1560
1527
|
return computePanelFlexBoxStyle({
|
|
1561
1528
|
dragState,
|
|
@@ -1563,7 +1530,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1563
1530
|
panelData: panelDataArray,
|
|
1564
1531
|
panelIndex
|
|
1565
1532
|
});
|
|
1566
|
-
}, [dragState, layout
|
|
1533
|
+
}, [dragState, layout]);
|
|
1567
1534
|
|
|
1568
1535
|
// External APIs are safe to memoize via committed values ref
|
|
1569
1536
|
const isPanelCollapsed = useCallback(panelData => {
|
|
@@ -1593,22 +1560,76 @@ function PanelGroupWithForwardedRef({
|
|
|
1593
1560
|
return !collapsible || panelSizePercentage > collapsedSizePercentage;
|
|
1594
1561
|
}, [groupId]);
|
|
1595
1562
|
const registerPanel = useCallback(panelData => {
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1563
|
+
const {
|
|
1564
|
+
autoSaveId,
|
|
1565
|
+
id: groupId,
|
|
1566
|
+
layout: prevLayout,
|
|
1567
|
+
onLayout,
|
|
1568
|
+
panelDataArray,
|
|
1569
|
+
storage
|
|
1570
|
+
} = committedValuesRef.current;
|
|
1571
|
+
panelDataArray.push(panelData);
|
|
1572
|
+
panelDataArray.sort((panelA, panelB) => {
|
|
1573
|
+
const orderA = panelA.order;
|
|
1574
|
+
const orderB = panelB.order;
|
|
1575
|
+
if (orderA == null && orderB == null) {
|
|
1576
|
+
return 0;
|
|
1577
|
+
} else if (orderA == null) {
|
|
1578
|
+
return -1;
|
|
1579
|
+
} else if (orderB == null) {
|
|
1580
|
+
return 1;
|
|
1581
|
+
} else {
|
|
1582
|
+
return orderA - orderB;
|
|
1583
|
+
}
|
|
1584
|
+
});
|
|
1585
|
+
|
|
1586
|
+
// Wait until all panels have registered before we try to compute layout;
|
|
1587
|
+
// doing it earlier is both wasteful and may trigger misleading warnings in development mode.
|
|
1588
|
+
const panelElements = getPanelElementsForGroup(groupId);
|
|
1589
|
+
if (panelElements.length !== panelDataArray.length) {
|
|
1590
|
+
return;
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
// If this panel has been configured to persist sizing information,
|
|
1594
|
+
// default size should be restored from local storage if possible.
|
|
1595
|
+
let unsafeLayout = null;
|
|
1596
|
+
if (autoSaveId) {
|
|
1597
|
+
unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
|
|
1598
|
+
}
|
|
1599
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1600
|
+
if (groupSizePixels <= 0) {
|
|
1601
|
+
if (shouldMonitorPixelBasedConstraints(panelDataArray.map(({
|
|
1602
|
+
constraints
|
|
1603
|
+
}) => constraints))) {
|
|
1604
|
+
// Wait until the group has rendered a non-zero size before computing layout.
|
|
1605
|
+
return;
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
if (unsafeLayout == null) {
|
|
1609
|
+
unsafeLayout = calculateUnsafeDefaultLayout({
|
|
1610
|
+
groupSizePixels,
|
|
1611
|
+
panelDataArray
|
|
1610
1612
|
});
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
// Validate even saved layouts in case something has changed since last render
|
|
1616
|
+
// e.g. for pixel groups, this could be the size of the window
|
|
1617
|
+
const nextLayout = validatePanelGroupLayout({
|
|
1618
|
+
groupSizePixels,
|
|
1619
|
+
layout: unsafeLayout,
|
|
1620
|
+
panelConstraints: panelDataArray.map(panelData => panelData.constraints)
|
|
1611
1621
|
});
|
|
1622
|
+
if (!areEqual(prevLayout, nextLayout)) {
|
|
1623
|
+
setLayout(nextLayout);
|
|
1624
|
+
committedValuesRef.current.layout = nextLayout;
|
|
1625
|
+
if (onLayout) {
|
|
1626
|
+
onLayout(nextLayout.map(sizePercentage => ({
|
|
1627
|
+
sizePercentage,
|
|
1628
|
+
sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
|
|
1629
|
+
})));
|
|
1630
|
+
}
|
|
1631
|
+
callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
|
|
1632
|
+
}
|
|
1612
1633
|
}, []);
|
|
1613
1634
|
const registerResizeHandle = useCallback(dragHandleId => {
|
|
1614
1635
|
return function resizeHandler(event) {
|
|
@@ -1678,6 +1699,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1678
1699
|
}
|
|
1679
1700
|
if (layoutChanged) {
|
|
1680
1701
|
setLayout(nextLayout);
|
|
1702
|
+
committedValuesRef.current.layout = nextLayout;
|
|
1681
1703
|
if (onLayout) {
|
|
1682
1704
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1683
1705
|
sizePercentage,
|
|
@@ -1715,6 +1737,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1715
1737
|
});
|
|
1716
1738
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
1717
1739
|
setLayout(nextLayout);
|
|
1740
|
+
committedValuesRef.current.layout = nextLayout;
|
|
1718
1741
|
if (onLayout) {
|
|
1719
1742
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1720
1743
|
sizePercentage,
|
|
@@ -1742,16 +1765,84 @@ function PanelGroupWithForwardedRef({
|
|
|
1742
1765
|
resetGlobalCursorStyle();
|
|
1743
1766
|
setDragState(null);
|
|
1744
1767
|
}, []);
|
|
1768
|
+
const unregisterPanelRef = useRef({
|
|
1769
|
+
pendingPanelIds: new Set(),
|
|
1770
|
+
timeout: null
|
|
1771
|
+
});
|
|
1745
1772
|
const unregisterPanel = useCallback(panelData => {
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1773
|
+
const {
|
|
1774
|
+
id: groupId,
|
|
1775
|
+
layout: prevLayout,
|
|
1776
|
+
onLayout,
|
|
1777
|
+
panelDataArray
|
|
1778
|
+
} = committedValuesRef.current;
|
|
1779
|
+
const index = panelDataArray.indexOf(panelData);
|
|
1780
|
+
if (index >= 0) {
|
|
1781
|
+
panelDataArray.splice(index, 1);
|
|
1782
|
+
unregisterPanelRef.current.pendingPanelIds.add(panelData.id);
|
|
1783
|
+
}
|
|
1784
|
+
if (unregisterPanelRef.current.timeout != null) {
|
|
1785
|
+
clearTimeout(unregisterPanelRef.current.timeout);
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
// Batch panel unmounts so that we only calculate layout once;
|
|
1789
|
+
// This is more efficient and avoids misleading warnings in development mode.
|
|
1790
|
+
// We can't check the DOM to detect this because Panel elements have not yet been removed.
|
|
1791
|
+
unregisterPanelRef.current.timeout = setTimeout(() => {
|
|
1792
|
+
const {
|
|
1793
|
+
pendingPanelIds
|
|
1794
|
+
} = unregisterPanelRef.current;
|
|
1795
|
+
panelIdToLastNotifiedMixedSizesMapRef.current;
|
|
1796
|
+
|
|
1797
|
+
// TRICKY
|
|
1798
|
+
// Strict effects mode
|
|
1799
|
+
let unmountDueToStrictMode = false;
|
|
1800
|
+
pendingPanelIds.forEach(panelId => {
|
|
1801
|
+
pendingPanelIds.delete(panelId);
|
|
1802
|
+
if (panelDataArray.find(({
|
|
1803
|
+
id
|
|
1804
|
+
}) => id === panelId) == null) {
|
|
1805
|
+
unmountDueToStrictMode = true;
|
|
1806
|
+
|
|
1807
|
+
// TRICKY
|
|
1808
|
+
// When a panel is removed from the group, we should delete the most recent prev-size entry for it.
|
|
1809
|
+
// If we don't do this, then a conditionally rendered panel might not call onResize when it's re-mounted.
|
|
1810
|
+
// Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
|
|
1811
|
+
delete panelIdToLastNotifiedMixedSizesMapRef.current[panelData.id];
|
|
1812
|
+
}
|
|
1813
|
+
});
|
|
1814
|
+
if (!unmountDueToStrictMode) {
|
|
1815
|
+
return;
|
|
1752
1816
|
}
|
|
1753
|
-
|
|
1754
|
-
|
|
1817
|
+
if (panelDataArray.length === 0) {
|
|
1818
|
+
// The group is unmounting; skip layout calculation.
|
|
1819
|
+
return;
|
|
1820
|
+
}
|
|
1821
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1822
|
+
let unsafeLayout = calculateUnsafeDefaultLayout({
|
|
1823
|
+
groupSizePixels,
|
|
1824
|
+
panelDataArray
|
|
1825
|
+
});
|
|
1826
|
+
|
|
1827
|
+
// Validate even saved layouts in case something has changed since last render
|
|
1828
|
+
// e.g. for pixel groups, this could be the size of the window
|
|
1829
|
+
const nextLayout = validatePanelGroupLayout({
|
|
1830
|
+
groupSizePixels,
|
|
1831
|
+
layout: unsafeLayout,
|
|
1832
|
+
panelConstraints: panelDataArray.map(panelData => panelData.constraints)
|
|
1833
|
+
});
|
|
1834
|
+
if (!areEqual(prevLayout, nextLayout)) {
|
|
1835
|
+
setLayout(nextLayout);
|
|
1836
|
+
committedValuesRef.current.layout = nextLayout;
|
|
1837
|
+
if (onLayout) {
|
|
1838
|
+
onLayout(nextLayout.map(sizePercentage => ({
|
|
1839
|
+
sizePercentage,
|
|
1840
|
+
sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
|
|
1841
|
+
})));
|
|
1842
|
+
}
|
|
1843
|
+
callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
|
|
1844
|
+
}
|
|
1845
|
+
}, 0);
|
|
1755
1846
|
}, []);
|
|
1756
1847
|
const context = useMemo(() => ({
|
|
1757
1848
|
collapsePanel,
|