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
@@ -63,24 +63,20 @@ function useUniqueId(idFromParams = null) {
63
63
  function PanelWithForwardedRef({
64
64
  children,
65
65
  className: classNameFromProps = "",
66
- collapsedSizePercentage,
67
- collapsedSizePixels,
66
+ collapsedSize,
68
67
  collapsible,
69
- dataAttributes,
70
- defaultSizePercentage,
71
- defaultSizePixels,
68
+ defaultSize,
72
69
  forwardedRef,
73
70
  id: idFromProps,
74
- maxSizePercentage,
75
- maxSizePixels,
76
- minSizePercentage,
77
- minSizePixels,
71
+ maxSize,
72
+ minSize,
78
73
  onCollapse,
79
74
  onExpand,
80
75
  onResize,
81
76
  order,
82
77
  style: styleFromProps,
83
- tagName: Type = "div"
78
+ tagName: Type = "div",
79
+ ...rest
84
80
  }) {
85
81
  const context = useContext(PanelGroupContext);
86
82
  if (context === null) {
@@ -105,15 +101,11 @@ function PanelWithForwardedRef({
105
101
  onResize
106
102
  },
107
103
  constraints: {
108
- collapsedSizePercentage,
109
- collapsedSizePixels,
104
+ collapsedSize,
110
105
  collapsible,
111
- defaultSizePercentage,
112
- defaultSizePixels,
113
- maxSizePercentage,
114
- maxSizePixels,
115
- minSizePercentage,
116
- minSizePixels
106
+ defaultSize,
107
+ maxSize,
108
+ minSize
117
109
  },
118
110
  id: panelId,
119
111
  idIsFromProps: idFromProps !== undefined,
@@ -141,19 +133,19 @@ function PanelWithForwardedRef({
141
133
  isExpanded() {
142
134
  return !isPanelCollapsed(panelDataRef.current);
143
135
  },
144
- resize: mixedSizes => {
145
- resizePanel(panelDataRef.current, mixedSizes);
136
+ resize: size => {
137
+ resizePanel(panelDataRef.current, size);
146
138
  }
147
139
  }), [collapsePanel, expandPanel, getPanelSize, isPanelCollapsed, panelId, resizePanel]);
148
140
  const style = getPanelStyle(panelDataRef.current);
149
141
  return createElement(Type, {
142
+ ...rest,
150
143
  children,
151
144
  className: classNameFromProps,
152
145
  style: {
153
146
  ...style,
154
147
  ...styleFromProps
155
148
  },
156
- ...dataAttributes,
157
149
  // CSS selectors
158
150
  "data-panel": "",
159
151
  "data-panel-id": panelId,
@@ -170,81 +162,11 @@ const Panel = forwardRef((props, ref) => createElement(PanelWithForwardedRef, {
170
162
  PanelWithForwardedRef.displayName = "Panel";
171
163
  Panel.displayName = "forwardRef(Panel)";
172
164
 
173
- function convertPixelsToPercentage(pixels, groupSizePixels) {
174
- return pixels / groupSizePixels * 100;
175
- }
176
-
177
- function convertPixelConstraintsToPercentages(panelConstraints, groupSizePixels) {
178
- let {
179
- collapsedSizePercentage = 0,
180
- collapsedSizePixels,
181
- defaultSizePercentage,
182
- defaultSizePixels,
183
- maxSizePercentage = 100,
184
- maxSizePixels,
185
- minSizePercentage = 0,
186
- minSizePixels
187
- } = panelConstraints;
188
- const hasPixelConstraints = collapsedSizePixels != null || defaultSizePixels != null || minSizePixels != null || maxSizePixels != null;
189
- if (hasPixelConstraints && groupSizePixels <= 0) {
190
- console.warn(`WARNING: Invalid group size: ${groupSizePixels}px`);
191
- return {
192
- collapsedSizePercentage: 0,
193
- defaultSizePercentage,
194
- maxSizePercentage: 0,
195
- minSizePercentage: 0
196
- };
197
- }
198
- if (collapsedSizePixels != null) {
199
- collapsedSizePercentage = convertPixelsToPercentage(collapsedSizePixels, groupSizePixels);
200
- }
201
- if (defaultSizePixels != null) {
202
- defaultSizePercentage = convertPixelsToPercentage(defaultSizePixels, groupSizePixels);
203
- }
204
- if (minSizePixels != null) {
205
- minSizePercentage = convertPixelsToPercentage(minSizePixels, groupSizePixels);
206
- }
207
- if (maxSizePixels != null) {
208
- maxSizePercentage = convertPixelsToPercentage(maxSizePixels, groupSizePixels);
209
- }
210
- return {
211
- collapsedSizePercentage,
212
- defaultSizePercentage,
213
- maxSizePercentage,
214
- minSizePercentage
215
- };
216
- }
217
-
218
- function computePercentagePanelConstraints(panelConstraintsArray, panelIndex, groupSizePixels) {
219
- // All panel constraints, excluding the current one
220
- let totalMinConstraints = 0;
221
- let totalMaxConstraints = 0;
222
- for (let index = 0; index < panelConstraintsArray.length; index++) {
223
- if (index !== panelIndex) {
224
- const {
225
- collapsible
226
- } = panelConstraintsArray[index];
227
- const {
228
- collapsedSizePercentage,
229
- maxSizePercentage,
230
- minSizePercentage
231
- } = convertPixelConstraintsToPercentages(panelConstraintsArray[index], groupSizePixels);
232
- totalMaxConstraints += maxSizePercentage;
233
- totalMinConstraints += collapsible ? collapsedSizePercentage : minSizePercentage;
234
- }
165
+ function assert(expectedCondition, message = "Assertion failed!") {
166
+ if (!expectedCondition) {
167
+ console.error(message);
168
+ throw Error(message);
235
169
  }
236
- const {
237
- collapsedSizePercentage,
238
- defaultSizePercentage,
239
- maxSizePercentage,
240
- minSizePercentage
241
- } = convertPixelConstraintsToPercentages(panelConstraintsArray[panelIndex], groupSizePixels);
242
- return {
243
- collapsedSizePercentage,
244
- defaultSizePercentage,
245
- maxSizePercentage: panelConstraintsArray.length > 1 ? Math.min(maxSizePercentage, 100 - totalMinConstraints) : maxSizePercentage,
246
- minSizePercentage: panelConstraintsArray.length > 1 ? Math.max(minSizePercentage, 100 - totalMaxConstraints) : minSizePercentage
247
- };
248
170
  }
249
171
 
250
172
  const PRECISION = 10;
@@ -266,56 +188,41 @@ function fuzzyNumbersEqual(actual, expected, fractionDigits) {
266
188
 
267
189
  // Panel size must be in percentages; pixel values should be pre-converted
268
190
  function resizePanel({
269
- groupSizePixels,
270
- panelConstraints,
191
+ panelConstraints: panelConstraintsArray,
271
192
  panelIndex,
272
193
  size
273
194
  }) {
274
- const hasPixelConstraints = panelConstraints.some(({
275
- collapsedSizePixels,
276
- defaultSizePixels,
277
- minSizePixels,
278
- maxSizePixels
279
- }) => collapsedSizePixels != null || defaultSizePixels != null || minSizePixels != null || maxSizePixels != null);
280
- if (hasPixelConstraints && groupSizePixels <= 0) {
281
- console.warn(`WARNING: Invalid group size: ${groupSizePixels}px`);
282
- return 0;
283
- }
195
+ const panelConstraints = panelConstraintsArray[panelIndex];
196
+ assert(panelConstraints != null);
284
197
  let {
285
- collapsible
286
- } = panelConstraints[panelIndex];
287
- const {
288
- collapsedSizePercentage,
289
- maxSizePercentage,
290
- minSizePercentage
291
- } = computePercentagePanelConstraints(panelConstraints, panelIndex, groupSizePixels);
292
- if (minSizePercentage != null) {
293
- if (fuzzyCompareNumbers(size, minSizePercentage) < 0) {
294
- if (collapsible) {
295
- // Collapsible panels should snap closed or open only once they cross the halfway point between collapsed and min size.
296
- const halfwayPoint = (collapsedSizePercentage + minSizePercentage) / 2;
297
- if (fuzzyCompareNumbers(size, halfwayPoint) < 0) {
298
- size = collapsedSizePercentage;
299
- } else {
300
- size = minSizePercentage;
301
- }
198
+ collapsedSize = 0,
199
+ collapsible,
200
+ maxSize = 100,
201
+ minSize = 0
202
+ } = panelConstraints;
203
+ if (fuzzyCompareNumbers(size, minSize) < 0) {
204
+ if (collapsible) {
205
+ // Collapsible panels should snap closed or open only once they cross the halfway point between collapsed and min size.
206
+ const halfwayPoint = (collapsedSize + minSize) / 2;
207
+ if (fuzzyCompareNumbers(size, halfwayPoint) < 0) {
208
+ size = collapsedSize;
302
209
  } else {
303
- size = minSizePercentage;
210
+ size = minSize;
304
211
  }
212
+ } else {
213
+ size = minSize;
305
214
  }
306
215
  }
307
- if (maxSizePercentage != null) {
308
- size = Math.min(maxSizePercentage, size);
309
- }
216
+ size = Math.min(maxSize, size);
217
+ size = parseFloat(size.toFixed(PRECISION));
310
218
  return size;
311
219
  }
312
220
 
313
221
  // All units must be in percentages; pixel values should be pre-converted
314
222
  function adjustLayoutByDelta({
315
223
  delta,
316
- groupSizePixels,
317
224
  layout: prevLayout,
318
- panelConstraints,
225
+ panelConstraints: panelConstraintsArray,
319
226
  pivotIndices,
320
227
  trigger
321
228
  }) {
@@ -323,6 +230,9 @@ function adjustLayoutByDelta({
323
230
  return prevLayout;
324
231
  }
325
232
  const nextLayout = [...prevLayout];
233
+ const [firstPivotIndex, secondPivotIndex] = pivotIndices;
234
+ assert(firstPivotIndex != null);
235
+ assert(secondPivotIndex != null);
326
236
  let deltaApplied = 0;
327
237
 
328
238
  //const DEBUG = [];
@@ -346,18 +256,23 @@ function adjustLayoutByDelta({
346
256
  if (trigger === "keyboard") {
347
257
  {
348
258
  // Check if we should expand a collapsed panel
349
- const index = delta < 0 ? pivotIndices[1] : pivotIndices[0];
350
- const constraints = panelConstraints[index];
259
+ const index = delta < 0 ? secondPivotIndex : firstPivotIndex;
260
+ const panelConstraints = panelConstraintsArray[index];
261
+ assert(panelConstraints);
262
+
351
263
  //DEBUG.push(`edge case check 1: ${index}`);
352
264
  //DEBUG.push(` -> collapsible? ${constraints.collapsible}`);
353
- if (constraints.collapsible) {
265
+ if (panelConstraints.collapsible) {
354
266
  const prevSize = prevLayout[index];
267
+ assert(prevSize != null);
268
+ const panelConstraints = panelConstraintsArray[index];
269
+ assert(panelConstraints);
355
270
  const {
356
- collapsedSizePercentage,
357
- minSizePercentage
358
- } = computePercentagePanelConstraints(panelConstraints, index, groupSizePixels);
359
- if (fuzzyNumbersEqual(prevSize, collapsedSizePercentage)) {
360
- const localDelta = minSizePercentage - prevSize;
271
+ collapsedSize = 0,
272
+ minSize = 0
273
+ } = panelConstraints;
274
+ if (fuzzyNumbersEqual(prevSize, collapsedSize)) {
275
+ const localDelta = minSize - prevSize;
361
276
  //DEBUG.push(` -> expand delta: ${localDelta}`);
362
277
 
363
278
  if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0) {
@@ -370,18 +285,26 @@ function adjustLayoutByDelta({
370
285
 
371
286
  {
372
287
  // Check if we should collapse a panel at its minimum size
373
- const index = delta < 0 ? pivotIndices[0] : pivotIndices[1];
374
- const constraints = panelConstraints[index];
288
+ const index = delta < 0 ? firstPivotIndex : secondPivotIndex;
289
+ const panelConstraints = panelConstraintsArray[index];
290
+ assert(panelConstraints);
291
+ const {
292
+ collapsible
293
+ } = panelConstraints;
294
+
375
295
  //DEBUG.push(`edge case check 2: ${index}`);
376
- //DEBUG.push(` -> collapsible? ${constraints.collapsible}`);
377
- if (constraints.collapsible) {
296
+ //DEBUG.push(` -> collapsible? ${collapsible}`);
297
+ if (collapsible) {
378
298
  const prevSize = prevLayout[index];
299
+ assert(prevSize != null);
300
+ const panelConstraints = panelConstraintsArray[index];
301
+ assert(panelConstraints);
379
302
  const {
380
- collapsedSizePercentage,
381
- minSizePercentage
382
- } = computePercentagePanelConstraints(panelConstraints, index, groupSizePixels);
383
- if (fuzzyNumbersEqual(prevSize, minSizePercentage)) {
384
- const localDelta = prevSize - collapsedSizePercentage;
303
+ collapsedSize = 0,
304
+ minSize = 0
305
+ } = panelConstraints;
306
+ if (fuzzyNumbersEqual(prevSize, minSize)) {
307
+ const localDelta = prevSize - collapsedSize;
385
308
  //DEBUG.push(` -> expand delta: ${localDelta}`);
386
309
 
387
310
  if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0) {
@@ -403,15 +326,15 @@ function adjustLayoutByDelta({
403
326
  // as an expanding panel might change from collapsed to min size.
404
327
 
405
328
  const increment = delta < 0 ? 1 : -1;
406
- let index = delta < 0 ? pivotIndices[1] : pivotIndices[0];
329
+ let index = delta < 0 ? secondPivotIndex : firstPivotIndex;
407
330
  let maxAvailableDelta = 0;
408
331
 
409
332
  //DEBUG.push("pre calc...");
410
333
  while (true) {
411
334
  const prevSize = prevLayout[index];
335
+ assert(prevSize != null);
412
336
  const maxSafeSize = resizePanel({
413
- groupSizePixels,
414
- panelConstraints,
337
+ panelConstraints: panelConstraintsArray,
415
338
  panelIndex: index,
416
339
  size: 100
417
340
  });
@@ -420,7 +343,7 @@ function adjustLayoutByDelta({
420
343
 
421
344
  maxAvailableDelta += delta;
422
345
  index += increment;
423
- if (index < 0 || index >= panelConstraints.length) {
346
+ if (index < 0 || index >= panelConstraintsArray.length) {
424
347
  break;
425
348
  }
426
349
  }
@@ -435,15 +358,15 @@ function adjustLayoutByDelta({
435
358
  {
436
359
  // Delta added to a panel needs to be subtracted from other panels (within the constraints that those panels allow).
437
360
 
438
- const pivotIndex = delta < 0 ? pivotIndices[0] : pivotIndices[1];
361
+ const pivotIndex = delta < 0 ? firstPivotIndex : secondPivotIndex;
439
362
  let index = pivotIndex;
440
- while (index >= 0 && index < panelConstraints.length) {
363
+ while (index >= 0 && index < panelConstraintsArray.length) {
441
364
  const deltaRemaining = Math.abs(delta) - Math.abs(deltaApplied);
442
365
  const prevSize = prevLayout[index];
366
+ assert(prevSize != null);
443
367
  const unsafeSize = prevSize - deltaRemaining;
444
368
  const safeSize = resizePanel({
445
- groupSizePixels,
446
- panelConstraints,
369
+ panelConstraints: panelConstraintsArray,
447
370
  panelIndex: index,
448
371
  size: unsafeSize
449
372
  });
@@ -475,11 +398,12 @@ function adjustLayoutByDelta({
475
398
  }
476
399
  {
477
400
  // Now distribute the applied delta to the panels in the other direction
478
- const pivotIndex = delta < 0 ? pivotIndices[1] : pivotIndices[0];
479
- const unsafeSize = prevLayout[pivotIndex] + deltaApplied;
401
+ const pivotIndex = delta < 0 ? secondPivotIndex : firstPivotIndex;
402
+ const prevSize = prevLayout[pivotIndex];
403
+ assert(prevSize != null);
404
+ const unsafeSize = prevSize + deltaApplied;
480
405
  const safeSize = resizePanel({
481
- groupSizePixels,
482
- panelConstraints,
406
+ panelConstraints: panelConstraintsArray,
483
407
  panelIndex: pivotIndex,
484
408
  size: unsafeSize
485
409
  });
@@ -490,14 +414,14 @@ function adjustLayoutByDelta({
490
414
  // Edge case where expanding or contracting one panel caused another one to change collapsed state
491
415
  if (!fuzzyNumbersEqual(safeSize, unsafeSize)) {
492
416
  let deltaRemaining = unsafeSize - safeSize;
493
- const pivotIndex = delta < 0 ? pivotIndices[1] : pivotIndices[0];
417
+ const pivotIndex = delta < 0 ? secondPivotIndex : firstPivotIndex;
494
418
  let index = pivotIndex;
495
- while (index >= 0 && index < panelConstraints.length) {
419
+ while (index >= 0 && index < panelConstraintsArray.length) {
496
420
  const prevSize = nextLayout[index];
421
+ assert(prevSize != null);
497
422
  const unsafeSize = prevSize + deltaRemaining;
498
423
  const safeSize = resizePanel({
499
- groupSizePixels,
500
- panelConstraints,
424
+ panelConstraints: panelConstraintsArray,
501
425
  panelIndex: index,
502
426
  size: unsafeSize
503
427
  });
@@ -521,9 +445,7 @@ function adjustLayoutByDelta({
521
445
  //DEBUG.push("");
522
446
 
523
447
  const totalSize = nextLayout.reduce((total, size) => size + total, 0);
524
- deltaApplied = 100 - totalSize;
525
448
  //DEBUG.push(`total size: ${totalSize}`);
526
- //DEBUG.push(` deltaApplied: ${deltaApplied}`);
527
449
  //console.log(DEBUG.join("\n"));
528
450
 
529
451
  if (!fuzzyNumbersEqual(totalSize, 100)) {
@@ -532,25 +454,6 @@ function adjustLayoutByDelta({
532
454
  return nextLayout;
533
455
  }
534
456
 
535
- function assert(expectedCondition, message = "Assertion failed!") {
536
- if (!expectedCondition) {
537
- console.error(message);
538
- throw Error(message);
539
- }
540
- }
541
-
542
- function getPercentageSizeFromMixedSizes({
543
- sizePercentage,
544
- sizePixels
545
- }, groupSizePixels) {
546
- if (sizePercentage != null) {
547
- return sizePercentage;
548
- } else if (sizePixels != null) {
549
- return convertPixelsToPercentage(sizePixels, groupSizePixels);
550
- }
551
- return undefined;
552
- }
553
-
554
457
  function getResizeHandleElementsForGroup(groupId) {
555
458
  return Array.from(document.querySelectorAll(`[data-panel-resize-handle-id][data-panel-group-id="${groupId}"]`));
556
459
  }
@@ -574,42 +477,6 @@ function getPanelGroupElement(id) {
574
477
  return null;
575
478
  }
576
479
 
577
- function calculateAvailablePanelSizeInPixels(groupId) {
578
- const panelGroupElement = getPanelGroupElement(groupId);
579
- if (panelGroupElement == null) {
580
- return NaN;
581
- }
582
- const direction = panelGroupElement.getAttribute("data-panel-group-direction");
583
- const resizeHandles = getResizeHandleElementsForGroup(groupId);
584
- if (direction === "horizontal") {
585
- return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
586
- return accumulated + handle.offsetWidth;
587
- }, 0);
588
- } else {
589
- return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
590
- return accumulated + handle.offsetHeight;
591
- }, 0);
592
- }
593
- }
594
-
595
- function getAvailableGroupSizePixels(groupId) {
596
- const panelGroupElement = getPanelGroupElement(groupId);
597
- if (panelGroupElement == null) {
598
- return NaN;
599
- }
600
- const direction = panelGroupElement.getAttribute("data-panel-group-direction");
601
- const resizeHandles = getResizeHandleElementsForGroup(groupId);
602
- if (direction === "horizontal") {
603
- return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
604
- return accumulated + handle.offsetWidth;
605
- }, 0);
606
- } else {
607
- return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
608
- return accumulated + handle.offsetHeight;
609
- }, 0);
610
- }
611
- }
612
-
613
480
  function getResizeHandleElement(id) {
614
481
  const element = document.querySelector(`[data-panel-resize-handle-id="${id}"]`);
615
482
  if (element) {
@@ -642,14 +509,18 @@ function useWindowSplitterPanelGroupBehavior({
642
509
  didWarnAboutMissingResizeHandle: false
643
510
  });
644
511
  useEffect(() => {
512
+ const eagerValues = eagerValuesRef.current;
513
+ assert(eagerValues);
645
514
  const {
646
515
  panelDataArray
647
- } = eagerValuesRef.current;
516
+ } = eagerValues;
648
517
  const groupElement = getPanelGroupElement(groupId);
649
518
  assert(groupElement != null, `No group found for id "${groupId}"`);
650
519
  const handles = getResizeHandleElementsForGroup(groupId);
520
+ assert(handles);
651
521
  const cleanupFunctions = handles.map(handle => {
652
522
  const handleId = handle.getAttribute("data-panel-resize-handle-id");
523
+ assert(handleId);
653
524
  const [idBefore, idAfter] = getResizeHandlePanelIds(groupId, handleId, panelDataArray);
654
525
  if (idBefore == null || idAfter == null) {
655
526
  return () => {};
@@ -665,21 +536,16 @@ function useWindowSplitterPanelGroupBehavior({
665
536
  const index = panelDataArray.findIndex(panelData => panelData.id === idBefore);
666
537
  if (index >= 0) {
667
538
  const panelData = panelDataArray[index];
539
+ assert(panelData);
668
540
  const size = layout[index];
669
- if (size != null && panelData.constraints.collapsible) {
670
- var _getPercentageSizeFro, _getPercentageSizeFro2;
671
- const groupSizePixels = getAvailableGroupSizePixels(groupId);
672
- const collapsedSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
673
- sizePercentage: panelData.constraints.collapsedSizePercentage,
674
- sizePixels: panelData.constraints.collapsedSizePixels
675
- }, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
676
- const minSize = (_getPercentageSizeFro2 = getPercentageSizeFromMixedSizes({
677
- sizePercentage: panelData.constraints.minSizePercentage,
678
- sizePixels: panelData.constraints.minSizePixels
679
- }, groupSizePixels)) !== null && _getPercentageSizeFro2 !== void 0 ? _getPercentageSizeFro2 : 0;
541
+ const {
542
+ collapsedSize = 0,
543
+ collapsible,
544
+ minSize = 0
545
+ } = panelData.constraints;
546
+ if (size != null && collapsible) {
680
547
  const nextLayout = adjustLayoutByDelta({
681
548
  delta: fuzzyNumbersEqual(size, collapsedSize) ? minSize - collapsedSize : collapsedSize - size,
682
- groupSizePixels,
683
549
  layout,
684
550
  panelConstraints: panelDataArray.map(panelData => panelData.constraints),
685
551
  pivotIndices: determinePivotIndices(groupId, handleId),
@@ -733,6 +599,7 @@ function getResizeEventCursorPosition(direction, event) {
733
599
  return isHorizontal ? event.clientX : event.clientY;
734
600
  } else if (isTouchEvent(event)) {
735
601
  const firstTouch = event.touches[0];
602
+ assert(firstTouch);
736
603
  return isHorizontal ? firstTouch.screenX : firstTouch.screenY;
737
604
  } else {
738
605
  throw Error(`Unsupported event type "${event.type}"`);
@@ -742,12 +609,15 @@ function getResizeEventCursorPosition(direction, event) {
742
609
  function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState) {
743
610
  const isHorizontal = direction === "horizontal";
744
611
  const handleElement = getResizeHandleElement(dragHandleId);
612
+ assert(handleElement);
745
613
  const groupId = handleElement.getAttribute("data-panel-group-id");
614
+ assert(groupId);
746
615
  let {
747
616
  initialCursorPosition
748
617
  } = initialDragState;
749
618
  const cursorPosition = getResizeEventCursorPosition(direction, event);
750
619
  const groupElement = getPanelGroupElement(groupId);
620
+ assert(groupElement);
751
621
  const groupRect = groupElement.getBoundingClientRect();
752
622
  const groupSizeInPixels = isHorizontal ? groupRect.width : groupRect.height;
753
623
  const offsetPixels = cursorPosition - initialCursorPosition;
@@ -756,19 +626,14 @@ function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDr
756
626
  }
757
627
 
758
628
  // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX
759
- function calculateDeltaPercentage(event, groupId, dragHandleId, direction, initialDragState, keyboardResizeByOptions) {
629
+ function calculateDeltaPercentage(event, dragHandleId, direction, initialDragState, keyboardResizeBy) {
760
630
  if (isKeyDown(event)) {
761
631
  const isHorizontal = direction === "horizontal";
762
- const groupElement = getPanelGroupElement(groupId);
763
- const rect = groupElement.getBoundingClientRect();
764
- const groupSizeInPixels = isHorizontal ? rect.width : rect.height;
765
632
  let delta = 0;
766
633
  if (event.shiftKey) {
767
634
  delta = 100;
768
- } else if (keyboardResizeByOptions.percentage != null) {
769
- delta = keyboardResizeByOptions.percentage;
770
- } else if (keyboardResizeByOptions.pixels != null) {
771
- delta = keyboardResizeByOptions.pixels / groupSizeInPixels;
635
+ } else if (keyboardResizeBy != null) {
636
+ delta = keyboardResizeBy;
772
637
  } else {
773
638
  delta = 10;
774
639
  }
@@ -795,37 +660,43 @@ function calculateDeltaPercentage(event, groupId, dragHandleId, direction, initi
795
660
  }
796
661
  return movement;
797
662
  } else {
663
+ if (initialDragState == null) {
664
+ return 0;
665
+ }
798
666
  return calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState);
799
667
  }
800
668
  }
801
669
 
802
670
  function calculateUnsafeDefaultLayout({
803
- groupSizePixels,
804
671
  panelDataArray
805
672
  }) {
806
673
  const layout = Array(panelDataArray.length);
807
- const panelDataConstraints = panelDataArray.map(panelData => panelData.constraints);
674
+ const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
808
675
  let numPanelsWithSizes = 0;
809
676
  let remainingSize = 100;
810
677
 
811
678
  // Distribute default sizes first
812
679
  for (let index = 0; index < panelDataArray.length; index++) {
680
+ const panelConstraints = panelConstraintsArray[index];
681
+ assert(panelConstraints);
813
682
  const {
814
- defaultSizePercentage
815
- } = computePercentagePanelConstraints(panelDataConstraints, index, groupSizePixels);
816
- if (defaultSizePercentage != null) {
683
+ defaultSize
684
+ } = panelConstraints;
685
+ if (defaultSize != null) {
817
686
  numPanelsWithSizes++;
818
- layout[index] = defaultSizePercentage;
819
- remainingSize -= defaultSizePercentage;
687
+ layout[index] = defaultSize;
688
+ remainingSize -= defaultSize;
820
689
  }
821
690
  }
822
691
 
823
692
  // Remaining size should be distributed evenly between panels without default sizes
824
693
  for (let index = 0; index < panelDataArray.length; index++) {
694
+ const panelConstraints = panelConstraintsArray[index];
695
+ assert(panelConstraints);
825
696
  const {
826
- defaultSizePercentage
827
- } = computePercentagePanelConstraints(panelDataConstraints, index, groupSizePixels);
828
- if (defaultSizePercentage != null) {
697
+ defaultSize
698
+ } = panelConstraints;
699
+ if (defaultSize != null) {
829
700
  continue;
830
701
  }
831
702
  const numRemainingPanels = panelDataArray.length - numPanelsWithSizes;
@@ -837,54 +708,36 @@ function calculateUnsafeDefaultLayout({
837
708
  return layout;
838
709
  }
839
710
 
840
- function convertPercentageToPixels(percentage, groupSizePixels) {
841
- return percentage / 100 * groupSizePixels;
842
- }
843
-
844
711
  // Layout should be pre-converted into percentages
845
- function callPanelCallbacks(groupId, panelsArray, layout, panelIdToLastNotifiedMixedSizesMap) {
846
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
847
- layout.forEach((sizePercentage, index) => {
712
+ function callPanelCallbacks(panelsArray, layout, panelIdToLastNotifiedSizeMap) {
713
+ layout.forEach((size, index) => {
848
714
  const panelData = panelsArray[index];
849
- if (!panelData) {
850
- // Handle initial mount (when panels are registered too late to be in the panels array)
851
- // The subsequent render+effects will handle the resize notification
852
- return;
853
- }
715
+ assert(panelData);
854
716
  const {
855
717
  callbacks,
856
718
  constraints,
857
719
  id: panelId
858
720
  } = panelData;
859
721
  const {
722
+ collapsedSize = 0,
860
723
  collapsible
861
724
  } = constraints;
862
- const mixedSizes = {
863
- sizePercentage,
864
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
865
- };
866
- const lastNotifiedMixedSizes = panelIdToLastNotifiedMixedSizesMap[panelId];
867
- if (lastNotifiedMixedSizes == null || mixedSizes.sizePercentage !== lastNotifiedMixedSizes.sizePercentage || mixedSizes.sizePixels !== lastNotifiedMixedSizes.sizePixels) {
868
- panelIdToLastNotifiedMixedSizesMap[panelId] = mixedSizes;
725
+ const lastNotifiedSize = panelIdToLastNotifiedSizeMap[panelId];
726
+ if (lastNotifiedSize == null || size !== lastNotifiedSize) {
727
+ panelIdToLastNotifiedSizeMap[panelId] = size;
869
728
  const {
870
729
  onCollapse,
871
730
  onExpand,
872
731
  onResize
873
732
  } = callbacks;
874
733
  if (onResize) {
875
- onResize(mixedSizes, lastNotifiedMixedSizes);
734
+ onResize(size, lastNotifiedSize);
876
735
  }
877
736
  if (collapsible && (onCollapse || onExpand)) {
878
- var _getPercentageSizeFro;
879
- const collapsedSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
880
- sizePercentage: constraints.collapsedSizePercentage,
881
- sizePixels: constraints.collapsedSizePixels
882
- }, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
883
- const size = getPercentageSizeFromMixedSizes(mixedSizes, groupSizePixels);
884
- if (onExpand && (lastNotifiedMixedSizes == null || lastNotifiedMixedSizes.sizePercentage === collapsedSize) && size !== collapsedSize) {
737
+ if (onExpand && (lastNotifiedSize == null || lastNotifiedSize === collapsedSize) && size !== collapsedSize) {
885
738
  onExpand();
886
739
  }
887
- if (onCollapse && (lastNotifiedMixedSizes == null || lastNotifiedMixedSizes.sizePercentage !== collapsedSize) && size === collapsedSize) {
740
+ if (onCollapse && (lastNotifiedSize == null || lastNotifiedSize !== collapsedSize) && size === collapsedSize) {
888
741
  onCollapse();
889
742
  }
890
743
  }
@@ -918,9 +771,10 @@ function computePanelFlexBoxStyle({
918
771
  const size = layout[panelIndex];
919
772
  let flexGrow;
920
773
  if (panelData.length === 1) {
921
- flexGrow = "100";
774
+ flexGrow = "1";
922
775
  } else if (size == null) {
923
- flexGrow = "0";
776
+ // Initial render (before panels have registered themselves)
777
+ flexGrow = "1";
924
778
  } else {
925
779
  flexGrow = size.toPrecision(precision);
926
780
  }
@@ -1066,31 +920,32 @@ function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
1066
920
  }
1067
921
  }
1068
922
 
1069
- function shouldMonitorPixelBasedConstraints(constraints) {
1070
- return constraints.some(constraints => {
1071
- return constraints.collapsedSizePixels !== undefined || constraints.maxSizePixels !== undefined || constraints.minSizePixels !== undefined;
1072
- });
1073
- }
1074
-
1075
923
  // All units must be in percentages; pixel values should be pre-converted
1076
924
  function validatePanelGroupLayout({
1077
- groupSizePixels,
1078
925
  layout: prevLayout,
1079
926
  panelConstraints
1080
927
  }) {
1081
928
  const nextLayout = [...prevLayout];
929
+ const nextLayoutTotalSize = nextLayout.reduce((accumulated, current) => accumulated + current, 0);
1082
930
 
1083
931
  // Validate layout expectations
1084
932
  if (nextLayout.length !== panelConstraints.length) {
1085
933
  throw Error(`Invalid ${panelConstraints.length} panel layout: ${nextLayout.map(size => `${size}%`).join(", ")}`);
1086
- } else if (!fuzzyNumbersEqual(nextLayout.reduce((accumulated, current) => accumulated + current, 0), 100)) ;
934
+ } else if (!fuzzyNumbersEqual(nextLayoutTotalSize, 100)) {
935
+ for (let index = 0; index < panelConstraints.length; index++) {
936
+ const unsafeSize = nextLayout[index];
937
+ assert(unsafeSize != null);
938
+ const safeSize = 100 / nextLayoutTotalSize * unsafeSize;
939
+ nextLayout[index] = safeSize;
940
+ }
941
+ }
1087
942
  let remainingSize = 0;
1088
943
 
1089
944
  // First pass: Validate the proposed layout given each panel's constraints
1090
945
  for (let index = 0; index < panelConstraints.length; index++) {
1091
946
  const unsafeSize = nextLayout[index];
947
+ assert(unsafeSize != null);
1092
948
  const safeSize = resizePanel({
1093
- groupSizePixels,
1094
949
  panelConstraints,
1095
950
  panelIndex: index,
1096
951
  size: unsafeSize
@@ -1106,9 +961,9 @@ function validatePanelGroupLayout({
1106
961
  if (!fuzzyNumbersEqual(remainingSize, 0)) {
1107
962
  for (let index = 0; index < panelConstraints.length; index++) {
1108
963
  const prevSize = nextLayout[index];
964
+ assert(prevSize != null);
1109
965
  const unsafeSize = prevSize + remainingSize;
1110
966
  const safeSize = resizePanel({
1111
- groupSizePixels,
1112
967
  panelConstraints,
1113
968
  panelIndex: index,
1114
969
  size: unsafeSize
@@ -1143,21 +998,20 @@ function PanelGroupWithForwardedRef({
1143
998
  autoSaveId = null,
1144
999
  children,
1145
1000
  className: classNameFromProps = "",
1146
- dataAttributes,
1147
1001
  direction,
1148
1002
  forwardedRef,
1149
- id: idFromProps,
1003
+ id: idFromProps = null,
1150
1004
  onLayout = null,
1151
- keyboardResizeByPercentage = null,
1152
- keyboardResizeByPixels = null,
1005
+ keyboardResizeBy = null,
1153
1006
  storage = defaultStorage,
1154
1007
  style: styleFromProps,
1155
- tagName: Type = "div"
1008
+ tagName: Type = "div",
1009
+ ...rest
1156
1010
  }) {
1157
1011
  const groupId = useUniqueId(idFromProps);
1158
1012
  const [dragState, setDragState] = useState(null);
1159
1013
  const [layout, setLayout] = useState([]);
1160
- const panelIdToLastNotifiedMixedSizesMapRef = useRef({});
1014
+ const panelIdToLastNotifiedSizeMapRef = useRef({});
1161
1015
  const panelSizeBeforeCollapseRef = useRef(new Map());
1162
1016
  const prevDeltaRef = useRef(0);
1163
1017
  const committedValuesRef = useRef({
@@ -1165,8 +1019,7 @@ function PanelGroupWithForwardedRef({
1165
1019
  direction,
1166
1020
  dragState,
1167
1021
  id: groupId,
1168
- keyboardResizeByPercentage,
1169
- keyboardResizeByPixels,
1022
+ keyboardResizeBy,
1170
1023
  onLayout,
1171
1024
  storage
1172
1025
  });
@@ -1182,33 +1035,20 @@ function PanelGroupWithForwardedRef({
1182
1035
  useImperativeHandle(forwardedRef, () => ({
1183
1036
  getId: () => committedValuesRef.current.id,
1184
1037
  getLayout: () => {
1185
- const {
1186
- id: groupId
1187
- } = committedValuesRef.current;
1188
1038
  const {
1189
1039
  layout
1190
1040
  } = eagerValuesRef.current;
1191
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1192
- return layout.map(sizePercentage => {
1193
- return {
1194
- sizePercentage,
1195
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1196
- };
1197
- });
1041
+ return layout;
1198
1042
  },
1199
- setLayout: mixedSizes => {
1043
+ setLayout: unsafeLayout => {
1200
1044
  const {
1201
- id: groupId,
1202
1045
  onLayout
1203
1046
  } = committedValuesRef.current;
1204
1047
  const {
1205
1048
  layout: prevLayout,
1206
1049
  panelDataArray
1207
1050
  } = eagerValuesRef.current;
1208
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1209
- const unsafeLayout = mixedSizes.map(mixedSize => getPercentageSizeFromMixedSizes(mixedSize, groupSizePixels));
1210
1051
  const safeLayout = validatePanelGroupLayout({
1211
- groupSizePixels,
1212
1052
  layout: unsafeLayout,
1213
1053
  panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1214
1054
  });
@@ -1216,16 +1056,12 @@ function PanelGroupWithForwardedRef({
1216
1056
  setLayout(safeLayout);
1217
1057
  eagerValuesRef.current.layout = safeLayout;
1218
1058
  if (onLayout) {
1219
- onLayout(safeLayout.map(sizePercentage => ({
1220
- sizePercentage,
1221
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1222
- })));
1059
+ onLayout(safeLayout);
1223
1060
  }
1224
- callPanelCallbacks(groupId, panelDataArray, safeLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1061
+ callPanelCallbacks(panelDataArray, safeLayout, panelIdToLastNotifiedSizeMapRef.current);
1225
1062
  }
1226
1063
  }
1227
1064
  }), []);
1228
-
1229
1065
  useWindowSplitterPanelGroupBehavior({
1230
1066
  committedValuesRef,
1231
1067
  eagerValuesRef,
@@ -1244,12 +1080,14 @@ function PanelGroupWithForwardedRef({
1244
1080
  if (layout.length === 0 || layout.length !== panelDataArray.length) {
1245
1081
  return;
1246
1082
  }
1083
+ let debouncedSave = debounceMap[autoSaveId];
1247
1084
 
1248
1085
  // Limit the frequency of localStorage updates.
1249
- if (!debounceMap[autoSaveId]) {
1250
- debounceMap[autoSaveId] = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1086
+ if (debouncedSave == null) {
1087
+ debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1088
+ debounceMap[autoSaveId] = debouncedSave;
1251
1089
  }
1252
- debounceMap[autoSaveId](autoSaveId, panelDataArray, layout, storage);
1090
+ debouncedSave(autoSaveId, panelDataArray, layout, storage);
1253
1091
  }
1254
1092
  }, [autoSaveId, layout, storage]);
1255
1093
 
@@ -1269,20 +1107,19 @@ function PanelGroupWithForwardedRef({
1269
1107
  if (panelData.constraints.collapsible) {
1270
1108
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1271
1109
  const {
1272
- collapsedSizePercentage,
1273
- panelSizePercentage,
1274
- pivotIndices,
1275
- groupSizePixels
1276
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
1277
- if (panelSizePercentage !== collapsedSizePercentage) {
1110
+ collapsedSize = 0,
1111
+ panelSize,
1112
+ pivotIndices
1113
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
1114
+ assert(panelSize != null);
1115
+ if (panelSize !== collapsedSize) {
1278
1116
  // Store size before collapse;
1279
1117
  // This is the size that gets restored if the expand() API is used.
1280
- panelSizeBeforeCollapseRef.current.set(panelData.id, panelSizePercentage);
1118
+ panelSizeBeforeCollapseRef.current.set(panelData.id, panelSize);
1281
1119
  const isLastPanel = panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
1282
- const delta = isLastPanel ? panelSizePercentage - collapsedSizePercentage : collapsedSizePercentage - panelSizePercentage;
1120
+ const delta = isLastPanel ? panelSize - collapsedSize : collapsedSize - panelSize;
1283
1121
  const nextLayout = adjustLayoutByDelta({
1284
1122
  delta,
1285
- groupSizePixels,
1286
1123
  layout: prevLayout,
1287
1124
  panelConstraints: panelConstraintsArray,
1288
1125
  pivotIndices,
@@ -1292,16 +1129,13 @@ function PanelGroupWithForwardedRef({
1292
1129
  setLayout(nextLayout);
1293
1130
  eagerValuesRef.current.layout = nextLayout;
1294
1131
  if (onLayout) {
1295
- onLayout(nextLayout.map(sizePercentage => ({
1296
- sizePercentage,
1297
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1298
- })));
1132
+ onLayout(nextLayout);
1299
1133
  }
1300
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1134
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1301
1135
  }
1302
1136
  }
1303
1137
  }
1304
- }, [groupId]);
1138
+ }, []);
1305
1139
 
1306
1140
  // External APIs are safe to memoize via committed values ref
1307
1141
  const expandPanel = useCallback(panelData => {
@@ -1315,21 +1149,19 @@ function PanelGroupWithForwardedRef({
1315
1149
  if (panelData.constraints.collapsible) {
1316
1150
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1317
1151
  const {
1318
- collapsedSizePercentage,
1319
- panelSizePercentage,
1320
- minSizePercentage,
1321
- pivotIndices,
1322
- groupSizePixels
1323
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
1324
- if (panelSizePercentage === collapsedSizePercentage) {
1152
+ collapsedSize = 0,
1153
+ panelSize,
1154
+ minSize = 0,
1155
+ pivotIndices
1156
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
1157
+ if (panelSize === collapsedSize) {
1325
1158
  // Restore this panel to the size it was before it was collapsed, if possible.
1326
- const prevPanelSizePercentage = panelSizeBeforeCollapseRef.current.get(panelData.id);
1327
- const baseSizePercentage = prevPanelSizePercentage != null && prevPanelSizePercentage >= minSizePercentage ? prevPanelSizePercentage : minSizePercentage;
1159
+ const prevPanelSize = panelSizeBeforeCollapseRef.current.get(panelData.id);
1160
+ const baseSize = prevPanelSize != null && prevPanelSize >= minSize ? prevPanelSize : minSize;
1328
1161
  const isLastPanel = panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
1329
- const delta = isLastPanel ? panelSizePercentage - baseSizePercentage : baseSizePercentage - panelSizePercentage;
1162
+ const delta = isLastPanel ? panelSize - baseSize : baseSize - panelSize;
1330
1163
  const nextLayout = adjustLayoutByDelta({
1331
1164
  delta,
1332
- groupSizePixels,
1333
1165
  layout: prevLayout,
1334
1166
  panelConstraints: panelConstraintsArray,
1335
1167
  pivotIndices,
@@ -1339,16 +1171,13 @@ function PanelGroupWithForwardedRef({
1339
1171
  setLayout(nextLayout);
1340
1172
  eagerValuesRef.current.layout = nextLayout;
1341
1173
  if (onLayout) {
1342
- onLayout(nextLayout.map(sizePercentage => ({
1343
- sizePercentage,
1344
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1345
- })));
1174
+ onLayout(nextLayout);
1346
1175
  }
1347
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1176
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1348
1177
  }
1349
1178
  }
1350
1179
  }
1351
- }, [groupId]);
1180
+ }, []);
1352
1181
 
1353
1182
  // External APIs are safe to memoize via committed values ref
1354
1183
  const getPanelSize = useCallback(panelData => {
@@ -1357,14 +1186,11 @@ function PanelGroupWithForwardedRef({
1357
1186
  panelDataArray
1358
1187
  } = eagerValuesRef.current;
1359
1188
  const {
1360
- panelSizePercentage,
1361
- panelSizePixels
1362
- } = panelDataHelper(groupId, panelDataArray, panelData, layout);
1363
- return {
1364
- sizePercentage: panelSizePercentage,
1365
- sizePixels: panelSizePixels
1366
- };
1367
- }, [groupId]);
1189
+ panelSize
1190
+ } = panelDataHelper(panelDataArray, panelData, layout);
1191
+ assert(panelSize != null);
1192
+ return panelSize;
1193
+ }, []);
1368
1194
 
1369
1195
  // This API should never read from committedValuesRef
1370
1196
  const getPanelStyle = useCallback(panelData => {
@@ -1387,12 +1213,12 @@ function PanelGroupWithForwardedRef({
1387
1213
  panelDataArray
1388
1214
  } = eagerValuesRef.current;
1389
1215
  const {
1390
- collapsedSizePercentage,
1216
+ collapsedSize,
1391
1217
  collapsible,
1392
- panelSizePercentage
1393
- } = panelDataHelper(groupId, panelDataArray, panelData, layout);
1394
- return collapsible === true && panelSizePercentage === collapsedSizePercentage;
1395
- }, [groupId]);
1218
+ panelSize
1219
+ } = panelDataHelper(panelDataArray, panelData, layout);
1220
+ return collapsible === true && panelSize === collapsedSize;
1221
+ }, []);
1396
1222
 
1397
1223
  // External APIs are safe to memoize via committed values ref
1398
1224
  const isPanelExpanded = useCallback(panelData => {
@@ -1401,12 +1227,13 @@ function PanelGroupWithForwardedRef({
1401
1227
  panelDataArray
1402
1228
  } = eagerValuesRef.current;
1403
1229
  const {
1404
- collapsedSizePercentage,
1230
+ collapsedSize = 0,
1405
1231
  collapsible,
1406
- panelSizePercentage
1407
- } = panelDataHelper(groupId, panelDataArray, panelData, layout);
1408
- return !collapsible || panelSizePercentage > collapsedSizePercentage;
1409
- }, [groupId]);
1232
+ panelSize
1233
+ } = panelDataHelper(panelDataArray, panelData, layout);
1234
+ assert(panelSize != null);
1235
+ return !collapsible || panelSize > collapsedSize;
1236
+ }, []);
1410
1237
  const registerPanel = useCallback(panelData => {
1411
1238
  const {
1412
1239
  autoSaveId,
@@ -1446,18 +1273,8 @@ function PanelGroupWithForwardedRef({
1446
1273
  if (autoSaveId) {
1447
1274
  unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
1448
1275
  }
1449
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1450
- if (groupSizePixels <= 0) {
1451
- if (shouldMonitorPixelBasedConstraints(panelDataArray.map(({
1452
- constraints
1453
- }) => constraints))) {
1454
- // Wait until the group has rendered a non-zero size before computing layout.
1455
- return;
1456
- }
1457
- }
1458
1276
  if (unsafeLayout == null) {
1459
1277
  unsafeLayout = calculateUnsafeDefaultLayout({
1460
- groupSizePixels,
1461
1278
  panelDataArray
1462
1279
  });
1463
1280
  }
@@ -1465,7 +1282,6 @@ function PanelGroupWithForwardedRef({
1465
1282
  // Validate even saved layouts in case something has changed since last render
1466
1283
  // e.g. for pixel groups, this could be the size of the window
1467
1284
  const nextLayout = validatePanelGroupLayout({
1468
- groupSizePixels,
1469
1285
  layout: unsafeLayout,
1470
1286
  panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1471
1287
  });
@@ -1477,12 +1293,9 @@ function PanelGroupWithForwardedRef({
1477
1293
  eagerValuesRef.current.layout = nextLayout;
1478
1294
  if (!areEqual(prevLayout, nextLayout)) {
1479
1295
  if (onLayout) {
1480
- onLayout(nextLayout.map(sizePercentage => ({
1481
- sizePercentage,
1482
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1483
- })));
1296
+ onLayout(nextLayout);
1484
1297
  }
1485
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1298
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1486
1299
  }
1487
1300
  }, []);
1488
1301
  const registerResizeHandle = useCallback(dragHandleId => {
@@ -1492,8 +1305,7 @@ function PanelGroupWithForwardedRef({
1492
1305
  direction,
1493
1306
  dragState,
1494
1307
  id: groupId,
1495
- keyboardResizeByPercentage,
1496
- keyboardResizeByPixels,
1308
+ keyboardResizeBy,
1497
1309
  onLayout
1498
1310
  } = committedValuesRef.current;
1499
1311
  const {
@@ -1504,10 +1316,7 @@ function PanelGroupWithForwardedRef({
1504
1316
  initialLayout
1505
1317
  } = dragState !== null && dragState !== void 0 ? dragState : {};
1506
1318
  const pivotIndices = determinePivotIndices(groupId, dragHandleId);
1507
- let delta = calculateDeltaPercentage(event, groupId, dragHandleId, direction, dragState, {
1508
- percentage: keyboardResizeByPercentage,
1509
- pixels: keyboardResizeByPixels
1510
- });
1319
+ let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy);
1511
1320
  if (delta === 0) {
1512
1321
  return;
1513
1322
  }
@@ -1517,11 +1326,9 @@ function PanelGroupWithForwardedRef({
1517
1326
  if (document.dir === "rtl" && isHorizontal) {
1518
1327
  delta = -delta;
1519
1328
  }
1520
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1521
1329
  const panelConstraints = panelDataArray.map(panelData => panelData.constraints);
1522
1330
  const nextLayout = adjustLayoutByDelta({
1523
1331
  delta,
1524
- groupSizePixels,
1525
1332
  layout: initialLayout !== null && initialLayout !== void 0 ? initialLayout : prevLayout,
1526
1333
  panelConstraints,
1527
1334
  pivotIndices,
@@ -1557,18 +1364,15 @@ function PanelGroupWithForwardedRef({
1557
1364
  setLayout(nextLayout);
1558
1365
  eagerValuesRef.current.layout = nextLayout;
1559
1366
  if (onLayout) {
1560
- onLayout(nextLayout.map(sizePercentage => ({
1561
- sizePercentage,
1562
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1563
- })));
1367
+ onLayout(nextLayout);
1564
1368
  }
1565
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1369
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1566
1370
  }
1567
1371
  };
1568
1372
  }, []);
1569
1373
 
1570
1374
  // External APIs are safe to memoize via committed values ref
1571
- const resizePanel = useCallback((panelData, mixedSizes) => {
1375
+ const resizePanel = useCallback((panelData, unsafePanelSize) => {
1572
1376
  const {
1573
1377
  onLayout
1574
1378
  } = committedValuesRef.current;
@@ -1578,16 +1382,14 @@ function PanelGroupWithForwardedRef({
1578
1382
  } = eagerValuesRef.current;
1579
1383
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1580
1384
  const {
1581
- groupSizePixels,
1582
- panelSizePercentage,
1385
+ panelSize,
1583
1386
  pivotIndices
1584
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
1585
- const sizePercentage = getPercentageSizeFromMixedSizes(mixedSizes, groupSizePixels);
1387
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
1388
+ assert(panelSize != null);
1586
1389
  const isLastPanel = panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
1587
- const delta = isLastPanel ? panelSizePercentage - sizePercentage : sizePercentage - panelSizePercentage;
1390
+ const delta = isLastPanel ? panelSize - unsafePanelSize : unsafePanelSize - panelSize;
1588
1391
  const nextLayout = adjustLayoutByDelta({
1589
1392
  delta,
1590
- groupSizePixels,
1591
1393
  layout: prevLayout,
1592
1394
  panelConstraints: panelConstraintsArray,
1593
1395
  pivotIndices,
@@ -1597,14 +1399,11 @@ function PanelGroupWithForwardedRef({
1597
1399
  setLayout(nextLayout);
1598
1400
  eagerValuesRef.current.layout = nextLayout;
1599
1401
  if (onLayout) {
1600
- onLayout(nextLayout.map(sizePercentage => ({
1601
- sizePercentage,
1602
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1603
- })));
1402
+ onLayout(nextLayout);
1604
1403
  }
1605
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1404
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1606
1405
  }
1607
- }, [groupId]);
1406
+ }, []);
1608
1407
  const startDragging = useCallback((dragHandleId, event) => {
1609
1408
  const {
1610
1409
  direction
@@ -1613,6 +1412,7 @@ function PanelGroupWithForwardedRef({
1613
1412
  layout
1614
1413
  } = eagerValuesRef.current;
1615
1414
  const handleElement = getResizeHandleElement(dragHandleId);
1415
+ assert(handleElement);
1616
1416
  const initialCursorPosition = getResizeEventCursorPosition(direction, event);
1617
1417
  setDragState({
1618
1418
  dragHandleId,
@@ -1631,7 +1431,6 @@ function PanelGroupWithForwardedRef({
1631
1431
  });
1632
1432
  const unregisterPanel = useCallback(panelData => {
1633
1433
  const {
1634
- id: groupId,
1635
1434
  onLayout
1636
1435
  } = committedValuesRef.current;
1637
1436
  const {
@@ -1654,7 +1453,7 @@ function PanelGroupWithForwardedRef({
1654
1453
  const {
1655
1454
  pendingPanelIds
1656
1455
  } = unregisterPanelRef.current;
1657
- const map = panelIdToLastNotifiedMixedSizesMapRef.current;
1456
+ const map = panelIdToLastNotifiedSizeMapRef.current;
1658
1457
 
1659
1458
  // TRICKY
1660
1459
  // Strict effects mode
@@ -1680,16 +1479,13 @@ function PanelGroupWithForwardedRef({
1680
1479
  // The group is unmounting; skip layout calculation.
1681
1480
  return;
1682
1481
  }
1683
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1684
1482
  let unsafeLayout = calculateUnsafeDefaultLayout({
1685
- groupSizePixels,
1686
1483
  panelDataArray
1687
1484
  });
1688
1485
 
1689
1486
  // Validate even saved layouts in case something has changed since last render
1690
1487
  // e.g. for pixel groups, this could be the size of the window
1691
1488
  const nextLayout = validatePanelGroupLayout({
1692
- groupSizePixels,
1693
1489
  layout: unsafeLayout,
1694
1490
  panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1695
1491
  });
@@ -1697,12 +1493,9 @@ function PanelGroupWithForwardedRef({
1697
1493
  setLayout(nextLayout);
1698
1494
  eagerValuesRef.current.layout = nextLayout;
1699
1495
  if (onLayout) {
1700
- onLayout(nextLayout.map(sizePercentage => ({
1701
- sizePercentage,
1702
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1703
- })));
1496
+ onLayout(nextLayout);
1704
1497
  }
1705
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1498
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1706
1499
  }
1707
1500
  }, 0);
1708
1501
  }, []);
@@ -1733,13 +1526,13 @@ function PanelGroupWithForwardedRef({
1733
1526
  return createElement(PanelGroupContext.Provider, {
1734
1527
  value: context
1735
1528
  }, createElement(Type, {
1529
+ ...rest,
1736
1530
  children,
1737
1531
  className: classNameFromProps,
1738
1532
  style: {
1739
1533
  ...style,
1740
1534
  ...styleFromProps
1741
1535
  },
1742
- ...dataAttributes,
1743
1536
  // CSS selectors
1744
1537
  "data-panel-group": "",
1745
1538
  "data-panel-group-direction": direction,
@@ -1752,22 +1545,16 @@ const PanelGroup = forwardRef((props, ref) => createElement(PanelGroupWithForwar
1752
1545
  }));
1753
1546
  PanelGroupWithForwardedRef.displayName = "PanelGroup";
1754
1547
  PanelGroup.displayName = "forwardRef(PanelGroup)";
1755
- function panelDataHelper(groupId, panelDataArray, panelData, layout) {
1548
+ function panelDataHelper(panelDataArray, panelData, layout) {
1756
1549
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1757
1550
  const panelIndex = panelDataArray.indexOf(panelData);
1758
1551
  const panelConstraints = panelConstraintsArray[panelIndex];
1759
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1760
- const percentagePanelConstraints = computePercentagePanelConstraints(panelConstraintsArray, panelIndex, groupSizePixels);
1761
1552
  const isLastPanel = panelIndex === panelDataArray.length - 1;
1762
1553
  const pivotIndices = isLastPanel ? [panelIndex - 1, panelIndex] : [panelIndex, panelIndex + 1];
1763
- const panelSizePercentage = layout[panelIndex];
1764
- const panelSizePixels = convertPercentageToPixels(panelSizePercentage, groupSizePixels);
1554
+ const panelSize = layout[panelIndex];
1765
1555
  return {
1766
- ...percentagePanelConstraints,
1767
- collapsible: panelConstraints.collapsible,
1768
- panelSizePercentage,
1769
- panelSizePixels,
1770
- groupSizePixels,
1556
+ ...panelConstraints,
1557
+ panelSize,
1771
1558
  pivotIndices
1772
1559
  };
1773
1560
  }
@@ -1807,6 +1594,7 @@ function useWindowSplitterResizeHandlerBehavior({
1807
1594
  {
1808
1595
  event.preventDefault();
1809
1596
  const groupId = handleElement.getAttribute("data-panel-group-id");
1597
+ assert(groupId);
1810
1598
  const handles = getResizeHandleElementsForGroup(groupId);
1811
1599
  const index = getResizeHandleElementIndex(groupId, handleId);
1812
1600
  assert(index !== null);
@@ -1827,12 +1615,13 @@ function useWindowSplitterResizeHandlerBehavior({
1827
1615
  function PanelResizeHandle({
1828
1616
  children = null,
1829
1617
  className: classNameFromProps = "",
1830
- dataAttributes,
1831
1618
  disabled = false,
1832
- id: idFromProps = null,
1619
+ id: idFromProps,
1833
1620
  onDragging,
1834
1621
  style: styleFromProps = {},
1835
- tagName: Type = "div"
1622
+ tabIndex = 0,
1623
+ tagName: Type = "div",
1624
+ ...rest
1836
1625
  }) {
1837
1626
  const divElementRef = useRef(null);
1838
1627
 
@@ -1862,8 +1651,9 @@ function PanelResizeHandle({
1862
1651
  const stopDraggingAndBlur = useCallback(() => {
1863
1652
  // Clicking on the drag handle shouldn't leave it focused;
1864
1653
  // That would cause the PanelGroup to think it was still active.
1865
- const div = divElementRef.current;
1866
- div.blur();
1654
+ const divElement = divElementRef.current;
1655
+ assert(divElement);
1656
+ divElement.blur();
1867
1657
  stopDragging();
1868
1658
  const {
1869
1659
  onDragging
@@ -1891,6 +1681,7 @@ function PanelResizeHandle({
1891
1681
  resizeHandler(event);
1892
1682
  };
1893
1683
  const divElement = divElementRef.current;
1684
+ assert(divElement);
1894
1685
  const targetDocument = divElement.ownerDocument;
1895
1686
  targetDocument.body.addEventListener("contextmenu", stopDraggingAndBlur);
1896
1687
  targetDocument.body.addEventListener("mousemove", onMove);
@@ -1918,15 +1709,18 @@ function PanelResizeHandle({
1918
1709
  userSelect: "none"
1919
1710
  };
1920
1711
  return createElement(Type, {
1712
+ ...rest,
1921
1713
  children,
1922
1714
  className: classNameFromProps,
1923
1715
  onBlur: () => setIsFocused(false),
1924
1716
  onFocus: () => setIsFocused(true),
1925
1717
  onMouseDown: event => {
1926
1718
  startDragging(resizeHandleId, event.nativeEvent);
1719
+ const callbacks = callbacksRef.current;
1720
+ assert(callbacks);
1927
1721
  const {
1928
1722
  onDragging
1929
- } = callbacksRef.current;
1723
+ } = callbacks;
1930
1724
  if (onDragging) {
1931
1725
  onDragging(true);
1932
1726
  }
@@ -1936,9 +1730,11 @@ function PanelResizeHandle({
1936
1730
  onTouchEnd: stopDraggingAndBlur,
1937
1731
  onTouchStart: event => {
1938
1732
  startDragging(resizeHandleId, event.nativeEvent);
1733
+ const callbacks = callbacksRef.current;
1734
+ assert(callbacks);
1939
1735
  const {
1940
1736
  onDragging
1941
- } = callbacksRef.current;
1737
+ } = callbacks;
1942
1738
  if (onDragging) {
1943
1739
  onDragging(true);
1944
1740
  }
@@ -1949,8 +1745,7 @@ function PanelResizeHandle({
1949
1745
  ...style,
1950
1746
  ...styleFromProps
1951
1747
  },
1952
- tabIndex: 0,
1953
- ...dataAttributes,
1748
+ tabIndex,
1954
1749
  // CSS selectors
1955
1750
  "data-panel-group-direction": direction,
1956
1751
  "data-panel-group-id": groupId,
@@ -1965,3 +1760,4 @@ PanelResizeHandle.displayName = "PanelResizeHandle";
1965
1760
  exports.Panel = Panel;
1966
1761
  exports.PanelGroup = PanelGroup;
1967
1762
  exports.PanelResizeHandle = PanelResizeHandle;
1763
+ exports.assert = assert;