react-resizable-panels 1.0.2 → 1.0.3

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.
@@ -960,11 +960,15 @@ function initializeDefaultStorage(storageObject) {
960
960
  }
961
961
  }
962
962
 
963
+ function getPanelGroupKey(autoSaveId) {
964
+ return `react-resizable-panels:${autoSaveId}`;
965
+ }
966
+
963
967
  // Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
964
968
  // so they should not be used as part of the serialization key.
965
969
  // Using the min/max size attributes should work well enough as a backup.
966
970
  // Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
967
- function getSerializationKey(panels) {
971
+ function getPanelKey(panels) {
968
972
  return panels.map(panel => {
969
973
  const {
970
974
  constraints,
@@ -981,7 +985,8 @@ function getSerializationKey(panels) {
981
985
  }
982
986
  function loadSerializedPanelGroupState(autoSaveId, storage) {
983
987
  try {
984
- const serialized = storage.getItem(`PanelGroup:layout:${autoSaveId}`);
988
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
989
+ const serialized = storage.getItem(panelGroupKey);
985
990
  if (serialized) {
986
991
  const parsed = JSON.parse(serialized);
987
992
  if (typeof parsed === "object" && parsed != null) {
@@ -991,21 +996,23 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
991
996
  } catch (error) {}
992
997
  return null;
993
998
  }
994
- function loadPanelLayout(autoSaveId, panels, storage) {
995
- const state = loadSerializedPanelGroupState(autoSaveId, storage);
996
- if (state) {
997
- var _state$key;
998
- const key = getSerializationKey(panels);
999
- return (_state$key = state[key]) !== null && _state$key !== void 0 ? _state$key : null;
1000
- }
1001
- return null;
999
+ function loadPanelGroupState(autoSaveId, panels, storage) {
1000
+ var _loadSerializedPanelG, _state$panelKey;
1001
+ const state = (_loadSerializedPanelG = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG !== void 0 ? _loadSerializedPanelG : {};
1002
+ const panelKey = getPanelKey(panels);
1003
+ return (_state$panelKey = state[panelKey]) !== null && _state$panelKey !== void 0 ? _state$panelKey : null;
1002
1004
  }
1003
- function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
1004
- const key = getSerializationKey(panels);
1005
- const state = loadSerializedPanelGroupState(autoSaveId, storage) || {};
1006
- state[key] = sizes;
1005
+ function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
1006
+ var _loadSerializedPanelG2;
1007
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
1008
+ const panelKey = getPanelKey(panels);
1009
+ const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
1010
+ state[panelKey] = {
1011
+ expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
1012
+ layout: sizes
1013
+ };
1007
1014
  try {
1008
- storage.setItem(`PanelGroup:layout:${autoSaveId}`, JSON.stringify(state));
1015
+ storage.setItem(panelGroupKey, JSON.stringify(state));
1009
1016
  } catch (error) {
1010
1017
  console.error(error);
1011
1018
  }
@@ -1149,7 +1156,6 @@ function PanelGroupWithForwardedRef({
1149
1156
  const groupId = useUniqueId(idFromProps);
1150
1157
  const [dragState, setDragState] = useState(null);
1151
1158
  const [layout, setLayout] = useState([]);
1152
- useState([]);
1153
1159
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1154
1160
  const panelSizeBeforeCollapseRef = useRef(new Map());
1155
1161
  const prevDeltaRef = useRef(0);
@@ -1232,13 +1238,15 @@ function PanelGroupWithForwardedRef({
1232
1238
 
1233
1239
  // Limit the frequency of localStorage updates.
1234
1240
  if (debouncedSave == null) {
1235
- debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1241
+ debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1236
1242
  debounceMap[autoSaveId] = debouncedSave;
1237
1243
  }
1238
1244
 
1239
- // Clone panel data array before saving since this array is mutated.
1240
- // If we don't clone, we run the risk of saving the wrong panel and layout pair.
1241
- debouncedSave(autoSaveId, [...panelDataArray], layout, storage);
1245
+ // Clone mutable data before passing to the debounced function,
1246
+ // else we run the risk of saving an incorrect combination of mutable and immutable values to state.
1247
+ const clonedPanelDataArray = [...panelDataArray];
1248
+ const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
1249
+ debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
1242
1250
  }
1243
1251
  }, [autoSaveId, layout, storage]);
1244
1252
 
@@ -1467,7 +1475,11 @@ function PanelGroupWithForwardedRef({
1467
1475
  // default size should be restored from local storage if possible.
1468
1476
  let unsafeLayout = null;
1469
1477
  if (autoSaveId) {
1470
- unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
1478
+ const state = loadPanelGroupState(autoSaveId, panelDataArray, storage);
1479
+ if (state) {
1480
+ panelSizeBeforeCollapseRef.current = new Map(Object.entries(state.expandToSizes));
1481
+ unsafeLayout = state.layout;
1482
+ }
1471
1483
  }
1472
1484
  if (unsafeLayout == null) {
1473
1485
  unsafeLayout = calculateUnsafeDefaultLayout({
@@ -835,11 +835,15 @@ function initializeDefaultStorage(storageObject) {
835
835
  }
836
836
  }
837
837
 
838
+ function getPanelGroupKey(autoSaveId) {
839
+ return `react-resizable-panels:${autoSaveId}`;
840
+ }
841
+
838
842
  // Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
839
843
  // so they should not be used as part of the serialization key.
840
844
  // Using the min/max size attributes should work well enough as a backup.
841
845
  // Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
842
- function getSerializationKey(panels) {
846
+ function getPanelKey(panels) {
843
847
  return panels.map(panel => {
844
848
  const {
845
849
  constraints,
@@ -856,7 +860,8 @@ function getSerializationKey(panels) {
856
860
  }
857
861
  function loadSerializedPanelGroupState(autoSaveId, storage) {
858
862
  try {
859
- const serialized = storage.getItem(`PanelGroup:layout:${autoSaveId}`);
863
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
864
+ const serialized = storage.getItem(panelGroupKey);
860
865
  if (serialized) {
861
866
  const parsed = JSON.parse(serialized);
862
867
  if (typeof parsed === "object" && parsed != null) {
@@ -866,12 +871,17 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
866
871
  } catch (error) {}
867
872
  return null;
868
873
  }
869
- function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
870
- const key = getSerializationKey(panels);
871
- const state = loadSerializedPanelGroupState(autoSaveId, storage) || {};
872
- state[key] = sizes;
874
+ function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
875
+ var _loadSerializedPanelG2;
876
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
877
+ const panelKey = getPanelKey(panels);
878
+ const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
879
+ state[panelKey] = {
880
+ expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
881
+ layout: sizes
882
+ };
873
883
  try {
874
- storage.setItem(`PanelGroup:layout:${autoSaveId}`, JSON.stringify(state));
884
+ storage.setItem(panelGroupKey, JSON.stringify(state));
875
885
  } catch (error) {
876
886
  console.error(error);
877
887
  }
@@ -1015,7 +1025,6 @@ function PanelGroupWithForwardedRef({
1015
1025
  const groupId = useUniqueId(idFromProps);
1016
1026
  const [dragState, setDragState] = useState(null);
1017
1027
  const [layout, setLayout] = useState([]);
1018
- useState([]);
1019
1028
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1020
1029
  const panelSizeBeforeCollapseRef = useRef(new Map());
1021
1030
  const prevDeltaRef = useRef(0);
@@ -1090,13 +1099,15 @@ function PanelGroupWithForwardedRef({
1090
1099
 
1091
1100
  // Limit the frequency of localStorage updates.
1092
1101
  if (debouncedSave == null) {
1093
- debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1102
+ debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1094
1103
  debounceMap[autoSaveId] = debouncedSave;
1095
1104
  }
1096
1105
 
1097
- // Clone panel data array before saving since this array is mutated.
1098
- // If we don't clone, we run the risk of saving the wrong panel and layout pair.
1099
- debouncedSave(autoSaveId, [...panelDataArray], layout, storage);
1106
+ // Clone mutable data before passing to the debounced function,
1107
+ // else we run the risk of saving an incorrect combination of mutable and immutable values to state.
1108
+ const clonedPanelDataArray = [...panelDataArray];
1109
+ const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
1110
+ debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
1100
1111
  }
1101
1112
  }, [autoSaveId, layout, storage]);
1102
1113
 
@@ -811,11 +811,15 @@ function initializeDefaultStorage(storageObject) {
811
811
  }
812
812
  }
813
813
 
814
+ function getPanelGroupKey(autoSaveId) {
815
+ return `react-resizable-panels:${autoSaveId}`;
816
+ }
817
+
814
818
  // Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
815
819
  // so they should not be used as part of the serialization key.
816
820
  // Using the min/max size attributes should work well enough as a backup.
817
821
  // Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
818
- function getSerializationKey(panels) {
822
+ function getPanelKey(panels) {
819
823
  return panels.map(panel => {
820
824
  const {
821
825
  constraints,
@@ -832,7 +836,8 @@ function getSerializationKey(panels) {
832
836
  }
833
837
  function loadSerializedPanelGroupState(autoSaveId, storage) {
834
838
  try {
835
- const serialized = storage.getItem(`PanelGroup:layout:${autoSaveId}`);
839
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
840
+ const serialized = storage.getItem(panelGroupKey);
836
841
  if (serialized) {
837
842
  const parsed = JSON.parse(serialized);
838
843
  if (typeof parsed === "object" && parsed != null) {
@@ -842,12 +847,17 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
842
847
  } catch (error) {}
843
848
  return null;
844
849
  }
845
- function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
846
- const key = getSerializationKey(panels);
847
- const state = loadSerializedPanelGroupState(autoSaveId, storage) || {};
848
- state[key] = sizes;
850
+ function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
851
+ var _loadSerializedPanelG2;
852
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
853
+ const panelKey = getPanelKey(panels);
854
+ const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
855
+ state[panelKey] = {
856
+ expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
857
+ layout: sizes
858
+ };
849
859
  try {
850
- storage.setItem(`PanelGroup:layout:${autoSaveId}`, JSON.stringify(state));
860
+ storage.setItem(panelGroupKey, JSON.stringify(state));
851
861
  } catch (error) {
852
862
  console.error(error);
853
863
  }
@@ -991,7 +1001,6 @@ function PanelGroupWithForwardedRef({
991
1001
  const groupId = useUniqueId(idFromProps);
992
1002
  const [dragState, setDragState] = useState(null);
993
1003
  const [layout, setLayout] = useState([]);
994
- useState([]);
995
1004
  const panelIdToLastNotifiedSizeMapRef = useRef({});
996
1005
  const panelSizeBeforeCollapseRef = useRef(new Map());
997
1006
  const prevDeltaRef = useRef(0);
@@ -1066,13 +1075,15 @@ function PanelGroupWithForwardedRef({
1066
1075
 
1067
1076
  // Limit the frequency of localStorage updates.
1068
1077
  if (debouncedSave == null) {
1069
- debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1078
+ debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1070
1079
  debounceMap[autoSaveId] = debouncedSave;
1071
1080
  }
1072
1081
 
1073
- // Clone panel data array before saving since this array is mutated.
1074
- // If we don't clone, we run the risk of saving the wrong panel and layout pair.
1075
- debouncedSave(autoSaveId, [...panelDataArray], layout, storage);
1082
+ // Clone mutable data before passing to the debounced function,
1083
+ // else we run the risk of saving an incorrect combination of mutable and immutable values to state.
1084
+ const clonedPanelDataArray = [...panelDataArray];
1085
+ const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
1086
+ debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
1076
1087
  }
1077
1088
  }, [autoSaveId, layout, storage]);
1078
1089
 
@@ -939,11 +939,15 @@ function initializeDefaultStorage(storageObject) {
939
939
  }
940
940
  }
941
941
 
942
+ function getPanelGroupKey(autoSaveId) {
943
+ return `react-resizable-panels:${autoSaveId}`;
944
+ }
945
+
942
946
  // Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
943
947
  // so they should not be used as part of the serialization key.
944
948
  // Using the min/max size attributes should work well enough as a backup.
945
949
  // Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
946
- function getSerializationKey(panels) {
950
+ function getPanelKey(panels) {
947
951
  return panels.map(panel => {
948
952
  const {
949
953
  constraints,
@@ -960,7 +964,8 @@ function getSerializationKey(panels) {
960
964
  }
961
965
  function loadSerializedPanelGroupState(autoSaveId, storage) {
962
966
  try {
963
- const serialized = storage.getItem(`PanelGroup:layout:${autoSaveId}`);
967
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
968
+ const serialized = storage.getItem(panelGroupKey);
964
969
  if (serialized) {
965
970
  const parsed = JSON.parse(serialized);
966
971
  if (typeof parsed === "object" && parsed != null) {
@@ -970,21 +975,23 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
970
975
  } catch (error) {}
971
976
  return null;
972
977
  }
973
- function loadPanelLayout(autoSaveId, panels, storage) {
974
- const state = loadSerializedPanelGroupState(autoSaveId, storage);
975
- if (state) {
976
- var _state$key;
977
- const key = getSerializationKey(panels);
978
- return (_state$key = state[key]) !== null && _state$key !== void 0 ? _state$key : null;
979
- }
980
- return null;
978
+ function loadPanelGroupState(autoSaveId, panels, storage) {
979
+ var _loadSerializedPanelG, _state$panelKey;
980
+ const state = (_loadSerializedPanelG = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG !== void 0 ? _loadSerializedPanelG : {};
981
+ const panelKey = getPanelKey(panels);
982
+ return (_state$panelKey = state[panelKey]) !== null && _state$panelKey !== void 0 ? _state$panelKey : null;
981
983
  }
982
- function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
983
- const key = getSerializationKey(panels);
984
- const state = loadSerializedPanelGroupState(autoSaveId, storage) || {};
985
- state[key] = sizes;
984
+ function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
985
+ var _loadSerializedPanelG2;
986
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
987
+ const panelKey = getPanelKey(panels);
988
+ const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
989
+ state[panelKey] = {
990
+ expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
991
+ layout: sizes
992
+ };
986
993
  try {
987
- storage.setItem(`PanelGroup:layout:${autoSaveId}`, JSON.stringify(state));
994
+ storage.setItem(panelGroupKey, JSON.stringify(state));
988
995
  } catch (error) {
989
996
  console.error(error);
990
997
  }
@@ -1081,7 +1088,6 @@ function PanelGroupWithForwardedRef({
1081
1088
  const groupId = useUniqueId(idFromProps);
1082
1089
  const [dragState, setDragState] = useState(null);
1083
1090
  const [layout, setLayout] = useState([]);
1084
- useState([]);
1085
1091
  const panelIdToLastNotifiedSizeMapRef = useRef({});
1086
1092
  const panelSizeBeforeCollapseRef = useRef(new Map());
1087
1093
  const prevDeltaRef = useRef(0);
@@ -1164,13 +1170,15 @@ function PanelGroupWithForwardedRef({
1164
1170
 
1165
1171
  // Limit the frequency of localStorage updates.
1166
1172
  if (debouncedSave == null) {
1167
- debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1173
+ debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1168
1174
  debounceMap[autoSaveId] = debouncedSave;
1169
1175
  }
1170
1176
 
1171
- // Clone panel data array before saving since this array is mutated.
1172
- // If we don't clone, we run the risk of saving the wrong panel and layout pair.
1173
- debouncedSave(autoSaveId, [...panelDataArray], layout, storage);
1177
+ // Clone mutable data before passing to the debounced function,
1178
+ // else we run the risk of saving an incorrect combination of mutable and immutable values to state.
1179
+ const clonedPanelDataArray = [...panelDataArray];
1180
+ const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
1181
+ debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
1174
1182
  }
1175
1183
  }, [autoSaveId, layout, storage]);
1176
1184
 
@@ -1357,7 +1365,11 @@ function PanelGroupWithForwardedRef({
1357
1365
  // default size should be restored from local storage if possible.
1358
1366
  let unsafeLayout = null;
1359
1367
  if (autoSaveId) {
1360
- unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
1368
+ const state = loadPanelGroupState(autoSaveId, panelDataArray, storage);
1369
+ if (state) {
1370
+ panelSizeBeforeCollapseRef.current = new Map(Object.entries(state.expandToSizes));
1371
+ unsafeLayout = state.layout;
1372
+ }
1361
1373
  }
1362
1374
  if (unsafeLayout == null) {
1363
1375
  unsafeLayout = calculateUnsafeDefaultLayout({
@@ -824,11 +824,15 @@ function initializeDefaultStorage(storageObject) {
824
824
  }
825
825
  }
826
826
 
827
+ function getPanelGroupKey(autoSaveId) {
828
+ return `react-resizable-panels:${autoSaveId}`;
829
+ }
830
+
827
831
  // Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
828
832
  // so they should not be used as part of the serialization key.
829
833
  // Using the min/max size attributes should work well enough as a backup.
830
834
  // Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
831
- function getSerializationKey(panels) {
835
+ function getPanelKey(panels) {
832
836
  return panels.map(panel => {
833
837
  const {
834
838
  constraints,
@@ -845,7 +849,8 @@ function getSerializationKey(panels) {
845
849
  }
846
850
  function loadSerializedPanelGroupState(autoSaveId, storage) {
847
851
  try {
848
- const serialized = storage.getItem(`PanelGroup:layout:${autoSaveId}`);
852
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
853
+ const serialized = storage.getItem(panelGroupKey);
849
854
  if (serialized) {
850
855
  const parsed = JSON.parse(serialized);
851
856
  if (typeof parsed === "object" && parsed != null) {
@@ -855,12 +860,17 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
855
860
  } catch (error) {}
856
861
  return null;
857
862
  }
858
- function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
859
- const key = getSerializationKey(panels);
860
- const state = loadSerializedPanelGroupState(autoSaveId, storage) || {};
861
- state[key] = sizes;
863
+ function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
864
+ var _loadSerializedPanelG2;
865
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
866
+ const panelKey = getPanelKey(panels);
867
+ const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
868
+ state[panelKey] = {
869
+ expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
870
+ layout: sizes
871
+ };
862
872
  try {
863
- storage.setItem(`PanelGroup:layout:${autoSaveId}`, JSON.stringify(state));
873
+ storage.setItem(panelGroupKey, JSON.stringify(state));
864
874
  } catch (error) {
865
875
  console.error(error);
866
876
  }
@@ -957,7 +967,6 @@ function PanelGroupWithForwardedRef({
957
967
  const groupId = useUniqueId(idFromProps);
958
968
  const [dragState, setDragState] = useState(null);
959
969
  const [layout, setLayout] = useState([]);
960
- useState([]);
961
970
  const panelIdToLastNotifiedSizeMapRef = useRef({});
962
971
  const panelSizeBeforeCollapseRef = useRef(new Map());
963
972
  const prevDeltaRef = useRef(0);
@@ -1032,13 +1041,15 @@ function PanelGroupWithForwardedRef({
1032
1041
 
1033
1042
  // Limit the frequency of localStorage updates.
1034
1043
  if (debouncedSave == null) {
1035
- debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1044
+ debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1036
1045
  debounceMap[autoSaveId] = debouncedSave;
1037
1046
  }
1038
1047
 
1039
- // Clone panel data array before saving since this array is mutated.
1040
- // If we don't clone, we run the risk of saving the wrong panel and layout pair.
1041
- debouncedSave(autoSaveId, [...panelDataArray], layout, storage);
1048
+ // Clone mutable data before passing to the debounced function,
1049
+ // else we run the risk of saving an incorrect combination of mutable and immutable values to state.
1050
+ const clonedPanelDataArray = [...panelDataArray];
1051
+ const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
1052
+ debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
1042
1053
  }
1043
1054
  }, [autoSaveId, layout, storage]);
1044
1055
 
@@ -800,11 +800,15 @@ function initializeDefaultStorage(storageObject) {
800
800
  }
801
801
  }
802
802
 
803
+ function getPanelGroupKey(autoSaveId) {
804
+ return `react-resizable-panels:${autoSaveId}`;
805
+ }
806
+
803
807
  // Note that Panel ids might be user-provided (stable) or useId generated (non-deterministic)
804
808
  // so they should not be used as part of the serialization key.
805
809
  // Using the min/max size attributes should work well enough as a backup.
806
810
  // Pre-sorting by minSize allows remembering layouts even if panels are re-ordered/dragged.
807
- function getSerializationKey(panels) {
811
+ function getPanelKey(panels) {
808
812
  return panels.map(panel => {
809
813
  const {
810
814
  constraints,
@@ -821,7 +825,8 @@ function getSerializationKey(panels) {
821
825
  }
822
826
  function loadSerializedPanelGroupState(autoSaveId, storage) {
823
827
  try {
824
- const serialized = storage.getItem(`PanelGroup:layout:${autoSaveId}`);
828
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
829
+ const serialized = storage.getItem(panelGroupKey);
825
830
  if (serialized) {
826
831
  const parsed = JSON.parse(serialized);
827
832
  if (typeof parsed === "object" && parsed != null) {
@@ -831,12 +836,17 @@ function loadSerializedPanelGroupState(autoSaveId, storage) {
831
836
  } catch (error) {}
832
837
  return null;
833
838
  }
834
- function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
835
- const key = getSerializationKey(panels);
836
- const state = loadSerializedPanelGroupState(autoSaveId, storage) || {};
837
- state[key] = sizes;
839
+ function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
840
+ var _loadSerializedPanelG2;
841
+ const panelGroupKey = getPanelGroupKey(autoSaveId);
842
+ const panelKey = getPanelKey(panels);
843
+ const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
844
+ state[panelKey] = {
845
+ expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
846
+ layout: sizes
847
+ };
838
848
  try {
839
- storage.setItem(`PanelGroup:layout:${autoSaveId}`, JSON.stringify(state));
849
+ storage.setItem(panelGroupKey, JSON.stringify(state));
840
850
  } catch (error) {
841
851
  console.error(error);
842
852
  }
@@ -933,7 +943,6 @@ function PanelGroupWithForwardedRef({
933
943
  const groupId = useUniqueId(idFromProps);
934
944
  const [dragState, setDragState] = useState(null);
935
945
  const [layout, setLayout] = useState([]);
936
- useState([]);
937
946
  const panelIdToLastNotifiedSizeMapRef = useRef({});
938
947
  const panelSizeBeforeCollapseRef = useRef(new Map());
939
948
  const prevDeltaRef = useRef(0);
@@ -1008,13 +1017,15 @@ function PanelGroupWithForwardedRef({
1008
1017
 
1009
1018
  // Limit the frequency of localStorage updates.
1010
1019
  if (debouncedSave == null) {
1011
- debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1020
+ debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1012
1021
  debounceMap[autoSaveId] = debouncedSave;
1013
1022
  }
1014
1023
 
1015
- // Clone panel data array before saving since this array is mutated.
1016
- // If we don't clone, we run the risk of saving the wrong panel and layout pair.
1017
- debouncedSave(autoSaveId, [...panelDataArray], layout, storage);
1024
+ // Clone mutable data before passing to the debounced function,
1025
+ // else we run the risk of saving an incorrect combination of mutable and immutable values to state.
1026
+ const clonedPanelDataArray = [...panelDataArray];
1027
+ const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
1028
+ debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
1018
1029
  }
1019
1030
  }, [autoSaveId, layout, storage]);
1020
1031
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-resizable-panels",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "React components for resizable panel groups/layouts",
5
5
  "author": "Brian Vaughn <brian.david.vaughn@gmail.com>",
6
6
  "license": "MIT",
package/src/PanelGroup.ts CHANGED
@@ -20,7 +20,10 @@ import { getResizeHandleElement } from "./utils/dom/getResizeHandleElement";
20
20
  import { isKeyDown, isMouseEvent, isTouchEvent } from "./utils/events";
21
21
  import { getResizeEventCursorPosition } from "./utils/getResizeEventCursorPosition";
22
22
  import { initializeDefaultStorage } from "./utils/initializeDefaultStorage";
23
- import { loadPanelLayout, savePanelGroupLayout } from "./utils/serialization";
23
+ import {
24
+ loadPanelGroupState,
25
+ savePanelGroupState,
26
+ } from "./utils/serialization";
24
27
  import { validatePanelConstraints } from "./utils/validatePanelConstraints";
25
28
  import { validatePanelGroupLayout } from "./utils/validatePanelGroupLayout";
26
29
  import {
@@ -79,7 +82,7 @@ export type PanelGroupProps = Omit<HTMLAttributes<ElementType>, "id"> &
79
82
  }>;
80
83
 
81
84
  const debounceMap: {
82
- [key: string]: typeof savePanelGroupLayout;
85
+ [key: string]: typeof savePanelGroupState;
83
86
  } = {};
84
87
 
85
88
  function PanelGroupWithForwardedRef({
@@ -102,7 +105,6 @@ function PanelGroupWithForwardedRef({
102
105
 
103
106
  const [dragState, setDragState] = useState<DragState | null>(null);
104
107
  const [layout, setLayout] = useState<number[]>([]);
105
- const [panelDataArray, setPanelDataArray] = useState<PanelData[]>([]);
106
108
 
107
109
  const panelIdToLastNotifiedSizeMapRef = useRef<Record<string, number>>({});
108
110
  const panelSizeBeforeCollapseRef = useRef<Map<string, number>>(new Map());
@@ -218,16 +220,26 @@ function PanelGroupWithForwardedRef({
218
220
  // Limit the frequency of localStorage updates.
219
221
  if (debouncedSave == null) {
220
222
  debouncedSave = debounce(
221
- savePanelGroupLayout,
223
+ savePanelGroupState,
222
224
  LOCAL_STORAGE_DEBOUNCE_INTERVAL
223
225
  );
224
226
 
225
227
  debounceMap[autoSaveId] = debouncedSave;
226
228
  }
227
229
 
228
- // Clone panel data array before saving since this array is mutated.
229
- // If we don't clone, we run the risk of saving the wrong panel and layout pair.
230
- debouncedSave(autoSaveId, [...panelDataArray], layout, storage);
230
+ // Clone mutable data before passing to the debounced function,
231
+ // else we run the risk of saving an incorrect combination of mutable and immutable values to state.
232
+ const clonedPanelDataArray = [...panelDataArray];
233
+ const clonedPanelSizesBeforeCollapse = new Map(
234
+ panelSizeBeforeCollapseRef.current
235
+ );
236
+ debouncedSave(
237
+ autoSaveId,
238
+ clonedPanelDataArray,
239
+ clonedPanelSizesBeforeCollapse,
240
+ layout,
241
+ storage
242
+ );
231
243
  }
232
244
  }, [autoSaveId, layout, storage]);
233
245
 
@@ -500,7 +512,13 @@ function PanelGroupWithForwardedRef({
500
512
  // default size should be restored from local storage if possible.
501
513
  let unsafeLayout: number[] | null = null;
502
514
  if (autoSaveId) {
503
- unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
515
+ const state = loadPanelGroupState(autoSaveId, panelDataArray, storage);
516
+ if (state) {
517
+ panelSizeBeforeCollapseRef.current = new Map(
518
+ Object.entries(state.expandToSizes)
519
+ );
520
+ unsafeLayout = state.layout;
521
+ }
504
522
  }
505
523
 
506
524
  if (unsafeLayout == null) {