react-resizable-panels 0.0.33 → 0.0.35

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/src/PanelGroup.ts CHANGED
@@ -11,15 +11,27 @@ import {
11
11
  } from "react";
12
12
 
13
13
  import { PanelGroupContext } from "./PanelContexts";
14
- import { Direction, PanelData, PanelGroupOnLayout, ResizeEvent } from "./types";
14
+ import {
15
+ Direction,
16
+ PanelData,
17
+ PanelGroupOnLayout,
18
+ ResizeEvent,
19
+ PanelGroupStorage,
20
+ } from "./types";
15
21
  import { loadPanelLayout, savePanelGroupLayout } from "./utils/serialization";
16
- import { getDragOffset, getMovement } from "./utils/coordinates";
22
+ import {
23
+ getDragOffset,
24
+ getMovement,
25
+ isMouseEvent,
26
+ isTouchEvent,
27
+ } from "./utils/coordinates";
17
28
  import {
18
29
  adjustByDelta,
19
30
  callPanelCallbacks,
20
31
  getBeforeAndAfterIds,
21
32
  getFlexGrow,
22
33
  getPanelGroup,
34
+ getResizeHandle,
23
35
  getResizeHandlePanelIds,
24
36
  panelsMapToSortedArray,
25
37
  } from "./utils/group";
@@ -28,10 +40,26 @@ import useUniqueId from "./hooks/useUniqueId";
28
40
  import { useWindowSplitterPanelGroupBehavior } from "./hooks/useWindowSplitterBehavior";
29
41
  import { resetGlobalCursorStyle, setGlobalCursorStyle } from "./utils/cursor";
30
42
  import debounce from "./utils/debounce";
43
+ import { areEqual } from "./utils/arrays";
31
44
 
32
45
  // Limit the frequency of localStorage updates.
33
46
  const savePanelGroupLayoutDebounced = debounce(savePanelGroupLayout, 100);
34
47
 
