react-resizable-panels 0.0.62 → 1.0.0-rc.1

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.
Files changed (73) hide show
  1. package/.eslintrc.cjs +1 -0
  2. package/CHANGELOG.md +9 -0
  3. package/dist/declarations/src/Panel.d.ts +19 -34
  4. package/dist/declarations/src/PanelGroup.d.ts +9 -13
  5. package/dist/declarations/src/PanelResizeHandle.d.ts +5 -7
  6. package/dist/declarations/src/index.d.ts +2 -2
  7. package/dist/declarations/src/types.d.ts +0 -7
  8. package/dist/declarations/src/utils/assert.d.ts +1 -0
  9. package/dist/declarations/src/vendor/react.d.ts +2 -2
  10. package/dist/react-resizable-panels.browser.cjs.js +255 -519
  11. package/dist/react-resizable-panels.browser.cjs.mjs +2 -1
  12. package/dist/react-resizable-panels.browser.development.cjs.js +281 -575
  13. package/dist/react-resizable-panels.browser.development.cjs.mjs +2 -1
  14. package/dist/react-resizable-panels.browser.development.esm.js +281 -576
  15. package/dist/react-resizable-panels.browser.esm.js +255 -520
  16. package/dist/react-resizable-panels.cjs.js +255 -519
  17. package/dist/react-resizable-panels.cjs.js.map +1 -0
  18. package/dist/react-resizable-panels.cjs.mjs +2 -1
  19. package/dist/react-resizable-panels.development.cjs.js +283 -577
  20. package/dist/react-resizable-panels.development.cjs.mjs +2 -1
  21. package/dist/react-resizable-panels.development.esm.js +283 -578
  22. package/dist/react-resizable-panels.development.node.cjs.js +269 -503
  23. package/dist/react-resizable-panels.development.node.cjs.mjs +2 -1
  24. package/dist/react-resizable-panels.development.node.esm.js +269 -504
  25. package/dist/react-resizable-panels.esm.js +255 -520
  26. package/dist/react-resizable-panels.esm.js.map +1 -0
  27. package/dist/react-resizable-panels.node.cjs.js +241 -445
  28. package/dist/react-resizable-panels.node.cjs.mjs +2 -1
  29. package/dist/react-resizable-panels.node.esm.js +241 -446
  30. package/package.json +1 -1
  31. package/src/Panel.test.tsx +74 -73
  32. package/src/Panel.ts +44 -68
  33. package/src/PanelGroup.test.tsx +43 -42
  34. package/src/PanelGroup.ts +189 -403
  35. package/src/PanelGroupContext.ts +2 -3
  36. package/src/PanelResizeHandle.test.tsx +68 -0
  37. package/src/PanelResizeHandle.ts +31 -22
  38. package/src/hooks/useWindowSplitterBehavior.ts +2 -1
  39. package/src/hooks/useWindowSplitterPanelGroupBehavior.ts +22 -33
  40. package/src/index.ts +4 -3
  41. package/src/types.ts +0 -9
  42. package/src/utils/adjustLayoutByDelta.test.ts +206 -336
  43. package/src/utils/adjustLayoutByDelta.ts +59 -51
  44. package/src/utils/assert.ts +1 -1
  45. package/src/utils/calculateAriaValues.test.ts +6 -11
  46. package/src/utils/calculateAriaValues.ts +7 -29
  47. package/src/utils/calculateDeltaPercentage.ts +8 -15
  48. package/src/utils/calculateDragOffsetPercentage.ts +11 -5
  49. package/src/utils/calculateUnsafeDefaultLayout.test.ts +4 -9
  50. package/src/utils/calculateUnsafeDefaultLayout.ts +13 -18
  51. package/src/utils/callPanelCallbacks.ts +11 -46
  52. package/src/utils/computePanelFlexBoxStyle.ts +3 -2
  53. package/src/utils/getResizeEventCursorPosition.ts +2 -0
  54. package/src/utils/resizePanel.test.ts +6 -52
  55. package/src/utils/resizePanel.ts +24 -46
  56. package/src/utils/test-utils.ts +6 -7
  57. package/src/utils/validatePanelConstraints.test.ts +12 -65
  58. package/src/utils/validatePanelConstraints.ts +26 -67
  59. package/src/utils/validatePanelGroupLayout.test.ts +27 -142
  60. package/src/utils/validatePanelGroupLayout.ts +17 -13
  61. package/src/vendor/react.ts +2 -0
  62. package/src/utils/computePercentagePanelConstraints.test.ts +0 -98
  63. package/src/utils/computePercentagePanelConstraints.ts +0 -56
  64. package/src/utils/convertPercentageToPixels.test.ts +0 -9
  65. package/src/utils/convertPercentageToPixels.ts +0 -6
  66. package/src/utils/convertPixelConstraintsToPercentages.test.ts +0 -47
  67. package/src/utils/convertPixelConstraintsToPercentages.ts +0 -72
  68. package/src/utils/convertPixelsToPercentage.test.ts +0 -9
  69. package/src/utils/convertPixelsToPercentage.ts +0 -6
  70. package/src/utils/getPercentageSizeFromMixedSizes.test.ts +0 -47
  71. package/src/utils/getPercentageSizeFromMixedSizes.ts +0 -15
  72. package/src/utils/shouldMonitorPixelBasedConstraints.test.ts +0 -23
  73. package/src/utils/shouldMonitorPixelBasedConstraints.ts +0 -13
