react-resizable-panels 0.0.54 → 0.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/dist/declarations/src/Panel.d.ts +5 -4
- package/dist/declarations/src/PanelGroup.d.ts +7 -3
- package/dist/declarations/src/index.d.ts +3 -2
- package/dist/declarations/src/types.d.ts +2 -1
- package/dist/declarations/src/utils/group.d.ts +29 -0
- package/dist/react-resizable-panels.browser.cjs.js +385 -108
- package/dist/react-resizable-panels.browser.cjs.mjs +2 -1
- package/dist/react-resizable-panels.browser.development.cjs.js +417 -108
- package/dist/react-resizable-panels.browser.development.cjs.mjs +2 -1
- package/dist/react-resizable-panels.browser.development.esm.js +417 -109
- package/dist/react-resizable-panels.browser.esm.js +385 -109
- package/dist/react-resizable-panels.cjs.js +385 -108
- package/dist/react-resizable-panels.cjs.js.map +1 -0
- package/dist/react-resizable-panels.cjs.mjs +2 -1
- package/dist/react-resizable-panels.development.cjs.js +417 -108
- package/dist/react-resizable-panels.development.cjs.mjs +2 -1
- package/dist/react-resizable-panels.development.esm.js +417 -109
- package/dist/react-resizable-panels.development.node.cjs.js +282 -76
- package/dist/react-resizable-panels.development.node.cjs.mjs +2 -1
- package/dist/react-resizable-panels.development.node.esm.js +282 -77
- package/dist/react-resizable-panels.esm.js +385 -109
- package/dist/react-resizable-panels.esm.js.map +1 -0
- package/dist/react-resizable-panels.node.cjs.js +254 -76
- package/dist/react-resizable-panels.node.cjs.mjs +2 -1
- package/dist/react-resizable-panels.node.esm.js +254 -77
- package/package.json +1 -1
- package/src/Panel.ts +32 -32
- package/src/PanelContexts.ts +4 -2
- package/src/PanelGroup.ts +221 -111
- package/src/hooks/useWindowSplitterBehavior.ts +14 -11
- package/src/index.ts +11 -3
- package/src/types.ts +2 -1
- package/src/utils/group.ts +327 -28
|
@@ -43,8 +43,8 @@ function PanelWithForwardedRef({
|
|
|
43
43
|
defaultSize = null,
|
|
44
44
|
forwardedRef,
|
|
45
45
|
id: idFromProps = null,
|
|
46
|
-
maxSize =
|
|
47
|
-
minSize
|
|
46
|
+
maxSize = null,
|
|
47
|
+
minSize,
|
|
48
48
|
onCollapse = null,
|
|
49
49
|
onResize = null,
|
|
50
50
|
order = null,
|
|
@@ -59,11 +59,22 @@ function PanelWithForwardedRef({
|
|
|
59
59
|
const {
|
|
60
60
|
collapsePanel,
|
|
61
61
|
expandPanel,
|
|
62
|
+
getPanelSize,
|
|
62
63
|
getPanelStyle,
|
|
63
64
|
registerPanel,
|
|
64
65
|
resizePanel,
|
|
66
|
+
units,
|
|
65
67
|
unregisterPanel
|
|
66
68
|
} = context;
|
|
69
|
+
if (minSize == null) {
|
|
70
|
+
if (units === "percentages") {
|
|
71
|
+
// Mimics legacy default value for percentage based panel groups
|
|
72
|
+
minSize = 10;
|
|
73
|
+
} else {
|
|
74
|
+
// There is no meaningful minimum pixel default we can provide
|
|
75
|
+
minSize = 0;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
67
78
|
|
|
68
79
|
// Use a ref to guard against users passing inline props
|
|
69
80
|
const callbacksRef = useRef({
|
|
@@ -74,22 +85,6 @@ function PanelWithForwardedRef({
|
|
|
74
85
|
callbacksRef.current.onCollapse = onCollapse;
|
|
75
86
|
callbacksRef.current.onResize = onResize;
|
|
76
87
|
});
|
|
77
|
-
|
|
78
|
-
// Basic props validation
|
|
79
|
-
if (minSize < 0 || minSize > 100) {
|
|
80
|
-
throw Error(`Panel minSize must be between 0 and 100, but was ${minSize}`);
|
|
81
|
-
} else if (maxSize < 0 || maxSize > 100) {
|
|
82
|
-
throw Error(`Panel maxSize must be between 0 and 100, but was ${maxSize}`);
|
|
83
|
-
} else {
|
|
84
|
-
if (defaultSize !== null) {
|
|
85
|
-
if (defaultSize < 0 || defaultSize > 100) {
|
|
86
|
-
throw Error(`Panel defaultSize must be between 0 and 100, but was ${defaultSize}`);
|
|
87
|
-
} else if (minSize > defaultSize && !collapsible) {
|
|
88
|
-
console.error(`Panel minSize ${minSize} cannot be greater than defaultSize ${defaultSize}`);
|
|
89
|
-
defaultSize = minSize;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
88
|
const style = getPanelStyle(panelId, defaultSize);
|
|
94
89
|
const committedValuesRef = useRef({
|
|
95
90
|
size: parseSizeFromStyle(style)
|
|
@@ -111,11 +106,14 @@ function PanelWithForwardedRef({
|
|
|
111
106
|
getCollapsed() {
|
|
112
107
|
return committedValuesRef.current.size === 0;
|
|
113
108
|
},
|
|
114
|
-
|
|
115
|
-
return
|
|
109
|
+
getId() {
|
|
110
|
+
return panelId;
|
|
111
|
+
},
|
|
112
|
+
getSize(units) {
|
|
113
|
+
return getPanelSize(panelId, units);
|
|
116
114
|
},
|
|
117
|
-
resize: percentage => resizePanel(panelId, percentage)
|
|
118
|
-
}), [collapsePanel, expandPanel, panelId, resizePanel]);
|
|
115
|
+
resize: (percentage, units) => resizePanel(panelId, percentage, units)
|
|
116
|
+
}), [collapsePanel, expandPanel, getPanelSize, panelId, resizePanel]);
|
|
119
117
|
return createElement(Type, {
|
|
120
118
|
children,
|
|
121
119
|
className: classNameFromProps,
|
|
@@ -151,7 +149,13 @@ function parseSizeFromStyle(style) {
|
|
|
151
149
|
|
|
152
150
|
const PRECISION = 10;
|
|
153
151
|
|
|
154
|
-
function adjustByDelta(event,
|
|
152
|
+
function adjustByDelta(event, committedValues, idBefore, idAfter, deltaPixels, prevSizes, panelSizeBeforeCollapse, initialDragState) {
|
|
153
|
+
const {
|
|
154
|
+
id: groupId,
|
|
155
|
+
panels,
|
|
156
|
+
units
|
|
157
|
+
} = committedValues;
|
|
158
|
+
const groupSizePixels = units === "pixels" ? getAvailableGroupSizePixels(groupId) : NaN;
|
|
155
159
|
const {
|
|
156
160
|
sizes: initialSizes
|
|
157
161
|
} = initialDragState || {};
|
|
@@ -159,9 +163,6 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
159
163
|
// If we're resizing by mouse or touch, use the initial sizes as a base.
|
|
160
164
|
// This has the benefit of causing force-collapsed panels to spring back open if drag is reversed.
|
|
161
165
|
const baseSizes = initialSizes || prevSizes;
|
|
162
|
-
if (delta === 0) {
|
|
163
|
-
return baseSizes;
|
|
164
|
-
}
|
|
165
166
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
166
167
|
const nextSizes = baseSizes.concat();
|
|
167
168
|
let deltaApplied = 0;
|
|
@@ -176,11 +177,11 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
176
177
|
|
|
177
178
|
// Max-bounds check the panel being expanded first.
|
|
178
179
|
{
|
|
179
|
-
const pivotId =
|
|
180
|
+
const pivotId = deltaPixels < 0 ? idAfter : idBefore;
|
|
180
181
|
const index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
181
182
|
const panel = panelsArray[index];
|
|
182
183
|
const baseSize = baseSizes[index];
|
|
183
|
-
const nextSize = safeResizePanel(panel, Math.abs(
|
|
184
|
+
const nextSize = safeResizePanel(units, groupSizePixels, panel, baseSize, baseSize + Math.abs(deltaPixels), event);
|
|
184
185
|
if (baseSize === nextSize) {
|
|
185
186
|
// If there's no room for the pivot panel to grow, we can ignore this drag update.
|
|
186
187
|
return baseSizes;
|
|
@@ -188,29 +189,29 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
188
189
|
if (nextSize === 0 && baseSize > 0) {
|
|
189
190
|
panelSizeBeforeCollapse.set(pivotId, baseSize);
|
|
190
191
|
}
|
|
191
|
-
|
|
192
|
+
deltaPixels = deltaPixels < 0 ? baseSize - nextSize : nextSize - baseSize;
|
|
192
193
|
}
|
|
193
194
|
}
|
|
194
|
-
let pivotId =
|
|
195
|
+
let pivotId = deltaPixels < 0 ? idBefore : idAfter;
|
|
195
196
|
let index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
196
197
|
while (true) {
|
|
197
198
|
const panel = panelsArray[index];
|
|
198
199
|
const baseSize = baseSizes[index];
|
|
199
|
-
const deltaRemaining = Math.abs(
|
|
200
|
-
const nextSize = safeResizePanel(panel,
|
|
200
|
+
const deltaRemaining = Math.abs(deltaPixels) - Math.abs(deltaApplied);
|
|
201
|
+
const nextSize = safeResizePanel(units, groupSizePixels, panel, baseSize, baseSize - deltaRemaining, event);
|
|
201
202
|
if (baseSize !== nextSize) {
|
|
202
203
|
if (nextSize === 0 && baseSize > 0) {
|
|
203
204
|
panelSizeBeforeCollapse.set(panel.current.id, baseSize);
|
|
204
205
|
}
|
|
205
206
|
deltaApplied += baseSize - nextSize;
|
|
206
207
|
nextSizes[index] = nextSize;
|
|
207
|
-
if (deltaApplied.toPrecision(PRECISION).localeCompare(Math.abs(
|
|
208
|
+
if (deltaApplied.toPrecision(PRECISION).localeCompare(Math.abs(deltaPixels).toPrecision(PRECISION), undefined, {
|
|
208
209
|
numeric: true
|
|
209
210
|
}) >= 0) {
|
|
210
211
|
break;
|
|
211
212
|
}
|
|
212
213
|
}
|
|
213
|
-
if (
|
|
214
|
+
if (deltaPixels < 0) {
|
|
214
215
|
if (--index < 0) {
|
|
215
216
|
break;
|
|
216
217
|
}
|
|
@@ -228,7 +229,7 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
228
229
|
}
|
|
229
230
|
|
|
230
231
|
// Adjust the pivot panel before, but only by the amount that surrounding panels were able to shrink/contract.
|
|
231
|
-
pivotId =
|
|
232
|
+
pivotId = deltaPixels < 0 ? idAfter : idBefore;
|
|
232
233
|
index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
233
234
|
nextSizes[index] = baseSizes[index] + deltaApplied;
|
|
234
235
|
return nextSizes;
|
|
@@ -280,6 +281,23 @@ function getBeforeAndAfterIds(id, panelsArray) {
|
|
|
280
281
|
const idAfter = isLastPanel ? id : panelsArray[index + 1].current.id;
|
|
281
282
|
return [idBefore, idAfter];
|
|
282
283
|
}
|
|
284
|
+
function getAvailableGroupSizePixels(groupId) {
|
|
285
|
+
const panelGroupElement = getPanelGroup(groupId);
|
|
286
|
+
if (panelGroupElement == null) {
|
|
287
|
+
return NaN;
|
|
288
|
+
}
|
|
289
|
+
const direction = panelGroupElement.getAttribute("data-panel-group-direction");
|
|
290
|
+
const resizeHandles = getResizeHandlesForGroup(groupId);
|
|
291
|
+
if (direction === "horizontal") {
|
|
292
|
+
return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
|
|
293
|
+
return accumulated + handle.offsetWidth;
|
|
294
|
+
}, 0);
|
|
295
|
+
} else {
|
|
296
|
+
return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
|
|
297
|
+
return accumulated + handle.offsetHeight;
|
|
298
|
+
}, 0);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
283
301
|
|
|
284
302
|
// This method returns a number between 1 and 100 representing
|
|
285
303
|
// the % of the group's overall space this panel should occupy.
|
|
@@ -350,18 +368,24 @@ function panelsMapToSortedArray(panels) {
|
|
|
350
368
|
}
|
|
351
369
|
});
|
|
352
370
|
}
|
|
353
|
-
function safeResizePanel(
|
|
354
|
-
|
|
355
|
-
const {
|
|
371
|
+
function safeResizePanel(units, groupSizePixels, panel, prevSize, nextSize, event = null) {
|
|
372
|
+
let {
|
|
356
373
|
collapsedSize,
|
|
357
374
|
collapsible,
|
|
358
375
|
maxSize,
|
|
359
376
|
minSize
|
|
360
377
|
} = panel.current;
|
|
378
|
+
if (units === "pixels") {
|
|
379
|
+
collapsedSize = collapsedSize / groupSizePixels * 100;
|
|
380
|
+
if (maxSize != null) {
|
|
381
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
382
|
+
}
|
|
383
|
+
minSize = minSize / groupSizePixels * 100;
|
|
384
|
+
}
|
|
361
385
|
if (collapsible) {
|
|
362
386
|
if (prevSize > collapsedSize) {
|
|
363
387
|
// Mimic VS COde behavior; collapse a panel if it's smaller than half of its min-size
|
|
364
|
-
if (
|
|
388
|
+
if (nextSize <= minSize / 2 + collapsedSize) {
|
|
365
389
|
return collapsedSize;
|
|
366
390
|
}
|
|
367
391
|
} else {
|
|
@@ -370,14 +394,97 @@ function safeResizePanel(panel, delta, prevSize, event) {
|
|
|
370
394
|
// Keyboard events should expand a collapsed panel to the min size,
|
|
371
395
|
// but mouse events should wait until the panel has reached its min size
|
|
372
396
|
// to avoid a visual flickering when dragging between collapsed and min size.
|
|
373
|
-
if (
|
|
397
|
+
if (nextSize < minSize) {
|
|
374
398
|
return collapsedSize;
|
|
375
399
|
}
|
|
376
400
|
}
|
|
377
401
|
}
|
|
378
402
|
}
|
|
379
|
-
|
|
380
|
-
|
|
403
|
+
return Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSize));
|
|
404
|
+
}
|
|
405
|
+
function validatePanelProps(units, panelData) {
|
|
406
|
+
const {
|
|
407
|
+
collapsible,
|
|
408
|
+
defaultSize,
|
|
409
|
+
maxSize,
|
|
410
|
+
minSize
|
|
411
|
+
} = panelData.current;
|
|
412
|
+
|
|
413
|
+
// Basic props validation
|
|
414
|
+
if (minSize < 0 || units === "percentages" && minSize > 100) {
|
|
415
|
+
panelData.current.minSize = 0;
|
|
416
|
+
}
|
|
417
|
+
if (maxSize != null) {
|
|
418
|
+
if (maxSize < 0 || units === "percentages" && maxSize > 100) {
|
|
419
|
+
panelData.current.maxSize = null;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
if (defaultSize !== null) {
|
|
423
|
+
if (defaultSize < 0 || units === "percentages" && defaultSize > 100) {
|
|
424
|
+
panelData.current.defaultSize = null;
|
|
425
|
+
} else if (defaultSize < minSize && !collapsible) {
|
|
426
|
+
panelData.current.defaultSize = minSize;
|
|
427
|
+
} else if (maxSize != null && defaultSize > maxSize) {
|
|
428
|
+
panelData.current.defaultSize = maxSize;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
function validatePanelGroupLayout({
|
|
433
|
+
groupId,
|
|
434
|
+
panels,
|
|
435
|
+
nextSizes,
|
|
436
|
+
prevSizes,
|
|
437
|
+
units
|
|
438
|
+
}) {
|
|
439
|
+
// Clone because this method modifies
|
|
440
|
+
nextSizes = [...nextSizes];
|
|
441
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
442
|
+
const groupSizePixels = units === "pixels" ? getAvailableGroupSizePixels(groupId) : NaN;
|
|
443
|
+
let remainingSize = 0;
|
|
444
|
+
|
|
445
|
+
// First, check all of the proposed sizes against the min/max constraints
|
|
446
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
447
|
+
const panel = panelsArray[index];
|
|
448
|
+
const prevSize = prevSizes[index];
|
|
449
|
+
const nextSize = nextSizes[index];
|
|
450
|
+
const safeNextSize = safeResizePanel(units, groupSizePixels, panel, prevSize, nextSize);
|
|
451
|
+
if (nextSize != safeNextSize) {
|
|
452
|
+
remainingSize += nextSize - safeNextSize;
|
|
453
|
+
nextSizes[index] = safeNextSize;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// If there is additional, left over space, assign it to any panel(s) that permits it
|
|
458
|
+
// (It's not worth taking multiple additional passes to evenly distribute)
|
|
459
|
+
if (remainingSize.toFixed(3) !== "0.000") {
|
|
460
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
461
|
+
const panel = panelsArray[index];
|
|
462
|
+
let {
|
|
463
|
+
maxSize,
|
|
464
|
+
minSize
|
|
465
|
+
} = panel.current;
|
|
466
|
+
if (units === "pixels") {
|
|
467
|
+
minSize = minSize / groupSizePixels * 100;
|
|
468
|
+
if (maxSize != null) {
|
|
469
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
const size = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSizes[index] + remainingSize));
|
|
473
|
+
if (size !== nextSizes[index]) {
|
|
474
|
+
remainingSize -= size - nextSizes[index];
|
|
475
|
+
nextSizes[index] = size;
|
|
476
|
+
|
|
477
|
+
// Fuzzy comparison to account for imprecise floating point math
|
|
478
|
+
if (Math.abs(remainingSize).toFixed(3) === "0.000") {
|
|
479
|
+
break;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// If we still have remainder, the requested layout wasn't valid and we should warn about it
|
|
486
|
+
if (remainingSize.toFixed(3) !== "0.000") ;
|
|
487
|
+
return nextSizes;
|
|
381
488
|
}
|
|
382
489
|
|
|
383
490
|
function assert(expectedCondition, message = "Assertion failed!") {
|
|
@@ -403,6 +510,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
403
510
|
panels
|
|
404
511
|
} = committedValuesRef.current;
|
|
405
512
|
const groupElement = getPanelGroup(groupId);
|
|
513
|
+
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
406
514
|
const {
|
|
407
515
|
height,
|
|
408
516
|
width
|
|
@@ -415,23 +523,28 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
415
523
|
if (idBefore == null || idAfter == null) {
|
|
416
524
|
return () => {};
|
|
417
525
|
}
|
|
418
|
-
let
|
|
419
|
-
let
|
|
526
|
+
let currentMinSize = 0;
|
|
527
|
+
let currentMaxSize = 100;
|
|
420
528
|
let totalMinSize = 0;
|
|
421
529
|
let totalMaxSize = 0;
|
|
422
530
|
|
|
423
531
|
// A panel's effective min/max sizes also need to account for other panel's sizes.
|
|
424
532
|
panelsArray.forEach(panelData => {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
533
|
+
const {
|
|
534
|
+
id,
|
|
535
|
+
maxSize,
|
|
536
|
+
minSize
|
|
537
|
+
} = panelData.current;
|
|
538
|
+
if (id === idBefore) {
|
|
539
|
+
currentMinSize = minSize;
|
|
540
|
+
currentMaxSize = maxSize != null ? maxSize : 100;
|
|
428
541
|
} else {
|
|
429
|
-
totalMinSize +=
|
|
430
|
-
totalMaxSize +=
|
|
542
|
+
totalMinSize += minSize;
|
|
543
|
+
totalMaxSize += maxSize != null ? maxSize : 100;
|
|
431
544
|
}
|
|
432
545
|
});
|
|
433
|
-
const ariaValueMax = Math.min(
|
|
434
|
-
const ariaValueMin = Math.max(
|
|
546
|
+
const ariaValueMax = Math.min(currentMaxSize, 100 - totalMinSize);
|
|
547
|
+
const ariaValueMin = Math.max(currentMinSize, (panelsArray.length - 1) * 100 - totalMaxSize);
|
|
435
548
|
const flexGrow = getFlexGrow(panels, idBefore, sizes);
|
|
436
549
|
handle.setAttribute("aria-valuemax", "" + Math.round(ariaValueMax));
|
|
437
550
|
handle.setAttribute("aria-valuemin", "" + Math.round(ariaValueMin));
|
|
@@ -455,7 +568,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
455
568
|
} else {
|
|
456
569
|
delta = -(direction === "horizontal" ? width : height);
|
|
457
570
|
}
|
|
458
|
-
const nextSizes = adjustByDelta(event,
|
|
571
|
+
const nextSizes = adjustByDelta(event, committedValuesRef.current, idBefore, idAfter, delta, sizes, panelSizeBeforeCollapse.current, null);
|
|
459
572
|
if (sizes !== nextSizes) {
|
|
460
573
|
setSizes(nextSizes);
|
|
461
574
|
}
|
|
@@ -762,9 +875,6 @@ const defaultStorage = {
|
|
|
762
875
|
// * dragHandleRect, sizes:
|
|
763
876
|
// When resizing is done via mouse/touch event– some initial state is stored
|
|
764
877
|
// so that any panels that contract will also expand if drag direction is reversed.
|
|
765
|
-
// TODO
|
|
766
|
-
// Within an active drag, remember original positions to refine more easily on expand.
|
|
767
|
-
// Look at what the Chrome devtools Sources does.
|
|
768
878
|
function PanelGroupWithForwardedRef({
|
|
769
879
|
autoSaveId,
|
|
770
880
|
children = null,
|
|
@@ -776,7 +886,8 @@ function PanelGroupWithForwardedRef({
|
|
|
776
886
|
onLayout,
|
|
777
887
|
storage = defaultStorage,
|
|
778
888
|
style: styleFromProps = {},
|
|
779
|
-
tagName: Type = "div"
|
|
889
|
+
tagName: Type = "div",
|
|
890
|
+
units = "percentages"
|
|
780
891
|
}) {
|
|
781
892
|
const groupId = useUniqueId(idFromProps);
|
|
782
893
|
const [activeHandleId, setActiveHandleId] = useState(null);
|
|
@@ -789,6 +900,7 @@ function PanelGroupWithForwardedRef({
|
|
|
789
900
|
useRef({
|
|
790
901
|
didLogDefaultSizeWarning: false,
|
|
791
902
|
didLogIdAndOrderWarning: false,
|
|
903
|
+
didLogInvalidLayoutWarning: false,
|
|
792
904
|
prevPanelIds: []
|
|
793
905
|
});
|
|
794
906
|
|
|
@@ -811,28 +923,52 @@ function PanelGroupWithForwardedRef({
|
|
|
811
923
|
// Store committed values to avoid unnecessarily re-running memoization/effects functions.
|
|
812
924
|
const committedValuesRef = useRef({
|
|
813
925
|
direction,
|
|
926
|
+
id: groupId,
|
|
814
927
|
panels,
|
|
815
|
-
sizes
|
|
928
|
+
sizes,
|
|
929
|
+
units
|
|
816
930
|
});
|
|
817
931
|
useImperativeHandle(forwardedRef, () => ({
|
|
818
|
-
|
|
932
|
+
getId: () => groupId,
|
|
933
|
+
getLayout: unitsFromParams => {
|
|
819
934
|
const {
|
|
820
|
-
sizes
|
|
935
|
+
sizes,
|
|
936
|
+
units: unitsFromProps
|
|
821
937
|
} = committedValuesRef.current;
|
|
822
|
-
|
|
938
|
+
const units = unitsFromParams ?? unitsFromProps;
|
|
939
|
+
if (units === "pixels") {
|
|
940
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
941
|
+
return sizes.map(size => size / 100 * groupSizePixels);
|
|
942
|
+
} else {
|
|
943
|
+
return sizes;
|
|
944
|
+
}
|
|
823
945
|
},
|
|
824
|
-
setLayout: sizes => {
|
|
825
|
-
const total = sizes.reduce((accumulated, current) => accumulated + current, 0);
|
|
826
|
-
assert(total === 100, "Panel sizes must add up to 100%");
|
|
946
|
+
setLayout: (sizes, unitsFromParams) => {
|
|
827
947
|
const {
|
|
828
|
-
|
|
948
|
+
id: groupId,
|
|
949
|
+
panels,
|
|
950
|
+
sizes: prevSizes,
|
|
951
|
+
units
|
|
829
952
|
} = committedValuesRef.current;
|
|
953
|
+
if ((unitsFromParams || units) === "pixels") {
|
|
954
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
955
|
+
sizes = sizes.map(size => size / groupSizePixels * 100);
|
|
956
|
+
}
|
|
830
957
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
831
958
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
832
|
-
|
|
833
|
-
|
|
959
|
+
const nextSizes = validatePanelGroupLayout({
|
|
960
|
+
groupId,
|
|
961
|
+
panels,
|
|
962
|
+
nextSizes: sizes,
|
|
963
|
+
prevSizes,
|
|
964
|
+
units
|
|
965
|
+
});
|
|
966
|
+
if (!areEqual(prevSizes, nextSizes)) {
|
|
967
|
+
setSizes(nextSizes);
|
|
968
|
+
callPanelCallbacks(panelsArray, nextSizes, panelIdToLastNotifiedSizeMap);
|
|
969
|
+
}
|
|
834
970
|
}
|
|
835
|
-
}), []);
|
|
971
|
+
}), [groupId]);
|
|
836
972
|
useWindowSplitterPanelGroupBehavior({
|
|
837
973
|
committedValuesRef,
|
|
838
974
|
groupId,
|
|
@@ -883,6 +1019,22 @@ function PanelGroupWithForwardedRef({
|
|
|
883
1019
|
debounceMap[autoSaveId](autoSaveId, panelsArray, sizes, storage);
|
|
884
1020
|
}
|
|
885
1021
|
}, [autoSaveId, panels, sizes, storage]);
|
|
1022
|
+
const getPanelSize = useCallback((id, unitsFromParams) => {
|
|
1023
|
+
const {
|
|
1024
|
+
panels,
|
|
1025
|
+
units: unitsFromProps
|
|
1026
|
+
} = committedValuesRef.current;
|
|
1027
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
1028
|
+
const index = panelsArray.findIndex(panel => panel.current.id === id);
|
|
1029
|
+
const size = sizes[index];
|
|
1030
|
+
const units = unitsFromParams ?? unitsFromProps;
|
|
1031
|
+
if (units === "pixels") {
|
|
1032
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1033
|
+
return size / 100 * groupSizePixels;
|
|
1034
|
+
} else {
|
|
1035
|
+
return size;
|
|
1036
|
+
}
|
|
1037
|
+
}, [groupId, sizes]);
|
|
886
1038
|
const getPanelStyle = useCallback((id, defaultSize) => {
|
|
887
1039
|
const {
|
|
888
1040
|
panels
|
|
@@ -913,6 +1065,10 @@ function PanelGroupWithForwardedRef({
|
|
|
913
1065
|
};
|
|
914
1066
|
}, [activeHandleId, disablePointerEventsDuringResize, sizes]);
|
|
915
1067
|
const registerPanel = useCallback((id, panelRef) => {
|
|
1068
|
+
const {
|
|
1069
|
+
units
|
|
1070
|
+
} = committedValuesRef.current;
|
|
1071
|
+
validatePanelProps(units, panelRef);
|
|
916
1072
|
setPanels(prevPanels => {
|
|
917
1073
|
if (prevPanels.has(id)) {
|
|
918
1074
|
return prevPanels;
|
|
@@ -949,7 +1105,10 @@ function PanelGroupWithForwardedRef({
|
|
|
949
1105
|
}
|
|
950
1106
|
const size = isHorizontal ? rect.width : rect.height;
|
|
951
1107
|
const delta = movement / size * 100;
|
|
952
|
-
|
|
1108
|
+
|
|
1109
|
+
// If a validateLayout method has been provided
|
|
1110
|
+
// it's important to use it before updating the mouse cursor
|
|
1111
|
+
const nextSizes = adjustByDelta(event, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, initialDragStateRef.current);
|
|
953
1112
|
const sizesChanged = !areEqual(prevSizes, nextSizes);
|
|
954
1113
|
|
|
955
1114
|
// Don't update cursor for resizes triggered by keyboard interactions.
|
|
@@ -976,6 +1135,8 @@ function PanelGroupWithForwardedRef({
|
|
|
976
1135
|
}
|
|
977
1136
|
if (sizesChanged) {
|
|
978
1137
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1138
|
+
|
|
1139
|
+
// It's okay to bypass in this case because we already validated above
|
|
979
1140
|
setSizes(nextSizes);
|
|
980
1141
|
|
|
981
1142
|
// If resize change handlers have been declared, this is the time to call them.
|
|
@@ -1029,7 +1190,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1029
1190
|
}
|
|
1030
1191
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1031
1192
|
const delta = isLastPanel ? currentSize : collapsedSize - currentSize;
|
|
1032
|
-
const nextSizes = adjustByDelta(null,
|
|
1193
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1033
1194
|
if (prevSizes !== nextSizes) {
|
|
1034
1195
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1035
1196
|
setSizes(nextSizes);
|
|
@@ -1072,7 +1233,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1072
1233
|
}
|
|
1073
1234
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1074
1235
|
const delta = isLastPanel ? collapsedSize - sizeBeforeCollapse : sizeBeforeCollapse;
|
|
1075
|
-
const nextSizes = adjustByDelta(null,
|
|
1236
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1076
1237
|
if (prevSizes !== nextSizes) {
|
|
1077
1238
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1078
1239
|
setSizes(nextSizes);
|
|
@@ -1082,21 +1243,34 @@ function PanelGroupWithForwardedRef({
|
|
|
1082
1243
|
callPanelCallbacks(panelsArray, nextSizes, panelIdToLastNotifiedSizeMap);
|
|
1083
1244
|
}
|
|
1084
1245
|
}, []);
|
|
1085
|
-
const resizePanel = useCallback((id, nextSize) => {
|
|
1246
|
+
const resizePanel = useCallback((id, nextSize, unitsFromParams) => {
|
|
1086
1247
|
const {
|
|
1248
|
+
id: groupId,
|
|
1087
1249
|
panels,
|
|
1088
|
-
sizes: prevSizes
|
|
1250
|
+
sizes: prevSizes,
|
|
1251
|
+
units
|
|
1089
1252
|
} = committedValuesRef.current;
|
|
1253
|
+
if ((unitsFromParams || units) === "pixels") {
|
|
1254
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1255
|
+
nextSize = nextSize / groupSizePixels * 100;
|
|
1256
|
+
}
|
|
1090
1257
|
const panel = panels.get(id);
|
|
1091
1258
|
if (panel == null) {
|
|
1092
1259
|
return;
|
|
1093
1260
|
}
|
|
1094
|
-
|
|
1261
|
+
let {
|
|
1095
1262
|
collapsedSize,
|
|
1096
1263
|
collapsible,
|
|
1097
1264
|
maxSize,
|
|
1098
1265
|
minSize
|
|
1099
1266
|
} = panel.current;
|
|
1267
|
+
if (units === "pixels") {
|
|
1268
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1269
|
+
minSize = minSize / groupSizePixels * 100;
|
|
1270
|
+
if (maxSize != null) {
|
|
1271
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1100
1274
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
1101
1275
|
const index = panelsArray.indexOf(panel);
|
|
1102
1276
|
if (index < 0) {
|
|
@@ -1107,7 +1281,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1107
1281
|
return;
|
|
1108
1282
|
}
|
|
1109
1283
|
if (collapsible && nextSize === collapsedSize) ; else {
|
|
1110
|
-
nextSize = Math.min(maxSize, Math.max(minSize, nextSize));
|
|
1284
|
+
nextSize = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSize));
|
|
1111
1285
|
}
|
|
1112
1286
|
const [idBefore, idAfter] = getBeforeAndAfterIds(id, panelsArray);
|
|
1113
1287
|
if (idBefore == null || idAfter == null) {
|
|
@@ -1115,7 +1289,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1115
1289
|
}
|
|
1116
1290
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1117
1291
|
const delta = isLastPanel ? currentSize - nextSize : nextSize - currentSize;
|
|
1118
|
-
const nextSizes = adjustByDelta(null,
|
|
1292
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1119
1293
|
if (prevSizes !== nextSizes) {
|
|
1120
1294
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1121
1295
|
setSizes(nextSizes);
|
|
@@ -1130,6 +1304,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1130
1304
|
collapsePanel,
|
|
1131
1305
|
direction,
|
|
1132
1306
|
expandPanel,
|
|
1307
|
+
getPanelSize,
|
|
1133
1308
|
getPanelStyle,
|
|
1134
1309
|
groupId,
|
|
1135
1310
|
registerPanel,
|
|
@@ -1151,8 +1326,9 @@ function PanelGroupWithForwardedRef({
|
|
|
1151
1326
|
setActiveHandleId(null);
|
|
1152
1327
|
initialDragStateRef.current = null;
|
|
1153
1328
|
},
|
|
1329
|
+
units,
|
|
1154
1330
|
unregisterPanel
|
|
1155
|
-
}), [activeHandleId, collapsePanel, direction, expandPanel, getPanelStyle, groupId, registerPanel, registerResizeHandle, resizePanel, unregisterPanel]);
|
|
1331
|
+
}), [activeHandleId, collapsePanel, direction, expandPanel, getPanelSize, getPanelStyle, groupId, registerPanel, registerResizeHandle, resizePanel, units, unregisterPanel]);
|
|
1156
1332
|
const style = {
|
|
1157
1333
|
display: "flex",
|
|
1158
1334
|
flexDirection: direction === "horizontal" ? "row" : "column",
|
|
@@ -1167,6 +1343,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1167
1343
|
"data-panel-group": "",
|
|
1168
1344
|
"data-panel-group-direction": direction,
|
|
1169
1345
|
"data-panel-group-id": groupId,
|
|
1346
|
+
"data-panel-group-units": units,
|
|
1170
1347
|
style: {
|
|
1171
1348
|
...style,
|
|
1172
1349
|
...styleFromProps
|
|
@@ -1316,4 +1493,4 @@ function PanelResizeHandle({
|
|
|
1316
1493
|
}
|
|
1317
1494
|
PanelResizeHandle.displayName = "PanelResizeHandle";
|
|
1318
1495
|
|
|
1319
|
-
export { Panel, PanelGroup, PanelResizeHandle };
|
|
1496
|
+
export { Panel, PanelGroup, PanelResizeHandle, getAvailableGroupSizePixels };
|