react-resizable-panels 0.0.59 → 0.0.61
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/dist/declarations/src/PanelGroup.d.ts +2 -2
- package/dist/react-resizable-panels.browser.cjs.js +226 -166
- package/dist/react-resizable-panels.browser.development.cjs.js +229 -169
- package/dist/react-resizable-panels.browser.development.esm.js +229 -169
- package/dist/react-resizable-panels.browser.esm.js +226 -166
- package/dist/react-resizable-panels.cjs.js +226 -166
- package/dist/react-resizable-panels.cjs.js.map +1 -1
- package/dist/react-resizable-panels.development.cjs.js +229 -169
- package/dist/react-resizable-panels.development.esm.js +229 -169
- package/dist/react-resizable-panels.development.node.cjs.js +273 -87
- package/dist/react-resizable-panels.development.node.esm.js +273 -87
- package/dist/react-resizable-panels.esm.js +226 -166
- package/dist/react-resizable-panels.esm.js.map +1 -1
- package/dist/react-resizable-panels.node.cjs.js +270 -84
- package/dist/react-resizable-panels.node.esm.js +270 -84
- package/package.json +1 -1
- package/src/Panel.ts +2 -0
- package/src/PanelGroup.ts +242 -208
- package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +12 -2
- package/src/utils/dom/getPanelElementsForGroup.ts +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.0.61
|
|
4
|
+
|
|
5
|
+
- Better unstable Offscreen/Activity API.
|
|
6
|
+
|
|
7
|
+
## 0.0.60
|
|
8
|
+
|
|
9
|
+
- Better support imperative API usage from mount effects.
|
|
10
|
+
- Better support strict effects mode.
|
|
11
|
+
- Better checks not to call `onResize` or `onLayout` more than once.
|
|
12
|
+
|
|
3
13
|
## 0.0.59
|
|
4
14
|
|
|
5
15
|
- Support imperative panel API usage on-mount.
|
|
@@ -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
|
|
@@ -709,6 +711,7 @@ function getResizeHandlePanelIds(groupId, handleId, panelsArray) {
|
|
|
709
711
|
|
|
710
712
|
function useWindowSplitterPanelGroupBehavior({
|
|
711
713
|
committedValuesRef,
|
|
714
|
+
eagerValuesRef,
|
|
712
715
|
groupId,
|
|
713
716
|
layout,
|
|
714
717
|
panelDataArray,
|
|
@@ -751,7 +754,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
751
754
|
useEffect(() => {
|
|
752
755
|
const {
|
|
753
756
|
panelDataArray
|
|
754
|
-
} =
|
|
757
|
+
} = eagerValuesRef.current;
|
|
755
758
|
const groupElement = getPanelGroupElement(groupId);
|
|
756
759
|
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
757
760
|
const handles = getResizeHandleElementsForGroup(groupId);
|
|
@@ -809,7 +812,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
809
812
|
return () => {
|
|
810
813
|
cleanupFunctions.forEach(cleanupFunction => cleanupFunction());
|
|
811
814
|
};
|
|
812
|
-
}, [committedValuesRef, groupId, layout, panelDataArray, setLayout]);
|
|
815
|
+
}, [committedValuesRef, eagerValuesRef, groupId, layout, panelDataArray, setLayout]);
|
|
813
816
|
}
|
|
814
817
|
|
|
815
818
|
function areEqual(arrayA, arrayB) {
|
|
@@ -1094,6 +1097,10 @@ function debounce(callback, durationMs = 10) {
|
|
|
1094
1097
|
return callable;
|
|
1095
1098
|
}
|
|
1096
1099
|
|
|
1100
|
+
function getPanelElementsForGroup(groupId) {
|
|
1101
|
+
return Array.from(document.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1097
1104
|
// PanelGroup might be rendering in a server-side environment where localStorage is not available
|
|
1098
1105
|
// or on a browser with cookies/storage disabled.
|
|
1099
1106
|
// In either case, this function avoids accessing localStorage until needed,
|
|
@@ -1243,7 +1250,7 @@ const defaultStorage = {
|
|
|
1243
1250
|
};
|
|
1244
1251
|
const debounceMap = {};
|
|
1245
1252
|
function PanelGroupWithForwardedRef({
|
|
1246
|
-
autoSaveId,
|
|
1253
|
+
autoSaveId = null,
|
|
1247
1254
|
children,
|
|
1248
1255
|
className: classNameFromProps = "",
|
|
1249
1256
|
dataAttributes,
|
|
@@ -1260,20 +1267,22 @@ function PanelGroupWithForwardedRef({
|
|
|
1260
1267
|
const groupId = useUniqueId(idFromProps);
|
|
1261
1268
|
const [dragState, setDragState] = useState(null);
|
|
1262
1269
|
const [layout, setLayout] = useState([]);
|
|
1263
|
-
const [panelDataArray, setPanelDataArray] = useState([]);
|
|
1264
1270
|
const panelIdToLastNotifiedMixedSizesMapRef = useRef({});
|
|
1265
1271
|
const panelSizeBeforeCollapseRef = useRef(new Map());
|
|
1266
1272
|
const prevDeltaRef = useRef(0);
|
|
1267
|
-
const [imperativeApiQueue, setImperativeApiQueue] = useState([]);
|
|
1268
1273
|
const committedValuesRef = useRef({
|
|
1274
|
+
autoSaveId,
|
|
1269
1275
|
direction,
|
|
1270
1276
|
dragState,
|
|
1271
1277
|
id: groupId,
|
|
1272
1278
|
keyboardResizeByPercentage,
|
|
1273
1279
|
keyboardResizeByPixels,
|
|
1274
|
-
layout,
|
|
1275
1280
|
onLayout,
|
|
1276
|
-
|
|
1281
|
+
storage
|
|
1282
|
+
});
|
|
1283
|
+
const eagerValuesRef = useRef({
|
|
1284
|
+
layout,
|
|
1285
|
+
panelDataArray: []
|
|
1277
1286
|
});
|
|
1278
1287
|
useRef({
|
|
1279
1288
|
didLogIdAndOrderWarning: false,
|
|
@@ -1284,9 +1293,11 @@ function PanelGroupWithForwardedRef({
|
|
|
1284
1293
|
getId: () => committedValuesRef.current.id,
|
|
1285
1294
|
getLayout: () => {
|
|
1286
1295
|
const {
|
|
1287
|
-
id: groupId
|
|
1288
|
-
layout
|
|
1296
|
+
id: groupId
|
|
1289
1297
|
} = committedValuesRef.current;
|
|
1298
|
+
const {
|
|
1299
|
+
layout
|
|
1300
|
+
} = eagerValuesRef.current;
|
|
1290
1301
|
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1291
1302
|
return layout.map(sizePercentage => {
|
|
1292
1303
|
return {
|
|
@@ -1298,10 +1309,12 @@ function PanelGroupWithForwardedRef({
|
|
|
1298
1309
|
setLayout: mixedSizes => {
|
|
1299
1310
|
const {
|
|
1300
1311
|
id: groupId,
|
|
1312
|
+
onLayout
|
|
1313
|
+
} = committedValuesRef.current;
|
|
1314
|
+
const {
|
|
1301
1315
|
layout: prevLayout,
|
|
1302
|
-
onLayout,
|
|
1303
1316
|
panelDataArray
|
|
1304
|
-
} =
|
|
1317
|
+
} = eagerValuesRef.current;
|
|
1305
1318
|
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1306
1319
|
const unsafeLayout = mixedSizes.map(mixedSize => getPercentageSizeFromMixedSizes(mixedSize, groupSizePixels));
|
|
1307
1320
|
const safeLayout = validatePanelGroupLayout({
|
|
@@ -1311,6 +1324,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1311
1324
|
});
|
|
1312
1325
|
if (!areEqual(prevLayout, safeLayout)) {
|
|
1313
1326
|
setLayout(safeLayout);
|
|
1327
|
+
eagerValuesRef.current.layout = safeLayout;
|
|
1314
1328
|
if (onLayout) {
|
|
1315
1329
|
onLayout(safeLayout.map(sizePercentage => ({
|
|
1316
1330
|
sizePercentage,
|
|
@@ -1322,21 +1336,30 @@ function PanelGroupWithForwardedRef({
|
|
|
1322
1336
|
}
|
|
1323
1337
|
}), []);
|
|
1324
1338
|
useIsomorphicLayoutEffect(() => {
|
|
1339
|
+
committedValuesRef.current.autoSaveId = autoSaveId;
|
|
1325
1340
|
committedValuesRef.current.direction = direction;
|
|
1326
1341
|
committedValuesRef.current.dragState = dragState;
|
|
1327
1342
|
committedValuesRef.current.id = groupId;
|
|
1328
|
-
committedValuesRef.current.layout = layout;
|
|
1329
1343
|
committedValuesRef.current.onLayout = onLayout;
|
|
1330
|
-
committedValuesRef.current.
|
|
1344
|
+
committedValuesRef.current.storage = storage;
|
|
1345
|
+
|
|
1346
|
+
// panelDataArray and layout are updated in-sync with scheduled state updates.
|
|
1347
|
+
// TODO [217] Move these values into a separate ref
|
|
1331
1348
|
});
|
|
1349
|
+
|
|
1332
1350
|
useWindowSplitterPanelGroupBehavior({
|
|
1333
1351
|
committedValuesRef,
|
|
1352
|
+
eagerValuesRef,
|
|
1334
1353
|
groupId,
|
|
1335
1354
|
layout,
|
|
1336
|
-
panelDataArray,
|
|
1355
|
+
panelDataArray: eagerValuesRef.current.panelDataArray,
|
|
1337
1356
|
setLayout
|
|
1338
1357
|
});
|
|
1339
1358
|
useEffect(() => {
|
|
1359
|
+
const {
|
|
1360
|
+
panelDataArray
|
|
1361
|
+
} = eagerValuesRef.current;
|
|
1362
|
+
|
|
1340
1363
|
// If this panel has been configured to persist sizing information, save sizes to local storage.
|
|
1341
1364
|
if (autoSaveId) {
|
|
1342
1365
|
if (layout.length === 0 || layout.length !== panelDataArray.length) {
|
|
@@ -1349,63 +1372,12 @@ function PanelGroupWithForwardedRef({
|
|
|
1349
1372
|
}
|
|
1350
1373
|
debounceMap[autoSaveId](autoSaveId, panelDataArray, layout, storage);
|
|
1351
1374
|
}
|
|
1352
|
-
}, [autoSaveId, layout,
|
|
1353
|
-
|
|
1354
|
-
// Once all panels have registered themselves,
|
|
1355
|
-
// Compute the initial sizes based on default weights.
|
|
1356
|
-
// This assumes that panels register during initial mount (no conditional rendering)!
|
|
1375
|
+
}, [autoSaveId, layout, storage]);
|
|
1357
1376
|
useIsomorphicLayoutEffect(() => {
|
|
1358
1377
|
const {
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
} = committedValuesRef.current;
|
|
1363
|
-
if (layout.length === panelDataArray.length) {
|
|
1364
|
-
// Only compute (or restore) default layout once per panel configuration.
|
|
1365
|
-
return;
|
|
1366
|
-
}
|
|
1367
|
-
|
|
1368
|
-
// If this panel has been configured to persist sizing information,
|
|
1369
|
-
// default size should be restored from local storage if possible.
|
|
1370
|
-
let unsafeLayout = null;
|
|
1371
|
-
if (autoSaveId) {
|
|
1372
|
-
unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
|
|
1373
|
-
}
|
|
1374
|
-
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1375
|
-
if (groupSizePixels <= 0) {
|
|
1376
|
-
if (shouldMonitorPixelBasedConstraints(panelDataArray.map(({
|
|
1377
|
-
constraints
|
|
1378
|
-
}) => constraints))) {
|
|
1379
|
-
// Wait until the group has rendered a non-zero size before computing layout.
|
|
1380
|
-
return;
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1383
|
-
if (unsafeLayout == null) {
|
|
1384
|
-
unsafeLayout = calculateUnsafeDefaultLayout({
|
|
1385
|
-
groupSizePixels,
|
|
1386
|
-
panelDataArray
|
|
1387
|
-
});
|
|
1388
|
-
}
|
|
1389
|
-
|
|
1390
|
-
// Validate even saved layouts in case something has changed since last render
|
|
1391
|
-
// e.g. for pixel groups, this could be the size of the window
|
|
1392
|
-
const validatedLayout = validatePanelGroupLayout({
|
|
1393
|
-
groupSizePixels,
|
|
1394
|
-
layout: unsafeLayout,
|
|
1395
|
-
panelConstraints: panelDataArray.map(panelData => panelData.constraints)
|
|
1396
|
-
});
|
|
1397
|
-
if (!areEqual(layout, validatedLayout)) {
|
|
1398
|
-
setLayout(validatedLayout);
|
|
1399
|
-
}
|
|
1400
|
-
if (onLayout) {
|
|
1401
|
-
onLayout(validatedLayout.map(sizePercentage => ({
|
|
1402
|
-
sizePercentage,
|
|
1403
|
-
sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
|
|
1404
|
-
})));
|
|
1405
|
-
}
|
|
1406
|
-
callPanelCallbacks(groupId, panelDataArray, validatedLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
|
|
1407
|
-
}, [autoSaveId, layout, panelDataArray, storage]);
|
|
1408
|
-
useIsomorphicLayoutEffect(() => {
|
|
1378
|
+
layout: prevLayout,
|
|
1379
|
+
panelDataArray
|
|
1380
|
+
} = eagerValuesRef.current;
|
|
1409
1381
|
const constraints = panelDataArray.map(({
|
|
1410
1382
|
constraints
|
|
1411
1383
|
}) => constraints);
|
|
@@ -1419,7 +1391,6 @@ function PanelGroupWithForwardedRef({
|
|
|
1419
1391
|
const resizeObserver = new ResizeObserver(() => {
|
|
1420
1392
|
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1421
1393
|
const {
|
|
1422
|
-
layout: prevLayout,
|
|
1423
1394
|
onLayout
|
|
1424
1395
|
} = committedValuesRef.current;
|
|
1425
1396
|
const nextLayout = validatePanelGroupLayout({
|
|
@@ -1429,6 +1400,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1429
1400
|
});
|
|
1430
1401
|
if (!areEqual(prevLayout, nextLayout)) {
|
|
1431
1402
|
setLayout(nextLayout);
|
|
1403
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1432
1404
|
if (onLayout) {
|
|
1433
1405
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1434
1406
|
sizePercentage,
|
|
@@ -1443,7 +1415,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1443
1415
|
resizeObserver.disconnect();
|
|
1444
1416
|
};
|
|
1445
1417
|
}
|
|
1446
|
-
}, [groupId
|
|
1418
|
+
}, [groupId]);
|
|
1447
1419
|
|
|
1448
1420
|
// DEV warnings
|
|
1449
1421
|
useEffect(() => {
|
|
@@ -1451,22 +1423,13 @@ function PanelGroupWithForwardedRef({
|
|
|
1451
1423
|
|
|
1452
1424
|
// External APIs are safe to memoize via committed values ref
|
|
1453
1425
|
const collapsePanel = useCallback(panelData => {
|
|
1426
|
+
const {
|
|
1427
|
+
onLayout
|
|
1428
|
+
} = committedValuesRef.current;
|
|
1454
1429
|
const {
|
|
1455
1430
|
layout: prevLayout,
|
|
1456
|
-
onLayout,
|
|
1457
1431
|
panelDataArray
|
|
1458
|
-
} =
|
|
1459
|
-
|
|
1460
|
-
// See issues/211
|
|
1461
|
-
if (panelDataArray.find(({
|
|
1462
|
-
id
|
|
1463
|
-
}) => id === panelData.id) == null) {
|
|
1464
|
-
setImperativeApiQueue(prev => [...prev, {
|
|
1465
|
-
panelData,
|
|
1466
|
-
type: "collapse"
|
|
1467
|
-
}]);
|
|
1468
|
-
return;
|
|
1469
|
-
}
|
|
1432
|
+
} = eagerValuesRef.current;
|
|
1470
1433
|
if (panelData.constraints.collapsible) {
|
|
1471
1434
|
const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
|
|
1472
1435
|
const {
|
|
@@ -1491,6 +1454,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1491
1454
|
});
|
|
1492
1455
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
1493
1456
|
setLayout(nextLayout);
|
|
1457
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1494
1458
|
if (onLayout) {
|
|
1495
1459
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1496
1460
|
sizePercentage,
|
|
@@ -1505,22 +1469,13 @@ function PanelGroupWithForwardedRef({
|
|
|
1505
1469
|
|
|
1506
1470
|
// External APIs are safe to memoize via committed values ref
|
|
1507
1471
|
const expandPanel = useCallback(panelData => {
|
|
1472
|
+
const {
|
|
1473
|
+
onLayout
|
|
1474
|
+
} = committedValuesRef.current;
|
|
1508
1475
|
const {
|
|
1509
1476
|
layout: prevLayout,
|
|
1510
|
-
onLayout,
|
|
1511
1477
|
panelDataArray
|
|
1512
|
-
} =
|
|
1513
|
-
|
|
1514
|
-
// See issues/211
|
|
1515
|
-
if (panelDataArray.find(({
|
|
1516
|
-
id
|
|
1517
|
-
}) => id === panelData.id) == null) {
|
|
1518
|
-
setImperativeApiQueue(prev => [...prev, {
|
|
1519
|
-
panelData,
|
|
1520
|
-
type: "expand"
|
|
1521
|
-
}]);
|
|
1522
|
-
return;
|
|
1523
|
-
}
|
|
1478
|
+
} = eagerValuesRef.current;
|
|
1524
1479
|
if (panelData.constraints.collapsible) {
|
|
1525
1480
|
const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
|
|
1526
1481
|
const {
|
|
@@ -1546,6 +1501,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1546
1501
|
});
|
|
1547
1502
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
1548
1503
|
setLayout(nextLayout);
|
|
1504
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1549
1505
|
if (onLayout) {
|
|
1550
1506
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1551
1507
|
sizePercentage,
|
|
@@ -1563,7 +1519,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1563
1519
|
const {
|
|
1564
1520
|
layout,
|
|
1565
1521
|
panelDataArray
|
|
1566
|
-
} =
|
|
1522
|
+
} = eagerValuesRef.current;
|
|
1567
1523
|
const {
|
|
1568
1524
|
panelSizePercentage,
|
|
1569
1525
|
panelSizePixels
|
|
@@ -1576,6 +1532,9 @@ function PanelGroupWithForwardedRef({
|
|
|
1576
1532
|
|
|
1577
1533
|
// This API should never read from committedValuesRef
|
|
1578
1534
|
const getPanelStyle = useCallback(panelData => {
|
|
1535
|
+
const {
|
|
1536
|
+
panelDataArray
|
|
1537
|
+
} = eagerValuesRef.current;
|
|
1579
1538
|
const panelIndex = panelDataArray.indexOf(panelData);
|
|
1580
1539
|
return computePanelFlexBoxStyle({
|
|
1581
1540
|
dragState,
|
|
@@ -1583,14 +1542,14 @@ function PanelGroupWithForwardedRef({
|
|
|
1583
1542
|
panelData: panelDataArray,
|
|
1584
1543
|
panelIndex
|
|
1585
1544
|
});
|
|
1586
|
-
}, [dragState, layout
|
|
1545
|
+
}, [dragState, layout]);
|
|
1587
1546
|
|
|
1588
1547
|
// External APIs are safe to memoize via committed values ref
|
|
1589
1548
|
const isPanelCollapsed = useCallback(panelData => {
|
|
1590
1549
|
const {
|
|
1591
1550
|
layout,
|
|
1592
1551
|
panelDataArray
|
|
1593
|
-
} =
|
|
1552
|
+
} = eagerValuesRef.current;
|
|
1594
1553
|
const {
|
|
1595
1554
|
collapsedSizePercentage,
|
|
1596
1555
|
collapsible,
|
|
@@ -1604,7 +1563,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1604
1563
|
const {
|
|
1605
1564
|
layout,
|
|
1606
1565
|
panelDataArray
|
|
1607
|
-
} =
|
|
1566
|
+
} = eagerValuesRef.current;
|
|
1608
1567
|
const {
|
|
1609
1568
|
collapsedSizePercentage,
|
|
1610
1569
|
collapsible,
|
|
@@ -1613,22 +1572,82 @@ function PanelGroupWithForwardedRef({
|
|
|
1613
1572
|
return !collapsible || panelSizePercentage > collapsedSizePercentage;
|
|
1614
1573
|
}, [groupId]);
|
|
1615
1574
|
const registerPanel = useCallback(panelData => {
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1575
|
+
const {
|
|
1576
|
+
autoSaveId,
|
|
1577
|
+
id: groupId,
|
|
1578
|
+
onLayout,
|
|
1579
|
+
storage
|
|
1580
|
+
} = committedValuesRef.current;
|
|
1581
|
+
const {
|
|
1582
|
+
layout: prevLayout,
|
|
1583
|
+
panelDataArray
|
|
1584
|
+
} = eagerValuesRef.current;
|
|
1585
|
+
panelDataArray.push(panelData);
|
|
1586
|
+
panelDataArray.sort((panelA, panelB) => {
|
|
1587
|
+
const orderA = panelA.order;
|
|
1588
|
+
const orderB = panelB.order;
|
|
1589
|
+
if (orderA == null && orderB == null) {
|
|
1590
|
+
return 0;
|
|
1591
|
+
} else if (orderA == null) {
|
|
1592
|
+
return -1;
|
|
1593
|
+
} else if (orderB == null) {
|
|
1594
|
+
return 1;
|
|
1595
|
+
} else {
|
|
1596
|
+
return orderA - orderB;
|
|
1597
|
+
}
|
|
1598
|
+
});
|
|
1599
|
+
|
|
1600
|
+
// Wait until all panels have registered before we try to compute layout;
|
|
1601
|
+
// doing it earlier is both wasteful and may trigger misleading warnings in development mode.
|
|
1602
|
+
const panelElements = getPanelElementsForGroup(groupId);
|
|
1603
|
+
if (panelElements.length !== panelDataArray.length) {
|
|
1604
|
+
return;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
// If this panel has been configured to persist sizing information,
|
|
1608
|
+
// default size should be restored from local storage if possible.
|
|
1609
|
+
let unsafeLayout = null;
|
|
1610
|
+
if (autoSaveId) {
|
|
1611
|
+
unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
|
|
1612
|
+
}
|
|
1613
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1614
|
+
if (groupSizePixels <= 0) {
|
|
1615
|
+
if (shouldMonitorPixelBasedConstraints(panelDataArray.map(({
|
|
1616
|
+
constraints
|
|
1617
|
+
}) => constraints))) {
|
|
1618
|
+
// Wait until the group has rendered a non-zero size before computing layout.
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
if (unsafeLayout == null) {
|
|
1623
|
+
unsafeLayout = calculateUnsafeDefaultLayout({
|
|
1624
|
+
groupSizePixels,
|
|
1625
|
+
panelDataArray
|
|
1630
1626
|
});
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
// Validate even saved layouts in case something has changed since last render
|
|
1630
|
+
// e.g. for pixel groups, this could be the size of the window
|
|
1631
|
+
const nextLayout = validatePanelGroupLayout({
|
|
1632
|
+
groupSizePixels,
|
|
1633
|
+
layout: unsafeLayout,
|
|
1634
|
+
panelConstraints: panelDataArray.map(panelData => panelData.constraints)
|
|
1631
1635
|
});
|
|
1636
|
+
|
|
1637
|
+
// Offscreen mode makes this a bit weird;
|
|
1638
|
+
// Panels unregister when hidden and re-register when shown again,
|
|
1639
|
+
// but the overall layout doesn't change between these two cases.
|
|
1640
|
+
setLayout(nextLayout);
|
|
1641
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1642
|
+
if (!areEqual(prevLayout, nextLayout)) {
|
|
1643
|
+
if (onLayout) {
|
|
1644
|
+
onLayout(nextLayout.map(sizePercentage => ({
|
|
1645
|
+
sizePercentage,
|
|
1646
|
+
sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
|
|
1647
|
+
})));
|
|
1648
|
+
}
|
|
1649
|
+
callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
|
|
1650
|
+
}
|
|
1632
1651
|
}, []);
|
|
1633
1652
|
const registerResizeHandle = useCallback(dragHandleId => {
|
|
1634
1653
|
return function resizeHandler(event) {
|
|
@@ -1639,10 +1658,12 @@ function PanelGroupWithForwardedRef({
|
|
|
1639
1658
|
id: groupId,
|
|
1640
1659
|
keyboardResizeByPercentage,
|
|
1641
1660
|
keyboardResizeByPixels,
|
|
1642
|
-
onLayout
|
|
1643
|
-
panelDataArray,
|
|
1644
|
-
layout: prevLayout
|
|
1661
|
+
onLayout
|
|
1645
1662
|
} = committedValuesRef.current;
|
|
1663
|
+
const {
|
|
1664
|
+
layout: prevLayout,
|
|
1665
|
+
panelDataArray
|
|
1666
|
+
} = eagerValuesRef.current;
|
|
1646
1667
|
const {
|
|
1647
1668
|
initialLayout
|
|
1648
1669
|
} = dragState !== null && dragState !== void 0 ? dragState : {};
|
|
@@ -1698,6 +1719,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1698
1719
|
}
|
|
1699
1720
|
if (layoutChanged) {
|
|
1700
1721
|
setLayout(nextLayout);
|
|
1722
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1701
1723
|
if (onLayout) {
|
|
1702
1724
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1703
1725
|
sizePercentage,
|
|
@@ -1711,23 +1733,13 @@ function PanelGroupWithForwardedRef({
|
|
|
1711
1733
|
|
|
1712
1734
|
// External APIs are safe to memoize via committed values ref
|
|
1713
1735
|
const resizePanel = useCallback((panelData, mixedSizes) => {
|
|
1736
|
+
const {
|
|
1737
|
+
onLayout
|
|
1738
|
+
} = committedValuesRef.current;
|
|
1714
1739
|
const {
|
|
1715
1740
|
layout: prevLayout,
|
|
1716
|
-
onLayout,
|
|
1717
1741
|
panelDataArray
|
|
1718
|
-
} =
|
|
1719
|
-
|
|
1720
|
-
// See issues/211
|
|
1721
|
-
if (panelDataArray.find(({
|
|
1722
|
-
id
|
|
1723
|
-
}) => id === panelData.id) == null) {
|
|
1724
|
-
setImperativeApiQueue(prev => [...prev, {
|
|
1725
|
-
panelData,
|
|
1726
|
-
mixedSizes,
|
|
1727
|
-
type: "resize"
|
|
1728
|
-
}]);
|
|
1729
|
-
return;
|
|
1730
|
-
}
|
|
1742
|
+
} = eagerValuesRef.current;
|
|
1731
1743
|
const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
|
|
1732
1744
|
const {
|
|
1733
1745
|
groupSizePixels,
|
|
@@ -1747,6 +1759,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1747
1759
|
});
|
|
1748
1760
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
1749
1761
|
setLayout(nextLayout);
|
|
1762
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1750
1763
|
if (onLayout) {
|
|
1751
1764
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1752
1765
|
sizePercentage,
|
|
@@ -1758,9 +1771,11 @@ function PanelGroupWithForwardedRef({
|
|
|
1758
1771
|
}, [groupId]);
|
|
1759
1772
|
const startDragging = useCallback((dragHandleId, event) => {
|
|
1760
1773
|
const {
|
|
1761
|
-
direction
|
|
1762
|
-
layout
|
|
1774
|
+
direction
|
|
1763
1775
|
} = committedValuesRef.current;
|
|
1776
|
+
const {
|
|
1777
|
+
layout
|
|
1778
|
+
} = eagerValuesRef.current;
|
|
1764
1779
|
const handleElement = getResizeHandleElement(dragHandleId);
|
|
1765
1780
|
const initialCursorPosition = getResizeEventCursorPosition(direction, event);
|
|
1766
1781
|
setDragState({
|
|
@@ -1774,42 +1789,87 @@ function PanelGroupWithForwardedRef({
|
|
|
1774
1789
|
resetGlobalCursorStyle();
|
|
1775
1790
|
setDragState(null);
|
|
1776
1791
|
}, []);
|
|
1792
|
+
const unregisterPanelRef = useRef({
|
|
1793
|
+
pendingPanelIds: new Set(),
|
|
1794
|
+
timeout: null
|
|
1795
|
+
});
|
|
1777
1796
|
const unregisterPanel = useCallback(panelData => {
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1797
|
+
const {
|
|
1798
|
+
id: groupId,
|
|
1799
|
+
onLayout
|
|
1800
|
+
} = committedValuesRef.current;
|
|
1801
|
+
const {
|
|
1802
|
+
layout: prevLayout,
|
|
1803
|
+
panelDataArray
|
|
1804
|
+
} = eagerValuesRef.current;
|
|
1805
|
+
const index = panelDataArray.indexOf(panelData);
|
|
1806
|
+
if (index >= 0) {
|
|
1807
|
+
panelDataArray.splice(index, 1);
|
|
1808
|
+
unregisterPanelRef.current.pendingPanelIds.add(panelData.id);
|
|
1809
|
+
}
|
|
1810
|
+
if (unregisterPanelRef.current.timeout != null) {
|
|
1811
|
+
clearTimeout(unregisterPanelRef.current.timeout);
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
// Batch panel unmounts so that we only calculate layout once;
|
|
1815
|
+
// This is more efficient and avoids misleading warnings in development mode.
|
|
1816
|
+
// We can't check the DOM to detect this because Panel elements have not yet been removed.
|
|
1817
|
+
unregisterPanelRef.current.timeout = setTimeout(() => {
|
|
1818
|
+
const {
|
|
1819
|
+
pendingPanelIds
|
|
1820
|
+
} = unregisterPanelRef.current;
|
|
1821
|
+
const map = panelIdToLastNotifiedMixedSizesMapRef.current;
|
|
1822
|
+
|
|
1823
|
+
// TRICKY
|
|
1824
|
+
// Strict effects mode
|
|
1825
|
+
let unmountDueToStrictMode = false;
|
|
1826
|
+
pendingPanelIds.forEach(panelId => {
|
|
1827
|
+
pendingPanelIds.delete(panelId);
|
|
1828
|
+
if (panelDataArray.find(({
|
|
1829
|
+
id
|
|
1830
|
+
}) => id === panelId) == null) {
|
|
1831
|
+
unmountDueToStrictMode = true;
|
|
1832
|
+
|
|
1833
|
+
// TRICKY
|
|
1834
|
+
// When a panel is removed from the group, we should delete the most recent prev-size entry for it.
|
|
1835
|
+
// If we don't do this, then a conditionally rendered panel might not call onResize when it's re-mounted.
|
|
1836
|
+
// Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
|
|
1837
|
+
delete map[panelData.id];
|
|
1838
|
+
}
|
|
1839
|
+
});
|
|
1840
|
+
if (!unmountDueToStrictMode) {
|
|
1841
|
+
return;
|
|
1784
1842
|
}
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1843
|
+
if (panelDataArray.length === 0) {
|
|
1844
|
+
// The group is unmounting; skip layout calculation.
|
|
1845
|
+
return;
|
|
1846
|
+
}
|
|
1847
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1848
|
+
let unsafeLayout = calculateUnsafeDefaultLayout({
|
|
1849
|
+
groupSizePixels,
|
|
1850
|
+
panelDataArray
|
|
1851
|
+
});
|
|
1788
1852
|
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
{
|
|
1807
|
-
resizePanel(current.panelData, current.mixedSizes);
|
|
1808
|
-
break;
|
|
1809
|
-
}
|
|
1853
|
+
// Validate even saved layouts in case something has changed since last render
|
|
1854
|
+
// e.g. for pixel groups, this could be the size of the window
|
|
1855
|
+
const nextLayout = validatePanelGroupLayout({
|
|
1856
|
+
groupSizePixels,
|
|
1857
|
+
layout: unsafeLayout,
|
|
1858
|
+
panelConstraints: panelDataArray.map(panelData => panelData.constraints)
|
|
1859
|
+
});
|
|
1860
|
+
if (!areEqual(prevLayout, nextLayout)) {
|
|
1861
|
+
setLayout(nextLayout);
|
|
1862
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1863
|
+
if (onLayout) {
|
|
1864
|
+
onLayout(nextLayout.map(sizePercentage => ({
|
|
1865
|
+
sizePercentage,
|
|
1866
|
+
sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
|
|
1867
|
+
})));
|
|
1868
|
+
}
|
|
1869
|
+
callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
|
|
1810
1870
|
}
|
|
1811
|
-
}
|
|
1812
|
-
}, [
|
|
1871
|
+
}, 0);
|
|
1872
|
+
}, []);
|
|
1813
1873
|
const context = useMemo(() => ({
|
|
1814
1874
|
collapsePanel,
|
|
1815
1875
|
direction,
|