package/src/PanelGroup.ts CHANGED
@@ -4,35 +4,31 @@ import { DragState, PanelGroupContext, ResizeEvent } from "./PanelGroupContext";
4
4
  import useIsomorphicLayoutEffect from "./hooks/useIsomorphicEffect";
5
5
  import useUniqueId from "./hooks/useUniqueId";
6
6
  import { useWindowSplitterPanelGroupBehavior } from "./hooks/useWindowSplitterPanelGroupBehavior";
7
- import { DataAttributes, Direction, MixedSizes } from "./types";
7
+ import { Direction } from "./types";
8
8
  import { adjustLayoutByDelta } from "./utils/adjustLayoutByDelta";
9
9
  import { areEqual } from "./utils/arrays";
10
+ import { assert } from "./utils/assert";
10
11
  import { calculateDeltaPercentage } from "./utils/calculateDeltaPercentage";
11
12
  import { calculateUnsafeDefaultLayout } from "./utils/calculateUnsafeDefaultLayout";
12
13
  import { callPanelCallbacks } from "./utils/callPanelCallbacks";
13
14
  import { compareLayouts } from "./utils/compareLayouts";
14
15
  import { computePanelFlexBoxStyle } from "./utils/computePanelFlexBoxStyle";
15
- import { computePercentagePanelConstraints } from "./utils/computePercentagePanelConstraints";
16
- import { convertPercentageToPixels } from "./utils/convertPercentageToPixels";
17
16
  import { resetGlobalCursorStyle, setGlobalCursorStyle } from "./utils/cursor";
18
17
  import debounce from "./utils/debounce";
19
18
  import { determinePivotIndices } from "./utils/determinePivotIndices";
20
- import { calculateAvailablePanelSizeInPixels } from "./utils/dom/calculateAvailablePanelSizeInPixels";
21
19
  import { getPanelElementsForGroup } from "./utils/dom/getPanelElementsForGroup";
22
- import { getPanelGroupElement } from "./utils/dom/getPanelGroupElement";
23
20
  import { getResizeHandleElement } from "./utils/dom/getResizeHandleElement";
24
21
  import { isKeyDown, isMouseEvent, isTouchEvent } from "./utils/events";
25
- import { getPercentageSizeFromMixedSizes } from "./utils/getPercentageSizeFromMixedSizes";
26
22
  import { getResizeEventCursorPosition } from "./utils/getResizeEventCursorPosition";
27
23
  import { initializeDefaultStorage } from "./utils/initializeDefaultStorage";
28
24
  import { loadPanelLayout, savePanelGroupLayout } from "./utils/serialization";
29
- import { shouldMonitorPixelBasedConstraints } from "./utils/shouldMonitorPixelBasedConstraints";
30
25
  import { validatePanelConstraints } from "./utils/validatePanelConstraints";
31
26
  import { validatePanelGroupLayout } from "./utils/validatePanelGroupLayout";
