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
|
@@ -91,6 +91,7 @@ function PanelWithForwardedRef({
|
|
|
91
91
|
expandPanel,
|
|
92
92
|
getPanelSize,
|
|
93
93
|
getPanelStyle,
|
|
94
|
+
groupId,
|
|
94
95
|
isPanelCollapsed,
|
|
95
96
|
registerPanel,
|
|
96
97
|
resizePanel,
|
|
@@ -156,6 +157,7 @@ function PanelWithForwardedRef({
|
|
|
156
157
|
// CSS selectors
|
|
157
158
|
"data-panel": "",
|
|
158
159
|
"data-panel-id": panelId,
|
|
160
|
+
"data-panel-group-id": groupId,
|
|
159
161
|
// e2e test attributes
|
|
160
162
|
"data-panel-collapsible": undefined,
|
|
161
163
|
"data-panel-size": undefined
|
|
@@ -630,6 +632,7 @@ function getResizeHandlePanelIds(groupId, handleId, panelsArray) {
|
|
|
630
632
|
|
|
631
633
|
function useWindowSplitterPanelGroupBehavior({
|
|
632
634
|
committedValuesRef,
|
|
635
|
+
eagerValuesRef,
|
|
633
636
|
groupId,
|
|
634
637
|
layout,
|
|
635
638
|
panelDataArray,
|
|
@@ -641,7 +644,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
641
644
|
useEffect(() => {
|
|
642
645
|
const {
|
|
643
646
|
panelDataArray
|
|
644
|
-
} =
|
|
647
|
+
} = eagerValuesRef.current;
|
|
645
648
|
const groupElement = getPanelGroupElement(groupId);
|
|
646
649
|
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
647
650
|
const handles = getResizeHandleElementsForGroup(groupId);
|
|
@@ -699,7 +702,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
699
702
|
return () => {
|
|
700
703
|
cleanupFunctions.forEach(cleanupFunction => cleanupFunction());
|
|
701
704
|
};
|
|
702
|
-
}, [committedValuesRef, groupId, layout, panelDataArray, setLayout]);
|
|
705
|
+
}, [committedValuesRef, eagerValuesRef, groupId, layout, panelDataArray, setLayout]);
|
|
703
706
|
}
|
|
704
707
|
|
|
705
708
|
function areEqual(arrayA, arrayB) {
|
|
@@ -796,6 +799,44 @@ function calculateDeltaPercentage(event, groupId, dragHandleId, direction, initi
|
|
|
796
799
|
}
|
|
797
800
|
}
|
|
798
801
|
|
|
802
|
+
function calculateUnsafeDefaultLayout({
|
|
803
|
+
groupSizePixels,
|
|
804
|
+
panelDataArray
|
|
805
|
+
}) {
|
|
806
|
+
const layout = Array(panelDataArray.length);
|
|
807
|
+
const panelDataConstraints = panelDataArray.map(panelData => panelData.constraints);
|
|
808
|
+
let numPanelsWithSizes = 0;
|
|
809
|
+
let remainingSize = 100;
|
|
810
|
+
|
|
811
|
+
// Distribute default sizes first
|
|
812
|
+
for (let index = 0; index < panelDataArray.length; index++) {
|
|
813
|
+
const {
|
|
814
|
+
defaultSizePercentage
|
|
815
|
+
} = computePercentagePanelConstraints(panelDataConstraints, index, groupSizePixels);
|
|
816
|
+
if (defaultSizePercentage != null) {
|
|
817
|
+
numPanelsWithSizes++;
|
|
818
|
+
layout[index] = defaultSizePercentage;
|
|
819
|
+
remainingSize -= defaultSizePercentage;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// Remaining size should be distributed evenly between panels without default sizes
|
|
824
|
+
for (let index = 0; index < panelDataArray.length; index++) {
|
|
825
|
+
const {
|
|
826
|
+
defaultSizePercentage
|
|
827
|
+
} = computePercentagePanelConstraints(panelDataConstraints, index, groupSizePixels);
|
|
828
|
+
if (defaultSizePercentage != null) {
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
const numRemainingPanels = panelDataArray.length - numPanelsWithSizes;
|
|
832
|
+
const size = remainingSize / numRemainingPanels;
|
|
833
|
+
numPanelsWithSizes++;
|
|
834
|
+
layout[index] = size;
|
|
835
|
+
remainingSize -= size;
|
|
836
|
+
}
|
|
837
|
+
return layout;
|
|
838
|
+
}
|
|
839
|
+
|
|
799
840
|
function convertPercentageToPixels(percentage, groupSizePixels) {
|
|
800
841
|
return percentage / 100 * groupSizePixels;
|
|
801
842
|
}
|
|
@@ -946,6 +987,10 @@ function debounce(callback, durationMs = 10) {
|
|
|
946
987
|
return callable;
|
|
947
988
|
}
|
|
948
989
|
|
|
990
|
+
function getPanelElementsForGroup(groupId) {
|
|
991
|
+
return Array.from(document.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
|
|
992
|
+
}
|
|
993
|
+
|
|
949
994
|
// PanelGroup might be rendering in a server-side environment where localStorage is not available
|
|
950
995
|
// or on a browser with cookies/storage disabled.
|
|
951
996
|
// In either case, this function avoids accessing localStorage until needed,
|
|
@@ -1001,6 +1046,15 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
|
1001
1046
|
} catch (error) {}
|
|
1002
1047
|
return null;
|
|
1003
1048
|
}
|
|
1049
|
+
function loadPanelLayout(autoSaveId, panels, storage) {
|
|
1050
|
+
const state = loadSerializedPanelGroupState(autoSaveId, storage);
|
|
1051
|
+
if (state) {
|
|
1052
|
+
var _state$key;
|
|
1053
|
+
const key = getSerializationKey(panels);
|
|
1054
|
+
return (_state$key = state[key]) !== null && _state$key !== void 0 ? _state$key : null;
|
|
1055
|
+
}
|
|
1056
|
+
return null;
|
|
1057
|
+
}
|
|
1004
1058
|
function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
|
|
1005
1059
|
const key = getSerializationKey(panels);
|
|
1006
1060
|
const state = loadSerializedPanelGroupState(autoSaveId, storage) || {};
|
|
@@ -1012,6 +1066,12 @@ function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
|
|
|
1012
1066
|
}
|
|
1013
1067
|
}
|
|
1014
1068
|
|
|
1069
|
+
function shouldMonitorPixelBasedConstraints(constraints) {
|
|
1070
|
+
return constraints.some(constraints => {
|
|
1071
|
+
return constraints.collapsedSizePixels !== undefined || constraints.maxSizePixels !== undefined || constraints.minSizePixels !== undefined;
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1015
1075
|
// All units must be in percentages; pixel values should be pre-converted
|
|
1016
1076
|
function validatePanelGroupLayout({
|
|
1017
1077
|
groupSizePixels,
|
|
@@ -1080,7 +1140,7 @@ const defaultStorage = {
|
|
|
1080
1140
|
};
|
|
1081
1141
|
const debounceMap = {};
|
|
1082
1142
|
function PanelGroupWithForwardedRef({
|
|
1083
|
-
autoSaveId,
|
|
1143
|
+
autoSaveId = null,
|
|
1084
1144
|
children,
|
|
1085
1145
|
className: classNameFromProps = "",
|
|
1086
1146
|
dataAttributes,
|
|
@@ -1097,20 +1157,22 @@ function PanelGroupWithForwardedRef({
|
|
|
1097
1157
|
const groupId = useUniqueId(idFromProps);
|
|
1098
1158
|
const [dragState, setDragState] = useState(null);
|
|
1099
1159
|
const [layout, setLayout] = useState([]);
|
|
1100
|
-
const [panelDataArray, setPanelDataArray] = useState([]);
|
|
1101
1160
|
const panelIdToLastNotifiedMixedSizesMapRef = useRef({});
|
|
1102
1161
|
const panelSizeBeforeCollapseRef = useRef(new Map());
|
|
1103
1162
|
const prevDeltaRef = useRef(0);
|
|
1104
|
-
const [imperativeApiQueue, setImperativeApiQueue] = useState([]);
|
|
1105
1163
|
const committedValuesRef = useRef({
|
|
1164
|
+
autoSaveId,
|
|
1106
1165
|
direction,
|
|
1107
1166
|
dragState,
|
|
1108
1167
|
id: groupId,
|
|
1109
1168
|
keyboardResizeByPercentage,
|
|
1110
1169
|
keyboardResizeByPixels,
|
|
1111
|
-
layout,
|
|
1112
1170
|
onLayout,
|
|
1113
|
-
|
|
1171
|
+
storage
|
|
1172
|
+
});
|
|
1173
|
+
const eagerValuesRef = useRef({
|
|
1174
|
+
layout,
|
|
1175
|
+
panelDataArray: []
|
|
1114
1176
|
});
|
|
1115
1177
|
useRef({
|
|
1116
1178
|
didLogIdAndOrderWarning: false,
|
|
@@ -1121,9 +1183,11 @@ function PanelGroupWithForwardedRef({
|
|
|
1121
1183
|
getId: () => committedValuesRef.current.id,
|
|
1122
1184
|
getLayout: () => {
|
|
1123
1185
|
const {
|
|
1124
|
-
id: groupId
|
|
1125
|
-
layout
|
|
1186
|
+
id: groupId
|
|
1126
1187
|
} = committedValuesRef.current;
|
|
1188
|
+
const {
|
|
1189
|
+
layout
|
|
1190
|
+
} = eagerValuesRef.current;
|
|
1127
1191
|
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1128
1192
|
return layout.map(sizePercentage => {
|
|
1129
1193
|
return {
|
|
@@ -1135,10 +1199,12 @@ function PanelGroupWithForwardedRef({
|
|
|
1135
1199
|
setLayout: mixedSizes => {
|
|
1136
1200
|
const {
|
|
1137
1201
|
id: groupId,
|
|
1202
|
+
onLayout
|
|
1203
|
+
} = committedValuesRef.current;
|
|
1204
|
+
const {
|
|
1138
1205
|
layout: prevLayout,
|
|
1139
|
-
onLayout,
|
|
1140
1206
|
panelDataArray
|
|
1141
|
-
} =
|
|
1207
|
+
} = eagerValuesRef.current;
|
|
1142
1208
|
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1143
1209
|
const unsafeLayout = mixedSizes.map(mixedSize => getPercentageSizeFromMixedSizes(mixedSize, groupSizePixels));
|
|
1144
1210
|
const safeLayout = validatePanelGroupLayout({
|
|
@@ -1148,6 +1214,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1148
1214
|
});
|
|
1149
1215
|
if (!areEqual(prevLayout, safeLayout)) {
|
|
1150
1216
|
setLayout(safeLayout);
|
|
1217
|
+
eagerValuesRef.current.layout = safeLayout;
|
|
1151
1218
|
if (onLayout) {
|
|
1152
1219
|
onLayout(safeLayout.map(sizePercentage => ({
|
|
1153
1220
|
sizePercentage,
|
|
@@ -1158,14 +1225,20 @@ function PanelGroupWithForwardedRef({
|
|
|
1158
1225
|
}
|
|
1159
1226
|
}
|
|
1160
1227
|
}), []);
|
|
1228
|
+
|
|
1161
1229
|
useWindowSplitterPanelGroupBehavior({
|
|
1162
1230
|
committedValuesRef,
|
|
1231
|
+
eagerValuesRef,
|
|
1163
1232
|
groupId,
|
|
1164
1233
|
layout,
|
|
1165
|
-
panelDataArray,
|
|
1234
|
+
panelDataArray: eagerValuesRef.current.panelDataArray,
|
|
1166
1235
|
setLayout
|
|
1167
1236
|
});
|
|
1168
1237
|
useEffect(() => {
|
|
1238
|
+
const {
|
|
1239
|
+
panelDataArray
|
|
1240
|
+
} = eagerValuesRef.current;
|
|
1241
|
+
|
|
1169
1242
|
// If this panel has been configured to persist sizing information, save sizes to local storage.
|
|
1170
1243
|
if (autoSaveId) {
|
|
1171
1244
|
if (layout.length === 0 || layout.length !== panelDataArray.length) {
|
|
@@ -1178,7 +1251,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1178
1251
|
}
|
|
1179
1252
|
debounceMap[autoSaveId](autoSaveId, panelDataArray, layout, storage);
|
|
1180
1253
|
}
|
|
1181
|
-
}, [autoSaveId, layout,
|
|
1254
|
+
}, [autoSaveId, layout, storage]);
|
|
1182
1255
|
|
|
1183
1256
|
// DEV warnings
|
|
1184
1257
|
useEffect(() => {
|
|
@@ -1186,22 +1259,13 @@ function PanelGroupWithForwardedRef({
|
|
|
1186
1259
|
|
|
1187
1260
|
// External APIs are safe to memoize via committed values ref
|
|
1188
1261
|
const collapsePanel = useCallback(panelData => {
|
|
1262
|
+
const {
|
|
1263
|
+
onLayout
|
|
1264
|
+
} = committedValuesRef.current;
|
|
1189
1265
|
const {
|
|
1190
1266
|
layout: prevLayout,
|
|
1191
|
-
onLayout,
|
|
1192
1267
|
panelDataArray
|
|
1193
|
-
} =
|
|
1194
|
-
|
|
1195
|
-
// See issues/211
|
|
1196
|
-
if (panelDataArray.find(({
|
|
1197
|
-
id
|
|
1198
|
-
}) => id === panelData.id) == null) {
|
|
1199
|
-
setImperativeApiQueue(prev => [...prev, {
|
|
1200
|
-
panelData,
|
|
1201
|
-
type: "collapse"
|
|
1202
|
-
}]);
|
|
1203
|
-
return;
|
|
1204
|
-
}
|
|
1268
|
+
} = eagerValuesRef.current;
|
|
1205
1269
|
if (panelData.constraints.collapsible) {
|
|
1206
1270
|
const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
|
|
1207
1271
|
const {
|
|
@@ -1226,6 +1290,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1226
1290
|
});
|
|
1227
1291
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
1228
1292
|
setLayout(nextLayout);
|
|
1293
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1229
1294
|
if (onLayout) {
|
|
1230
1295
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1231
1296
|
sizePercentage,
|
|
@@ -1240,22 +1305,13 @@ function PanelGroupWithForwardedRef({
|
|
|
1240
1305
|
|
|
1241
1306
|
// External APIs are safe to memoize via committed values ref
|
|
1242
1307
|
const expandPanel = useCallback(panelData => {
|
|
1308
|
+
const {
|
|
1309
|
+
onLayout
|
|
1310
|
+
} = committedValuesRef.current;
|
|
1243
1311
|
const {
|
|
1244
1312
|
layout: prevLayout,
|
|
1245
|
-
onLayout,
|
|
1246
1313
|
panelDataArray
|
|
1247
|
-
} =
|
|
1248
|
-
|
|
1249
|
-
// See issues/211
|
|
1250
|
-
if (panelDataArray.find(({
|
|
1251
|
-
id
|
|
1252
|
-
}) => id === panelData.id) == null) {
|
|
1253
|
-
setImperativeApiQueue(prev => [...prev, {
|
|
1254
|
-
panelData,
|
|
1255
|
-
type: "expand"
|
|
1256
|
-
}]);
|
|
1257
|
-
return;
|
|
1258
|
-
}
|
|
1314
|
+
} = eagerValuesRef.current;
|
|
1259
1315
|
if (panelData.constraints.collapsible) {
|
|
1260
1316
|
const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
|
|
1261
1317
|
const {
|
|
@@ -1281,6 +1337,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1281
1337
|
});
|
|
1282
1338
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
1283
1339
|
setLayout(nextLayout);
|
|
1340
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1284
1341
|
if (onLayout) {
|
|
1285
1342
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1286
1343
|
sizePercentage,
|
|
@@ -1298,7 +1355,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1298
1355
|
const {
|
|
1299
1356
|
layout,
|
|
1300
1357
|
panelDataArray
|
|
1301
|
-
} =
|
|
1358
|
+
} = eagerValuesRef.current;
|
|
1302
1359
|
const {
|
|
1303
1360
|
panelSizePercentage,
|
|
1304
1361
|
panelSizePixels
|
|
@@ -1311,6 +1368,9 @@ function PanelGroupWithForwardedRef({
|
|
|
1311
1368
|
|
|
1312
1369
|
// This API should never read from committedValuesRef
|
|
1313
1370
|
const getPanelStyle = useCallback(panelData => {
|
|
1371
|
+
const {
|
|
1372
|
+
panelDataArray
|
|
1373
|
+
} = eagerValuesRef.current;
|
|
1314
1374
|
const panelIndex = panelDataArray.indexOf(panelData);
|
|
1315
1375
|
return computePanelFlexBoxStyle({
|
|
1316
1376
|
dragState,
|
|
@@ -1318,14 +1378,14 @@ function PanelGroupWithForwardedRef({
|
|
|
1318
1378
|
panelData: panelDataArray,
|
|
1319
1379
|
panelIndex
|
|
1320
1380
|
});
|
|
1321
|
-
}, [dragState, layout
|
|
1381
|
+
}, [dragState, layout]);
|
|
1322
1382
|
|
|
1323
1383
|
// External APIs are safe to memoize via committed values ref
|
|
1324
1384
|
const isPanelCollapsed = useCallback(panelData => {
|
|
1325
1385
|
const {
|
|
1326
1386
|
layout,
|
|
1327
1387
|
panelDataArray
|
|
1328
|
-
} =
|
|
1388
|
+
} = eagerValuesRef.current;
|
|
1329
1389
|
const {
|
|
1330
1390
|
collapsedSizePercentage,
|
|
1331
1391
|
collapsible,
|
|
@@ -1339,7 +1399,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1339
1399
|
const {
|
|
1340
1400
|
layout,
|
|
1341
1401
|
panelDataArray
|
|
1342
|
-
} =
|
|
1402
|
+
} = eagerValuesRef.current;
|
|
1343
1403
|
const {
|
|
1344
1404
|
collapsedSizePercentage,
|
|
1345
1405
|
collapsible,
|
|
@@ -1348,22 +1408,82 @@ function PanelGroupWithForwardedRef({
|
|
|
1348
1408
|
return !collapsible || panelSizePercentage > collapsedSizePercentage;
|
|
1349
1409
|
}, [groupId]);
|
|
1350
1410
|
const registerPanel = useCallback(panelData => {
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1411
|
+
const {
|
|
1412
|
+
autoSaveId,
|
|
1413
|
+
id: groupId,
|
|
1414
|
+
onLayout,
|
|
1415
|
+
storage
|
|
1416
|
+
} = committedValuesRef.current;
|
|
1417
|
+
const {
|
|
1418
|
+
layout: prevLayout,
|
|
1419
|
+
panelDataArray
|
|
1420
|
+
} = eagerValuesRef.current;
|
|
1421
|
+
panelDataArray.push(panelData);
|
|
1422
|
+
panelDataArray.sort((panelA, panelB) => {
|
|
1423
|
+
const orderA = panelA.order;
|
|
1424
|
+
const orderB = panelB.order;
|
|
1425
|
+
if (orderA == null && orderB == null) {
|
|
1426
|
+
return 0;
|
|
1427
|
+
} else if (orderA == null) {
|
|
1428
|
+
return -1;
|
|
1429
|
+
} else if (orderB == null) {
|
|
1430
|
+
return 1;
|
|
1431
|
+
} else {
|
|
1432
|
+
return orderA - orderB;
|
|
1433
|
+
}
|
|
1434
|
+
});
|
|
1435
|
+
|
|
1436
|
+
// Wait until all panels have registered before we try to compute layout;
|
|
1437
|
+
// doing it earlier is both wasteful and may trigger misleading warnings in development mode.
|
|
1438
|
+
const panelElements = getPanelElementsForGroup(groupId);
|
|
1439
|
+
if (panelElements.length !== panelDataArray.length) {
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
// If this panel has been configured to persist sizing information,
|
|
1444
|
+
// default size should be restored from local storage if possible.
|
|
1445
|
+
let unsafeLayout = null;
|
|
1446
|
+
if (autoSaveId) {
|
|
1447
|
+
unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
|
|
1448
|
+
}
|
|
1449
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1450
|
+
if (groupSizePixels <= 0) {
|
|
1451
|
+
if (shouldMonitorPixelBasedConstraints(panelDataArray.map(({
|
|
1452
|
+
constraints
|
|
1453
|
+
}) => constraints))) {
|
|
1454
|
+
// Wait until the group has rendered a non-zero size before computing layout.
|
|
1455
|
+
return;
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
if (unsafeLayout == null) {
|
|
1459
|
+
unsafeLayout = calculateUnsafeDefaultLayout({
|
|
1460
|
+
groupSizePixels,
|
|
1461
|
+
panelDataArray
|
|
1365
1462
|
});
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
// Validate even saved layouts in case something has changed since last render
|
|
1466
|
+
// e.g. for pixel groups, this could be the size of the window
|
|
1467
|
+
const nextLayout = validatePanelGroupLayout({
|
|
1468
|
+
groupSizePixels,
|
|
1469
|
+
layout: unsafeLayout,
|
|
1470
|
+
panelConstraints: panelDataArray.map(panelData => panelData.constraints)
|
|
1366
1471
|
});
|
|
1472
|
+
|
|
1473
|
+
// Offscreen mode makes this a bit weird;
|
|
1474
|
+
// Panels unregister when hidden and re-register when shown again,
|
|
1475
|
+
// but the overall layout doesn't change between these two cases.
|
|
1476
|
+
setLayout(nextLayout);
|
|
1477
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1478
|
+
if (!areEqual(prevLayout, nextLayout)) {
|
|
1479
|
+
if (onLayout) {
|
|
1480
|
+
onLayout(nextLayout.map(sizePercentage => ({
|
|
1481
|
+
sizePercentage,
|
|
1482
|
+
sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
|
|
1483
|
+
})));
|
|
1484
|
+
}
|
|
1485
|
+
callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
|
|
1486
|
+
}
|
|
1367
1487
|
}, []);
|
|
1368
1488
|
const registerResizeHandle = useCallback(dragHandleId => {
|
|
1369
1489
|
return function resizeHandler(event) {
|
|
@@ -1374,10 +1494,12 @@ function PanelGroupWithForwardedRef({
|
|
|
1374
1494
|
id: groupId,
|
|
1375
1495
|
keyboardResizeByPercentage,
|
|
1376
1496
|
keyboardResizeByPixels,
|
|
1377
|
-
onLayout
|
|
1378
|
-
panelDataArray,
|
|
1379
|
-
layout: prevLayout
|
|
1497
|
+
onLayout
|
|
1380
1498
|
} = committedValuesRef.current;
|
|
1499
|
+
const {
|
|
1500
|
+
layout: prevLayout,
|
|
1501
|
+
panelDataArray
|
|
1502
|
+
} = eagerValuesRef.current;
|
|
1381
1503
|
const {
|
|
1382
1504
|
initialLayout
|
|
1383
1505
|
} = dragState !== null && dragState !== void 0 ? dragState : {};
|
|
@@ -1433,6 +1555,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1433
1555
|
}
|
|
1434
1556
|
if (layoutChanged) {
|
|
1435
1557
|
setLayout(nextLayout);
|
|
1558
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1436
1559
|
if (onLayout) {
|
|
1437
1560
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1438
1561
|
sizePercentage,
|
|
@@ -1446,23 +1569,13 @@ function PanelGroupWithForwardedRef({
|
|
|
1446
1569
|
|
|
1447
1570
|
// External APIs are safe to memoize via committed values ref
|
|
1448
1571
|
const resizePanel = useCallback((panelData, mixedSizes) => {
|
|
1572
|
+
const {
|
|
1573
|
+
onLayout
|
|
1574
|
+
} = committedValuesRef.current;
|
|
1449
1575
|
const {
|
|
1450
1576
|
layout: prevLayout,
|
|
1451
|
-
onLayout,
|
|
1452
1577
|
panelDataArray
|
|
1453
|
-
} =
|
|
1454
|
-
|
|
1455
|
-
// See issues/211
|
|
1456
|
-
if (panelDataArray.find(({
|
|
1457
|
-
id
|
|
1458
|
-
}) => id === panelData.id) == null) {
|
|
1459
|
-
setImperativeApiQueue(prev => [...prev, {
|
|
1460
|
-
panelData,
|
|
1461
|
-
mixedSizes,
|
|
1462
|
-
type: "resize"
|
|
1463
|
-
}]);
|
|
1464
|
-
return;
|
|
1465
|
-
}
|
|
1578
|
+
} = eagerValuesRef.current;
|
|
1466
1579
|
const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
|
|
1467
1580
|
const {
|
|
1468
1581
|
groupSizePixels,
|
|
@@ -1482,6 +1595,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1482
1595
|
});
|
|
1483
1596
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
1484
1597
|
setLayout(nextLayout);
|
|
1598
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1485
1599
|
if (onLayout) {
|
|
1486
1600
|
onLayout(nextLayout.map(sizePercentage => ({
|
|
1487
1601
|
sizePercentage,
|
|
@@ -1493,9 +1607,11 @@ function PanelGroupWithForwardedRef({
|
|
|
1493
1607
|
}, [groupId]);
|
|
1494
1608
|
const startDragging = useCallback((dragHandleId, event) => {
|
|
1495
1609
|
const {
|
|
1496
|
-
direction
|
|
1497
|
-
layout
|
|
1610
|
+
direction
|
|
1498
1611
|
} = committedValuesRef.current;
|
|
1612
|
+
const {
|
|
1613
|
+
layout
|
|
1614
|
+
} = eagerValuesRef.current;
|
|
1499
1615
|
const handleElement = getResizeHandleElement(dragHandleId);
|
|
1500
1616
|
const initialCursorPosition = getResizeEventCursorPosition(direction, event);
|
|
1501
1617
|
setDragState({
|
|
@@ -1509,16 +1625,86 @@ function PanelGroupWithForwardedRef({
|
|
|
1509
1625
|
resetGlobalCursorStyle();
|
|
1510
1626
|
setDragState(null);
|
|
1511
1627
|
}, []);
|
|
1628
|
+
const unregisterPanelRef = useRef({
|
|
1629
|
+
pendingPanelIds: new Set(),
|
|
1630
|
+
timeout: null
|
|
1631
|
+
});
|
|
1512
1632
|
const unregisterPanel = useCallback(panelData => {
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1633
|
+
const {
|
|
1634
|
+
id: groupId,
|
|
1635
|
+
onLayout
|
|
1636
|
+
} = committedValuesRef.current;
|
|
1637
|
+
const {
|
|
1638
|
+
layout: prevLayout,
|
|
1639
|
+
panelDataArray
|
|
1640
|
+
} = eagerValuesRef.current;
|
|
1641
|
+
const index = panelDataArray.indexOf(panelData);
|
|
1642
|
+
if (index >= 0) {
|
|
1643
|
+
panelDataArray.splice(index, 1);
|
|
1644
|
+
unregisterPanelRef.current.pendingPanelIds.add(panelData.id);
|
|
1645
|
+
}
|
|
1646
|
+
if (unregisterPanelRef.current.timeout != null) {
|
|
1647
|
+
clearTimeout(unregisterPanelRef.current.timeout);
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
// Batch panel unmounts so that we only calculate layout once;
|
|
1651
|
+
// This is more efficient and avoids misleading warnings in development mode.
|
|
1652
|
+
// We can't check the DOM to detect this because Panel elements have not yet been removed.
|
|
1653
|
+
unregisterPanelRef.current.timeout = setTimeout(() => {
|
|
1654
|
+
const {
|
|
1655
|
+
pendingPanelIds
|
|
1656
|
+
} = unregisterPanelRef.current;
|
|
1657
|
+
const map = panelIdToLastNotifiedMixedSizesMapRef.current;
|
|
1658
|
+
|
|
1659
|
+
// TRICKY
|
|
1660
|
+
// Strict effects mode
|
|
1661
|
+
let unmountDueToStrictMode = false;
|
|
1662
|
+
pendingPanelIds.forEach(panelId => {
|
|
1663
|
+
pendingPanelIds.delete(panelId);
|
|
1664
|
+
if (panelDataArray.find(({
|
|
1665
|
+
id
|
|
1666
|
+
}) => id === panelId) == null) {
|
|
1667
|
+
unmountDueToStrictMode = true;
|
|
1668
|
+
|
|
1669
|
+
// TRICKY
|
|
1670
|
+
// When a panel is removed from the group, we should delete the most recent prev-size entry for it.
|
|
1671
|
+
// If we don't do this, then a conditionally rendered panel might not call onResize when it's re-mounted.
|
|
1672
|
+
// Strict effects mode makes this tricky though because all panels will be registered, unregistered, then re-registered on mount.
|
|
1673
|
+
delete map[panelData.id];
|
|
1674
|
+
}
|
|
1675
|
+
});
|
|
1676
|
+
if (!unmountDueToStrictMode) {
|
|
1677
|
+
return;
|
|
1519
1678
|
}
|
|
1520
|
-
|
|
1521
|
-
|
|
1679
|
+
if (panelDataArray.length === 0) {
|
|
1680
|
+
// The group is unmounting; skip layout calculation.
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
|
|
1684
|
+
let unsafeLayout = calculateUnsafeDefaultLayout({
|
|
1685
|
+
groupSizePixels,
|
|
1686
|
+
panelDataArray
|
|
1687
|
+
});
|
|
1688
|
+
|
|
1689
|
+
// Validate even saved layouts in case something has changed since last render
|
|
1690
|
+
// e.g. for pixel groups, this could be the size of the window
|
|
1691
|
+
const nextLayout = validatePanelGroupLayout({
|
|
1692
|
+
groupSizePixels,
|
|
1693
|
+
layout: unsafeLayout,
|
|
1694
|
+
panelConstraints: panelDataArray.map(panelData => panelData.constraints)
|
|
1695
|
+
});
|
|
1696
|
+
if (!areEqual(prevLayout, nextLayout)) {
|
|
1697
|
+
setLayout(nextLayout);
|
|
1698
|
+
eagerValuesRef.current.layout = nextLayout;
|
|
1699
|
+
if (onLayout) {
|
|
1700
|
+
onLayout(nextLayout.map(sizePercentage => ({
|
|
1701
|
+
sizePercentage,
|
|
1702
|
+
sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
|
|
1703
|
+
})));
|
|
1704
|
+
}
|
|
1705
|
+
callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
|
|
1706
|
+
}
|
|
1707
|
+
}, 0);
|
|
1522
1708
|
}, []);
|
|
1523
1709
|
const context = useMemo(() => ({
|
|
1524
1710
|
collapsePanel,
|