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
@@ -43,24 +43,20 @@ function useUniqueId(idFromParams = null) {
43
43
  function PanelWithForwardedRef({
44
44
  children,
45
45
  className: classNameFromProps = "",
46
- collapsedSizePercentage,
47
- collapsedSizePixels,
46
+ collapsedSize,
48
47
  collapsible,
49
- dataAttributes,
50
- defaultSizePercentage,
51
- defaultSizePixels,
48
+ defaultSize,
52
49
  forwardedRef,
53
50
  id: idFromProps,
54
- maxSizePercentage,
55
- maxSizePixels,
56
- minSizePercentage,
57
- minSizePixels,
51
+ maxSize,
52
+ minSize,
58
53
  onCollapse,
59
54
  onExpand,
60
55
  onResize,
61
56
  order,
62
57
  style: styleFromProps,
63
- tagName: Type = "div"
58
+ tagName: Type = "div",
59
+ ...rest
64
60
  }) {
65
61
  const context = useContext(PanelGroupContext);
66
62
  if (context === null) {
@@ -85,15 +81,11 @@ function PanelWithForwardedRef({
85
81
  onResize
86
82
  },
87
83
  constraints: {
88
- collapsedSizePercentage,
89
- collapsedSizePixels,
84
+ collapsedSize,
90
85
  collapsible,
91
- defaultSizePercentage,
92
- defaultSizePixels,
93
- maxSizePercentage,
94
- maxSizePixels,
95
- minSizePercentage,
96
- minSizePixels
86
+ defaultSize,
87
+ maxSize,
88
+ minSize
97
89
  },
98
90
  id: panelId,
99
91
  idIsFromProps: idFromProps !== undefined,
@@ -107,9 +99,9 @@ function PanelWithForwardedRef({
107
99
  // but effects don't run on the server, so we can't do it there
108
100
  {
109
101
  if (!devWarningsRef.current.didLogMissingDefaultSizeWarning) {
110
- if (!isBrowser && defaultSizePercentage == null && defaultSizePixels == null) {
102
+ if (!isBrowser && defaultSize == null) {
111
103
  devWarningsRef.current.didLogMissingDefaultSizeWarning = true;
112
- console.warn(`WARNING: Panel defaultSizePercentage or defaultSizePixels prop recommended to avoid layout shift after server rendering`);
104
+ console.warn(`WARNING: Panel defaultSize prop recommended to avoid layout shift after server rendering`);
113
105
  }
114
106
  }
115
107
  }
@@ -124,15 +116,11 @@ function PanelWithForwardedRef({
124
116
  callbacks.onCollapse = onCollapse;
125
117
  callbacks.onExpand = onExpand;
126
118
  callbacks.onResize = onResize;
127
- constraints.collapsedSizePercentage = collapsedSizePercentage;
128
- constraints.collapsedSizePixels = collapsedSizePixels;
119
+ constraints.collapsedSize = collapsedSize;
129
120
  constraints.collapsible = collapsible;
130
- constraints.defaultSizePercentage = defaultSizePercentage;
131
- constraints.defaultSizePixels = defaultSizePixels;
132
- constraints.maxSizePercentage = maxSizePercentage;
133
- constraints.maxSizePixels = maxSizePixels;
134
- constraints.minSizePercentage = minSizePercentage;
135
- constraints.minSizePixels = minSizePixels;
121
+ constraints.defaultSize = defaultSize;
122
+ constraints.maxSize = maxSize;
123
+ constraints.minSize = minSize;
136
124
  });
137
125
  useIsomorphicLayoutEffect(() => {
138
126
  const panelData = panelDataRef.current;
@@ -160,19 +148,19 @@ function PanelWithForwardedRef({
160
148
  isExpanded() {
161
149
  return !isPanelCollapsed(panelDataRef.current);
162
150
  },
163
- resize: mixedSizes => {
164
- resizePanel(panelDataRef.current, mixedSizes);
151
+ resize: size => {
152
+ resizePanel(panelDataRef.current, size);
165
153
  }
166
154
  }), [collapsePanel, expandPanel, getPanelSize, isPanelCollapsed, panelId, resizePanel]);
167
155
  const style = getPanelStyle(panelDataRef.current);
168
156
  return createElement(Type, {
157
+ ...rest,
169
158
  children,
170
159
  className: classNameFromProps,
171
160
  style: {
172
161
  ...style,
173
162
  ...styleFromProps
174
163
  },
175
- ...dataAttributes,
176
164
  // CSS selectors
177
165
  "data-panel": "",
178
166
  "data-panel-id": panelId,
@@ -189,81 +177,11 @@ const Panel = forwardRef((props, ref) => createElement(PanelWithForwardedRef, {
189
177
  PanelWithForwardedRef.displayName = "Panel";
190
178
  Panel.displayName = "forwardRef(Panel)";
191
179
 
192
- function convertPixelsToPercentage(pixels, groupSizePixels) {
193
- return pixels / groupSizePixels * 100;
194
- }
195
-
196
- function convertPixelConstraintsToPercentages(panelConstraints, groupSizePixels) {
197
- let {
198
- collapsedSizePercentage = 0,
199
- collapsedSizePixels,
200
- defaultSizePercentage,
201
- defaultSizePixels,
202
- maxSizePercentage = 100,
203
- maxSizePixels,
204
- minSizePercentage = 0,
205
- minSizePixels
206
- } = panelConstraints;
207
- const hasPixelConstraints = collapsedSizePixels != null || defaultSizePixels != null || minSizePixels != null || maxSizePixels != null;
208
- if (hasPixelConstraints && groupSizePixels <= 0) {
209
- console.warn(`WARNING: Invalid group size: ${groupSizePixels}px`);
210
- return {
211
- collapsedSizePercentage: 0,
212
- defaultSizePercentage,
213
- maxSizePercentage: 0,
214
- minSizePercentage: 0
215
- };
216
- }
217
- if (collapsedSizePixels != null) {
218
- collapsedSizePercentage = convertPixelsToPercentage(collapsedSizePixels, groupSizePixels);
219
- }
220
- if (defaultSizePixels != null) {
221
- defaultSizePercentage = convertPixelsToPercentage(defaultSizePixels, groupSizePixels);
222
- }
223
- if (minSizePixels != null) {
224
- minSizePercentage = convertPixelsToPercentage(minSizePixels, groupSizePixels);
225
- }
226
- if (maxSizePixels != null) {
227
- maxSizePercentage = convertPixelsToPercentage(maxSizePixels, groupSizePixels);
228
- }
229
- return {
230
- collapsedSizePercentage,
231
- defaultSizePercentage,
232
- maxSizePercentage,
233
- minSizePercentage
234
- };
235
- }
236
-
237
- function computePercentagePanelConstraints(panelConstraintsArray, panelIndex, groupSizePixels) {
238
- // All panel constraints, excluding the current one
239
- let totalMinConstraints = 0;
240
- let totalMaxConstraints = 0;
241
- for (let index = 0; index < panelConstraintsArray.length; index++) {
242
- if (index !== panelIndex) {
243
- const {
244
- collapsible
245
- } = panelConstraintsArray[index];
246
- const {
247
- collapsedSizePercentage,
248
- maxSizePercentage,
249
- minSizePercentage
250
- } = convertPixelConstraintsToPercentages(panelConstraintsArray[index], groupSizePixels);
251
- totalMaxConstraints += maxSizePercentage;
252
- totalMinConstraints += collapsible ? collapsedSizePercentage : minSizePercentage;
253
- }
180
+ function assert(expectedCondition, message = "Assertion failed!") {
181
+ if (!expectedCondition) {
182
+ console.error(message);
183
+ throw Error(message);
254
184
  }
255
- const {
256
- collapsedSizePercentage,
257
- defaultSizePercentage,
258
- maxSizePercentage,
259
- minSizePercentage
260
- } = convertPixelConstraintsToPercentages(panelConstraintsArray[panelIndex], groupSizePixels);
261
- return {
262
- collapsedSizePercentage,
263
- defaultSizePercentage,
264
- maxSizePercentage: panelConstraintsArray.length > 1 ? Math.min(maxSizePercentage, 100 - totalMinConstraints) : maxSizePercentage,
265
- minSizePercentage: panelConstraintsArray.length > 1 ? Math.max(minSizePercentage, 100 - totalMaxConstraints) : minSizePercentage
266
- };
267
185
  }
268
186
 
269
187
  const PRECISION = 10;
@@ -285,56 +203,41 @@ function fuzzyNumbersEqual(actual, expected, fractionDigits) {
285
203
 
286
204
  // Panel size must be in percentages; pixel values should be pre-converted
287
205
  function resizePanel({
288
- groupSizePixels,
289
- panelConstraints,
206
+ panelConstraints: panelConstraintsArray,
290
207
  panelIndex,
291
208
  size
292
209
  }) {
293
- const hasPixelConstraints = panelConstraints.some(({
294
- collapsedSizePixels,
295
- defaultSizePixels,
296
- minSizePixels,
297
- maxSizePixels
298
- }) => collapsedSizePixels != null || defaultSizePixels != null || minSizePixels != null || maxSizePixels != null);
299
- if (hasPixelConstraints && groupSizePixels <= 0) {
300
- console.warn(`WARNING: Invalid group size: ${groupSizePixels}px`);
301
- return 0;
302
- }
210
+ const panelConstraints = panelConstraintsArray[panelIndex];
211
+ assert(panelConstraints != null);
303
212
  let {
304
- collapsible
305
- } = panelConstraints[panelIndex];
306
- const {
307
- collapsedSizePercentage,
308
- maxSizePercentage,
309
- minSizePercentage
310
- } = computePercentagePanelConstraints(panelConstraints, panelIndex, groupSizePixels);
311
- if (minSizePercentage != null) {
312
- if (fuzzyCompareNumbers(size, minSizePercentage) < 0) {
313
- if (collapsible) {
314
- // Collapsible panels should snap closed or open only once they cross the halfway point between collapsed and min size.
315
- const halfwayPoint = (collapsedSizePercentage + minSizePercentage) / 2;
316
- if (fuzzyCompareNumbers(size, halfwayPoint) < 0) {
317
- size = collapsedSizePercentage;
318
- } else {
319
- size = minSizePercentage;
320
- }
213
+ collapsedSize = 0,
214
+ collapsible,
215
+ maxSize = 100,
216
+ minSize = 0
217
+ } = panelConstraints;
218
+ if (fuzzyCompareNumbers(size, minSize) < 0) {
219
+ if (collapsible) {
220
+ // Collapsible panels should snap closed or open only once they cross the halfway point between collapsed and min size.
221
+ const halfwayPoint = (collapsedSize + minSize) / 2;
222
+ if (fuzzyCompareNumbers(size, halfwayPoint) < 0) {
223
+ size = collapsedSize;
321
224
  } else {
322
- size = minSizePercentage;
225
+ size = minSize;
323
226
  }
227
+ } else {
228
+ size = minSize;
324
229
  }
325
230
  }
326
- if (maxSizePercentage != null) {
327
- size = Math.min(maxSizePercentage, size);
328
- }
231
+ size = Math.min(maxSize, size);
232
+ size = parseFloat(size.toFixed(PRECISION));
329
233
  return size;
330
234
  }
331
235
 
332
236
  // All units must be in percentages; pixel values should be pre-converted
333
237
  function adjustLayoutByDelta({
334
238
  delta,
335
- groupSizePixels,
336
239
  layout: prevLayout,
337
- panelConstraints,
240
+ panelConstraints: panelConstraintsArray,
338
241
  pivotIndices,
339
242
  trigger
340
243
  }) {
@@ -342,6 +245,9 @@ function adjustLayoutByDelta({
342
245
  return prevLayout;
343
246
  }
344
247
  const nextLayout = [...prevLayout];
248
+ const [firstPivotIndex, secondPivotIndex] = pivotIndices;
249
+ assert(firstPivotIndex != null);
250
+ assert(secondPivotIndex != null);
345
251
  let deltaApplied = 0;
346
252
 
347
253
  //const DEBUG = [];
@@ -365,18 +271,23 @@ function adjustLayoutByDelta({
365
271
  if (trigger === "keyboard") {
366
272
  {
367
273
  // Check if we should expand a collapsed panel
368
- const index = delta < 0 ? pivotIndices[1] : pivotIndices[0];
369
- const constraints = panelConstraints[index];
274
+ const index = delta < 0 ? secondPivotIndex : firstPivotIndex;
275
+ const panelConstraints = panelConstraintsArray[index];
276
+ assert(panelConstraints);
277
+
370
278
  //DEBUG.push(`edge case check 1: ${index}`);
371
279
  //DEBUG.push(` -> collapsible? ${constraints.collapsible}`);
372
- if (constraints.collapsible) {
280
+ if (panelConstraints.collapsible) {
373
281
  const prevSize = prevLayout[index];
282
+ assert(prevSize != null);
283
+ const panelConstraints = panelConstraintsArray[index];
284
+ assert(panelConstraints);
374
285
  const {
375
- collapsedSizePercentage,
376
- minSizePercentage
377
- } = computePercentagePanelConstraints(panelConstraints, index, groupSizePixels);
378
- if (fuzzyNumbersEqual(prevSize, collapsedSizePercentage)) {
379
- const localDelta = minSizePercentage - prevSize;
286
+ collapsedSize = 0,
287
+ minSize = 0
288
+ } = panelConstraints;
289
+ if (fuzzyNumbersEqual(prevSize, collapsedSize)) {
290
+ const localDelta = minSize - prevSize;
380
291
  //DEBUG.push(` -> expand delta: ${localDelta}`);
381
292
 
382
293
  if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0) {
@@ -389,18 +300,26 @@ function adjustLayoutByDelta({
389
300
 
390
301
  {
391
302
  // Check if we should collapse a panel at its minimum size
392
- const index = delta < 0 ? pivotIndices[0] : pivotIndices[1];
393
- const constraints = panelConstraints[index];
303
+ const index = delta < 0 ? firstPivotIndex : secondPivotIndex;
304
+ const panelConstraints = panelConstraintsArray[index];
305
+ assert(panelConstraints);
306
+ const {
307
+ collapsible
308
+ } = panelConstraints;
309
+
394
310
  //DEBUG.push(`edge case check 2: ${index}`);
395
- //DEBUG.push(` -> collapsible? ${constraints.collapsible}`);
396
- if (constraints.collapsible) {
311
+ //DEBUG.push(` -> collapsible? ${collapsible}`);
312
+ if (collapsible) {
397
313
  const prevSize = prevLayout[index];
314
+ assert(prevSize != null);
315
+ const panelConstraints = panelConstraintsArray[index];
316
+ assert(panelConstraints);
398
317
  const {
399
- collapsedSizePercentage,
400
- minSizePercentage
401
- } = computePercentagePanelConstraints(panelConstraints, index, groupSizePixels);
402
- if (fuzzyNumbersEqual(prevSize, minSizePercentage)) {
403
- const localDelta = prevSize - collapsedSizePercentage;
318
+ collapsedSize = 0,
319
+ minSize = 0
320
+ } = panelConstraints;
321
+ if (fuzzyNumbersEqual(prevSize, minSize)) {
322
+ const localDelta = prevSize - collapsedSize;
404
323
  //DEBUG.push(` -> expand delta: ${localDelta}`);
405
324
 
406
325
  if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0) {
@@ -422,15 +341,15 @@ function adjustLayoutByDelta({
422
341
  // as an expanding panel might change from collapsed to min size.
423
342
 
424
343
  const increment = delta < 0 ? 1 : -1;
425
- let index = delta < 0 ? pivotIndices[1] : pivotIndices[0];
344
+ let index = delta < 0 ? secondPivotIndex : firstPivotIndex;
426
345
  let maxAvailableDelta = 0;
427
346
 
428
347
  //DEBUG.push("pre calc...");
429
348
  while (true) {
430
349
  const prevSize = prevLayout[index];
350
+ assert(prevSize != null);
431
351
  const maxSafeSize = resizePanel({
432
- groupSizePixels,
433
- panelConstraints,
352
+ panelConstraints: panelConstraintsArray,
434
353
  panelIndex: index,
435
354
  size: 100
436
355
  });
@@ -439,7 +358,7 @@ function adjustLayoutByDelta({
439
358
 
440
359
  maxAvailableDelta += delta;
441
360
  index += increment;
442
- if (index < 0 || index >= panelConstraints.length) {
361
+ if (index < 0 || index >= panelConstraintsArray.length) {
443
362
  break;
444
363
  }
445
364
  }
@@ -454,15 +373,15 @@ function adjustLayoutByDelta({
454
373
  {
455
374
  // Delta added to a panel needs to be subtracted from other panels (within the constraints that those panels allow).
456
375
 
457
- const pivotIndex = delta < 0 ? pivotIndices[0] : pivotIndices[1];
376
+ const pivotIndex = delta < 0 ? firstPivotIndex : secondPivotIndex;
458
377
  let index = pivotIndex;
459
- while (index >= 0 && index < panelConstraints.length) {
378
+ while (index >= 0 && index < panelConstraintsArray.length) {
460
379
  const deltaRemaining = Math.abs(delta) - Math.abs(deltaApplied);
461
380
  const prevSize = prevLayout[index];
381
+ assert(prevSize != null);
462
382
  const unsafeSize = prevSize - deltaRemaining;
463
383
  const safeSize = resizePanel({
464
- groupSizePixels,
465
- panelConstraints,
384
+ panelConstraints: panelConstraintsArray,
466
385
  panelIndex: index,
467
386
  size: unsafeSize
468
387
  });
@@ -494,11 +413,12 @@ function adjustLayoutByDelta({
494
413
  }
495
414
  {
496
415
  // Now distribute the applied delta to the panels in the other direction
497
- const pivotIndex = delta < 0 ? pivotIndices[1] : pivotIndices[0];
498
- const unsafeSize = prevLayout[pivotIndex] + deltaApplied;
416
+ const pivotIndex = delta < 0 ? secondPivotIndex : firstPivotIndex;
417
+ const prevSize = prevLayout[pivotIndex];
418
+ assert(prevSize != null);
419
+ const unsafeSize = prevSize + deltaApplied;
499
420
  const safeSize = resizePanel({
500
- groupSizePixels,
501
- panelConstraints,
421
+ panelConstraints: panelConstraintsArray,
502
422
  panelIndex: pivotIndex,
503
423
  size: unsafeSize
504
424
  });
@@ -509,14 +429,14 @@ function adjustLayoutByDelta({
509
429
  // Edge case where expanding or contracting one panel caused another one to change collapsed state
510
430
  if (!fuzzyNumbersEqual(safeSize, unsafeSize)) {
511
431
  let deltaRemaining = unsafeSize - safeSize;
512
- const pivotIndex = delta < 0 ? pivotIndices[1] : pivotIndices[0];
432
+ const pivotIndex = delta < 0 ? secondPivotIndex : firstPivotIndex;
513
433
  let index = pivotIndex;
514
- while (index >= 0 && index < panelConstraints.length) {
434
+ while (index >= 0 && index < panelConstraintsArray.length) {
515
435
  const prevSize = nextLayout[index];
436
+ assert(prevSize != null);
516
437
  const unsafeSize = prevSize + deltaRemaining;
517
438
  const safeSize = resizePanel({
518
- groupSizePixels,
519
- panelConstraints,
439
+ panelConstraints: panelConstraintsArray,
520
440
  panelIndex: index,
521
441
  size: unsafeSize
522
442
  });
@@ -540,9 +460,7 @@ function adjustLayoutByDelta({
540
460
  //DEBUG.push("");
541
461
 
542
462
  const totalSize = nextLayout.reduce((total, size) => size + total, 0);
543
- deltaApplied = 100 - totalSize;
544
463
  //DEBUG.push(`total size: ${totalSize}`);
545
- //DEBUG.push(` deltaApplied: ${deltaApplied}`);
546
464
  //console.log(DEBUG.join("\n"));
547
465
 
548
466
  if (!fuzzyNumbersEqual(totalSize, 100)) {
@@ -551,27 +469,7 @@ function adjustLayoutByDelta({
551
469
  return nextLayout;
552
470
  }
553
471
 
554
- function assert(expectedCondition, message = "Assertion failed!") {
555
- if (!expectedCondition) {
556
- console.error(message);
557
- throw Error(message);
558
- }
559
- }
560
-
561
- function getPercentageSizeFromMixedSizes({
562
- sizePercentage,
563
- sizePixels
564
- }, groupSizePixels) {
565
- if (sizePercentage != null) {
566
- return sizePercentage;
567
- } else if (sizePixels != null) {
568
- return convertPixelsToPercentage(sizePixels, groupSizePixels);
569
- }
570
- return undefined;
571
- }
572
-
573
472
  function calculateAriaValues({
574
- groupSizePixels,
575
473
  layout,
576
474
  panelsArray,
577
475
  pivotIndices
@@ -580,28 +478,19 @@ function calculateAriaValues({
580
478
  let currentMaxSize = 100;
581
479
  let totalMinSize = 0;
582
480
  let totalMaxSize = 0;
481
+ const firstIndex = pivotIndices[0];
482
+ assert(firstIndex != null);
583
483
 
584
484
  // A panel's effective min/max sizes also need to account for other panel's sizes.
585
485
  panelsArray.forEach((panelData, index) => {
586
- var _getPercentageSizeFro, _getPercentageSizeFro2;
587
486
  const {
588
487
  constraints
589
488
  } = panelData;
590
489
  const {
591
- maxSizePercentage,
592
- maxSizePixels,
593
- minSizePercentage,
594
- minSizePixels
490
+ maxSize = 100,
491
+ minSize = 0
595
492
  } = constraints;
596
- const minSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
597
- sizePercentage: minSizePercentage,
598
- sizePixels: minSizePixels
599
- }, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
600
- const maxSize = (_getPercentageSizeFro2 = getPercentageSizeFromMixedSizes({
601
- sizePercentage: maxSizePercentage,
602
- sizePixels: maxSizePixels
603
- }, groupSizePixels)) !== null && _getPercentageSizeFro2 !== void 0 ? _getPercentageSizeFro2 : 100;
604
- if (index === pivotIndices[0]) {
493
+ if (index === firstIndex) {
605
494
  currentMinSize = minSize;
606
495
  currentMaxSize = maxSize;
607
496
  } else {
@@ -611,7 +500,7 @@ function calculateAriaValues({
611
500
  });
612
501
  const valueMax = Math.min(currentMaxSize, 100 - totalMinSize);
613
502
  const valueMin = Math.max(currentMinSize, 100 - totalMaxSize);
614
- const valueNow = layout[pivotIndices[0]];
503
+ const valueNow = layout[firstIndex];
615
504
  return {
616
505
  valueMax,
617
506
  valueMin,
@@ -642,42 +531,6 @@ function getPanelGroupElement(id) {
642
531
  return null;
643
532
  }
644
533
 
645
- function calculateAvailablePanelSizeInPixels(groupId) {
646
- const panelGroupElement = getPanelGroupElement(groupId);
647
- if (panelGroupElement == null) {
648
- return NaN;
649
- }
650
- const direction = panelGroupElement.getAttribute("data-panel-group-direction");
651
- const resizeHandles = getResizeHandleElementsForGroup(groupId);
652
- if (direction === "horizontal") {
653
- return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
654
- return accumulated + handle.offsetWidth;
655
- }, 0);
656
- } else {
657
- return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
658
- return accumulated + handle.offsetHeight;
659
- }, 0);
660
- }
661
- }
662
-
663
- function getAvailableGroupSizePixels(groupId) {
664
- const panelGroupElement = getPanelGroupElement(groupId);
665
- if (panelGroupElement == null) {
666
- return NaN;
667
- }
668
- const direction = panelGroupElement.getAttribute("data-panel-group-direction");
669
- const resizeHandles = getResizeHandleElementsForGroup(groupId);
670
- if (direction === "horizontal") {
671
- return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
672
- return accumulated + handle.offsetWidth;
673
- }, 0);
674
- } else {
675
- return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
676
- return accumulated + handle.offsetHeight;
677
- }, 0);
678
- }
679
- }
680
-
681
534
  function getResizeHandleElement(id) {
682
535
  const element = document.querySelector(`[data-panel-resize-handle-id="${id}"]`);
683
536
  if (element) {
@@ -710,7 +563,6 @@ function useWindowSplitterPanelGroupBehavior({
710
563
  didWarnAboutMissingResizeHandle: false
711
564
  });
712
565
  useIsomorphicLayoutEffect(() => {
713
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
714
566
  const resizeHandleElements = getResizeHandleElementsForGroup(groupId);
715
567
  for (let index = 0; index < panelDataArray.length - 1; index++) {
716
568
  const {
@@ -718,7 +570,6 @@ function useWindowSplitterPanelGroupBehavior({
718
570
  valueMin,
719
571
  valueNow
720
572
  } = calculateAriaValues({
721
- groupSizePixels,
722
573
  layout,
723
574
  panelsArray: panelDataArray,
724
575
  pivotIndices: [index, index + 1]
@@ -735,10 +586,12 @@ function useWindowSplitterPanelGroupBehavior({
735
586
  }
736
587
  }
737
588
  } else {
738
- resizeHandleElement.setAttribute("aria-controls", panelDataArray[index].id);
589
+ const panelData = panelDataArray[index];
590
+ assert(panelData);
591
+ resizeHandleElement.setAttribute("aria-controls", panelData.id);
739
592
  resizeHandleElement.setAttribute("aria-valuemax", "" + Math.round(valueMax));
740
593
  resizeHandleElement.setAttribute("aria-valuemin", "" + Math.round(valueMin));
741
- resizeHandleElement.setAttribute("aria-valuenow", "" + Math.round(valueNow));
594
+ resizeHandleElement.setAttribute("aria-valuenow", valueNow != null ? "" + Math.round(valueNow) : "");
742
595
  }
743
596
  }
744
597
  return () => {
@@ -751,14 +604,18 @@ function useWindowSplitterPanelGroupBehavior({
751
604
  };
752
605
  }, [groupId, layout, panelDataArray]);
753
606
  useEffect(() => {
607
+ const eagerValues = eagerValuesRef.current;
608
+ assert(eagerValues);
754
609
  const {
755
610
  panelDataArray
756
- } = eagerValuesRef.current;
611
+ } = eagerValues;
757
612
  const groupElement = getPanelGroupElement(groupId);
758
613
  assert(groupElement != null, `No group found for id "${groupId}"`);
759
614
  const handles = getResizeHandleElementsForGroup(groupId);
615
+ assert(handles);
760
616
  const cleanupFunctions = handles.map(handle => {
761
617
  const handleId = handle.getAttribute("data-panel-resize-handle-id");
618
+ assert(handleId);
762
619
  const [idBefore, idAfter] = getResizeHandlePanelIds(groupId, handleId, panelDataArray);
763
620
  if (idBefore == null || idAfter == null) {
764
621
  return () => {};
@@ -774,21 +631,16 @@ function useWindowSplitterPanelGroupBehavior({
774
631
  const index = panelDataArray.findIndex(panelData => panelData.id === idBefore);
775
632
  if (index >= 0) {
776
633
  const panelData = panelDataArray[index];
634
+ assert(panelData);
777
635
  const size = layout[index];
778
- if (size != null && panelData.constraints.collapsible) {
779
- var _getPercentageSizeFro, _getPercentageSizeFro2;
780
- const groupSizePixels = getAvailableGroupSizePixels(groupId);
781
- const collapsedSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
782
- sizePercentage: panelData.constraints.collapsedSizePercentage,
783
- sizePixels: panelData.constraints.collapsedSizePixels
784
- }, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
785
- const minSize = (_getPercentageSizeFro2 = getPercentageSizeFromMixedSizes({
786
- sizePercentage: panelData.constraints.minSizePercentage,
787
- sizePixels: panelData.constraints.minSizePixels
788
- }, groupSizePixels)) !== null && _getPercentageSizeFro2 !== void 0 ? _getPercentageSizeFro2 : 0;
636
+ const {
637
+ collapsedSize = 0,
638
+ collapsible,
639
+ minSize = 0
640
+ } = panelData.constraints;
641
+ if (size != null && collapsible) {
789
642
  const nextLayout = adjustLayoutByDelta({
790
643
  delta: fuzzyNumbersEqual(size, collapsedSize) ? minSize - collapsedSize : collapsedSize - size,
791
- groupSizePixels,
792
644
  layout,
793
645
  panelConstraints: panelDataArray.map(panelData => panelData.constraints),
794
646
  pivotIndices: determinePivotIndices(groupId, handleId),
@@ -842,6 +694,7 @@ function getResizeEventCursorPosition(direction, event) {
842
694
  return isHorizontal ? event.clientX : event.clientY;
843
695
  } else if (isTouchEvent(event)) {
844
696
  const firstTouch = event.touches[0];
697
+ assert(firstTouch);
845
698
  return isHorizontal ? firstTouch.screenX : firstTouch.screenY;
846
699
  } else {
847
700
  throw Error(`Unsupported event type "${event.type}"`);
@@ -851,12 +704,15 @@ function getResizeEventCursorPosition(direction, event) {
851
704
  function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState) {
852
705
  const isHorizontal = direction === "horizontal";
853
706
  const handleElement = getResizeHandleElement(dragHandleId);
707
+ assert(handleElement);
854
708
  const groupId = handleElement.getAttribute("data-panel-group-id");
709
+ assert(groupId);
855
710
  let {
856
711
  initialCursorPosition
857
712
  } = initialDragState;
858
713
  const cursorPosition = getResizeEventCursorPosition(direction, event);
859
714
  const groupElement = getPanelGroupElement(groupId);
715
+ assert(groupElement);
860
716
  const groupRect = groupElement.getBoundingClientRect();
861
717
  const groupSizeInPixels = isHorizontal ? groupRect.width : groupRect.height;
862
718
  const offsetPixels = cursorPosition - initialCursorPosition;
@@ -865,19 +721,14 @@ function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDr
865
721
  }
866
722
 
867
723
  // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/movementX
868
- function calculateDeltaPercentage(event, groupId, dragHandleId, direction, initialDragState, keyboardResizeByOptions) {
724
+ function calculateDeltaPercentage(event, dragHandleId, direction, initialDragState, keyboardResizeBy) {
869
725
  if (isKeyDown(event)) {
870
726
  const isHorizontal = direction === "horizontal";
871
- const groupElement = getPanelGroupElement(groupId);
872
- const rect = groupElement.getBoundingClientRect();
873
- const groupSizeInPixels = isHorizontal ? rect.width : rect.height;
874
727
  let delta = 0;
875
728
  if (event.shiftKey) {
876
729
  delta = 100;
877
- } else if (keyboardResizeByOptions.percentage != null) {
878
- delta = keyboardResizeByOptions.percentage;
879
- } else if (keyboardResizeByOptions.pixels != null) {
880
- delta = keyboardResizeByOptions.pixels / groupSizeInPixels;
730
+ } else if (keyboardResizeBy != null) {
731
+ delta = keyboardResizeBy;
881
732
  } else {
882
733
  delta = 10;
883
734
  }
@@ -904,37 +755,43 @@ function calculateDeltaPercentage(event, groupId, dragHandleId, direction, initi
904
755
  }
905
756
  return movement;
906
757
  } else {
758
+ if (initialDragState == null) {
759
+ return 0;
760
+ }
907
761
  return calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState);
908
762
  }
909
763
  }
910
764
 
911
765
  function calculateUnsafeDefaultLayout({
912
- groupSizePixels,
913
766
  panelDataArray
914
767
  }) {
915
768
  const layout = Array(panelDataArray.length);
916
- const panelDataConstraints = panelDataArray.map(panelData => panelData.constraints);
769
+ const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
917
770
  let numPanelsWithSizes = 0;
918
771
  let remainingSize = 100;
919
772
 
920
773
  // Distribute default sizes first
921
774
  for (let index = 0; index < panelDataArray.length; index++) {
775
+ const panelConstraints = panelConstraintsArray[index];
776
+ assert(panelConstraints);
922
777
  const {
923
- defaultSizePercentage
924
- } = computePercentagePanelConstraints(panelDataConstraints, index, groupSizePixels);
925
- if (defaultSizePercentage != null) {
778
+ defaultSize
779
+ } = panelConstraints;
780
+ if (defaultSize != null) {
926
781
  numPanelsWithSizes++;
927
- layout[index] = defaultSizePercentage;
928
- remainingSize -= defaultSizePercentage;
782
+ layout[index] = defaultSize;
783
+ remainingSize -= defaultSize;
929
784
  }
930
785
  }
931
786
 
932
787
  // Remaining size should be distributed evenly between panels without default sizes
933
788
  for (let index = 0; index < panelDataArray.length; index++) {
789
+ const panelConstraints = panelConstraintsArray[index];
790
+ assert(panelConstraints);
934
791
  const {
935
- defaultSizePercentage
936
- } = computePercentagePanelConstraints(panelDataConstraints, index, groupSizePixels);
937
- if (defaultSizePercentage != null) {
792
+ defaultSize
793
+ } = panelConstraints;
794
+ if (defaultSize != null) {
938
795
  continue;
939
796
  }
940
797
  const numRemainingPanels = panelDataArray.length - numPanelsWithSizes;
@@ -946,54 +803,36 @@ function calculateUnsafeDefaultLayout({
946
803
  return layout;
947
804
  }
948
805
 
949
- function convertPercentageToPixels(percentage, groupSizePixels) {
950
- return percentage / 100 * groupSizePixels;
951
- }
952
-
953
806
  // Layout should be pre-converted into percentages
954
- function callPanelCallbacks(groupId, panelsArray, layout, panelIdToLastNotifiedMixedSizesMap) {
955
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
956
- layout.forEach((sizePercentage, index) => {
807
+ function callPanelCallbacks(panelsArray, layout, panelIdToLastNotifiedSizeMap) {
808
+ layout.forEach((size, index) => {
957
809
  const panelData = panelsArray[index];
958
- if (!panelData) {
959
- // Handle initial mount (when panels are registered too late to be in the panels array)
960
- // The subsequent render+effects will handle the resize notification
961
- return;
962
- }
810
+ assert(panelData);
963
811
  const {
964
812
  callbacks,
965
813
  constraints,
966
814
  id: panelId
967
815
  } = panelData;
968
816
  const {
817
+ collapsedSize = 0,
969
818
  collapsible
970
819
  } = constraints;
971
- const mixedSizes = {
972
- sizePercentage,
973
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
974
- };
975
- const lastNotifiedMixedSizes = panelIdToLastNotifiedMixedSizesMap[panelId];
976
- if (lastNotifiedMixedSizes == null || mixedSizes.sizePercentage !== lastNotifiedMixedSizes.sizePercentage || mixedSizes.sizePixels !== lastNotifiedMixedSizes.sizePixels) {
977
- panelIdToLastNotifiedMixedSizesMap[panelId] = mixedSizes;
820
+ const lastNotifiedSize = panelIdToLastNotifiedSizeMap[panelId];
821
+ if (lastNotifiedSize == null || size !== lastNotifiedSize) {
822
+ panelIdToLastNotifiedSizeMap[panelId] = size;
978
823
  const {
979
824
  onCollapse,
980
825
  onExpand,
981
826
  onResize
982
827
  } = callbacks;
983
828
  if (onResize) {
984
- onResize(mixedSizes, lastNotifiedMixedSizes);
829
+ onResize(size, lastNotifiedSize);
985
830
  }
986
831
  if (collapsible && (onCollapse || onExpand)) {
987
- var _getPercentageSizeFro;
988
- const collapsedSize = (_getPercentageSizeFro = getPercentageSizeFromMixedSizes({
989
- sizePercentage: constraints.collapsedSizePercentage,
990
- sizePixels: constraints.collapsedSizePixels
991
- }, groupSizePixels)) !== null && _getPercentageSizeFro !== void 0 ? _getPercentageSizeFro : 0;
992
- const size = getPercentageSizeFromMixedSizes(mixedSizes, groupSizePixels);
993
- if (onExpand && (lastNotifiedMixedSizes == null || lastNotifiedMixedSizes.sizePercentage === collapsedSize) && size !== collapsedSize) {
832
+ if (onExpand && (lastNotifiedSize == null || lastNotifiedSize === collapsedSize) && size !== collapsedSize) {
994
833
  onExpand();
995
834
  }
996
- if (onCollapse && (lastNotifiedMixedSizes == null || lastNotifiedMixedSizes.sizePercentage !== collapsedSize) && size === collapsedSize) {
835
+ if (onCollapse && (lastNotifiedSize == null || lastNotifiedSize !== collapsedSize) && size === collapsedSize) {
997
836
  onCollapse();
998
837
  }
999
838
  }
@@ -1027,9 +866,10 @@ function computePanelFlexBoxStyle({
1027
866
  const size = layout[panelIndex];
1028
867
  let flexGrow;
1029
868
  if (panelData.length === 1) {
1030
- flexGrow = "100";
869
+ flexGrow = "1";
1031
870
  } else if (size == null) {
1032
- flexGrow = "0";
871
+ // Initial render (before panels have registered themselves)
872
+ flexGrow = "1";
1033
873
  } else {
1034
874
  flexGrow = size.toPrecision(precision);
1035
875
  }
@@ -1175,74 +1015,39 @@ function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
1175
1015
  }
1176
1016
  }
1177
1017
 
1178
- function shouldMonitorPixelBasedConstraints(constraints) {
1179
- return constraints.some(constraints => {
1180
- return constraints.collapsedSizePixels !== undefined || constraints.maxSizePixels !== undefined || constraints.minSizePixels !== undefined;
1181
- });
1182
- }
1183
-
1184
1018
  function validatePanelConstraints({
1185
- groupSizePixels,
1186
- panelConstraints,
1019
+ panelConstraints: panelConstraintsArray,
1187
1020
  panelId,
1188
1021
  panelIndex
1189
1022
  }) {
1190
1023
  {
1191
1024
  const warnings = [];
1192
- {
1193
- const {
1194
- collapsedSizePercentage,
1195
- collapsedSizePixels,
1196
- defaultSizePercentage,
1197
- defaultSizePixels,
1198
- maxSizePercentage,
1199
- maxSizePixels,
1200
- minSizePercentage,
1201
- minSizePixels
1202
- } = panelConstraints[panelIndex];
1203
- const conflictingUnits = [];
1204
- if (collapsedSizePercentage != null && collapsedSizePixels != null) {
1205
- conflictingUnits.push("collapsed size");
1206
- }
1207
- if (defaultSizePercentage != null && defaultSizePixels != null) {
1208
- conflictingUnits.push("default size");
1209
- }
1210
- if (maxSizePercentage != null && maxSizePixels != null) {
1211
- conflictingUnits.push("max size");
1212
- }
1213
- if (minSizePercentage != null && minSizePixels != null) {
1214
- conflictingUnits.push("min size");
1215
- }
1216
- if (conflictingUnits.length > 0) {
1217
- warnings.push(`should not specify both percentage and pixel units for: ${conflictingUnits.join(", ")}`);
1218
- }
1025
+ const panelConstraints = panelConstraintsArray[panelIndex];
1026
+ assert(panelConstraints);
1027
+ const {
1028
+ collapsedSize = 0,
1029
+ defaultSize,
1030
+ maxSize = 100,
1031
+ minSize = 0
1032
+ } = panelConstraints;
1033
+ if (minSize > maxSize) {
1034
+ warnings.push(`min size (${minSize}%) should not be greater than max size (${maxSize}%)`);
1219
1035
  }
1220
- {
1221
- const {
1222
- collapsedSizePercentage,
1223
- defaultSizePercentage,
1224
- maxSizePercentage,
1225
- minSizePercentage
1226
- } = computePercentagePanelConstraints(panelConstraints, panelIndex, groupSizePixels);
1227
- if (minSizePercentage > maxSizePercentage) {
1228
- warnings.push(`min size (${minSizePercentage}%) should not be greater than max size (${maxSizePercentage}%)`);
1229
- }
1230
- if (defaultSizePercentage != null) {
1231
- if (defaultSizePercentage < 0) {
1232
- warnings.push("default size should not be less than 0");
1233
- } else if (defaultSizePercentage < minSizePercentage) {
1234
- warnings.push("default size should not be less than min size");
1235
- }
1236
- if (defaultSizePercentage > 100) {
1237
- warnings.push("default size should not be greater than 100");
1238
- } else if (defaultSizePercentage > maxSizePercentage) {
1239
- warnings.push("default size should not be greater than max size");
1240
- }
1036
+ if (defaultSize != null) {
1037
+ if (defaultSize < 0) {
1038
+ warnings.push("default size should not be less than 0");
1039
+ } else if (defaultSize < minSize) {
1040
+ warnings.push("default size should not be less than min size");
1241
1041
  }
1242
- if (collapsedSizePercentage > minSizePercentage) {
1243
- warnings.push("collapsed size should not be greater than min size");
1042
+ if (defaultSize > 100) {
1043
+ warnings.push("default size should not be greater than 100");
1044
+ } else if (defaultSize > maxSize) {
1045
+ warnings.push("default size should not be greater than max size");
1244
1046
  }
1245
1047
  }
1048
+ if (collapsedSize > minSize) {
1049
+ warnings.push("collapsed size should not be greater than min size");
1050
+ }
1246
1051
  if (warnings.length > 0) {
1247
1052
  const name = panelId != null ? `Panel "${panelId}"` : "Panel";
1248
1053
  console.warn(`${name} has an invalid configuration:\n\n${warnings.join("\n")}`);
@@ -1254,20 +1059,26 @@ function validatePanelConstraints({
1254
1059
 
1255
1060
  // All units must be in percentages; pixel values should be pre-converted
1256
1061
  function validatePanelGroupLayout({
1257
- groupSizePixels,
1258
1062
  layout: prevLayout,
1259
1063
  panelConstraints
1260
1064
  }) {
1261
1065
  const nextLayout = [...prevLayout];
1066
+ const nextLayoutTotalSize = nextLayout.reduce((accumulated, current) => accumulated + current, 0);
1262
1067
 
1263
1068
  // Validate layout expectations
1264
1069
  if (nextLayout.length !== panelConstraints.length) {
1265
1070
  throw Error(`Invalid ${panelConstraints.length} panel layout: ${nextLayout.map(size => `${size}%`).join(", ")}`);
1266
- } else if (!fuzzyNumbersEqual(nextLayout.reduce((accumulated, current) => accumulated + current, 0), 100)) {
1071
+ } else if (!fuzzyNumbersEqual(nextLayoutTotalSize, 100)) {
1267
1072
  // This is not ideal so we should warn about it, but it may be recoverable in some cases
1268
1073
  // (especially if the amount is small)
1269
1074
  {
1270
- console.warn(`WARNING: Invalid layout total size: ${nextLayout.map(size => `${size}%`).join(", ")}`);
1075
+ console.warn(`WARNING: Invalid layout total size: ${nextLayout.map(size => `${size}%`).join(", ")}. Layout normalization will be applied.`);
1076
+ }
1077
+ for (let index = 0; index < panelConstraints.length; index++) {
1078
+ const unsafeSize = nextLayout[index];
1079
+ assert(unsafeSize != null);
1080
+ const safeSize = 100 / nextLayoutTotalSize * unsafeSize;
1081
+ nextLayout[index] = safeSize;
1271
1082
  }
1272
1083
  }
1273
1084
  let remainingSize = 0;
@@ -1275,8 +1086,8 @@ function validatePanelGroupLayout({
1275
1086
  // First pass: Validate the proposed layout given each panel's constraints
1276
1087
  for (let index = 0; index < panelConstraints.length; index++) {
1277
1088
  const unsafeSize = nextLayout[index];
1089
+ assert(unsafeSize != null);
1278
1090
  const safeSize = resizePanel({
1279
- groupSizePixels,
1280
1091
  panelConstraints,
1281
1092
  panelIndex: index,
1282
1093
  size: unsafeSize
@@ -1292,9 +1103,9 @@ function validatePanelGroupLayout({
1292
1103
  if (!fuzzyNumbersEqual(remainingSize, 0)) {
1293
1104
  for (let index = 0; index < panelConstraints.length; index++) {
1294
1105
  const prevSize = nextLayout[index];
1106
+ assert(prevSize != null);
1295
1107
  const unsafeSize = prevSize + remainingSize;
1296
1108
  const safeSize = resizePanel({
1297
- groupSizePixels,
1298
1109
  panelConstraints,
1299
1110
  panelIndex: index,
1300
1111
  size: unsafeSize
@@ -1329,21 +1140,20 @@ function PanelGroupWithForwardedRef({
1329
1140
  autoSaveId = null,
1330
1141
  children,
1331
1142
  className: classNameFromProps = "",
1332
- dataAttributes,
1333
1143
  direction,
1334
1144
  forwardedRef,
1335
- id: idFromProps,
1145
+ id: idFromProps = null,
1336
1146
  onLayout = null,
1337
- keyboardResizeByPercentage = null,
1338
- keyboardResizeByPixels = null,
1147
+ keyboardResizeBy = null,
1339
1148
  storage = defaultStorage,
1340
1149
  style: styleFromProps,
1341
- tagName: Type = "div"
1150
+ tagName: Type = "div",
1151
+ ...rest
1342
1152
  }) {
1343
1153
  const groupId = useUniqueId(idFromProps);
1344
1154
  const [dragState, setDragState] = useState(null);
1345
1155
  const [layout, setLayout] = useState([]);
1346
- const panelIdToLastNotifiedMixedSizesMapRef = useRef({});
1156
+ const panelIdToLastNotifiedSizeMapRef = useRef({});
1347
1157
  const panelSizeBeforeCollapseRef = useRef(new Map());
1348
1158
  const prevDeltaRef = useRef(0);
1349
1159
  const committedValuesRef = useRef({
@@ -1351,8 +1161,7 @@ function PanelGroupWithForwardedRef({
1351
1161
  direction,
1352
1162
  dragState,
1353
1163
  id: groupId,
1354
- keyboardResizeByPercentage,
1355
- keyboardResizeByPixels,
1164
+ keyboardResizeBy,
1356
1165
  onLayout,
1357
1166
  storage
1358
1167
  });
@@ -1368,33 +1177,20 @@ function PanelGroupWithForwardedRef({
1368
1177
  useImperativeHandle(forwardedRef, () => ({
1369
1178
  getId: () => committedValuesRef.current.id,
1370
1179
  getLayout: () => {
1371
- const {
1372
- id: groupId
1373
- } = committedValuesRef.current;
1374
1180
  const {
1375
1181
  layout
1376
1182
  } = eagerValuesRef.current;
1377
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1378
- return layout.map(sizePercentage => {
1379
- return {
1380
- sizePercentage,
1381
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1382
- };
1383
- });
1183
+ return layout;
1384
1184
  },
1385
- setLayout: mixedSizes => {
1185
+ setLayout: unsafeLayout => {
1386
1186
  const {
1387
- id: groupId,
1388
1187
  onLayout
1389
1188
  } = committedValuesRef.current;
1390
1189
  const {
1391
1190
  layout: prevLayout,
1392
1191
  panelDataArray
1393
1192
  } = eagerValuesRef.current;
1394
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1395
- const unsafeLayout = mixedSizes.map(mixedSize => getPercentageSizeFromMixedSizes(mixedSize, groupSizePixels));
1396
1193
  const safeLayout = validatePanelGroupLayout({
1397
- groupSizePixels,
1398
1194
  layout: unsafeLayout,
1399
1195
  panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1400
1196
  });
@@ -1402,12 +1198,9 @@ function PanelGroupWithForwardedRef({
1402
1198
  setLayout(safeLayout);
1403
1199
  eagerValuesRef.current.layout = safeLayout;
1404
1200
  if (onLayout) {
1405
- onLayout(safeLayout.map(sizePercentage => ({
1406
- sizePercentage,
1407
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1408
- })));
1201
+ onLayout(safeLayout);
1409
1202
  }
1410
- callPanelCallbacks(groupId, panelDataArray, safeLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1203
+ callPanelCallbacks(panelDataArray, safeLayout, panelIdToLastNotifiedSizeMapRef.current);
1411
1204
  }
1412
1205
  }
1413
1206
  }), []);
@@ -1418,11 +1211,7 @@ function PanelGroupWithForwardedRef({
1418
1211
  committedValuesRef.current.id = groupId;
1419
1212
  committedValuesRef.current.onLayout = onLayout;
1420
1213
  committedValuesRef.current.storage = storage;
1421
-
1422
- // panelDataArray and layout are updated in-sync with scheduled state updates.
1423
- // TODO [217] Move these values into a separate ref
1424
1214
  });
1425
-
1426
1215
  useWindowSplitterPanelGroupBehavior({
1427
1216
  committedValuesRef,
1428
1217
  eagerValuesRef,
@@ -1441,57 +1230,16 @@ function PanelGroupWithForwardedRef({
1441
1230
  if (layout.length === 0 || layout.length !== panelDataArray.length) {
1442
1231
  return;
1443
1232
  }
1233
+ let debouncedSave = debounceMap[autoSaveId];
1444
1234
 
1445
1235
  // Limit the frequency of localStorage updates.
1446
- if (!debounceMap[autoSaveId]) {
1447
- debounceMap[autoSaveId] = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1236
+ if (debouncedSave == null) {
1237
+ debouncedSave = debounce(savePanelGroupLayout, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
1238
+ debounceMap[autoSaveId] = debouncedSave;
1448
1239
  }
1449
- debounceMap[autoSaveId](autoSaveId, panelDataArray, layout, storage);
1240
+ debouncedSave(autoSaveId, panelDataArray, layout, storage);
1450
1241
  }
1451
1242
  }, [autoSaveId, layout, storage]);
1452
- useIsomorphicLayoutEffect(() => {
1453
- const {
1454
- layout: prevLayout,
1455
- panelDataArray
1456
- } = eagerValuesRef.current;
1457
- const constraints = panelDataArray.map(({
1458
- constraints
1459
- }) => constraints);
1460
- if (!shouldMonitorPixelBasedConstraints(constraints)) {
1461
- // Avoid the overhead of ResizeObserver if no pixel constraints require monitoring
1462
- return;
1463
- }
1464
- if (typeof ResizeObserver === "undefined") {
1465
- console.warn(`WARNING: Pixel based constraints require ResizeObserver but it is not supported by the current browser.`);
1466
- } else {
1467
- const resizeObserver = new ResizeObserver(() => {
1468
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1469
- const {
1470
- onLayout
1471
- } = committedValuesRef.current;
1472
- const nextLayout = validatePanelGroupLayout({
1473
- groupSizePixels,
1474
- layout: prevLayout,
1475
- panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1476
- });
1477
- if (!areEqual(prevLayout, nextLayout)) {
1478
- setLayout(nextLayout);
1479
- eagerValuesRef.current.layout = nextLayout;
1480
- if (onLayout) {
1481
- onLayout(nextLayout.map(sizePercentage => ({
1482
- sizePercentage,
1483
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1484
- })));
1485
- }
1486
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1487
- }
1488
- });
1489
- resizeObserver.observe(getPanelGroupElement(groupId));
1490
- return () => {
1491
- resizeObserver.disconnect();
1492
- };
1493
- }
1494
- }, [groupId]);
1495
1243
 
1496
1244
  // DEV warnings
1497
1245
  useEffect(() => {
@@ -1522,12 +1270,12 @@ function PanelGroupWithForwardedRef({
1522
1270
  }
1523
1271
  if (!didLogPanelConstraintsWarning) {
1524
1272
  const panelConstraints = panelDataArray.map(panelData => panelData.constraints);
1525
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1526
1273
  for (let panelIndex = 0; panelIndex < panelConstraints.length; panelIndex++) {
1274
+ const panelData = panelDataArray[panelIndex];
1275
+ assert(panelData);
1527
1276
  const isValid = validatePanelConstraints({
1528
- groupSizePixels,
1529
1277
  panelConstraints,
1530
- panelId: panelDataArray[panelIndex].id,
1278
+ panelId: panelData.id,
1531
1279
  panelIndex
1532
1280
  });
1533
1281
  if (!isValid) {
@@ -1551,20 +1299,19 @@ function PanelGroupWithForwardedRef({
1551
1299
  if (panelData.constraints.collapsible) {
1552
1300
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1553
1301
  const {
1554
- collapsedSizePercentage,
1555
- panelSizePercentage,
1556
- pivotIndices,
1557
- groupSizePixels
1558
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
1559
- if (panelSizePercentage !== collapsedSizePercentage) {
1302
+ collapsedSize = 0,
1303
+ panelSize,
1304
+ pivotIndices
1305
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
1306
+ assert(panelSize != null);
1307
+ if (panelSize !== collapsedSize) {
1560
1308
  // Store size before collapse;
1561
1309
  // This is the size that gets restored if the expand() API is used.
1562
- panelSizeBeforeCollapseRef.current.set(panelData.id, panelSizePercentage);
1310
+ panelSizeBeforeCollapseRef.current.set(panelData.id, panelSize);
1563
1311
  const isLastPanel = panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
1564
- const delta = isLastPanel ? panelSizePercentage - collapsedSizePercentage : collapsedSizePercentage - panelSizePercentage;
1312
+ const delta = isLastPanel ? panelSize - collapsedSize : collapsedSize - panelSize;
1565
1313
  const nextLayout = adjustLayoutByDelta({
1566
1314
  delta,
1567
- groupSizePixels,
1568
1315
  layout: prevLayout,
1569
1316
  panelConstraints: panelConstraintsArray,
1570
1317
  pivotIndices,
@@ -1574,16 +1321,13 @@ function PanelGroupWithForwardedRef({
1574
1321
  setLayout(nextLayout);
1575
1322
  eagerValuesRef.current.layout = nextLayout;
1576
1323
  if (onLayout) {
1577
- onLayout(nextLayout.map(sizePercentage => ({
1578
- sizePercentage,
1579
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1580
- })));
1324
+ onLayout(nextLayout);
1581
1325
  }
1582
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1326
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1583
1327
  }
1584
1328
  }
1585
1329
  }
1586
- }, [groupId]);
1330
+ }, []);
1587
1331
 
1588
1332
  // External APIs are safe to memoize via committed values ref
1589
1333
  const expandPanel = useCallback(panelData => {
@@ -1597,21 +1341,19 @@ function PanelGroupWithForwardedRef({
1597
1341
  if (panelData.constraints.collapsible) {
1598
1342
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1599
1343
  const {
1600
- collapsedSizePercentage,
1601
- panelSizePercentage,
1602
- minSizePercentage,
1603
- pivotIndices,
1604
- groupSizePixels
1605
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
1606
- if (panelSizePercentage === collapsedSizePercentage) {
1344
+ collapsedSize = 0,
1345
+ panelSize,
1346
+ minSize = 0,
1347
+ pivotIndices
1348
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
1349
+ if (panelSize === collapsedSize) {
1607
1350
  // Restore this panel to the size it was before it was collapsed, if possible.
1608
- const prevPanelSizePercentage = panelSizeBeforeCollapseRef.current.get(panelData.id);
1609
- const baseSizePercentage = prevPanelSizePercentage != null && prevPanelSizePercentage >= minSizePercentage ? prevPanelSizePercentage : minSizePercentage;
1351
+ const prevPanelSize = panelSizeBeforeCollapseRef.current.get(panelData.id);
1352
+ const baseSize = prevPanelSize != null && prevPanelSize >= minSize ? prevPanelSize : minSize;
1610
1353
  const isLastPanel = panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
1611
- const delta = isLastPanel ? panelSizePercentage - baseSizePercentage : baseSizePercentage - panelSizePercentage;
1354
+ const delta = isLastPanel ? panelSize - baseSize : baseSize - panelSize;
1612
1355
  const nextLayout = adjustLayoutByDelta({
1613
1356
  delta,
1614
- groupSizePixels,
1615
1357
  layout: prevLayout,
1616
1358
  panelConstraints: panelConstraintsArray,
1617
1359
  pivotIndices,
@@ -1621,16 +1363,13 @@ function PanelGroupWithForwardedRef({
1621
1363
  setLayout(nextLayout);
1622
1364
  eagerValuesRef.current.layout = nextLayout;
1623
1365
  if (onLayout) {
1624
- onLayout(nextLayout.map(sizePercentage => ({
1625
- sizePercentage,
1626
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1627
- })));
1366
+ onLayout(nextLayout);
1628
1367
  }
1629
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1368
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1630
1369
  }
1631
1370
  }
1632
1371
  }
1633
- }, [groupId]);
1372
+ }, []);
1634
1373
 
1635
1374
  // External APIs are safe to memoize via committed values ref
1636
1375
  const getPanelSize = useCallback(panelData => {
@@ -1639,14 +1378,11 @@ function PanelGroupWithForwardedRef({
1639
1378
  panelDataArray
1640
1379
  } = eagerValuesRef.current;
1641
1380
  const {
1642
- panelSizePercentage,
1643
- panelSizePixels
1644
- } = panelDataHelper(groupId, panelDataArray, panelData, layout);
1645
- return {
1646
- sizePercentage: panelSizePercentage,
1647
- sizePixels: panelSizePixels
1648
- };
1649
- }, [groupId]);
1381
+ panelSize
1382
+ } = panelDataHelper(panelDataArray, panelData, layout);
1383
+ assert(panelSize != null);
1384
+ return panelSize;
1385
+ }, []);
1650
1386
 
1651
1387
  // This API should never read from committedValuesRef
1652
1388
  const getPanelStyle = useCallback(panelData => {
@@ -1669,12 +1405,12 @@ function PanelGroupWithForwardedRef({
1669
1405
  panelDataArray
1670
1406
  } = eagerValuesRef.current;
1671
1407
  const {
1672
- collapsedSizePercentage,
1408
+ collapsedSize,
1673
1409
  collapsible,
1674
- panelSizePercentage
1675
- } = panelDataHelper(groupId, panelDataArray, panelData, layout);
1676
- return collapsible === true && panelSizePercentage === collapsedSizePercentage;
1677
- }, [groupId]);
1410
+ panelSize
1411
+ } = panelDataHelper(panelDataArray, panelData, layout);
1412
+ return collapsible === true && panelSize === collapsedSize;
1413
+ }, []);
1678
1414
 
1679
1415
  // External APIs are safe to memoize via committed values ref
1680
1416
  const isPanelExpanded = useCallback(panelData => {
@@ -1683,12 +1419,13 @@ function PanelGroupWithForwardedRef({
1683
1419
  panelDataArray
1684
1420
  } = eagerValuesRef.current;
1685
1421
  const {
1686
- collapsedSizePercentage,
1422
+ collapsedSize = 0,
1687
1423
  collapsible,
1688
- panelSizePercentage
1689
- } = panelDataHelper(groupId, panelDataArray, panelData, layout);
1690
- return !collapsible || panelSizePercentage > collapsedSizePercentage;
1691
- }, [groupId]);
1424
+ panelSize
1425
+ } = panelDataHelper(panelDataArray, panelData, layout);
1426
+ assert(panelSize != null);
1427
+ return !collapsible || panelSize > collapsedSize;
1428
+ }, []);
1692
1429
  const registerPanel = useCallback(panelData => {
1693
1430
  const {
1694
1431
  autoSaveId,
@@ -1728,18 +1465,8 @@ function PanelGroupWithForwardedRef({
1728
1465
  if (autoSaveId) {
1729
1466
  unsafeLayout = loadPanelLayout(autoSaveId, panelDataArray, storage);
1730
1467
  }
1731
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1732
- if (groupSizePixels <= 0) {
1733
- if (shouldMonitorPixelBasedConstraints(panelDataArray.map(({
1734
- constraints
1735
- }) => constraints))) {
1736
- // Wait until the group has rendered a non-zero size before computing layout.
1737
- return;
1738
- }
1739
- }
1740
1468
  if (unsafeLayout == null) {
1741
1469
  unsafeLayout = calculateUnsafeDefaultLayout({
1742
- groupSizePixels,
1743
1470
  panelDataArray
1744
1471
  });
1745
1472
  }
@@ -1747,7 +1474,6 @@ function PanelGroupWithForwardedRef({
1747
1474
  // Validate even saved layouts in case something has changed since last render
1748
1475
  // e.g. for pixel groups, this could be the size of the window
1749
1476
  const nextLayout = validatePanelGroupLayout({
1750
- groupSizePixels,
1751
1477
  layout: unsafeLayout,
1752
1478
  panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1753
1479
  });
@@ -1759,12 +1485,9 @@ function PanelGroupWithForwardedRef({
1759
1485
  eagerValuesRef.current.layout = nextLayout;
1760
1486
  if (!areEqual(prevLayout, nextLayout)) {
1761
1487
  if (onLayout) {
1762
- onLayout(nextLayout.map(sizePercentage => ({
1763
- sizePercentage,
1764
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1765
- })));
1488
+ onLayout(nextLayout);
1766
1489
  }
1767
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1490
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1768
1491
  }
1769
1492
  }, []);
1770
1493
  const registerResizeHandle = useCallback(dragHandleId => {
@@ -1774,8 +1497,7 @@ function PanelGroupWithForwardedRef({
1774
1497
  direction,
1775
1498
  dragState,
1776
1499
  id: groupId,
1777
- keyboardResizeByPercentage,
1778
- keyboardResizeByPixels,
1500
+ keyboardResizeBy,
1779
1501
  onLayout
1780
1502
  } = committedValuesRef.current;
1781
1503
  const {
@@ -1786,10 +1508,7 @@ function PanelGroupWithForwardedRef({
1786
1508
  initialLayout
1787
1509
  } = dragState !== null && dragState !== void 0 ? dragState : {};
1788
1510
  const pivotIndices = determinePivotIndices(groupId, dragHandleId);
1789
- let delta = calculateDeltaPercentage(event, groupId, dragHandleId, direction, dragState, {
1790
- percentage: keyboardResizeByPercentage,
1791
- pixels: keyboardResizeByPixels
1792
- });
1511
+ let delta = calculateDeltaPercentage(event, dragHandleId, direction, dragState, keyboardResizeBy);
1793
1512
  if (delta === 0) {
1794
1513
  return;
1795
1514
  }
@@ -1799,11 +1518,9 @@ function PanelGroupWithForwardedRef({
1799
1518
  if (document.dir === "rtl" && isHorizontal) {
1800
1519
  delta = -delta;
1801
1520
  }
1802
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1803
1521
  const panelConstraints = panelDataArray.map(panelData => panelData.constraints);
1804
1522
  const nextLayout = adjustLayoutByDelta({
1805
1523
  delta,
1806
- groupSizePixels,
1807
1524
  layout: initialLayout !== null && initialLayout !== void 0 ? initialLayout : prevLayout,
1808
1525
  panelConstraints,
1809
1526
  pivotIndices,
@@ -1839,18 +1556,15 @@ function PanelGroupWithForwardedRef({
1839
1556
  setLayout(nextLayout);
1840
1557
  eagerValuesRef.current.layout = nextLayout;
1841
1558
  if (onLayout) {
1842
- onLayout(nextLayout.map(sizePercentage => ({
1843
- sizePercentage,
1844
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1845
- })));
1559
+ onLayout(nextLayout);
1846
1560
  }
1847
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1561
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1848
1562
  }
1849
1563
  };
1850
1564
  }, []);
1851
1565
 
1852
1566
  // External APIs are safe to memoize via committed values ref
1853
- const resizePanel = useCallback((panelData, mixedSizes) => {
1567
+ const resizePanel = useCallback((panelData, unsafePanelSize) => {
1854
1568
  const {
1855
1569
  onLayout
1856
1570
  } = committedValuesRef.current;
@@ -1860,16 +1574,14 @@ function PanelGroupWithForwardedRef({
1860
1574
  } = eagerValuesRef.current;
1861
1575
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
1862
1576
  const {
1863
- groupSizePixels,
1864
- panelSizePercentage,
1577
+ panelSize,
1865
1578
  pivotIndices
1866
- } = panelDataHelper(groupId, panelDataArray, panelData, prevLayout);
1867
- const sizePercentage = getPercentageSizeFromMixedSizes(mixedSizes, groupSizePixels);
1579
+ } = panelDataHelper(panelDataArray, panelData, prevLayout);
1580
+ assert(panelSize != null);
1868
1581
  const isLastPanel = panelDataArray.indexOf(panelData) === panelDataArray.length - 1;
1869
- const delta = isLastPanel ? panelSizePercentage - sizePercentage : sizePercentage - panelSizePercentage;
1582
+ const delta = isLastPanel ? panelSize - unsafePanelSize : unsafePanelSize - panelSize;
1870
1583
  const nextLayout = adjustLayoutByDelta({
1871
1584
  delta,
1872
- groupSizePixels,
1873
1585
  layout: prevLayout,
1874
1586
  panelConstraints: panelConstraintsArray,
1875
1587
  pivotIndices,
@@ -1879,14 +1591,11 @@ function PanelGroupWithForwardedRef({
1879
1591
  setLayout(nextLayout);
1880
1592
  eagerValuesRef.current.layout = nextLayout;
1881
1593
  if (onLayout) {
1882
- onLayout(nextLayout.map(sizePercentage => ({
1883
- sizePercentage,
1884
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1885
- })));
1594
+ onLayout(nextLayout);
1886
1595
  }
1887
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1596
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1888
1597
  }
1889
- }, [groupId]);
1598
+ }, []);
1890
1599
  const startDragging = useCallback((dragHandleId, event) => {
1891
1600
  const {
1892
1601
  direction
@@ -1895,6 +1604,7 @@ function PanelGroupWithForwardedRef({
1895
1604
  layout
1896
1605
  } = eagerValuesRef.current;
1897
1606
  const handleElement = getResizeHandleElement(dragHandleId);
1607
+ assert(handleElement);
1898
1608
  const initialCursorPosition = getResizeEventCursorPosition(direction, event);
1899
1609
  setDragState({
1900
1610
  dragHandleId,
@@ -1913,7 +1623,6 @@ function PanelGroupWithForwardedRef({
1913
1623
  });
1914
1624
  const unregisterPanel = useCallback(panelData => {
1915
1625
  const {
1916
- id: groupId,
1917
1626
  onLayout
1918
1627
  } = committedValuesRef.current;
1919
1628
  const {
@@ -1936,7 +1645,7 @@ function PanelGroupWithForwardedRef({
1936
1645
  const {
1937
1646
  pendingPanelIds
1938
1647
  } = unregisterPanelRef.current;
1939
- const map = panelIdToLastNotifiedMixedSizesMapRef.current;
1648
+ const map = panelIdToLastNotifiedSizeMapRef.current;
1940
1649
 
1941
1650
  // TRICKY
1942
1651
  // Strict effects mode
@@ -1962,16 +1671,13 @@ function PanelGroupWithForwardedRef({
1962
1671
  // The group is unmounting; skip layout calculation.
1963
1672
  return;
1964
1673
  }
1965
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
1966
1674
  let unsafeLayout = calculateUnsafeDefaultLayout({
1967
- groupSizePixels,
1968
1675
  panelDataArray
1969
1676
  });
1970
1677
 
1971
1678
  // Validate even saved layouts in case something has changed since last render
1972
1679
  // e.g. for pixel groups, this could be the size of the window
1973
1680
  const nextLayout = validatePanelGroupLayout({
1974
- groupSizePixels,
1975
1681
  layout: unsafeLayout,
1976
1682
  panelConstraints: panelDataArray.map(panelData => panelData.constraints)
1977
1683
  });
@@ -1979,12 +1685,9 @@ function PanelGroupWithForwardedRef({
1979
1685
  setLayout(nextLayout);
1980
1686
  eagerValuesRef.current.layout = nextLayout;
1981
1687
  if (onLayout) {
1982
- onLayout(nextLayout.map(sizePercentage => ({
1983
- sizePercentage,
1984
- sizePixels: convertPercentageToPixels(sizePercentage, groupSizePixels)
1985
- })));
1688
+ onLayout(nextLayout);
1986
1689
  }
1987
- callPanelCallbacks(groupId, panelDataArray, nextLayout, panelIdToLastNotifiedMixedSizesMapRef.current);
1690
+ callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
1988
1691
  }
1989
1692
  }, 0);
1990
1693
  }, []);
@@ -2015,13 +1718,13 @@ function PanelGroupWithForwardedRef({
2015
1718
  return createElement(PanelGroupContext.Provider, {
2016
1719
  value: context
2017
1720
  }, createElement(Type, {
1721
+ ...rest,
2018
1722
  children,
2019
1723
  className: classNameFromProps,
2020
1724
  style: {
2021
1725
  ...style,
2022
1726
  ...styleFromProps
2023
1727
  },
2024
- ...dataAttributes,
2025
1728
  // CSS selectors
2026
1729
  "data-panel-group": "",
2027
1730
  "data-panel-group-direction": direction,
@@ -2034,22 +1737,16 @@ const PanelGroup = forwardRef((props, ref) => createElement(PanelGroupWithForwar
2034
1737
  }));
2035
1738
  PanelGroupWithForwardedRef.displayName = "PanelGroup";
2036
1739
  PanelGroup.displayName = "forwardRef(PanelGroup)";
2037
- function panelDataHelper(groupId, panelDataArray, panelData, layout) {
1740
+ function panelDataHelper(panelDataArray, panelData, layout) {
2038
1741
  const panelConstraintsArray = panelDataArray.map(panelData => panelData.constraints);
2039
1742
  const panelIndex = panelDataArray.indexOf(panelData);
2040
1743
  const panelConstraints = panelConstraintsArray[panelIndex];
2041
- const groupSizePixels = calculateAvailablePanelSizeInPixels(groupId);
2042
- const percentagePanelConstraints = computePercentagePanelConstraints(panelConstraintsArray, panelIndex, groupSizePixels);
2043
1744
  const isLastPanel = panelIndex === panelDataArray.length - 1;
2044
1745
  const pivotIndices = isLastPanel ? [panelIndex - 1, panelIndex] : [panelIndex, panelIndex + 1];
2045
- const panelSizePercentage = layout[panelIndex];
2046
- const panelSizePixels = convertPercentageToPixels(panelSizePercentage, groupSizePixels);
1746
+ const panelSize = layout[panelIndex];
2047
1747
  return {
2048
- ...percentagePanelConstraints,
2049
- collapsible: panelConstraints.collapsible,
2050
- panelSizePercentage,
2051
- panelSizePixels,
2052
- groupSizePixels,
1748
+ ...panelConstraints,
1749
+ panelSize,
2053
1750
  pivotIndices
2054
1751
  };
2055
1752
  }
@@ -2089,6 +1786,7 @@ function useWindowSplitterResizeHandlerBehavior({
2089
1786
  {
2090
1787
  event.preventDefault();
2091
1788
  const groupId = handleElement.getAttribute("data-panel-group-id");
1789
+ assert(groupId);
2092
1790
  const handles = getResizeHandleElementsForGroup(groupId);
2093
1791
  const index = getResizeHandleElementIndex(groupId, handleId);
2094
1792
  assert(index !== null);
@@ -2109,12 +1807,13 @@ function useWindowSplitterResizeHandlerBehavior({
2109
1807
  function PanelResizeHandle({
2110
1808
  children = null,
2111
1809
  className: classNameFromProps = "",
2112
- dataAttributes,
2113
1810
  disabled = false,
2114
- id: idFromProps = null,
1811
+ id: idFromProps,
2115
1812
  onDragging,
2116
1813
  style: styleFromProps = {},
2117
- tagName: Type = "div"
1814
+ tabIndex = 0,
1815
+ tagName: Type = "div",
1816
+ ...rest
2118
1817
  }) {
2119
1818
  const divElementRef = useRef(null);
2120
1819
 
@@ -2144,8 +1843,9 @@ function PanelResizeHandle({
2144
1843
  const stopDraggingAndBlur = useCallback(() => {
2145
1844
  // Clicking on the drag handle shouldn't leave it focused;
2146
1845
  // That would cause the PanelGroup to think it was still active.
2147
- const div = divElementRef.current;
2148
- div.blur();
1846
+ const divElement = divElementRef.current;
1847
+ assert(divElement);
1848
+ divElement.blur();
2149
1849
  stopDragging();
2150
1850
  const {
2151
1851
  onDragging
@@ -2173,6 +1873,7 @@ function PanelResizeHandle({
2173
1873
  resizeHandler(event);
2174
1874
  };
2175
1875
  const divElement = divElementRef.current;
1876
+ assert(divElement);
2176
1877
  const targetDocument = divElement.ownerDocument;
2177
1878
  targetDocument.body.addEventListener("contextmenu", stopDraggingAndBlur);
2178
1879
  targetDocument.body.addEventListener("mousemove", onMove);
@@ -2200,15 +1901,18 @@ function PanelResizeHandle({
2200
1901
  userSelect: "none"
2201
1902
  };
2202
1903
  return createElement(Type, {
1904
+ ...rest,
2203
1905
  children,
2204
1906
  className: classNameFromProps,
2205
1907
  onBlur: () => setIsFocused(false),
2206
1908
  onFocus: () => setIsFocused(true),
2207
1909
  onMouseDown: event => {
2208
1910
  startDragging(resizeHandleId, event.nativeEvent);
1911
+ const callbacks = callbacksRef.current;
1912
+ assert(callbacks);
2209
1913
  const {
2210
1914
  onDragging
2211
- } = callbacksRef.current;
1915
+ } = callbacks;
2212
1916
  if (onDragging) {
2213
1917
  onDragging(true);
2214
1918
  }
@@ -2218,9 +1922,11 @@ function PanelResizeHandle({
2218
1922
  onTouchEnd: stopDraggingAndBlur,
2219
1923
  onTouchStart: event => {
2220
1924
  startDragging(resizeHandleId, event.nativeEvent);
1925
+ const callbacks = callbacksRef.current;
1926
+ assert(callbacks);
2221
1927
  const {
2222
1928
  onDragging
2223
- } = callbacksRef.current;
1929
+ } = callbacks;
2224
1930
  if (onDragging) {
2225
1931
  onDragging(true);
2226
1932
  }
@@ -2231,8 +1937,7 @@ function PanelResizeHandle({
2231
1937
  ...style,
2232
1938
  ...styleFromProps
2233
1939
  },
2234
- tabIndex: 0,
2235
- ...dataAttributes,
1940
+ tabIndex,
2236
1941
  // CSS selectors
2237
1942
  "data-panel-group-direction": direction,
2238
1943
  "data-panel-group-id": groupId,
@@ -2244,4 +1949,4 @@ function PanelResizeHandle({
2244
1949
  }
2245
1950
  PanelResizeHandle.displayName = "PanelResizeHandle";
2246
1951
 
2247
- export { Panel, PanelGroup, PanelResizeHandle };
1952
+ export { Panel, PanelGroup, PanelResizeHandle, assert };