32
27
  import {
33
28
  CSSProperties,
34
29
  ElementType,
35
30
  ForwardedRef,
31
+ HTMLAttributes,
36
32
  PropsWithChildren,
37
33
  createElement,
38
34
  forwardRef,
@@ -48,8 +44,8 @@ const LOCAL_STORAGE_DEBOUNCE_INTERVAL = 100;
48
44
 
49
45
  export type ImperativePanelGroupHandle = {
50
46
  getId: () => string;
51
- getLayout: () => MixedSizes[];
52
- setLayout: (layout: Partial<MixedSizes>[]) => void;
47
+ getLayout: () => number[];
48
+ setLayout: (layout: number[]) => void;
53
49
  };
54
50
 
55
51
  export type PanelGroupStorage = {
@@ -57,7 +53,7 @@ export type PanelGroupStorage = {
57
53
  setItem(name: string, value: string): void;
58
54
  };
59
55
 
60
- export type PanelGroupOnLayout = (layout: MixedSizes[]) => void;
56
+ export type PanelGroupOnLayout = (layout: number[]) => void;
61
57
 
62
58
  const defaultStorage: PanelGroupStorage = {
63
59
  getItem: (name: string) => {
@@ -70,19 +66,18 @@ const defaultStorage: PanelGroupStorage = {
70
66
  },
71
67
  };
72
68
 
73
- export type PanelGroupProps = PropsWithChildren<{
74
- autoSaveId?: string | null;
75
- className?: string;
76
- dataAttributes?: DataAttributes;
77
- direction: Direction;
78
- id?: string | null;
79
- keyboardResizeByPercentage?: number | null;
80
- keyboardResizeByPixels?: number | null;
81
- onLayout?: PanelGroupOnLayout | null;
82
- storage?: PanelGroupStorage;
83
- style?: CSSProperties;
84
- tagName?: ElementType;
85
- }>;
69
+ export type PanelGroupProps = Omit<HTMLAttributes<ElementType>, "id"> &
70
+ PropsWithChildren<{
71
+ autoSaveId?: string | null;
72
+ className?: string;
73
+ direction: Direction;
74
+ id?: string | null;
75
+ keyboardResizeBy?: number | null;
76
+ onLayout?: PanelGroupOnLayout | null;
77
+ storage?: PanelGroupStorage;
78
+ style?: CSSProperties;
79
+ tagName?: ElementType;
80
+ }>;
86
81
 
87
82
  const debounceMap: {
88
83
  [key: string]: typeof savePanelGroupLayout;
@@ -92,16 +87,15 @@ function PanelGroupWithForwardedRef({
92
87
  autoSaveId = null,
93
88
  children,
94
89
  className: classNameFromProps = "",
95
- dataAttributes,
96
90
  direction,
97
91
  forwardedRef,
98
- id: idFromProps,
92
+ id: idFromProps = null,
99
93
  onLayout = null,
100
- keyboardResizeByPercentage = null,
101
- keyboardResizeByPixels = null,
94
+ keyboardResizeBy = null,
102
95
  storage = defaultStorage,
103
96
  style: styleFromProps,
104
97
  tagName: Type = "div",
98
+ ...rest
105
99
  }: PanelGroupProps & {
106
100
  forwardedRef: ForwardedRef<ImperativePanelGroupHandle>;
107
101
  }) {
@@ -110,9 +104,7 @@ function PanelGroupWithForwardedRef({
110
104
  const [dragState, setDragState] = useState<DragState | null>(null);
111
105
  const [layout, setLayout] = useState<number[]>([]);
112
106
 
113
- const panelIdToLastNotifiedMixedSizesMapRef = useRef<
114
- Record<string, MixedSizes>
115
- >({});
107
+ const panelIdToLastNotifiedSizeMapRef = useRef<Record<string, number>>({});
116
108
  const panelSizeBeforeCollapseRef = useRef<Map<string, number>>(new Map());
117
109
  const prevDeltaRef = useRef<number>(0);
118
110
 
@@ -121,8 +113,7 @@ function PanelGroupWithForwardedRef({
121
113
  direction: Direction;
122
114
  dragState: DragState | null;
123
115
  id: string;
124
- keyboardResizeByPercentage: number | null;
125
- keyboardResizeByPixels: number | null;
116
+ keyboardResizeBy: number | null;
126
117
  onLayout: PanelGroupOnLayout | null;
127
118
  storage: PanelGroupStorage;
128
119
  }>({
@@ -130,8 +121,7 @@ function PanelGroupWithForwardedRef({
130
121
  direction,
131
122
  dragState,
132
123
  id: groupId,
133
- keyboardResizeByPercentage,
134
- keyboardResizeByPixels,
124
+ keyboardResizeBy,
135
125
  onLayout,
136
126
  storage,
137
127
  });
@@ -159,34 +149,15 @@ function PanelGroupWithForwardedRef({
159
149
  () => ({
160
150
  getId: () => committedValuesRef.current.id,
161
151
  getLayout: () => {
162
- const { id: groupId } = committedValuesRef.current;
163
152
  const { layout } = eagerValuesRef.current;
164
153
 
165
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
166
-
167
- return layout.map((sizePercentage) => {
168
- return {
169
- sizePercentage,
170
- sizePixels: convertPercentageToPixels(
171
- sizePercentage,
172
- groupSizePixels
173
- ),
174
- };
175
- });
154
+ return layout;
176
155
  },
177
- setLayout: (mixedSizes: Partial<MixedSizes>[]) => {
178
- const { id: groupId, onLayout } = committedValuesRef.current;
156
+ setLayout: (unsafeLayout: number[]) => {
157
+ const { onLayout } = committedValuesRef.current;
179
158
  const { layout: prevLayout, panelDataArray } = eagerValuesRef.current;
180
159
 
181
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
182
-
183
- const unsafeLayout = mixedSizes.map(
184
- (mixedSize) =>
185
- getPercentageSizeFromMixedSizes(mixedSize, groupSizePixels)!
186
- );
187
-
188
160
  const safeLayout = validatePanelGroupLayout({
189
- groupSizePixels,
190
161
  layout: unsafeLayout,
191
162
  panelConstraints: panelDataArray.map(
192
163
  (panelData) => panelData.constraints
@@ -199,22 +170,13 @@ function PanelGroupWithForwardedRef({
199
170
  eagerValuesRef.current.layout = safeLayout;
200
171
 
201
172
  if (onLayout) {
202
- onLayout(
203
- safeLayout.map((sizePercentage) => ({
204
- sizePercentage,
205
- sizePixels: convertPercentageToPixels(
206
- sizePercentage,
207
- groupSizePixels
208
- ),
209
- }))
210
- );
173
+ onLayout(safeLayout);
211
174
  }
212
175
 
213
176
  callPanelCallbacks(
214
- groupId,
215
177
  panelDataArray,
216
178
  safeLayout,
217
- panelIdToLastNotifiedMixedSizesMapRef.current
179
+ panelIdToLastNotifiedSizeMapRef.current
218
180
  );
219
181
  }
220
182
  },
@@ -229,9 +191,6 @@ function PanelGroupWithForwardedRef({
229
191
  committedValuesRef.current.id = groupId;
230
192
  committedValuesRef.current.onLayout = onLayout;
231
193
  committedValuesRef.current.storage = storage;
232
-
233
- // panelDataArray and layout are updated in-sync with scheduled state updates.
234
- // TODO [217] Move these values into a separate ref
235
194
  });
236
195
 
237
196
  useWindowSplitterPanelGroupBehavior({
@@ -252,77 +211,21 @@ function PanelGroupWithForwardedRef({
252
211
  return;
253
212
  }
254
213
 
214
+ let debouncedSave = debounceMap[autoSaveId];
215
+
255
216
  // Limit the frequency of localStorage updates.
256
- if (!debounceMap[autoSaveId]) {
257
- debounceMap[autoSaveId] = debounce(
217
+ if (debouncedSave == null) {
218
+ debouncedSave = debounce(
258
219
  savePanelGroupLayout,
259
220
  LOCAL_STORAGE_DEBOUNCE_INTERVAL
260
221
  );
261
- }
262
- debounceMap[autoSaveId](autoSaveId, panelDataArray, layout, storage);
263
- }
264
- }, [autoSaveId, layout, storage]);
265
-
266
- useIsomorphicLayoutEffect(() => {
267
- const { layout: prevLayout, panelDataArray } = eagerValuesRef.current;
268
-
269
- const constraints = panelDataArray.map(({ constraints }) => constraints);
270
- if (!shouldMonitorPixelBasedConstraints(constraints)) {
271
- // Avoid the overhead of ResizeObserver if no pixel constraints require monitoring
272
- return;
273
- }
274
-
275
- if (typeof ResizeObserver === "undefined") {
276
- console.warn(
277
- `WARNING: Pixel based constraints require ResizeObserver but it is not supported by the current browser.`
278
- );
279
- } else {
280
- const resizeObserver = new ResizeObserver(() => {
281
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
282
-
283
- const { onLayout } = committedValuesRef.current;
284
-
285
- const nextLayout = validatePanelGroupLayout({
286
- groupSizePixels,
287
- layout: prevLayout,
288
- panelConstraints: panelDataArray.map(
289
- (panelData) => panelData.constraints
290
- ),
291
- });
292
-
293
- if (!areEqual(prevLayout, nextLayout)) {
294
- setLayout(nextLayout);
295
-
296
- eagerValuesRef.current.layout = nextLayout;
297
-
298
- if (onLayout) {
299
- onLayout(
300
- nextLayout.map((sizePercentage) => ({
301
- sizePercentage,
302
- sizePixels: convertPercentageToPixels(
303
- sizePercentage,
304
- groupSizePixels
305
- ),
306
- }))
307
- );
308
- }
309
-
310
- callPanelCallbacks(
311
- groupId,
312
- panelDataArray,
313
- nextLayout,
314
- panelIdToLastNotifiedMixedSizesMapRef.current
315
- );
316
- }
317
- });
318
222
 
319
- resizeObserver.observe(getPanelGroupElement(groupId)!);
223
+ debounceMap[autoSaveId] = debouncedSave;
224
+ }
320
225
 
321
- return () => {
322
- resizeObserver.disconnect();
323
- };
226
+ debouncedSave(autoSaveId, panelDataArray, layout, storage);
324
227
  }
325
- }, [groupId]);
228
+ }, [autoSaveId, layout, storage]);
326
229
 
327
230
  // DEV warnings
328
231
  useEffect(() => {
@@ -362,17 +265,17 @@ function PanelGroupWithForwardedRef({
362
265
  (panelData) => panelData.constraints
363
266
  );
364
267
 
365
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
366
-
367
268
  for (
368
269
  let panelIndex = 0;
369
270
  panelIndex < panelConstraints.length;
370
271
  panelIndex++
371
272
  ) {
273
+ const panelData = panelDataArray[panelIndex];
274
+ assert(panelData);
275
+
372
276
  const isValid = validatePanelConstraints({
373
- groupSizePixels,
374
277
  panelConstraints,
375
- panelId: panelDataArray[panelIndex].id,
278
+ panelId: panelData.id,
376
279
  panelIndex,
377
280
  });
378
281
 
@@ -387,170 +290,130 @@ function PanelGroupWithForwardedRef({
387
290
  });
388
291
 
389
292
  // External APIs are safe to memoize via committed values ref
390
- const collapsePanel = useCallback(
391
- (panelData: PanelData) => {
392
- const { onLayout } = committedValuesRef.current;
393
- const { layout: prevLayout, panelDataArray } = eagerValuesRef.current;
293
+ const collapsePanel = useCallback((panelData: PanelData) => {
294
+ const { onLayout } = committedValuesRef.current;
295
+ const { layout: prevLayout, panelDataArray } = eagerValuesRef.current;
394
296
 
395
- if (panelData.constraints.collapsible) {
396
- const panelConstraintsArray = panelDataArray.map(
397
- (panelData) => panelData.constraints
398
- );
297
+ if (panelData.constraints.collapsible) {
298
+ const panelConstraintsArray = panelDataArray.map(
299
+ (panelData) => panelData.constraints
300
+ );
399
301
 
400
- const {
401
- collapsedSizePercentage,
402
- panelSizePercentage,
403
- pivotIndices,
404
- groupSizePixels,
405
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
406
-
407
- if (panelSizePercentage !== collapsedSizePercentage) {
408
- // Store size before collapse;
409
- // This is the size that gets restored if the expand() API is used.
410
- panelSizeBeforeCollapseRef.current.set(
411
- panelData.id,
412
- panelSizePercentage
413
- );
302
+ const {
303
+ collapsedSize = 0,
304
+ panelSize,
305
+ pivotIndices,
306
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
414
307
 
415
- const isLastPanel =
416
- panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
417
- const delta = isLastPanel
418
- ? panelSizePercentage - collapsedSizePercentage
419
- : collapsedSizePercentage - panelSizePercentage;
420
-
421
- const nextLayout = adjustLayoutByDelta({
422
- delta,
423
- groupSizePixels,
424
- layout: prevLayout,
425
- panelConstraints: panelConstraintsArray,
426
- pivotIndices,
427
- trigger: "imperative-api",
428
- });
308
+ assert(panelSize != null);
429
309
 
430
- if (!compareLayouts(prevLayout, nextLayout)) {
431
- setLayout(nextLayout);
310
+ if (panelSize !== collapsedSize) {
311
+ // Store size before collapse;
312
+ // This is the size that gets restored if the expand() API is used.
313
+ panelSizeBeforeCollapseRef.current.set(panelData.id, panelSize);
432
314
 
433
- eagerValuesRef.current.layout = nextLayout;
315
+ const isLastPanel =
316
+ panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
317
+ const delta = isLastPanel
318
+ ? panelSize - collapsedSize
319
+ : collapsedSize - panelSize;
434
320
 
435
- if (onLayout) {
436
- onLayout(
437
- nextLayout.map((sizePercentage) => ({
438
- sizePercentage,
439
- sizePixels: convertPercentageToPixels(
440
- sizePercentage,
441
- groupSizePixels
442
- ),
443
- }))
444
- );
445
- }
321
+ const nextLayout = adjustLayoutByDelta({
322
+ delta,
323
+ layout: prevLayout,
324
+ panelConstraints: panelConstraintsArray,
325
+ pivotIndices,
326
+ trigger: "imperative-api",
327
+ });
446
328
 
447
- callPanelCallbacks(
448
- groupId,
449
- panelDataArray,
450
- nextLayout,
451
- panelIdToLastNotifiedMixedSizesMapRef.current
452
- );
329
+ if (!compareLayouts(prevLayout, nextLayout)) {
330
+ setLayout(nextLayout);
331
+
332
+ eagerValuesRef.current.layout = nextLayout;
333
+
334
+ if (onLayout) {
335
+ onLayout(nextLayout);
453
336
  }
337
+
338
+ callPanelCallbacks(
339
+ panelDataArray,
340
+ nextLayout,
341
+ panelIdToLastNotifiedSizeMapRef.current
342
+ );
454
343
  }
455
344
  }
456
- },
457
- [groupId]
458
- );
345
+ }
346
+ }, []);
459
347
 
460
348
  // External APIs are safe to memoize via committed values ref
461
- const expandPanel = useCallback(
462
- (panelData: PanelData) => {
463
- const { onLayout } = committedValuesRef.current;
464
- const { layout: prevLayout, panelDataArray } = eagerValuesRef.current;
349
+ const expandPanel = useCallback((panelData: PanelData) => {
350
+ const { onLayout } = committedValuesRef.current;
351
+ const { layout: prevLayout, panelDataArray } = eagerValuesRef.current;
465
352
 
466
- if (panelData.constraints.collapsible) {
467
- const panelConstraintsArray = panelDataArray.map(
468
- (panelData) => panelData.constraints
353
+ if (panelData.constraints.collapsible) {
354
+ const panelConstraintsArray = panelDataArray.map(
355
+ (panelData) => panelData.constraints
356
+ );
357
+
358
+ const {
359
+ collapsedSize = 0,
360
+ panelSize,
361
+ minSize = 0,
362
+ pivotIndices,
363
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
364
+
365
+ if (panelSize === collapsedSize) {
366
+ // Restore this panel to the size it was before it was collapsed, if possible.
367
+ const prevPanelSize = panelSizeBeforeCollapseRef.current.get(
368
+ panelData.id
469
369
  );
470
370
 
471
- const {
472
- collapsedSizePercentage,
473
- panelSizePercentage,
474
- minSizePercentage,
475
- pivotIndices,
476
- groupSizePixels,
477
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
478
-
479
- if (panelSizePercentage === collapsedSizePercentage) {
480
- // Restore this panel to the size it was before it was collapsed, if possible.
481
- const prevPanelSizePercentage =
482
- panelSizeBeforeCollapseRef.current.get(panelData.id);
483
-
484
- const baseSizePercentage =
485
- prevPanelSizePercentage != null &&
486
- prevPanelSizePercentage >= minSizePercentage
487
- ? prevPanelSizePercentage
488
- : minSizePercentage;
489
-
490
- const isLastPanel =
491
- panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
492
- const delta = isLastPanel
493
- ? panelSizePercentage - baseSizePercentage
494
- : baseSizePercentage - panelSizePercentage;
495
-
496
- const nextLayout = adjustLayoutByDelta({
497
- delta,
498
- groupSizePixels,
499
- layout: prevLayout,
500
- panelConstraints: panelConstraintsArray,
501
- pivotIndices,
502
- trigger: "imperative-api",
503
- });
371
+ const baseSize =
372
+ prevPanelSize != null && prevPanelSize >= minSize
373
+ ? prevPanelSize
374
+ : minSize;
504
375
 
505
- if (!compareLayouts(prevLayout, nextLayout)) {
506
- setLayout(nextLayout);
376
+ const isLastPanel =
377
+ panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
378
+ const delta = isLastPanel ? panelSize - baseSize : baseSize - panelSize;
507
379
 
508
- eagerValuesRef.current.layout = nextLayout;
380
+ const nextLayout = adjustLayoutByDelta({
381
+ delta,
382
+ layout: prevLayout,
383
+ panelConstraints: panelConstraintsArray,
384
+ pivotIndices,
385
+ trigger: "imperative-api",
386
+ });
509
387
 
510
- if (onLayout) {
511
- onLayout(
512
- nextLayout.map((sizePercentage) => ({
513
- sizePercentage,
514
- sizePixels: convertPercentageToPixels(
515
- sizePercentage,
516
- groupSizePixels
517
- ),
518
- }))
519
- );
520
- }
388
+ if (!compareLayouts(prevLayout, nextLayout)) {
389
+ setLayout(nextLayout);
521
390
 
522
- callPanelCallbacks(
523
- groupId,
524
- panelDataArray,
525
- nextLayout,
526
- panelIdToLastNotifiedMixedSizesMapRef.current
527
- );
391
+ eagerValuesRef.current.layout = nextLayout;
392
+
393
+ if (onLayout) {
394
+ onLayout(nextLayout);
528
395
  }
396
+
397
+ callPanelCallbacks(
398
+ panelDataArray,
399
+ nextLayout,
400
+ panelIdToLastNotifiedSizeMapRef.current
401
+ );
529
402
  }
530
403
  }
531
- },
532
- [groupId]
533
- );
404
+ }
405
+ }, []);
534
406
 
535
407
  // External APIs are safe to memoize via committed values ref
536
- const getPanelSize = useCallback(
537
- (panelData: PanelData) => {
538
- const { layout, panelDataArray } = eagerValuesRef.current;
408
+ const getPanelSize = useCallback((panelData: PanelData) => {
409
+ const { layout, panelDataArray } = eagerValuesRef.current;
539
410
 
540
- const { panelSizePercentage, panelSizePixels } = panelDataHelper(
541
- groupId,
542
- panelDataArray,
543
- panelData,
544
- layout
545
- );
411
+ const { panelSize } = panelDataHelper(panelDataArray, panelData, layout);
546
412
 
547
- return {
548
- sizePercentage: panelSizePercentage,
549
- sizePixels: panelSizePixels,
550
- };
551
- },
552
- [groupId]
553
- );
413
+ assert(panelSize != null);
414
+
415
+ return panelSize;
416
+ }, []);
554
417
 
555
418
  // This API should never read from committedValuesRef
556
419
  const getPanelStyle = useCallback(
@@ -570,32 +433,32 @@ function PanelGroupWithForwardedRef({
570
433
  );
571
434
 
572
435
  // External APIs are safe to memoize via committed values ref
573
- const isPanelCollapsed = useCallback(
574
- (panelData: PanelData) => {
575
- const { layout, panelDataArray } = eagerValuesRef.current;
436
+ const isPanelCollapsed = useCallback((panelData: PanelData) => {
437
+ const { layout, panelDataArray } = eagerValuesRef.current;
576
438
 
577
- const { collapsedSizePercentage, collapsible, panelSizePercentage } =
578
- panelDataHelper(groupId, panelDataArray, panelData, layout);
439
+ const { collapsedSize, collapsible, panelSize } = panelDataHelper(
440
+ panelDataArray,
441
+ panelData,
442
+ layout
443
+ );
579
444
 
580
- return (
581
- collapsible === true && panelSizePercentage === collapsedSizePercentage
582
- );
583
- },
584
- [groupId]
585
- );
445
+ return collapsible === true && panelSize === collapsedSize;
446
+ }, []);
586
447
 
587
448
  // External APIs are safe to memoize via committed values ref
588
- const isPanelExpanded = useCallback(
589
- (panelData: PanelData) => {
590
- const { layout, panelDataArray } = eagerValuesRef.current;
449
+ const isPanelExpanded = useCallback((panelData: PanelData) => {
450
+ const { layout, panelDataArray } = eagerValuesRef.current;
591
451
 
592
- const { collapsedSizePercentage, collapsible, panelSizePercentage } =
593
- panelDataHelper(groupId, panelDataArray, panelData, layout);
452
+ const {
453
+ collapsedSize = 0,
454
+ collapsible,
455
+ panelSize,
456
+ } = panelDataHelper(panelDataArray, panelData, layout);
594
457
 
595
- return !collapsible || panelSizePercentage > collapsedSizePercentage;
596
- },
597
- [groupId]
598
- );
458
+ assert(panelSize != null);
459
+
460
+ return !collapsible || panelSize > collapsedSize;
461
+ }, []);
599
462
 
600
463
  const registerPanel = useCallback((panelData: PanelData) => {
601
464
  const {
@@ -635,21 +498,8 @@ function PanelGroupWithForwardedRef({
635
498
  unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
636
499
  }
637
500
 
638
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
639
- if (groupSizePixels <= 0) {
640
- if (
641
- shouldMonitorPixelBasedConstraints(
642
- panelDataArray.map(({ constraints }) => constraints)
643
- )
644
- ) {
645
- // Wait until the group has rendered a non-zero size before computing layout.
646
- return;
647
- }
648
- }
649
-
650
501
  if (unsafeLayout == null) {
651
502
  unsafeLayout = calculateUnsafeDefaultLayout({
652
- groupSizePixels,
653
503
  panelDataArray,
654
504
  });
655
505
  }
@@ -657,7 +507,6 @@ function PanelGroupWithForwardedRef({
657
507
  // Validate even saved layouts in case something has changed since last render
658
508
  // e.g. for pixel groups, this could be the size of the window
659
509
  const nextLayout = validatePanelGroupLayout({
660
- groupSizePixels,
661
510
  layout: unsafeLayout,
662
511
  panelConstraints: panelDataArray.map(
663
512
  (panelData) => panelData.constraints
@@ -673,22 +522,13 @@ function PanelGroupWithForwardedRef({
673
522
 
674
523
  if (!areEqual(prevLayout, nextLayout)) {
675
524
  if (onLayout) {
676
- onLayout(
677
- nextLayout.map((sizePercentage) => ({
678
- sizePercentage,
679
- sizePixels: convertPercentageToPixels(
680
- sizePercentage,
681
- groupSizePixels
682
- ),
683
- }))
684
- );
525
+ onLayout(nextLayout);
685
526
  }
686
527
 
687
528
  callPanelCallbacks(
688
- groupId,
689
529
  panelDataArray,
690
530
  nextLayout,
691
- panelIdToLastNotifiedMixedSizesMapRef.current
531
+ panelIdToLastNotifiedSizeMapRef.current
692
532
  );
693
533
  }
694
534
  }, []);
@@ -701,8 +541,7 @@ function PanelGroupWithForwardedRef({
701
541
  direction,
702
542
  dragState,
703
543
  id: groupId,
704
- keyboardResizeByPercentage,
705
- keyboardResizeByPixels,
544
+ keyboardResizeBy,
706
545
  onLayout,
707
546
  } = committedValuesRef.current;
708
547
  const { layout: prevLayout, panelDataArray } = eagerValuesRef.current;
@@ -713,14 +552,10 @@ function PanelGroupWithForwardedRef({
713
552
 
714
553
  let delta = calculateDeltaPercentage(
715
554
  event,
716
- groupId,
717
555
  dragHandleId,
718
556
  direction,
719
- dragState!,
720
- {
721
- percentage: keyboardResizeByPercentage,
722
- pixels: keyboardResizeByPixels,
723
- }
557
+ dragState,
558
+ keyboardResizeBy
724
559
  );
725
560
  if (delta === 0) {
726
561
  return;
@@ -732,14 +567,12 @@ function PanelGroupWithForwardedRef({
732
567
  delta = -delta;
733
568
  }
734
569
 
735
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
736
570
  const panelConstraints = panelDataArray.map(
737
571
  (panelData) => panelData.constraints
738
572
  );
739
573
 
740
574
  const nextLayout = adjustLayoutByDelta({
741
575
  delta,
742
- groupSizePixels,
743
576
  layout: initialLayout ?? prevLayout,
744
577
  panelConstraints,
745
578
  pivotIndices,
@@ -782,22 +615,13 @@ function PanelGroupWithForwardedRef({
782
615
  eagerValuesRef.current.layout = nextLayout;
783
616
 
784
617
  if (onLayout) {
785
- onLayout(
786
- nextLayout.map((sizePercentage) => ({
787
- sizePercentage,
788
- sizePixels: convertPercentageToPixels(
789
- sizePercentage,
790
- groupSizePixels
791
- ),
792
- }))
793
- );
618
+ onLayout(nextLayout);
794
619
  }
795
620
 
796
621
  callPanelCallbacks(
797
- groupId,
798
622
  panelDataArray,
799
623
  nextLayout,
800
- panelIdToLastNotifiedMixedSizesMapRef.current
624
+ panelIdToLastNotifiedSizeMapRef.current
801
625
  );
802
626
  }
803
627
  };
@@ -805,7 +629,7 @@ function PanelGroupWithForwardedRef({
805
629
 
806
630
  // External APIs are safe to memoize via committed values ref
807
631
  const resizePanel = useCallback(
808
- (panelData: PanelData, mixedSizes: Partial<MixedSizes>) => {
632
+ (panelData: PanelData, unsafePanelSize: number) => {
809
633
  const { onLayout } = committedValuesRef.current;
810
634
 
811
635
  const { layout: prevLayout, panelDataArray } = eagerValuesRef.current;
@@ -814,23 +638,22 @@ function PanelGroupWithForwardedRef({
814
638
  (panelData) => panelData.constraints
815
639
  );
816
640
 
817
- const { groupSizePixels, panelSizePercentage, pivotIndices } =
818
- panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
641
+ const { panelSize, pivotIndices } = panelDataHelper(
642
+ panelDataArray,
643
+ panelData,
644
+ prevLayout
645
+ );
819
646
 
820
- const sizePercentage = getPercentageSizeFromMixedSizes(
821
- mixedSizes,
822
- groupSizePixels
823
- )!;
647
+ assert(panelSize != null);
824
648
 
825
649
  const isLastPanel =
826
650
  panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
827
651
  const delta = isLastPanel
828
- ? panelSizePercentage - sizePercentage
829
- : sizePercentage - panelSizePercentage;
652
+ ? panelSize - unsafePanelSize
653
+ : unsafePanelSize - panelSize;
830
654
 
831
655
  const nextLayout = adjustLayoutByDelta({
832
656
  delta,
833
- groupSizePixels,
834
657
  layout: prevLayout,
835
658
  panelConstraints: panelConstraintsArray,
836
659
  pivotIndices,
@@ -843,26 +666,17 @@ function PanelGroupWithForwardedRef({
843
666
  eagerValuesRef.current.layout = nextLayout;
844
667
 
845
668
  if (onLayout) {
846
- onLayout(
847
- nextLayout.map((sizePercentage) => ({
848
- sizePercentage,
849
- sizePixels: convertPercentageToPixels(
850
- sizePercentage,
851
- groupSizePixels
852
- ),
853
- }))
854
- );
669
+ onLayout(nextLayout);
855
670
  }
856
671
 
857
672
  callPanelCallbacks(
858
- groupId,
859
673
  panelDataArray,
860
674
  nextLayout,
861
- panelIdToLastNotifiedMixedSizesMapRef.current
675
+ panelIdToLastNotifiedSizeMapRef.current
862
676
  );
863
677
  }
864
678
  },
865
- [groupId]
679
+ []
866
680
  );
867
681
 
868
682
  const startDragging = useCallback(
@@ -870,7 +684,8 @@ function PanelGroupWithForwardedRef({
870
684
  const { direction } = committedValuesRef.current;
871
685
  const { layout } = eagerValuesRef.current;
872
686
 
873
- const handleElement = getResizeHandleElement(dragHandleId)!;
687
+ const handleElement = getResizeHandleElement(dragHandleId);
688
+ assert(handleElement);
874
689
 
875
690
  const initialCursorPosition = getResizeEventCursorPosition(
876
691
  direction,
@@ -900,7 +715,7 @@ function PanelGroupWithForwardedRef({
900
715
  timeout: null,
901
716
  });
902
717
  const unregisterPanel = useCallback((panelData: PanelData) => {
903
- const { id: groupId, onLayout } = committedValuesRef.current;
718
+ const { onLayout } = committedValuesRef.current;
904
719
  const { layout: prevLayout, panelDataArray } = eagerValuesRef.current;
905
720
 
906
721
  const index = panelDataArray.indexOf(panelData);
@@ -918,7 +733,7 @@ function PanelGroupWithForwardedRef({
918
733
  // We can't check the DOM to detect this because Panel elements have not yet been removed.
919
734
  unregisterPanelRef.current.timeout = setTimeout(() => {
920
735
  const { pendingPanelIds } = unregisterPanelRef.current;
921
- const map = panelIdToLastNotifiedMixedSizesMapRef.current;
736
+ const map = panelIdToLastNotifiedSizeMapRef.current;
922
737
 
923
738
  // TRICKY
924
739
  // Strict effects mode
@@ -946,17 +761,13 @@ function PanelGroupWithForwardedRef({
946
761
  return;
947
762
  }
948
763
 
949
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
950
-
951
764
  let unsafeLayout: number[] = calculateUnsafeDefaultLayout({
952
- groupSizePixels,
953
765
  panelDataArray,
954
766
  });
955
767
 
956
768
  // Validate even saved layouts in case something has changed since last render
957
769
  // e.g. for pixel groups, this could be the size of the window
958
770
  const nextLayout = validatePanelGroupLayout({
959
- groupSizePixels,
960
771
  layout: unsafeLayout,
961
772
  panelConstraints: panelDataArray.map(
962
773
  (panelData) => panelData.constraints
@@ -969,22 +780,13 @@ function PanelGroupWithForwardedRef({
969
780
  eagerValuesRef.current.layout = nextLayout;
970
781
 
971
782
  if (onLayout) {
972
- onLayout(
973
- nextLayout.map((sizePercentage) => ({
974
- sizePercentage,
975
- sizePixels: convertPercentageToPixels(
976
- sizePercentage,
977
- groupSizePixels
978
- ),
979
- }))
980
- );
783
+ onLayout(nextLayout);
981
784
  }
982
785
 
983
786
  callPanelCallbacks(
984
- groupId,
985
787
  panelDataArray,
986
788
  nextLayout,
987
- panelIdToLastNotifiedMixedSizesMapRef.current
789
+ panelIdToLastNotifiedSizeMapRef.current
988
790
  );
989
791
  }
990
792
  }, 0);
@@ -1039,6 +841,8 @@ function PanelGroupWithForwardedRef({
1039
841
  PanelGroupContext.Provider,
1040
842
  { value: context },
1041
843
  createElement(Type, {
844
+ ...rest,
845
+
1042
846
  children,
1043
847
  className: classNameFromProps,
1044
848
  style: {
@@ -1046,8 +850,6 @@ function PanelGroupWithForwardedRef({
1046
850
  ...styleFromProps,
1047
851
  },
1048
852
 
1049
- ...dataAttributes,
1050
-
1051
853
  // CSS selectors
1052
854
  "data-panel-group": "",
1053
855
  "data-panel-group-direction": direction,
@@ -1067,7 +869,6 @@ PanelGroupWithForwardedRef.displayName = "PanelGroup";
1067
869
  PanelGroup.displayName = "forwardRef(PanelGroup)";
1068
870
 
1069
871
  function panelDataHelper(
1070
- groupId: string,
1071
872
  panelDataArray: PanelData[],
1072
873
  panelData: PanelData,
1073
874
  layout: number[]
@@ -1079,31 +880,16 @@ function panelDataHelper(
1079
880
  const panelIndex = panelDataArray.indexOf(panelData);
1080
881
  const panelConstraints = panelConstraintsArray[panelIndex];
1081
882
 
1082
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1083
-
1084
- const percentagePanelConstraints = computePercentagePanelConstraints(
1085
- panelConstraintsArray,
1086
- panelIndex,
1087
- groupSizePixels
1088
- );
1089
-
1090
883
  const isLastPanel = panelIndex === panelDataArray.length - 1;
1091
884
  const pivotIndices = isLastPanel
1092
885
  ? [panelIndex - 1, panelIndex]
1093
886
  : [panelIndex, panelIndex + 1];
1094
887
 
1095
- const panelSizePercentage = layout[panelIndex];
1096
- const panelSizePixels = convertPercentageToPixels(
1097
- panelSizePercentage,
1098
- groupSizePixels
1099
- );
888
+ const panelSize = layout[panelIndex];
1100
889
 
1101
890
  return {
1102
- ...percentagePanelConstraints,
1103
- collapsible: panelConstraints.collapsible,
1104
- panelSizePercentage,
1105
- panelSizePixels,
1106
- groupSizePixels,
891
+ ...panelConstraints,
892
+ panelSize,
1107
893
  pivotIndices,
1108
894
  };
1109
895
  }