react-resizable-panels 0.0.63 → 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 (72) hide show
  1. package/.eslintrc.cjs +1 -0
  2. package/CHANGELOG.md +5 -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 +252 -517
  11. package/dist/react-resizable-panels.browser.cjs.mjs +2 -1
  12. package/dist/react-resizable-panels.browser.development.cjs.js +278 -573
  13. package/dist/react-resizable-panels.browser.development.cjs.mjs +2 -1
  14. package/dist/react-resizable-panels.browser.development.esm.js +278 -574
  15. package/dist/react-resizable-panels.browser.esm.js +252 -518
  16. package/dist/react-resizable-panels.cjs.js +252 -517
  17. package/dist/react-resizable-panels.cjs.js.map +1 -1
  18. package/dist/react-resizable-panels.cjs.mjs +2 -1
  19. package/dist/react-resizable-panels.development.cjs.js +280 -575
  20. package/dist/react-resizable-panels.development.cjs.mjs +2 -1
  21. package/dist/react-resizable-panels.development.esm.js +280 -576
  22. package/dist/react-resizable-panels.development.node.cjs.js +266 -501
  23. package/dist/react-resizable-panels.development.node.cjs.mjs +2 -1
  24. package/dist/react-resizable-panels.development.node.esm.js +266 -502
  25. package/dist/react-resizable-panels.esm.js +252 -518
  26. package/dist/react-resizable-panels.esm.js.map +1 -1
  27. package/dist/react-resizable-panels.node.cjs.js +238 -443
  28. package/dist/react-resizable-panels.node.cjs.mjs +2 -1
  29. package/dist/react-resizable-panels.node.esm.js +238 -444
  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/getResizeEventCursorPosition.ts +2 -0
  53. package/src/utils/resizePanel.test.ts +6 -52
  54. package/src/utils/resizePanel.ts +24 -46
  55. package/src/utils/test-utils.ts +6 -7
  56. package/src/utils/validatePanelConstraints.test.ts +12 -65
  57. package/src/utils/validatePanelConstraints.ts +26 -67
  58. package/src/utils/validatePanelGroupLayout.test.ts +27 -142
  59. package/src/utils/validatePanelGroupLayout.ts +17 -13
  60. package/src/vendor/react.ts +2 -0
  61. package/src/utils/computePercentagePanelConstraints.test.ts +0 -98
  62. package/src/utils/computePercentagePanelConstraints.ts +0 -56
  63. package/src/utils/convertPercentageToPixels.test.ts +0 -9
  64. package/src/utils/convertPercentageToPixels.ts +0 -6
  65. package/src/utils/convertPixelConstraintsToPercentages.test.ts +0 -47
  66. package/src/utils/convertPixelConstraintsToPercentages.ts +0 -72
  67. package/src/utils/convertPixelsToPercentage.test.ts +0 -9
  68. package/src/utils/convertPixelsToPercentage.ts +0 -6
  69. package/src/utils/getPercentageSizeFromMixedSizes.test.ts +0 -47
  70. package/src/utils/getPercentageSizeFromMixedSizes.ts +0 -15
  71. package/src/utils/shouldMonitorPixelBasedConstraints.test.ts +0 -23
  72. package/src/utils/shouldMonitorPixelBasedConstraints.ts +0 -13