48
+ function throwServerError() {
49
+ throw new Error('PanelGroup "storage" prop required for server rendering.');
50
+ }
51
+
52
+ const defaultStorage: PanelGroupStorage = {
53
+ getItem:
54
+ typeof localStorage !== "undefined"
55
+ ? (name: string) => localStorage.getItem(name)
56
+ : (throwServerError as any),
57
+ setItem:
58
+ typeof localStorage !== "undefined"
59
+ ? (name: string, value: string) => localStorage.setItem(name, value)
60
+ : (throwServerError as any),
61
+ };
62
+
35
63
  export type CommittedValues = {
36
64
  direction: Direction;
37
65
  panels: Map<string, PanelData>;
@@ -40,6 +68,19 @@ export type CommittedValues = {
40
68
 
41
69
  export type PanelDataMap = Map<string, PanelData>;
42
70
 
71
+ // Initial drag state serves a few purposes:
72
+ // * dragOffset:
73
+ // Resize is calculated by the distance between the current pointer event and the resize handle being "dragged"
74
+ // This value accounts for the initial offset when the touch/click starts, so the handle doesn't appear to "jump"
75
+ // * dragHandleRect, sizes:
76
+ // When resizing is done via mouse/touch event– some initial state is stored
77
+ // so that any panels that contract will also expand if drag direction is reversed.
78
+ export type InitialDragState = {
79
+ dragHandleRect: DOMRect;
80
+ dragOffset: number;
81
+ sizes: number[];
82
+ };
83
+
43
84
  // TODO
44
85
  // Within an active drag, remember original positions to refine more easily on expand.
45
86
  // Look at what the Chrome devtools Sources does.
@@ -51,6 +92,7 @@ export type PanelGroupProps = {
51
92
  direction: Direction;
52
93
  id?: string | null;
53
94
  onLayout?: PanelGroupOnLayout;
95
+ storage?: PanelGroupStorage;
54
96
  style?: CSSProperties;
55
97
  tagName?: ElementType;
56
98
  };
@@ -62,6 +104,7 @@ export function PanelGroup({
62
104
  direction,
63
105
  id: idFromProps = null,
64
106
  onLayout = null,
107
+ storage = defaultStorage,
65
108
  style: styleFromProps = {},
66
109
  tagName: Type = "div",
67
110
  }: PanelGroupProps) {
@@ -70,6 +113,11 @@ export function PanelGroup({
70
113
  const [activeHandleId, setActiveHandleId] = useState<string | null>(null);
71
114
  const [panels, setPanels] = useState<PanelDataMap>(new Map());
72
115
 
116
+ // When resizing is done via mouse/touch event–
117
+ // We store the initial Panel sizes in this ref, and apply move deltas to them instead of to the current sizes.
118
+ // This has the benefit of causing force-collapsed panels to spring back open if drag is reversed.
119
+ const initialDragStateRef = useRef<InitialDragState | null>(null);
120
+
73
121
  // Use a ref to guard against users passing inline props
74
122
  const callbacksRef = useRef<{
75
123
  onLayout: PanelGroupOnLayout | null;
@@ -81,13 +129,11 @@ export function PanelGroup({
81
129
  // 0-1 values representing the relative size of each panel.
82
130
  const [sizes, setSizes] = useState<number[]>([]);
83
131
 
84
- // Resize is calculated by the distance between the current pointer event and the resize handle being "dragged"
85
- // This value accounts for the initial offset when the touch/click starts, so the handle doesn't appear to "jump"
86
- const dragOffsetRef = useRef<number>(0);
87
-
88
132
  // Used to support imperative collapse/expand API.
89
133
  const panelSizeBeforeCollapse = useRef<Map<string, number>>(new Map());
90
134
 
135
+ const prevDeltaRef = useRef<number>(0);
136
+
91
137
  // Store committed values to avoid unnecessarily re-running memoization/effects functions.
92
138
  const committedValuesRef = useRef<CommittedValues>({
93
139
  direction,
@@ -155,7 +201,7 @@ export function PanelGroup({
155
201
  let defaultSizes: number[] | undefined = undefined;
156
202
  if (autoSaveId) {
157
203
  const panelsArray = panelsMapToSortedArray(panels);
158
- defaultSizes = loadPanelLayout(autoSaveId, panelsArray);
204
+ defaultSizes = loadPanelLayout(autoSaveId, panelsArray, storage);
159
205
  }
160
206
 
161
207
  if (defaultSizes != null) {
@@ -213,7 +259,7 @@ export function PanelGroup({
213
259
 
214
260
  const panelsArray = panelsMapToSortedArray(panels);
215
261
 
216
- savePanelGroupLayoutDebounced(autoSaveId, panelsArray, sizes);
262
+ savePanelGroupLayoutDebounced(autoSaveId, panelsArray, sizes, storage);
217
263
  }
218
264
  }, [autoSaveId, panels, sizes]);
219
265
 
@@ -295,7 +341,7 @@ export function PanelGroup({
295
341
  panelsArray,
296
342
  direction,
297
343
  prevSizes,
298
- dragOffsetRef.current
344
+ initialDragStateRef.current
299
345
  );
300
346
  if (movement === 0) {
301
347
  return;
@@ -314,30 +360,47 @@ export function PanelGroup({
314
360
  idAfter,
315
361
  delta,
316
362
  prevSizes,
317
- panelSizeBeforeCollapse.current
363
+ panelSizeBeforeCollapse.current,
364
+ initialDragStateRef.current
318
365
  );
319
- if (prevSizes === nextSizes) {
320
- // If the pointer has moved too far to resize the panel any further,
321
- // update the cursor style for a visual clue.
322
- // This mimics VS Code behavior.
323
- if (isHorizontal) {
324
- setGlobalCursorStyle(
325
- movement < 0 ? "horizontal-min" : "horizontal-max"
326
- );
327
- } else {
328
- setGlobalCursorStyle(
329
- movement < 0 ? "vertical-min" : "vertical-max"
330
- );
366
+
367
+ const sizesChanged = !areEqual(prevSizes, nextSizes);
368
+
369
+ // Don't update cursor for resizes triggered by keyboard interactions.
370
+ if (isMouseEvent(event) || isTouchEvent(event)) {
371
+ // Watch for multiple subsequent deltas; this might occur for tiny cursor movements.
372
+ // In this case, Panel sizes might not change–
373
+ // but updating cursor in this scenario would cause a flicker.
374
+ if (prevDeltaRef.current != delta) {
375
+ if (!sizesChanged) {
376
+ // If the pointer has moved too far to resize the panel any further,
377
+ // update the cursor style for a visual clue.
378
+ // This mimics VS Code behavior.
379
+
380
+ if (isHorizontal) {
381
+ setGlobalCursorStyle(
382
+ movement < 0 ? "horizontal-min" : "horizontal-max"
383
+ );
384
+ } else {
385
+ setGlobalCursorStyle(
386
+ movement < 0 ? "vertical-min" : "vertical-max"
387
+ );
388
+ }
389
+ } else {
390
+ // Reset the cursor style to the the normal resize cursor.
391
+ setGlobalCursorStyle(isHorizontal ? "horizontal" : "vertical");
392
+ }
331
393
  }
332
- } else {
333
- // Reset the cursor style to the the normal resize cursor.
334
- setGlobalCursorStyle(isHorizontal ? "horizontal" : "vertical");
394
+ }
335
395
 
396
+ if (sizesChanged) {
336
397
  // If resize change handlers have been declared, this is the time to call them.
337
398
  callPanelCallbacks(panelsArray, prevSizes, nextSizes);
338
399
 
339
400
  setSizes(nextSizes);
340
401
  }
402
+
403
+ prevDeltaRef.current = delta;
341
404
  };
342
405
 
343
406
  return resizeHandler;
@@ -396,7 +459,8 @@ export function PanelGroup({
396
459
  idAfter,
397
460
  delta,
398
461
  prevSizes,
399
- panelSizeBeforeCollapse.current
462
+ panelSizeBeforeCollapse.current,
463
+ null
400
464
  );
401
465
  if (prevSizes !== nextSizes) {
402
466
  // If resize change handlers have been declared, this is the time to call them.
@@ -448,7 +512,8 @@ export function PanelGroup({
448
512
  idAfter,
449
513
  delta,
450
514
  prevSizes,
451
- panelSizeBeforeCollapse.current
515
+ panelSizeBeforeCollapse.current,
516
+ null
452
517
  );
453
518
  if (prevSizes !== nextSizes) {
454
519
  // If resize change handlers have been declared, this is the time to call them.
@@ -478,6 +543,12 @@ export function PanelGroup({
478
543
  return;
479
544
  }
480
545
 
546
+ if (panel.collapsible && nextSize === 0) {
547
+ // This is a valid resize state.
548
+ } else {
549
+ nextSize = Math.min(panel.maxSize, Math.max(panel.minSize, nextSize));
550
+ }
551
+
481
552
  const [idBefore, idAfter] = getBeforeAndAfterIds(id, panelsArray);
482
553
  if (idBefore == null || idAfter == null) {
483
554
  return;
@@ -493,7 +564,8 @@ export function PanelGroup({
493
564
  idAfter,
494
565
  delta,
495
566
  prevSizes,
496
- panelSizeBeforeCollapse.current
567
+ panelSizeBeforeCollapse.current,
568
+ null
497
569
  );
498
570
  if (prevSizes !== nextSizes) {
499
571
  // If resize change handlers have been declared, this is the time to call them.
@@ -517,11 +589,21 @@ export function PanelGroup({
517
589
  startDragging: (id: string, event: ResizeEvent) => {
518
590
  setActiveHandleId(id);
519
591
 
520
- dragOffsetRef.current = getDragOffset(event, id, direction);
592
+ if (isMouseEvent(event) || isTouchEvent(event)) {
593
+ const handleElement = getResizeHandle(id);
594
+
595
+ initialDragStateRef.current = {
596
+ dragHandleRect: handleElement.getBoundingClientRect(),
597
+ dragOffset: getDragOffset(event, id, direction),
598
+ sizes: committedValuesRef.current.sizes,
599
+ };
600
+ }
521
601
  },
522
602
  stopDragging: () => {
523
603
  resetGlobalCursorStyle();
524
604
  setActiveHandleId(null);
605
+
606
+ initialDragStateRef.current = null;
525
607
  },
526
608
  unregisterPanel,
527
609
  }),
@@ -551,6 +633,7 @@ export function PanelGroup({
551
633
  children: createElement(Type, {
552
634
  children,
553
635
  className: classNameFromProps,
636
+ "data-panel-group": "",
554
637
  "data-panel-group-direction": direction,
555
638
  "data-panel-group-id": groupId,
556
639
  style: { ...style, ...styleFromProps },
@@ -108,7 +108,8 @@ export function useWindowSplitterPanelGroupBehavior({
108
108
  idAfter,
109
109
  delta,
110
110
  sizes,
111
- panelSizeBeforeCollapse.current
111
+ panelSizeBeforeCollapse.current,
112
+ null
112
113
  );
113
114
  if (sizes !== nextSizes) {
114
115
  setSizes(nextSizes);
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@ import { PanelResizeHandle } from "./PanelResizeHandle";
5
5
  import type { ImperativePanelHandle, PanelProps } from "./Panel";
6
6
  import type { PanelGroupProps } from "./PanelGroup";
7
7
  import type { PanelResizeHandleProps } from "./PanelResizeHandle";
8
+ import type { PanelGroupStorage } from "./types";
8
9
 
9
10
  export {
10
11
  Panel,
@@ -14,6 +15,7 @@ export {
14
15
  // TypeScript types
15
16
  ImperativePanelHandle,
16
17
  PanelGroupProps,
18
+ PanelGroupStorage,
17
19
  PanelProps,
18
20
  PanelResizeHandleProps,
19
21
  };
package/src/types.ts CHANGED
@@ -2,6 +2,11 @@ import { RefObject } from "react";
2
2
 
3
3
  export type Direction = "horizontal" | "vertical";
4
4
 
5
+ export type PanelGroupStorage = {
6
+ getItem(name: string): string | null;
7
+ setItem(name: string, value: string): void;
8
+ };
9
+
5
10
  export type PanelGroupOnLayout = (sizes: number[]) => void;
6
11
  export type PanelOnCollapse = (collapsed: boolean) => void;
7
12
  export type PanelOnResize = (size: number) => void;
@@ -0,0 +1,13 @@
1
+ export function areEqual(arrayA: any[], arrayB: any[]): boolean {
2
+ if (arrayA.length !== arrayB.length) {
3
+ return false;
4
+ }
5
+
6
+ for (let index = 0; index < arrayA.length; index++) {
7
+ if (arrayA[index] !== arrayB[index]) {
8
+ return false;
9
+ }
10
+ }
11
+
12
+ return true;
13
+ }
@@ -1,4 +1,5 @@
1
1
  import { PRECISION } from "../constants";
2
+ import { InitialDragState } from "../PanelGroup";
2
3
  import { Direction, PanelData, ResizeEvent } from "../types";
3
4
  import {
4
5
  getPanelGroup,
@@ -20,7 +21,8 @@ export function getDragOffset(
20
21
  event: ResizeEvent,
21
22
  handleId: string,
22
23
  direction: Direction,
23
- initialOffset: number = 0
24
+ initialOffset: number = 0,
25
+ initialHandleElementRect: DOMRect | null = null
24
26
  ): number {
25
27
  const isHorizontal = direction === "horizontal";
26
28
 
@@ -35,7 +37,8 @@ export function getDragOffset(
35
37
  }
36
38
 
37
39
  const handleElement = getResizeHandle(handleId);
38
- const rect = handleElement.getBoundingClientRect();
40
+ const rect =
41
+ initialHandleElementRect || handleElement.getBoundingClientRect();
39
42
  const elementOffset = isHorizontal ? rect.left : rect.top;
40
43
 
41
44
  return pointerOffset - elementOffset - initialOffset;
@@ -48,9 +51,19 @@ export function getMovement(
48
51
  handleId: string,
49
52
  panelsArray: PanelData[],
50
53
  direction: Direction,
51
- sizes: number[],
52
- initialOffset: number
54
+ prevSizes: number[],
55
+ initialDragState: InitialDragState | null
53
56
  ): number {
57
+ const {
58
+ dragOffset = 0,
59
+ dragHandleRect,
60
+ sizes: initialSizes,
61
+ } = initialDragState || {};
62
+
63
+ // If we're resizing by mouse or touch, use the initial sizes as a base.
64
+ // This has the benefit of causing force-collapsed panels to spring back open if drag is reversed.
65
+ const baseSizes = initialSizes || prevSizes;
66
+
54
67
  if (isKeyDown(event)) {
55
68
  const isHorizontal = direction === "horizontal";
56
69
 
@@ -98,10 +111,10 @@ export function getMovement(
98
111
  );
99
112
  const targetPanel = panelsArray[targetPanelIndex];
100
113
  if (targetPanel.collapsible) {
101
- const prevSize = sizes[targetPanelIndex];
114
+ const baseSize = baseSizes[targetPanelIndex];
102
115
  if (
103
- prevSize === 0 ||
104
- prevSize.toPrecision(PRECISION) ===
116
+ baseSize === 0 ||
117
+ baseSize.toPrecision(PRECISION) ===
105
118
  targetPanel.minSize.toPrecision(PRECISION)
106
119
  ) {
107
120
  movement =
@@ -113,7 +126,13 @@ export function getMovement(
113
126
 
114
127
  return movement;
115
128
  } else {
116
- return getDragOffset(event, handleId, direction, initialOffset);
129
+ return getDragOffset(
130
+ event,
131
+ handleId,
132
+ direction,
133
+ dragOffset,
134
+ dragHandleRect
135
+ );
117
136
  }
118
137
  }
119
138
 
@@ -1,4 +1,5 @@
1
1
  import { PRECISION } from "../constants";
2
+ import { InitialDragState } from "../PanelGroup";
2
3
  import { PanelData, ResizeEvent } from "../types";
3
4
 
4
5
  export function adjustByDelta(
@@ -8,15 +9,22 @@ export function adjustByDelta(
8
9
  idAfter: string,
9
10
  delta: number,
10
11
  prevSizes: number[],
11
- panelSizeBeforeCollapse: Map<string, number>
12
+ panelSizeBeforeCollapse: Map<string, number>,
13
+ initialDragState: InitialDragState | null
12
14
  ): number[] {
15
+ const { sizes: initialSizes } = initialDragState || {};
16
+
17
+ // If we're resizing by mouse or touch, use the initial sizes as a base.
18
+ // This has the benefit of causing force-collapsed panels to spring back open if drag is reversed.
19
+ const baseSizes = initialSizes || prevSizes;
20
+
13
21
  if (delta === 0) {
14
- return prevSizes;
22
+ return baseSizes;
15
23
  }
16
24
 
17
25
  const panelsArray = panelsMapToSortedArray(panels);
18
26
 
19
- const nextSizes = prevSizes.concat();
27
+ const nextSizes = baseSizes.concat();
20
28
 
21
29
  let deltaApplied = 0;
22
30
 
@@ -33,17 +41,18 @@ export function adjustByDelta(
33
41
  const pivotId = delta < 0 ? idAfter : idBefore;
34
42
  const index = panelsArray.findIndex((panel) => panel.id === pivotId);
35
43
  const panel = panelsArray[index];
36
- const prevSize = prevSizes[index];
44
+ const baseSize = baseSizes[index];
37
45
 
38
- const nextSize = safeResizePanel(panel, Math.abs(delta), prevSize, event);
39
- if (prevSize === nextSize) {
40
- return prevSizes;
46
+ const nextSize = safeResizePanel(panel, Math.abs(delta), baseSize, event);
47
+ if (baseSize === nextSize) {
48
+ // If there's no room for the pivot panel to grow, we can ignore this drag update.
49
+ return baseSizes;
41
50
  } else {
42
- if (nextSize === 0 && prevSize > 0) {
43
- panelSizeBeforeCollapse.set(pivotId, prevSize);
51
+ if (nextSize === 0 && baseSize > 0) {
52
+ panelSizeBeforeCollapse.set(pivotId, baseSize);
44
53
  }
45
54
 
46
- delta = delta < 0 ? prevSize - nextSize : nextSize - prevSize;
55
+ delta = delta < 0 ? baseSize - nextSize : nextSize - baseSize;
47
56
  }
48
57
  }
49
58
 
@@ -51,24 +60,32 @@ export function adjustByDelta(
51
60
  let index = panelsArray.findIndex((panel) => panel.id === pivotId);
52
61
  while (true) {
53
62
  const panel = panelsArray[index];
54
- const prevSize = prevSizes[index];
63
+ const baseSize = baseSizes[index];
64
+
65
+ const deltaRemaining = Math.abs(delta) - Math.abs(deltaApplied);
55
66
 
56
67
  const nextSize = safeResizePanel(
57
68
  panel,
58
- 0 - Math.abs(delta),
59
- prevSize,
69
+ 0 - deltaRemaining,
70
+ baseSize,
60
71
  event
61
72
  );
62
- if (prevSize !== nextSize) {
63
- if (nextSize === 0 && prevSize > 0) {
64
- panelSizeBeforeCollapse.set(panel.id, prevSize);
73
+ if (baseSize !== nextSize) {
74
+ if (nextSize === 0 && baseSize > 0) {
75
+ panelSizeBeforeCollapse.set(panel.id, baseSize);
65
76
  }
66
77
 
67
- deltaApplied += prevSize - nextSize;
78
+ deltaApplied += baseSize - nextSize;
68
79
 
69
80
  nextSizes[index] = nextSize;
70
81
 
71
- if (deltaApplied.toPrecision(PRECISION) >= delta.toPrecision(PRECISION)) {
82
+ if (
83
+ deltaApplied
84
+ .toPrecision(PRECISION)
85
+ .localeCompare(Math.abs(delta).toPrecision(PRECISION), undefined, {
86
+ numeric: true,
87
+ }) >= 0
88
+ ) {
72
89
  break;
73
90
  }
74
91
  }
@@ -87,13 +104,13 @@ export function adjustByDelta(
87
104
  // If we were unable to resize any of the panels panels, return the previous state.
88
105
  // This will essentially bailout and ignore the "mousemove" event.
89
106
  if (deltaApplied === 0) {
90
- return prevSizes;
107
+ return baseSizes;
91
108
  }
92
109
 
93
110
  // Adjust the pivot panel before, but only by the amount that surrounding panels were able to shrink/contract.
94
111
  pivotId = delta < 0 ? idAfter : idBefore;
95
112
  index = panelsArray.findIndex((panel) => panel.id === pivotId);
96
- nextSizes[index] = prevSizes[index] + deltaApplied;
113
+ nextSizes[index] = baseSizes[index] + deltaApplied;
97
114
 
98
115
  return nextSizes;
99
116
  }
@@ -199,7 +216,7 @@ export function getResizeHandleIndex(id: string): number | null {
199
216
  const index = handles.findIndex(
200
217
  (handle) => handle.getAttribute("data-panel-resize-handle-id") === id
201
218
  );
202
- return index || null;
219
+ return index ?? null;
203
220
  }
204
221
 
205
222
  export function getResizeHandles(): HTMLDivElement[] {
@@ -223,8 +240,8 @@ export function getResizeHandlePanelIds(
223
240
  const handles = getResizeHandlesForGroup(groupId);
224
241
  const index = handles.indexOf(handle);
225
242
 
226
- const idBefore: string | null = panelsArray[index]?.id || null;
227
- const idAfter: string | null = panelsArray[index + 1]?.id || null;
243
+ const idBefore: string | null = panelsArray[index]?.id ?? null;
244
+ const idAfter: string | null = panelsArray[index + 1]?.id ?? null;
228
245
 
229
246
  return [idBefore, idAfter];
230
247
  }
@@ -1,4 +1,4 @@
1
- import { PanelData } from "../types";
1
+ import { PanelData, PanelGroupStorage } from "../types";
2
2
 
3
3
  type SerializedPanelGroupState = { [panelIds: string]: number[] };
4
4
 
@@ -17,10 +17,11 @@ function getSerializationKey(panels: PanelData[]): string {
17
17
  }
18
18
 
19
19
  function loadSerializedPanelGroupState(
20
- autoSaveId: string
20
+ autoSaveId: string,
21
+ storage: PanelGroupStorage
21
22
  ): SerializedPanelGroupState | null {
22
23
  try {
23
- const serialized = localStorage.getItem(`PanelGroup:sizes:${autoSaveId}`);
24
+ const serialized = storage.getItem(`PanelGroup:sizes:${autoSaveId}`);
24
25
  if (serialized) {
25
26
  const parsed = JSON.parse(serialized);
26
27
  if (typeof parsed === "object" && parsed != null) {
@@ -34,12 +35,13 @@ function loadSerializedPanelGroupState(
34
35
 
35
36
  export function loadPanelLayout(
36
37
  autoSaveId: string,
37
- panels: PanelData[]
38
+ panels: PanelData[],
39
+ storage: PanelGroupStorage
38
40
  ): number[] | null {
39
- const state = loadSerializedPanelGroupState(autoSaveId);
41
+ const state = loadSerializedPanelGroupState(autoSaveId, storage);
40
42
  if (state) {
41
43
  const key = getSerializationKey(panels);
42
- return state[key] || null;
44
+ return state[key] ?? null;
43
45
  }
44
46
 
45
47
  return null;
@@ -48,17 +50,15 @@ export function loadPanelLayout(
48
50
  export function savePanelGroupLayout(
49
51
  autoSaveId: string,
50
52
  panels: PanelData[],
51
- sizes: number[]
53
+ sizes: number[],
54
+ storage: PanelGroupStorage
52
55
  ): void {
53
56
  const key = getSerializationKey(panels);
54
- const state = loadSerializedPanelGroupState(autoSaveId) || {};
57
+ const state = loadSerializedPanelGroupState(autoSaveId, storage) || {};
55
58
  state[key] = sizes;
56
59
 
57
60
  try {
58
- localStorage.setItem(
59
- `PanelGroup:sizes:${autoSaveId}`,
60
- JSON.stringify(state)
61
- );
61
+ storage.setItem(`PanelGroup:sizes:${autoSaveId}`, JSON.stringify(state));
62
62
  } catch (error) {
63
63
  console.error(error);
64
64
  }