@@ -39,24 +39,20 @@ function useUniqueId(idFromParams = null) {
39
39
  function PanelWithForwardedRef({
40
40
  children,
41
41
  className: classNameFromProps = "",
42
- collapsedSizePercentage,
43
- collapsedSizePixels,
42
+ collapsedSize,
44
43
  collapsible,
45
- dataAttributes,
46
- defaultSizePercentage,
47
- defaultSizePixels,
44
+ defaultSize,
48
45
  forwardedRef,
49
46
  id: idFromProps,
50
- maxSizePercentage,
51
- maxSizePixels,
52
- minSizePercentage,
53
- minSizePixels,
47
+ maxSize,
48
+ minSize,
54
49
  onCollapse,
55
50
  onExpand,
56
51
  onResize,
57
52
  order,
58
53
  style: styleFromProps,
59
- tagName: Type = "div"
54
+ tagName: Type = "div",
55
+ ...rest
60
56
  }) {
61
57
  const context = useContext(PanelGroupContext);
62
58
  if (context === null) {
@@ -81,15 +77,11 @@ function PanelWithForwardedRef({
81
77
  onResize
82
78
  },
83
79
  constraints: {
84
- collapsedSizePercentage,
85
- collapsedSizePixels,
80
+ collapsedSize,
86
81
  collapsible,
87
- defaultSizePercentage,
88
- defaultSizePixels,
89
- maxSizePercentage,
90
- maxSizePixels,
91
- minSizePercentage,
92
- minSizePixels
82
+ defaultSize,
83
+ maxSize,
84
+ minSize
93
85
  },
94
86
  id: panelId,
95
87
  idIsFromProps: idFromProps !== undefined,
@@ -117,19 +109,19 @@ function PanelWithForwardedRef({
117
109
  isExpanded() {
118
110
  return !isPanelCollapsed(panelDataRef.current);
119
111
  },
120
- resize: mixedSizes => {
121
- resizePanel(panelDataRef.current, mixedSizes);
112
+ resize: size => {
113
+ resizePanel(panelDataRef.current, size);
122
114
  }
123
115
  }), [collapsePanel, expandPanel, getPanelSize, isPanelCollapsed, panelId, resizePanel]);
124
116
  const style = getPanelStyle(panelDataRef.current);
125
117
  return createElement(Type, {
118
+ ...rest,
126
119
  children,
127
120
  className: classNameFromProps,
128
121
  style: {
129
122
  ...style,
130
123
  ...styleFromProps
131
124
  },
132
- ...dataAttributes,
133
125
  // CSS selectors
134
126
  "data-panel": "",
135
127
  "data-panel-id": panelId,
@@ -146,81 +138,11 @@ const Panel = forwardRef((props, ref) => createElement(PanelWithForwardedRef, {
146
138
  PanelWithForwardedRef.displayName = "Panel";
147
139
  Panel.displayName = "forwardRef(Panel)";
148
140
 
149
- function convertPixelsToPercentage(pixels, groupSizePixels) {
150
- return pixels / groupSizePixels * 100;
151
- }
152
-
153
- function convertPixelConstraintsToPercentages(panelConstraints, groupSizePixels) {
154
- let {
155
- collapsedSizePercentage = 0,
156
- collapsedSizePixels,
157
- defaultSizePercentage,
158
- defaultSizePixels,
159
- maxSizePercentage = 100,
160
- maxSizePixels,
161
- minSizePercentage = 0,
162
- minSizePixels
163
- } = panelConstraints;
164
- const hasPixelConstraints = collapsedSizePixels != null || defaultSizePixels != null || minSizePixels != null || maxSizePixels != null;
165
- if (hasPixelConstraints && groupSizePixels <= 0) {
166
- console.warn(`WARNING: Invalid group size: ${groupSizePixels}px`);
167
- return {
168
- collapsedSizePercentage: 0,
169
- defaultSizePercentage,
170
- maxSizePercentage: 0,
171
- minSizePercentage: 0
172
- };
173
- }
174
- if (collapsedSizePixels != null) {
175
- collapsedSizePercentage = convertPixelsToPercentage(collapsedSizePixels, groupSizePixels);
176
- }
177
- if (defaultSizePixels != null) {
178
- defaultSizePercentage = convertPixelsToPercentage(defaultSizePixels, groupSizePixels);
179
- }
180
- if (minSizePixels != null) {
181
- minSizePercentage = convertPixelsToPercentage(minSizePixels, groupSizePixels);
182
- }
183
- if (maxSizePixels != null) {
184
- maxSizePercentage = convertPixelsToPercentage(maxSizePixels, groupSizePixels);
185
- }
186
- return {
187
- collapsedSizePercentage,
188
- defaultSizePercentage,
189
- maxSizePercentage,
190
- minSizePercentage
191
- };
192
- }
193
-
194
- function computePercentagePanelConstraints(panelConstraintsArray, panelIndex, groupSizePixels) {
195
- // All panel constraints, excluding the current one
196
- let totalMinConstraints = 0;
197
- let totalMaxConstraints = 0;
198
- for (let index = 0; index < panelConstraintsArray.length; index++) {
199
- if (index !== panelIndex) {
200
- const {
201
- collapsible
202
- } = panelConstraintsArray[index];
203
- const {
204
- collapsedSizePercentage,
205
- maxSizePercentage,
206
- minSizePercentage
207
- } = convertPixelConstraintsToPercentages(panelConstraintsArray[index], groupSizePixels);
208
- totalMaxConstraints += maxSizePercentage;
209
- totalMinConstraints += collapsible ? collapsedSizePercentage : minSizePercentage;
210
- }
141
+ function assert(expectedCondition, message = "Assertion failed!") {
142
+ if (!expectedCondition) {
143
+ console.error(message);
144
+ throw Error(message);
211
145
  }
212
- const {
213
- collapsedSizePercentage,
214
- defaultSizePercentage,
215
- maxSizePercentage,
216
- minSizePercentage
217
- } = convertPixelConstraintsToPercentages(panelConstraintsArray[panelIndex], groupSizePixels);
218
- return {
219
- collapsedSizePercentage,
220
- defaultSizePercentage,
221
- maxSizePercentage: panelConstraintsArray.length > 1 ? Math.min(maxSizePercentage, 100 - totalMinConstraints) : maxSizePercentage,
222
- minSizePercentage: panelConstraintsArray.length > 1 ? Math.max(minSizePercentage, 100 - totalMaxConstraints) : minSizePercentage
223
- };
224
146
  }
225
147
 
226
148
  const PRECISION = 10;
@@ -242,56 +164,41 @@ function fuzzyNumbersEqual(actual, expected, fractionDigits) {
242
164
 
243
165
  // Panel size must be in percentages; pixel values should be pre-converted
244
166
  function resizePanel({
245
- groupSizePixels,
246
- panelConstraints,
167
+ panelConstraints: panelConstraintsArray,
247
168
  panelIndex,
248
169
  size
249
170
  }) {
250
- const hasPixelConstraints = panelConstraints.some(({
251
- collapsedSizePixels,
252
- defaultSizePixels,
253
- minSizePixels,
254
- maxSizePixels
255
- }) => collapsedSizePixels != null || defaultSizePixels != null || minSizePixels != null || maxSizePixels != null);
256
- if (hasPixelConstraints && groupSizePixels <= 0) {
257
- console.warn(`WARNING: Invalid group size: ${groupSizePixels}px`);
258
- return 0;
259
- }
171
+ const panelConstraints = panelConstraintsArray[panelIndex];
172
+ assert(panelConstraints != null);
260
173
  let {
261
- collapsible
262
- } = panelConstraints[panelIndex];
263
- const {
264
- collapsedSizePercentage,
265
- maxSizePercentage,
266
- minSizePercentage
267
- } = computePercentagePanelConstraints(panelConstraints, panelIndex, groupSizePixels);
268
- if (minSizePercentage != null) {
269
- if (fuzzyCompareNumbers(size, minSizePercentage) < 0) {
270
- if (collapsible) {
271
- // Collapsible panels should snap closed or open only once they cross the halfway point between collapsed and min size.
272
- const halfwayPoint = (collapsedSizePercentage + minSizePercentage) / 2;
273
- if (fuzzyCompareNumbers(size, halfwayPoint) < 0) {
274
- size = collapsedSizePercentage;
275
- } else {
276
- size = minSizePercentage;
277
- }
174
+ collapsedSize = 0,
175
+ collapsible,
176
+ maxSize = 100,
177
+ minSize = 0
178
+ } = panelConstraints;
179
+ if (fuzzyCompareNumbers(size, minSize) < 0) {
180
+ if (collapsible) {
181
+ // Collapsible panels should snap closed or open only once they cross the halfway point between collapsed and min size.
182
+ const halfwayPoint = (collapsedSize + minSize) / 2;
183
+ if (fuzzyCompareNumbers(size, halfwayPoint) < 0) {
184
+ size = collapsedSize;
278
185
  } else {
279
- size = minSizePercentage;
186
+ size = minSize;
280
187
  }
188
+ } else {
189
+ size = minSize;
281
190
  }
282
191
  }
283
- if (maxSizePercentage != null) {
284
- size = Math.min(maxSizePercentage, size);
285
- }
192
+ size = Math.min(maxSize, size);
193
+ size = parseFloat(size.toFixed(PRECISION));
286
194
  return size;
287
195
  }
288
196
 
289
197
  // All units must be in percentages; pixel values should be pre-converted
290
198
  function adjustLayoutByDelta({
291
199
  delta,
292
- groupSizePixels,
293
200
  layout: prevLayout,
294
- panelConstraints,
201
+ panelConstraints: panelConstraintsArray,
295
202
  pivotIndices,
296
203
  trigger
297
204
  }) {
@@ -299,6 +206,9 @@ function adjustLayoutByDelta({
299
206
  return prevLayout;
300
207
  }
301
208
  const nextLayout = [...prevLayout];
209
+ const [firstPivotIndex, secondPivotIndex] = pivotIndices;
210
+ assert(firstPivotIndex != null);
211
+ assert(secondPivotIndex != null);
302
212
  let deltaApplied = 0;
303
213
 
304
214
  //const DEBUG = [];
@@ -322,18 +232,23 @@ function adjustLayoutByDelta({
322
232
  if (trigger === "keyboard") {
323
233
  {
324
234
  // Check if we should expand a collapsed panel
325
- const index = delta < 0 ? pivotIndices[1] : pivotIndices[0];
326
- const constraints = panelConstraints[index];
235
+ const index = delta < 0 ? secondPivotIndex : firstPivotIndex;
236
+ const panelConstraints = panelConstraintsArray[index];
237
+ assert(panelConstraints);
238
+
327
239
  //DEBUG.push(`edge case check 1: ${index}`);
328
240
  //DEBUG.push(` -> collapsible? ${constraints.collapsible}`);
329
- if (constraints.collapsible) {
241
+ if (panelConstraints.collapsible) {
330
242
  const prevSize = prevLayout[index];
243
+ assert(prevSize != null);
244
+ const panelConstraints = panelConstraintsArray[index];
245
+ assert(panelConstraints);
331
246
  const {
332
- collapsedSizePercentage,
333
- minSizePercentage
334
- } = computePercentagePanelConstraints(panelConstraints, index, groupSizePixels);
335
- if (fuzzyNumbersEqual(prevSize, collapsedSizePercentage)) {
336
- const localDelta = minSizePercentage - prevSize;
247
+ collapsedSize = 0,
248
+ minSize = 0
249
+ } = panelConstraints;
250
+ if (fuzzyNumbersEqual(prevSize, collapsedSize)) {
251
+ const localDelta = minSize - prevSize;
337
252
  //DEBUG.push(` -> expand delta: ${localDelta}`);
338
253
 
339
254
  if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0) {
@@ -346,18 +261,26 @@ function adjustLayoutByDelta({
346
261
 
347
262
  {
348
263
  // Check if we should collapse a panel at its minimum size
349
- const index = delta < 0 ? pivotIndices[0] : pivotIndices[1];
350
- const constraints = panelConstraints[index];
264
+ const index = delta < 0 ? firstPivotIndex : secondPivotIndex;
265
+ const panelConstraints = panelConstraintsArray[index];
266
+ assert(panelConstraints);
267
+ const {
268
+ collapsible
269
+ } = panelConstraints;
270
+
351
271
  //DEBUG.push(`edge case check 2: ${index}`);
352
- //DEBUG.push(` -> collapsible? ${constraints.collapsible}`);
353
- if (constraints.collapsible) {
272
+ //DEBUG.push(` -> collapsible? ${collapsible}`);
273
+ if (collapsible) {
354
274
  const prevSize = prevLayout[index];
275
+ assert(prevSize != null);
276
+ const panelConstraints = panelConstraintsArray[index];
277
+ assert(panelConstraints);
355
278
  const {
356
- collapsedSizePercentage,
357
- minSizePercentage
358
- } = computePercentagePanelConstraints(panelConstraints, index, groupSizePixels);
359
- if (fuzzyNumbersEqual(prevSize, minSizePercentage)) {
360
- const localDelta = prevSize - collapsedSizePercentage;
279
+ collapsedSize = 0,
280
+ minSize = 0
281
+ } = panelConstraints;
282
+ if (fuzzyNumbersEqual(prevSize, minSize)) {
283
+ const localDelta = prevSize - collapsedSize;
361
284
  //DEBUG.push(` -> expand delta: ${localDelta}`);
362
285
 
363
286
  if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0) {
@@ -379,15 +302,15 @@ function adjustLayoutByDelta({
379
302
  // as an expanding panel might change from collapsed to min size.
380
303
 
381
304
  const increment = delta < 0 ? 1 : -1;
382
- let index = delta < 0 ? pivotIndices[1] : pivotIndices[0];
305
+ let index = delta < 0 ? secondPivotIndex : firstPivotIndex;
383
306
  let maxAvailableDelta = 0;
384
307
 
385
308
  //DEBUG.push("pre calc...");
386
309
  while (true) {
387
310
  const prevSize = prevLayout[index];
311
+ assert(prevSize != null);
388
312
  const maxSafeSize = resizePanel({
389
- groupSizePixels,
390
- panelConstraints,
313
+ panelConstraints: panelConstraintsArray,
391
314
  panelIndex: index,
392
315
  size: 100
393
316
  });
@@ -396,7 +319,7 @@ function adjustLayoutByDelta({
396
319
 
397
320
  maxAvailableDelta += delta;
398
321
  index += increment;
399
- if (index < 0 || index >= panelConstraints.length) {
322
+ if (index < 0 || index >= panelConstraintsArray.length) {
400
323
  break;
401
324
  }
402
325
  }
@@ -411,15 +334,15 @@ function adjustLayoutByDelta({
411
334
  {
412
335
  // Delta added to a panel needs to be subtracted from other panels (within the constraints that those panels allow).
413
336
 
414
- const pivotIndex = delta < 0 ? pivotIndices[0] : pivotIndices[1];
337
+ const pivotIndex = delta < 0 ? firstPivotIndex : secondPivotIndex;
415
338
  let index = pivotIndex;
416
- while (index >= 0 && index < panelConstraints.length) {
339
+ while (index >= 0 && index < panelConstraintsArray.length) {
417
340
  const deltaRemaining = Math.abs(delta) - Math.abs(deltaApplied);
418
341
  const prevSize = prevLayout[index];
342
+ assert(prevSize != null);
419
343
  const unsafeSize = prevSize - deltaRemaining;
420
344
  const safeSize = resizePanel({
421
- groupSizePixels,
422
- panelConstraints,
345
+ panelConstraints: panelConstraintsArray,
423
346
  panelIndex: index,
424
347
  size: unsafeSize
425
348
  });
@@ -451,11 +374,12 @@ function adjustLayoutByDelta({
451
374
  }
452
375
  {
453
376
  // Now distribute the applied delta to the panels in the other direction
454
- const pivotIndex = delta < 0 ? pivotIndices[1] : pivotIndices[0];
455
- const unsafeSize = prevLayout[pivotIndex] + deltaApplied;
377
+ const pivotIndex = delta < 0 ? secondPivotIndex : firstPivotIndex;
378
+ const prevSize = prevLayout[pivotIndex];
379
+ assert(prevSize != null);
380
+ const unsafeSize = prevSize + deltaApplied;
456
381
  const safeSize = resizePanel({
457
- groupSizePixels,
458
- panelConstraints,
382
+ panelConstraints: panelConstraintsArray,
459
383
  panelIndex: pivotIndex,
460
384
  size: unsafeSize
461
385
  });
@@ -466,14 +390,14 @@ function adjustLayoutByDelta({
466
390
  // Edge case where expanding or contracting one panel caused another one to change collapsed state
467
391
  if (!fuzzyNumbersEqual(safeSize, unsafeSize)) {
468
392
  let deltaRemaining = unsafeSize - safeSize;
469
- const pivotIndex = delta < 0 ? pivotIndices[1] : pivotIndices[0];
393
+ const pivotIndex = delta < 0 ? secondPivotIndex : firstPivotIndex;
470
394
  let index = pivotIndex;
471
- while (index >= 0 && index < panelConstraints.length) {
395
+ while (index >= 0 && index < panelConstraintsArray.length) {
472
396
  const prevSize = nextLayout[index];
397
+ assert(prevSize != null);
473
398
  const unsafeSize = prevSize + deltaRemaining;
474
399
  const safeSize = resizePanel({
475
- groupSizePixels,
476
- panelConstraints,
400
+ panelConstraints: panelConstraintsArray,
477
401
  panelIndex: index,
478
402
  size: unsafeSize
479
403
  });
@@ -497,9 +421,7 @@ function adjustLayoutByDelta({
497
421
  //DEBUG.push("");
498
422
 
499
423
  const totalSize = nextLayout.reduce((total, size) => size + total, 0);
500
- deltaApplied = 100 - totalSize;
501
424
  //DEBUG.push(`total size: ${totalSize}`);
502
- //DEBUG.push(` deltaApplied: ${deltaApplied}`);
503
425
  //console.log(DEBUG.join("\n"));
504
426
 
505
427
  if (!fuzzyNumbersEqual(totalSize, 100)) {
@@ -508,25 +430,6 @@ function adjustLayoutByDelta({
508
430
  return nextLayout;
509
431
  }
510
432
 
511
- function assert(expectedCondition, message = "Assertion failed!") {
512
- if (!expectedCondition) {
513
- console.error(message);
514
- throw Error(message);
515
- }
516
- }
517
-
518
- function getPercentageSizeFromMixedSizes({
519
- sizePercentage,
520
- sizePixels
521
- }, groupSizePixels) {
522
- if (sizePercentage != null) {
523
- return sizePercentage;
524
- } else if (sizePixels != null) {
525
- return convertPixelsToPercentage(sizePixels, groupSizePixels);
526
- }
527
- return undefined;
528
- }
529
-
530
433
  function getResizeHandleElementsForGroup(groupId) {
531
434
  return Array.from(document.querySelectorAll(`[data-panel-resize-handle-id][data-panel-group-id="${groupId}"]`));
532
435
  }
@@ -550,42 +453,6 @@ function getPanelGroupElement(id) {
550
453
  return null;
551
454
  }
552
455
 
553
- function calculateAvailablePanelSizeInPixels(groupId) {
554
- const panelGroupElement = getPanelGroupElement(groupId);
555
- if (panelGroupElement == null) {
556
- return NaN;
557
- }
558
- const direction = panelGroupElement.getAttribute("data-panel-group-direction");
559
- const resizeHandles = getResizeHandleElementsForGroup(groupId);
560
- if (direction === "horizontal") {
561
- return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
562
- return accumulated + handle.offsetWidth;
563
- }, 0);
564
- } else {
565
- return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
566
- return accumulated + handle.offsetHeight;
567
- }, 0);
568
- }
569
- }
570
-
571
- function getAvailableGroupSizePixels(groupId) {
572
- const panelGroupElement = getPanelGroupElement(groupId);
573
- if (panelGroupElement == null) {
574
- return NaN;
575
- }
576
- const direction = panelGroupElement.getAttribute("data-panel-group-direction");
577
- const resizeHandles = getResizeHandleElementsForGroup(groupId);
578
- if (direction === "horizontal") {
579
- return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
580
- return accumulated + handle.offsetWidth;
581
- }, 0);
582
- } else {
583
- return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
584
- return accumulated + handle.offsetHeight;
585
- }, 0);
586
- }
587
- }
588
-
589
456
  function getResizeHandleElement(id) {
590
457
  const element = document.querySelector(`[data-panel-resize-handle-id="${id}"]`);
591
458
  if (element) {
@@ -618,14 +485,18 @@ function useWindowSplitterPanelGroupBehavior({
618
485
  didWarnAboutMissingResizeHandle: false
619
486
  });
620
487
  useEffect(() => {
488
+ const eagerValues = eagerValuesRef.current;
489
+ assert(eagerValues);
621
490
  const {
622
491
  panelDataArray
623
- } = eagerValuesRef.current;
492
+ } = eagerValues;
624
493
  const groupElement = getPanelGroupElement(groupId);
625
494
  assert(groupElement != null, `No group found for id "${groupId}"`);
626
495
  const handles = getResizeHandleElementsForGroup(groupId);
496
+ assert(handles);
627
497
  const cleanupFunctions = handles.map(handle => {
628
498
  const handleId = handle.getAttribute("data-panel-resize-handle-id");
499
+ assert(handleId);
629
500
  const [idBefore, idAfter] = getResizeHandlePanelIds(groupId, handleId, panelDataArray);
630
501
  if (idBefore == null || idAfter == null) {
631
502
  return () => {};
@@ -641,21 +512,16 @@ function useWindowSplitterPanelGroupBehavior({
641
512
  const index = panelDataArray.findIndex(panelData => panelData.id === idBefore);
642
513
  if (index >= 0) {
643
514
  const panelData = panelDataArray[index];
515
+ assert(panelData);
644
516
  const size = layout[index];
645
- if (size != null && panelData.constraints.collapsible) {
646
- var _getPercentageSizeFro, _getPercentageSizeFro2;
647
- const groupSizePixels = getAvailableGroupSizePixels(groupId);
648
- const collapsedSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
649
- sizePercentage: panelData.constraints.collapsedSizePercentage,
650
- sizePixels: panelData.constraints.collapsedSizePixels
651
- }, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
652
- const minSize = (_getPercentageSizeFro2 = getPercentageSizeFromMixedSizes({
653
- sizePercentage: panelData.constraints.minSizePercentage,
654
- sizePixels: panelData.constraints.minSizePixels
655
- }, groupSizePixels)) !== null && _getPercentageSizeFro2 !== void 0 ? _getPercentageSizeFro2 : 0;
517
+ const {
518
+ collapsedSize = 0,
519
+ collapsible,
520
+ minSize = 0
521
+ } = panelData.constraints;
522
+ if (size != null && collapsible) {
656
523
  const nextLayout = adjustLayoutByDelta({
657
524
  delta: fuzzyNumbersEqual(size, collapsedSize) ? minSize - collapsedSize : collapsedSize - size,
658
- groupSizePixels,
659
525
  layout,
660
526
  panelConstraints: panelDataArray.map(panelData => panelData.constraints),
661
527
  pivotIndices: determinePivotIndices(groupId, handleId),
@@ -709,6 +575,7 @@ function getResizeEventCursorPosition(direction, event) {
709
575
  return isHorizontal ? event.clientX : event.clientY;
710
576
  } else if (isTouchEvent(event)) {
711
577
  const firstTouch = event.touches[0];
578
+ assert(firstTouch);
712
579
  return isHorizontal ? firstTouch.screenX : firstTouch.screenY;
713
580
  } else {
714
581
  throw Error(`Unsupported event type "${event.type}"`);
@@ -718,12 +585,15 @@ function getResizeEventCursorPosition(direction, event) {
718
585
  function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState) {
719
586
  const isHorizontal = direction === "horizontal";
720
587
  const handleElement = getResizeHandleElement(dragHandleId);
588
+ assert(handleElement);
721
589
  const groupId = handleElement.getAttribute("data-panel-group-id");
590
+ assert(groupId);
722
591
  let {
723
592
  initialCursorPosition
724
593
  } = initialDragState;
725
594
  const cursorPosition = getResizeEventCursorPosition(direction, event);
726
595
  const groupElement = getPanelGroupElement(groupId);
596
+ assert(groupElement);
727
597
  const groupRect = groupElement.getBoundingClientRect();
728
598
  const groupSizeInPixels = isHorizontal ? groupRect.width : groupRect.height;
729
599
  const offsetPixels = cursorPosition - initialCursorPosition;
@@ -732,19 +602,14 @@ function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDr
732
602
  }
733
603
 
734
604
  // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX
735
- function calculateDeltaPercentage(event, groupId, dragHandleId, direction, initialDragState, keyboardResizeByOptions) {
605
+ function calculateDeltaPercentage(event, dragHandleId, direction, initialDragState, keyboardResizeBy) {
736
606
  if (isKeyDown(event)) {
737
607
  const isHorizontal = direction === "horizontal";
738
- const groupElement = getPanelGroupElement(groupId);
739
- const rect = groupElement.getBoundingClientRect();
740
- const groupSizeInPixels = isHorizontal ? rect.width : rect.height;
741
608
  let delta = 0;
742
609
  if (event.shiftKey) {
743
610
  delta = 100;
744
- } else if (keyboardResizeByOptions.percentage != null) {
745
- delta = keyboardResizeByOptions.percentage;
746
- } else if (keyboardResizeByOptions.pixels != null) {
747
- delta = keyboardResizeByOptions.pixels / groupSizeInPixels;
611
+ } else if (keyboardResizeBy != null) {
612
+ delta = keyboardResizeBy;
748
613
  } else {
749
614
  delta = 10;
750
615
  }
@@ -771,37 +636,43 @@ function calculateDeltaPercentage(event, groupId, dragHandleId, direction, initi
771
636
  }
772
637
  return movement;
773
638
  } else {
639
+ if (initialDragState == null) {
640
+ return 0;
641
+ }
774
642
  return calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState);
775
643
  }
776
644
  }
777
645
 
778
646
  function calculateUnsafeDefaultLayout({
779
- groupSizePixels,
780
647
  panelDataArray
781
648
  }) {
782
649
  const layout = Array(panelDataArray.length);
783
- const panelDataConstraints = panelDataArray.map(panelData => panelData.constraints);
650
+ const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
784
651
  let numPanelsWithSizes = 0;
785
652
  let remainingSize = 100;
786
653
 
787
654
  // Distribute default sizes first
788
655
  for (let index = 0; index < panelDataArray.length; index++) {
656
+ const panelConstraints = panelConstraintsArray[index];
657
+ assert(panelConstraints);
789
658
  const {
790
- defaultSizePercentage
791
- } = computePercentagePanelConstraints(panelDataConstraints, index, groupSizePixels);
792
- if (defaultSizePercentage != null) {
659
+ defaultSize
660
+ } = panelConstraints;
661
+ if (defaultSize != null) {
793
662
  numPanelsWithSizes++;
794
- layout[index] = defaultSizePercentage;
795
- remainingSize -= defaultSizePercentage;
663
+ layout[index] = defaultSize;
664
+ remainingSize -= defaultSize;
796
665
  }
797
666
  }
798
667
 
799
668
  // Remaining size should be distributed evenly between panels without default sizes
800
669
  for (let index = 0; index < panelDataArray.length; index++) {
670
+ const panelConstraints = panelConstraintsArray[index];
671
+ assert(panelConstraints);
801
672
  const {
802
- defaultSizePercentage
803
- } = computePercentagePanelConstraints(panelDataConstraints, index, groupSizePixels);
804
- if (defaultSizePercentage != null) {
673
+ defaultSize
674
+ } = panelConstraints;
675
+ if (defaultSize != null) {
805
676
  continue;
806
677
  }
807
678
  const numRemainingPanels = panelDataArray.length - numPanelsWithSizes;
@@ -813,54 +684,36 @@ function calculateUnsafeDefaultLayout({
813
684
  return layout;
814
685
  }
815
686
 
816
- function convertPercentageToPixels(percentage, groupSizePixels) {
817
- return percentage / 100 * groupSizePixels;
818
- }
819
-
820
687
  // Layout should be pre-converted into percentages
821
- function callPanelCallbacks(groupId, panelsArray, layout, panelIdToLastNotifiedMixedSizesMap) {
822
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
823
- layout.forEach((sizePercentage, index) => {
688
+ function callPanelCallbacks(panelsArray, layout, panelIdToLastNotifiedSizeMap) {
689
+ layout.forEach((size, index) => {
824
690
  const panelData = panelsArray[index];
825
- if (!panelData) {
826
- // Handle initial mount (when panels are registered too late to be in the panels array)
827
- // The subsequent render+effects will handle the resize notification
828
- return;
829
- }
691
+ assert(panelData);
830
692
  const {
831
693
  callbacks,
832
694
  constraints,
833
695
  id: panelId
834
696
  } = panelData;
835
697
  const {
698
+ collapsedSize = 0,
836
699
  collapsible
837
700
  } = constraints;
838
- const mixedSizes = {
839
- sizePercentage,
840
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
841
- };
842
- const lastNotifiedMixedSizes = panelIdToLastNotifiedMixedSizesMap[panelId];
843
- if (lastNotifiedMixedSizes == null || mixedSizes.sizePercentage !== lastNotifiedMixedSizes.sizePercentage || mixedSizes.sizePixels !== lastNotifiedMixedSizes.sizePixels) {
844
- panelIdToLastNotifiedMixedSizesMap[panelId] = mixedSizes;
701
+ const lastNotifiedSize = panelIdToLastNotifiedSizeMap[panelId];
702
+ if (lastNotifiedSize == null || size !== lastNotifiedSize) {
703
+ panelIdToLastNotifiedSizeMap[panelId] = size;
845
704
  const {
846
705
  onCollapse,
847
706
  onExpand,
848
707
  onResize
849
708
  } = callbacks;
850
709
  if (onResize) {
851
- onResize(mixedSizes, lastNotifiedMixedSizes);
710
+ onResize(size, lastNotifiedSize);
852
711
  }
853
712
  if (collapsible && (onCollapse || onExpand)) {
854
- var _getPercentageSizeFro;
855
- const collapsedSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
856
- sizePercentage: constraints.collapsedSizePercentage,
857
- sizePixels: constraints.collapsedSizePixels
858
- }, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
859
- const size = getPercentageSizeFromMixedSizes(mixedSizes, groupSizePixels);
860
- if (onExpand && (lastNotifiedMixedSizes == null || lastNotifiedMixedSizes.sizePercentage === collapsedSize) && size !== collapsedSize) {
713
+ if (onExpand && (lastNotifiedSize == null || lastNotifiedSize === collapsedSize) && size !== collapsedSize) {
861
714
  onExpand();
862
715
  }
863
- if (onCollapse && (lastNotifiedMixedSizes == null || lastNotifiedMixedSizes.sizePercentage !== collapsedSize) && size === collapsedSize) {
716
+ if (onCollapse && (lastNotifiedSize == null || lastNotifiedSize !== collapsedSize) && size === collapsedSize) {
864
717
  onCollapse();
865
718
  }
866
719
  }
@@ -1043,31 +896,32 @@ function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
1043
896
  }
1044
897
  }
1045
898
 
1046
- function shouldMonitorPixelBasedConstraints(constraints) {
1047
- return constraints.some(constraints => {
1048
- return constraints.collapsedSizePixels !== undefined || constraints.maxSizePixels !== undefined || constraints.minSizePixels !== undefined;
1049
- });
1050
- }
1051
-
1052
899
  // All units must be in percentages; pixel values should be pre-converted
1053
900
  function validatePanelGroupLayout({
1054
- groupSizePixels,
1055
901
  layout: prevLayout,
1056
902
  panelConstraints
1057
903
  }) {
1058
904
  const nextLayout = [...prevLayout];
905
+ const nextLayoutTotalSize = nextLayout.reduce((accumulated, current) => accumulated + current, 0);
1059
906
 
1060
907
  // Validate layout expectations
1061
908
  if (nextLayout.length !== panelConstraints.length) {
1062
909
  throw Error(`Invalid ${panelConstraints.length} panel layout: ${nextLayout.map(size => `${size}%`).join(", ")}`);
1063
- } else if (!fuzzyNumbersEqual(nextLayout.reduce((accumulated, current) => accumulated + current, 0), 100)) ;
910
+ } else if (!fuzzyNumbersEqual(nextLayoutTotalSize, 100)) {
911
+ for (let index = 0; index < panelConstraints.length; index++) {
912
+ const unsafeSize = nextLayout[index];
913
+ assert(unsafeSize != null);
914
+ const safeSize = 100 / nextLayoutTotalSize * unsafeSize;
915
+ nextLayout[index] = safeSize;
916
+ }
917
+ }
1064
918
  let remainingSize = 0;
1065
919
 
1066
920
  // First pass: Validate the proposed layout given each panel's constraints
1067
921
  for (let index = 0; index < panelConstraints.length; index++) {
1068
922
  const unsafeSize = nextLayout[index];
923
+ assert(unsafeSize != null);
1069
924
  const safeSize = resizePanel({
1070
- groupSizePixels,
1071
925
  panelConstraints,
1072
926
  panelIndex: index,
1073
927
  size: unsafeSize
@@ -1083,9 +937,9 @@ function validatePanelGroupLayout({
1083
937
  if (!fuzzyNumbersEqual(remainingSize, 0)) {
1084
938
  for (let index = 0; index < panelConstraints.length; index++) {
1085
939
  const prevSize = nextLayout[index];
940
+ assert(prevSize != null);
1086
941
  const unsafeSize = prevSize + remainingSize;
1087
942
  const safeSize = resizePanel({
1088
- groupSizePixels,
1089
943
  panelConstraints,
1090
944
  panelIndex: index,
1091
945
  size: unsafeSize
@@ -1120,21 +974,20 @@ function PanelGroupWithForwardedRef({
1120
974
  autoSaveId = null,
1121
975
  children,
1122
976
  className: classNameFromProps = "",
1123
- dataAttributes,
1124
977
  direction,
1125
978
  forwardedRef,
1126
- id: idFromProps,
979
+ id: idFromProps = null,
1127
980
  onLayout = null,
1128
- keyboardResizeByPercentage = null,
1129
- keyboardResizeByPixels = null,
981
+ keyboardResizeBy = null,
1130
982
  storage = defaultStorage,
1131
983
  style: styleFromProps,
1132
- tagName: Type = "div"
984
+ tagName: Type = "div",
985
+ ...rest
1133
986
  }) {
1134
987
  const groupId = useUniqueId(idFromProps);
1135
988
  const [dragState, setDragState] = useState(null);
1136
989
  const [layout, setLayout] = useState([]);
1137
- const panelIdToLastNotifiedMixedSizesMapRef = useRef({});
990
+ const panelIdToLastNotifiedSizeMapRef = useRef({});
1138
991
  const panelSizeBeforeCollapseRef = useRef(new Map());
1139
992
  const prevDeltaRef = useRef(0);
1140
993
  const committedValuesRef = useRef({
@@ -1142,8 +995,7 @@ function PanelGroupWithForwardedRef({
1142
995
  direction,
1143
996
  dragState,
1144
997
  id: groupId,
1145
- keyboardResizeByPercentage,
1146
- keyboardResizeByPixels,
998
+ keyboardResizeBy,
1147
999
  onLayout,
1148
1000
  storage
1149
1001
  });
@@ -1159,33 +1011,20 @@ function PanelGroupWithForwardedRef({
1159
1011
  useImperativeHandle(forwardedRef, () => ({
1160
1012
  getId: () => committedValuesRef.current.id,
1161
1013
  getLayout: () => {
1162
- const {
1163
- id: groupId
1164
- } = committedValuesRef.current;
1165
1014
  const {
1166
1015
  layout
1167
1016
  } = eagerValuesRef.current;
1168
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1169
- return layout.map(sizePercentage => {
1170
- return {
1171
- sizePercentage,
1172
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1173
- };
1174
- });
1017
+ return layout;
1175
1018
  },
1176
- setLayout: mixedSizes => {
1019
+ setLayout: unsafeLayout => {
1177
1020
  const {
1178
- id: groupId,
1179
1021
  onLayout
1180
1022
  } = committedValuesRef.current;
1181
1023
  const {
1182
1024
  layout: prevLayout,
1183
1025
  panelDataArray
1184
1026
  } = eagerValuesRef.current;
1185
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1186
- const unsafeLayout = mixedSizes.map(mixedSize => getPercentageSizeFromMixedSizes(mixedSize, groupSizePixels));
1187
1027
  const safeLayout = validatePanelGroupLayout({
1188
- groupSizePixels,
1189
1028
  layout: unsafeLayout,
1190
1029
  panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1191
1030
  });
@@ -1193,16 +1032,12 @@ function PanelGroupWithForwardedRef({
1193
1032
  setLayout(safeLayout);
1194
1033
  eagerValuesRef.current.layout = safeLayout;
1195
1034
  if (onLayout) {
1196
- onLayout(safeLayout.map(sizePercentage => ({
1197
- sizePercentage,
1198
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1199
- })));
1035
+ onLayout(safeLayout);
1200
1036
  }
1201
- callPanelCallbacks(groupId, panelDataArray, safeLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1037
+ callPanelCallbacks(panelDataArray, safeLayout, panelIdToLastNotifiedSizeMapRef.current);
1202
1038
  }
1203
1039
  }
1204
1040
  }), []);
1205
-
1206
1041
  useWindowSplitterPanelGroupBehavior({
1207
1042
  committedValuesRef,
1208
1043
  eagerValuesRef,
@@ -1221,12 +1056,14 @@ function PanelGroupWithForwardedRef({
1221
1056
  if (layout.length === 0 || layout.length !== panelDataArray.length) {
1222
1057
  return;
1223
1058
  }
1059
+ let debouncedSave = debounceMap[autoSaveId];
1224
1060
 
1225
1061
  // Limit the frequency of localStorage updates.
1226
- if (!debounceMap[autoSaveId]) {
1227
- debounceMap[autoSaveId] = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1062
+ if (debouncedSave == null) {
1063
+ debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1064
+ debounceMap[autoSaveId] = debouncedSave;
1228
1065
  }
1229
- debounceMap[autoSaveId](autoSaveId, panelDataArray, layout, storage);
1066
+ debouncedSave(autoSaveId, panelDataArray, layout, storage);
1230
1067
  }
1231
1068
  }, [autoSaveId, layout, storage]);
1232
1069
 
@@ -1246,20 +1083,19 @@ function PanelGroupWithForwardedRef({
1246
1083
  if (panelData.constraints.collapsible) {
1247
1084
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1248
1085
  const {
1249
- collapsedSizePercentage,
1250
- panelSizePercentage,
1251
- pivotIndices,
1252
- groupSizePixels
1253
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
1254
- if (panelSizePercentage !== collapsedSizePercentage) {
1086
+ collapsedSize = 0,
1087
+ panelSize,
1088
+ pivotIndices
1089
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
1090
+ assert(panelSize != null);
1091
+ if (panelSize !== collapsedSize) {
1255
1092
  // Store size before collapse;
1256
1093
  // This is the size that gets restored if the expand() API is used.
1257
- panelSizeBeforeCollapseRef.current.set(panelData.id, panelSizePercentage);
1094
+ panelSizeBeforeCollapseRef.current.set(panelData.id, panelSize);
1258
1095
  const isLastPanel = panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
1259
- const delta = isLastPanel ? panelSizePercentage - collapsedSizePercentage : collapsedSizePercentage - panelSizePercentage;
1096
+ const delta = isLastPanel ? panelSize - collapsedSize : collapsedSize - panelSize;
1260
1097
  const nextLayout = adjustLayoutByDelta({
1261
1098
  delta,
1262
- groupSizePixels,
1263
1099
  layout: prevLayout,
1264
1100
  panelConstraints: panelConstraintsArray,
1265
1101
  pivotIndices,
@@ -1269,16 +1105,13 @@ function PanelGroupWithForwardedRef({
1269
1105
  setLayout(nextLayout);
1270
1106
  eagerValuesRef.current.layout = nextLayout;
1271
1107
  if (onLayout) {
1272
- onLayout(nextLayout.map(sizePercentage => ({
1273
- sizePercentage,
1274
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1275
- })));
1108
+ onLayout(nextLayout);
1276
1109
  }
1277
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1110
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1278
1111
  }
1279
1112
  }
1280
1113
  }
1281
- }, [groupId]);
1114
+ }, []);
1282
1115
 
1283
1116
  // External APIs are safe to memoize via committed values ref
1284
1117
  const expandPanel = useCallback(panelData => {
@@ -1292,21 +1125,19 @@ function PanelGroupWithForwardedRef({
1292
1125
  if (panelData.constraints.collapsible) {
1293
1126
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1294
1127
  const {
1295
- collapsedSizePercentage,
1296
- panelSizePercentage,
1297
- minSizePercentage,
1298
- pivotIndices,
1299
- groupSizePixels
1300
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
1301
- if (panelSizePercentage === collapsedSizePercentage) {
1128
+ collapsedSize = 0,
1129
+ panelSize,
1130
+ minSize = 0,
1131
+ pivotIndices
1132
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
1133
+ if (panelSize === collapsedSize) {
1302
1134
  // Restore this panel to the size it was before it was collapsed, if possible.
1303
- const prevPanelSizePercentage = panelSizeBeforeCollapseRef.current.get(panelData.id);
1304
- const baseSizePercentage = prevPanelSizePercentage != null && prevPanelSizePercentage >= minSizePercentage ? prevPanelSizePercentage : minSizePercentage;
1135
+ const prevPanelSize = panelSizeBeforeCollapseRef.current.get(panelData.id);
1136
+ const baseSize = prevPanelSize != null && prevPanelSize >= minSize ? prevPanelSize : minSize;
1305
1137
  const isLastPanel = panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
1306
- const delta = isLastPanel ? panelSizePercentage - baseSizePercentage : baseSizePercentage - panelSizePercentage;
1138
+ const delta = isLastPanel ? panelSize - baseSize : baseSize - panelSize;
1307
1139
  const nextLayout = adjustLayoutByDelta({
1308
1140
  delta,
1309
- groupSizePixels,
1310
1141
  layout: prevLayout,
1311
1142
  panelConstraints: panelConstraintsArray,
1312
1143
  pivotIndices,
@@ -1316,16 +1147,13 @@ function PanelGroupWithForwardedRef({
1316
1147
  setLayout(nextLayout);
1317
1148
  eagerValuesRef.current.layout = nextLayout;
1318
1149
  if (onLayout) {
1319
- onLayout(nextLayout.map(sizePercentage => ({
1320
- sizePercentage,
1321
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1322
- })));
1150
+ onLayout(nextLayout);
1323
1151
  }
1324
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1152
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1325
1153
  }
1326
1154
  }
1327
1155
  }
1328
- }, [groupId]);
1156
+ }, []);
1329
1157
 
1330
1158
  // External APIs are safe to memoize via committed values ref
1331
1159
  const getPanelSize = useCallback(panelData => {
@@ -1334,14 +1162,11 @@ function PanelGroupWithForwardedRef({
1334
1162
  panelDataArray
1335
1163
  } = eagerValuesRef.current;
1336
1164
  const {
1337
- panelSizePercentage,
1338
- panelSizePixels
1339
- } = panelDataHelper(groupId, panelDataArray, panelData, layout);
1340
- return {
1341
- sizePercentage: panelSizePercentage,
1342
- sizePixels: panelSizePixels
1343
- };
1344
- }, [groupId]);
1165
+ panelSize
1166
+ } = panelDataHelper(panelDataArray, panelData, layout);
1167
+ assert(panelSize != null);
1168
+ return panelSize;
1169
+ }, []);
1345
1170
 
1346
1171
  // This API should never read from committedValuesRef
1347
1172
  const getPanelStyle = useCallback(panelData => {
@@ -1364,12 +1189,12 @@ function PanelGroupWithForwardedRef({
1364
1189
  panelDataArray
1365
1190
  } = eagerValuesRef.current;
1366
1191
  const {
1367
- collapsedSizePercentage,
1192
+ collapsedSize,
1368
1193
  collapsible,
1369
- panelSizePercentage
1370
- } = panelDataHelper(groupId, panelDataArray, panelData, layout);
1371
- return collapsible === true && panelSizePercentage === collapsedSizePercentage;
1372
- }, [groupId]);
1194
+ panelSize
1195
+ } = panelDataHelper(panelDataArray, panelData, layout);
1196
+ return collapsible === true && panelSize === collapsedSize;
1197
+ }, []);
1373
1198
 
1374
1199
  // External APIs are safe to memoize via committed values ref
1375
1200
  const isPanelExpanded = useCallback(panelData => {
@@ -1378,12 +1203,13 @@ function PanelGroupWithForwardedRef({
1378
1203
  panelDataArray
1379
1204
  } = eagerValuesRef.current;
1380
1205
  const {
1381
- collapsedSizePercentage,
1206
+ collapsedSize = 0,
1382
1207
  collapsible,
1383
- panelSizePercentage
1384
- } = panelDataHelper(groupId, panelDataArray, panelData, layout);
1385
- return !collapsible || panelSizePercentage > collapsedSizePercentage;
1386
- }, [groupId]);
1208
+ panelSize
1209
+ } = panelDataHelper(panelDataArray, panelData, layout);
1210
+ assert(panelSize != null);
1211
+ return !collapsible || panelSize > collapsedSize;
1212
+ }, []);
1387
1213
  const registerPanel = useCallback(panelData => {
1388
1214
  const {
1389
1215
  autoSaveId,
@@ -1423,18 +1249,8 @@ function PanelGroupWithForwardedRef({
1423
1249
  if (autoSaveId) {
1424
1250
  unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
1425
1251
  }
1426
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1427
- if (groupSizePixels <= 0) {
1428
- if (shouldMonitorPixelBasedConstraints(panelDataArray.map(({
1429
- constraints
1430
- }) => constraints))) {
1431
- // Wait until the group has rendered a non-zero size before computing layout.
1432
- return;
1433
- }
1434
- }
1435
1252
  if (unsafeLayout == null) {
1436
1253
  unsafeLayout = calculateUnsafeDefaultLayout({
1437
- groupSizePixels,
1438
1254
  panelDataArray
1439
1255
  });
1440
1256
  }
@@ -1442,7 +1258,6 @@ function PanelGroupWithForwardedRef({
1442
1258
  // Validate even saved layouts in case something has changed since last render
1443
1259
  // e.g. for pixel groups, this could be the size of the window
1444
1260
  const nextLayout = validatePanelGroupLayout({
1445
- groupSizePixels,
1446
1261
  layout: unsafeLayout,
1447
1262
  panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1448
1263
  });
@@ -1454,12 +1269,9 @@ function PanelGroupWithForwardedRef({
1454
1269
  eagerValuesRef.current.layout = nextLayout;
1455
1270
  if (!areEqual(prevLayout, nextLayout)) {
1456
1271
  if (onLayout) {
1457
- onLayout(nextLayout.map(sizePercentage => ({
1458
- sizePercentage,
1459
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1460
- })));
1272
+ onLayout(nextLayout);
1461
1273
  }
1462
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1274
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1463
1275
  }
1464
1276
  }, []);
1465
1277
  const registerResizeHandle = useCallback(dragHandleId => {
@@ -1469,8 +1281,7 @@ function PanelGroupWithForwardedRef({
1469
1281
  direction,
1470
1282
  dragState,
1471
1283
  id: groupId,
1472
- keyboardResizeByPercentage,
1473
- keyboardResizeByPixels,
1284
+ keyboardResizeBy,
1474
1285
  onLayout
1475
1286
  } = committedValuesRef.current;
1476
1287
  const {
@@ -1481,10 +1292,7 @@ function PanelGroupWithForwardedRef({
1481
1292
  initialLayout
1482
1293
  } = dragState !== null && dragState !== void 0 ? dragState : {};
1483
1294
  const pivotIndices = determinePivotIndices(groupId, dragHandleId);
1484
- let delta = calculateDeltaPercentage(event, groupId, dragHandleId, direction, dragState, {
1485
- percentage: keyboardResizeByPercentage,
1486
- pixels: keyboardResizeByPixels
1487
- });
1295
+ let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy);
1488
1296
  if (delta === 0) {
1489
1297
  return;
1490
1298
  }
@@ -1494,11 +1302,9 @@ function PanelGroupWithForwardedRef({
1494
1302
  if (document.dir === "rtl" && isHorizontal) {
1495
1303
  delta = -delta;
1496
1304
  }
1497
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1498
1305
  const panelConstraints = panelDataArray.map(panelData => panelData.constraints);
1499
1306
  const nextLayout = adjustLayoutByDelta({
1500
1307
  delta,
1501
- groupSizePixels,
1502
1308
  layout: initialLayout !== null && initialLayout !== void 0 ? initialLayout : prevLayout,
1503
1309
  panelConstraints,
1504
1310
  pivotIndices,
@@ -1534,18 +1340,15 @@ function PanelGroupWithForwardedRef({
1534
1340
  setLayout(nextLayout);
1535
1341
  eagerValuesRef.current.layout = nextLayout;
1536
1342
  if (onLayout) {
1537
- onLayout(nextLayout.map(sizePercentage => ({
1538
- sizePercentage,
1539
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1540
- })));
1343
+ onLayout(nextLayout);
1541
1344
  }
1542
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1345
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1543
1346
  }
1544
1347
  };
1545
1348
  }, []);
1546
1349
 
1547
1350
  // External APIs are safe to memoize via committed values ref
1548
- const resizePanel = useCallback((panelData, mixedSizes) => {
1351
+ const resizePanel = useCallback((panelData, unsafePanelSize) => {
1549
1352
  const {
1550
1353
  onLayout
1551
1354
  } = committedValuesRef.current;
@@ -1555,16 +1358,14 @@ function PanelGroupWithForwardedRef({
1555
1358
  } = eagerValuesRef.current;
1556
1359
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1557
1360
  const {
1558
- groupSizePixels,
1559
- panelSizePercentage,
1361
+ panelSize,
1560
1362
  pivotIndices
1561
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
1562
- const sizePercentage = getPercentageSizeFromMixedSizes(mixedSizes, groupSizePixels);
1363
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
1364
+ assert(panelSize != null);
1563
1365
  const isLastPanel = panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
1564
- const delta = isLastPanel ? panelSizePercentage - sizePercentage : sizePercentage - panelSizePercentage;
1366
+ const delta = isLastPanel ? panelSize - unsafePanelSize : unsafePanelSize - panelSize;
1565
1367
  const nextLayout = adjustLayoutByDelta({
1566
1368
  delta,
1567
- groupSizePixels,
1568
1369
  layout: prevLayout,
1569
1370
  panelConstraints: panelConstraintsArray,
1570
1371
  pivotIndices,
@@ -1574,14 +1375,11 @@ function PanelGroupWithForwardedRef({
1574
1375
  setLayout(nextLayout);
1575
1376
  eagerValuesRef.current.layout = nextLayout;
1576
1377
  if (onLayout) {
1577
- onLayout(nextLayout.map(sizePercentage => ({
1578
- sizePercentage,
1579
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1580
- })));
1378
+ onLayout(nextLayout);
1581
1379
  }
1582
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1380
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1583
1381
  }
1584
- }, [groupId]);
1382
+ }, []);
1585
1383
  const startDragging = useCallback((dragHandleId, event) => {
1586
1384
  const {
1587
1385
  direction
@@ -1590,6 +1388,7 @@ function PanelGroupWithForwardedRef({
1590
1388
  layout
1591
1389
  } = eagerValuesRef.current;
1592
1390
  const handleElement = getResizeHandleElement(dragHandleId);
1391
+ assert(handleElement);
1593
1392
  const initialCursorPosition = getResizeEventCursorPosition(direction, event);
1594
1393
  setDragState({
1595
1394
  dragHandleId,
@@ -1608,7 +1407,6 @@ function PanelGroupWithForwardedRef({
1608
1407
  });
1609
1408
  const unregisterPanel = useCallback(panelData => {
1610
1409
  const {
1611
- id: groupId,
1612
1410
  onLayout
1613
1411
  } = committedValuesRef.current;
1614
1412
  const {
@@ -1631,7 +1429,7 @@ function PanelGroupWithForwardedRef({
1631
1429
  const {
1632
1430
  pendingPanelIds
1633
1431
  } = unregisterPanelRef.current;
1634
- const map = panelIdToLastNotifiedMixedSizesMapRef.current;
1432
+ const map = panelIdToLastNotifiedSizeMapRef.current;
1635
1433
 
1636
1434
  // TRICKY
1637
1435
  // Strict effects mode
@@ -1657,16 +1455,13 @@ function PanelGroupWithForwardedRef({
1657
1455
  // The group is unmounting; skip layout calculation.
1658
1456
  return;
1659
1457
  }
1660
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1661
1458
  let unsafeLayout = calculateUnsafeDefaultLayout({
1662
- groupSizePixels,
1663
1459
  panelDataArray
1664
1460
  });
1665
1461
 
1666
1462
  // Validate even saved layouts in case something has changed since last render
1667
1463
  // e.g. for pixel groups, this could be the size of the window
1668
1464
  const nextLayout = validatePanelGroupLayout({
1669
- groupSizePixels,
1670
1465
  layout: unsafeLayout,
1671
1466
  panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1672
1467
  });
@@ -1674,12 +1469,9 @@ function PanelGroupWithForwardedRef({
1674
1469
  setLayout(nextLayout);
1675
1470
  eagerValuesRef.current.layout = nextLayout;
1676
1471
  if (onLayout) {
1677
- onLayout(nextLayout.map(sizePercentage => ({
1678
- sizePercentage,
1679
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1680
- })));
1472
+ onLayout(nextLayout);
1681
1473
  }
1682
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1474
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1683
1475
  }
1684
1476
  }, 0);
1685
1477
  }, []);
@@ -1710,13 +1502,13 @@ function PanelGroupWithForwardedRef({
1710
1502
  return createElement(PanelGroupContext.Provider, {
1711
1503
  value: context
1712
1504
  }, createElement(Type, {
1505
+ ...rest,
1713
1506
  children,
1714
1507
  className: classNameFromProps,
1715
1508
  style: {
1716
1509
  ...style,
1717
1510
  ...styleFromProps
1718
1511
  },
1719
- ...dataAttributes,
1720
1512
  // CSS selectors
1721
1513
  "data-panel-group": "",
1722
1514
  "data-panel-group-direction": direction,
@@ -1729,22 +1521,16 @@ const PanelGroup = forwardRef((props, ref) => createElement(PanelGroupWithForwar
1729
1521
  }));
1730
1522
  PanelGroupWithForwardedRef.displayName = "PanelGroup";
1731
1523
  PanelGroup.displayName = "forwardRef(PanelGroup)";
1732
- function panelDataHelper(groupId, panelDataArray, panelData, layout) {
1524
+ function panelDataHelper(panelDataArray, panelData, layout) {
1733
1525
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1734
1526
  const panelIndex = panelDataArray.indexOf(panelData);
1735
1527
  const panelConstraints = panelConstraintsArray[panelIndex];
1736
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1737
- const percentagePanelConstraints = computePercentagePanelConstraints(panelConstraintsArray, panelIndex, groupSizePixels);
1738
1528
  const isLastPanel = panelIndex === panelDataArray.length - 1;
1739
1529
  const pivotIndices = isLastPanel ? [panelIndex - 1, panelIndex] : [panelIndex, panelIndex + 1];
1740
- const panelSizePercentage = layout[panelIndex];
1741
- const panelSizePixels = convertPercentageToPixels(panelSizePercentage, groupSizePixels);
1530
+ const panelSize = layout[panelIndex];
1742
1531
  return {
1743
- ...percentagePanelConstraints,
1744
- collapsible: panelConstraints.collapsible,
1745
- panelSizePercentage,
1746
- panelSizePixels,
1747
- groupSizePixels,
1532
+ ...panelConstraints,
1533
+ panelSize,
1748
1534
  pivotIndices
1749
1535
  };
1750
1536
  }
@@ -1784,6 +1570,7 @@ function useWindowSplitterResizeHandlerBehavior({
1784
1570
  {
1785
1571
  event.preventDefault();
1786
1572
  const groupId = handleElement.getAttribute("data-panel-group-id");
1573
+ assert(groupId);
1787
1574
  const handles = getResizeHandleElementsForGroup(groupId);
1788
1575
  const index = getResizeHandleElementIndex(groupId, handleId);
1789
1576
  assert(index !== null);
@@ -1804,12 +1591,13 @@ function useWindowSplitterResizeHandlerBehavior({
1804
1591
  function PanelResizeHandle({
1805
1592
  children = null,
1806
1593
  className: classNameFromProps = "",
1807
- dataAttributes,
1808
1594
  disabled = false,
1809
- id: idFromProps = null,
1595
+ id: idFromProps,
1810
1596
  onDragging,
1811
1597
  style: styleFromProps = {},
1812
- tagName: Type = "div"
1598
+ tabIndex = 0,
1599
+ tagName: Type = "div",
1600
+ ...rest
1813
1601
  }) {
1814
1602
  const divElementRef = useRef(null);
1815
1603
 
@@ -1839,8 +1627,9 @@ function PanelResizeHandle({
1839
1627
  const stopDraggingAndBlur = useCallback(() => {
1840
1628
  // Clicking on the drag handle shouldn't leave it focused;
1841
1629
  // That would cause the PanelGroup to think it was still active.
1842
- const div = divElementRef.current;
1843
- div.blur();
1630
+ const divElement = divElementRef.current;
1631
+ assert(divElement);
1632
+ divElement.blur();
1844
1633
  stopDragging();
1845
1634
  const {
1846
1635
  onDragging
@@ -1868,6 +1657,7 @@ function PanelResizeHandle({
1868
1657
  resizeHandler(event);
1869
1658
  };
1870
1659
  const divElement = divElementRef.current;
1660
+ assert(divElement);
1871
1661
  const targetDocument = divElement.ownerDocument;
1872
1662
  targetDocument.body.addEventListener("contextmenu", stopDraggingAndBlur);
1873
1663
  targetDocument.body.addEventListener("mousemove", onMove);
@@ -1895,15 +1685,18 @@ function PanelResizeHandle({
1895
1685
  userSelect: "none"
1896
1686
  };
1897
1687
  return createElement(Type, {
1688
+ ...rest,
1898
1689
  children,
1899
1690
  className: classNameFromProps,
1900
1691
  onBlur: () => setIsFocused(false),
1901
1692
  onFocus: () => setIsFocused(true),
1902
1693
  onMouseDown: event => {
1903
1694
  startDragging(resizeHandleId, event.nativeEvent);
1695
+ const callbacks = callbacksRef.current;
1696
+ assert(callbacks);
1904
1697
  const {
1905
1698
  onDragging
1906
- } = callbacksRef.current;
1699
+ } = callbacks;
1907
1700
  if (onDragging) {
1908
1701
  onDragging(true);
1909
1702
  }
@@ -1913,9 +1706,11 @@ function PanelResizeHandle({
1913
1706
  onTouchEnd: stopDraggingAndBlur,
1914
1707
  onTouchStart: event => {
1915
1708
  startDragging(resizeHandleId, event.nativeEvent);
1709
+ const callbacks = callbacksRef.current;
1710
+ assert(callbacks);
1916
1711
  const {
1917
1712
  onDragging
1918
- } = callbacksRef.current;
1713
+ } = callbacks;
1919
1714
  if (onDragging) {
1920
1715
  onDragging(true);
1921
1716
  }
@@ -1926,8 +1721,7 @@ function PanelResizeHandle({
1926
1721
  ...style,
1927
1722
  ...styleFromProps
1928
1723
  },
1929
- tabIndex: 0,
1930
- ...dataAttributes,
1724
+ tabIndex,
1931
1725
  // CSS selectors
1932
1726
  "data-panel-group-direction": direction,
1933
1727
  "data-panel-group-id": groupId,
@@ -1939,4 +1733,4 @@ function PanelResizeHandle({
1939
1733
  }
1940
1734
  PanelResizeHandle.displayName = "PanelResizeHandle";
1941
1735
 
1942
- export { Panel, PanelGroup, PanelResizeHandle };
1736
+ export { Panel, PanelGroup, PanelResizeHandle, assert };