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
|
@@ -67,8 +67,8 @@ function PanelWithForwardedRef({
|
|
|
67
67
|
defaultSize = null,
|
|
68
68
|
forwardedRef,
|
|
69
69
|
id: idFromProps = null,
|
|
70
|
-
maxSize =
|
|
71
|
-
minSize
|
|
70
|
+
maxSize = null,
|
|
71
|
+
minSize,
|
|
72
72
|
onCollapse = null,
|
|
73
73
|
onResize = null,
|
|
74
74
|
order = null,
|
|
@@ -83,11 +83,22 @@ function PanelWithForwardedRef({
|
|
|
83
83
|
const {
|
|
84
84
|
collapsePanel,
|
|
85
85
|
expandPanel,
|
|
86
|
+
getPanelSize,
|
|
86
87
|
getPanelStyle,
|
|
87
88
|
registerPanel,
|
|
88
89
|
resizePanel,
|
|
90
|
+
units,
|
|
89
91
|
unregisterPanel
|
|
90
92
|
} = context;
|
|
93
|
+
if (minSize == null) {
|
|
94
|
+
if (units === "percentages") {
|
|
95
|
+
// Mimics legacy default value for percentage based panel groups
|
|
96
|
+
minSize = 10;
|
|
97
|
+
} else {
|
|
98
|
+
// There is no meaningful minimum pixel default we can provide
|
|
99
|
+
minSize = 0;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
91
102
|
|
|
92
103
|
// Use a ref to guard against users passing inline props
|
|
93
104
|
const callbacksRef = useRef({
|
|
@@ -98,22 +109,6 @@ function PanelWithForwardedRef({
|
|
|
98
109
|
callbacksRef.current.onCollapse = onCollapse;
|
|
99
110
|
callbacksRef.current.onResize = onResize;
|
|
100
111
|
});
|
|
101
|
-
|
|
102
|
-
// Basic props validation
|
|
103
|
-
if (minSize < 0 || minSize > 100) {
|
|
104
|
-
throw Error(`Panel minSize must be between 0 and 100, but was ${minSize}`);
|
|
105
|
-
} else if (maxSize < 0 || maxSize > 100) {
|
|
106
|
-
throw Error(`Panel maxSize must be between 0 and 100, but was ${maxSize}`);
|
|
107
|
-
} else {
|
|
108
|
-
if (defaultSize !== null) {
|
|
109
|
-
if (defaultSize < 0 || defaultSize > 100) {
|
|
110
|
-
throw Error(`Panel defaultSize must be between 0 and 100, but was ${defaultSize}`);
|
|
111
|
-
} else if (minSize > defaultSize && !collapsible) {
|
|
112
|
-
console.error(`Panel minSize ${minSize} cannot be greater than defaultSize ${defaultSize}`);
|
|
113
|
-
defaultSize = minSize;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
112
|
const style = getPanelStyle(panelId, defaultSize);
|
|
118
113
|
const committedValuesRef = useRef({
|
|
119
114
|
size: parseSizeFromStyle(style)
|
|
@@ -135,11 +130,14 @@ function PanelWithForwardedRef({
|
|
|
135
130
|
getCollapsed() {
|
|
136
131
|
return committedValuesRef.current.size === 0;
|
|
137
132
|
},
|
|
138
|
-
|
|
139
|
-
return
|
|
133
|
+
getId() {
|
|
134
|
+
return panelId;
|
|
135
|
+
},
|
|
136
|
+
getSize(units) {
|
|
137
|
+
return getPanelSize(panelId, units);
|
|
140
138
|
},
|
|
141
|
-
resize: percentage => resizePanel(panelId, percentage)
|
|
142
|
-
}), [collapsePanel, expandPanel, panelId, resizePanel]);
|
|
139
|
+
resize: (percentage, units) => resizePanel(panelId, percentage, units)
|
|
140
|
+
}), [collapsePanel, expandPanel, getPanelSize, panelId, resizePanel]);
|
|
143
141
|
return createElement(Type, {
|
|
144
142
|
children,
|
|
145
143
|
className: classNameFromProps,
|
|
@@ -175,7 +173,13 @@ function parseSizeFromStyle(style) {
|
|
|
175
173
|
|
|
176
174
|
const PRECISION = 10;
|
|
177
175
|
|
|
178
|
-
function adjustByDelta(event,
|
|
176
|
+
function adjustByDelta(event, committedValues, idBefore, idAfter, deltaPixels, prevSizes, panelSizeBeforeCollapse, initialDragState) {
|
|
177
|
+
const {
|
|
178
|
+
id: groupId,
|
|
179
|
+
panels,
|
|
180
|
+
units
|
|
181
|
+
} = committedValues;
|
|
182
|
+
const groupSizePixels = units === "pixels" ? getAvailableGroupSizePixels(groupId) : NaN;
|
|
179
183
|
const {
|
|
180
184
|
sizes: initialSizes
|
|
181
185
|
} = initialDragState || {};
|
|
@@ -183,9 +187,6 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
183
187
|
// If we're resizing by mouse or touch, use the initial sizes as a base.
|
|
184
188
|
// This has the benefit of causing force-collapsed panels to spring back open if drag is reversed.
|
|
185
189
|
const baseSizes = initialSizes || prevSizes;
|
|
186
|
-
if (delta === 0) {
|
|
187
|
-
return baseSizes;
|
|
188
|
-
}
|
|
189
190
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
190
191
|
const nextSizes = baseSizes.concat();
|
|
191
192
|
let deltaApplied = 0;
|
|
@@ -200,11 +201,11 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
200
201
|
|
|
201
202
|
// Max-bounds check the panel being expanded first.
|
|
202
203
|
{
|
|
203
|
-
const pivotId =
|
|
204
|
+
const pivotId = deltaPixels < 0 ? idAfter : idBefore;
|
|
204
205
|
const index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
205
206
|
const panel = panelsArray[index];
|
|
206
207
|
const baseSize = baseSizes[index];
|
|
207
|
-
const nextSize = safeResizePanel(panel, Math.abs(
|
|
208
|
+
const nextSize = safeResizePanel(units, groupSizePixels, panel, baseSize, baseSize + Math.abs(deltaPixels), event);
|
|
208
209
|
if (baseSize === nextSize) {
|
|
209
210
|
// If there's no room for the pivot panel to grow, we can ignore this drag update.
|
|
210
211
|
return baseSizes;
|
|
@@ -212,29 +213,29 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
212
213
|
if (nextSize === 0 && baseSize > 0) {
|
|
213
214
|
panelSizeBeforeCollapse.set(pivotId, baseSize);
|
|
214
215
|
}
|
|
215
|
-
|
|
216
|
+
deltaPixels = deltaPixels < 0 ? baseSize - nextSize : nextSize - baseSize;
|
|
216
217
|
}
|
|
217
218
|
}
|
|
218
|
-
let pivotId =
|
|
219
|
+
let pivotId = deltaPixels < 0 ? idBefore : idAfter;
|
|
219
220
|
let index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
220
221
|
while (true) {
|
|
221
222
|
const panel = panelsArray[index];
|
|
222
223
|
const baseSize = baseSizes[index];
|
|
223
|
-
const deltaRemaining = Math.abs(
|
|
224
|
-
const nextSize = safeResizePanel(panel,
|
|
224
|
+
const deltaRemaining = Math.abs(deltaPixels) - Math.abs(deltaApplied);
|
|
225
|
+
const nextSize = safeResizePanel(units, groupSizePixels, panel, baseSize, baseSize - deltaRemaining, event);
|
|
225
226
|
if (baseSize !== nextSize) {
|
|
226
227
|
if (nextSize === 0 && baseSize > 0) {
|
|
227
228
|
panelSizeBeforeCollapse.set(panel.current.id, baseSize);
|
|
228
229
|
}
|
|
229
230
|
deltaApplied += baseSize - nextSize;
|
|
230
231
|
nextSizes[index] = nextSize;
|
|
231
|
-
if (deltaApplied.toPrecision(PRECISION).localeCompare(Math.abs(
|
|
232
|
+
if (deltaApplied.toPrecision(PRECISION).localeCompare(Math.abs(deltaPixels).toPrecision(PRECISION), undefined, {
|
|
232
233
|
numeric: true
|
|
233
234
|
}) >= 0) {
|
|
234
235
|
break;
|
|
235
236
|
}
|
|
236
237
|
}
|
|
237
|
-
if (
|
|
238
|
+
if (deltaPixels < 0) {
|
|
238
239
|
if (--index < 0) {
|
|
239
240
|
break;
|
|
240
241
|
}
|
|
@@ -252,7 +253,7 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
252
253
|
}
|
|
253
254
|
|
|
254
255
|
// Adjust the pivot panel before, but only by the amount that surrounding panels were able to shrink/contract.
|
|
255
|
-
pivotId =
|
|
256
|
+
pivotId = deltaPixels < 0 ? idAfter : idBefore;
|
|
256
257
|
index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
257
258
|
nextSizes[index] = baseSizes[index] + deltaApplied;
|
|
258
259
|
return nextSizes;
|
|
@@ -304,6 +305,23 @@ function getBeforeAndAfterIds(id, panelsArray) {
|
|
|
304
305
|
const idAfter = isLastPanel ? id : panelsArray[index + 1].current.id;
|
|
305
306
|
return [idBefore, idAfter];
|
|
306
307
|
}
|
|
308
|
+
function getAvailableGroupSizePixels(groupId) {
|
|
309
|
+
const panelGroupElement = getPanelGroup(groupId);
|
|
310
|
+
if (panelGroupElement == null) {
|
|
311
|
+
return NaN;
|
|
312
|
+
}
|
|
313
|
+
const direction = panelGroupElement.getAttribute("data-panel-group-direction");
|
|
314
|
+
const resizeHandles = getResizeHandlesForGroup(groupId);
|
|
315
|
+
if (direction === "horizontal") {
|
|
316
|
+
return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
|
|
317
|
+
return accumulated + handle.offsetWidth;
|
|
318
|
+
}, 0);
|
|
319
|
+
} else {
|
|
320
|
+
return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
|
|
321
|
+
return accumulated + handle.offsetHeight;
|
|
322
|
+
}, 0);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
307
325
|
|
|
308
326
|
// This method returns a number between 1 and 100 representing
|
|
309
327
|
// the % of the group's overall space this panel should occupy.
|
|
@@ -374,18 +392,24 @@ function panelsMapToSortedArray(panels) {
|
|
|
374
392
|
}
|
|
375
393
|
});
|
|
376
394
|
}
|
|
377
|
-
function safeResizePanel(
|
|
378
|
-
|
|
379
|
-
const {
|
|
395
|
+
function safeResizePanel(units, groupSizePixels, panel, prevSize, nextSize, event = null) {
|
|
396
|
+
let {
|
|
380
397
|
collapsedSize,
|
|
381
398
|
collapsible,
|
|
382
399
|
maxSize,
|
|
383
400
|
minSize
|
|
384
401
|
} = panel.current;
|
|
402
|
+
if (units === "pixels") {
|
|
403
|
+
collapsedSize = collapsedSize / groupSizePixels * 100;
|
|
404
|
+
if (maxSize != null) {
|
|
405
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
406
|
+
}
|
|
407
|
+
minSize = minSize / groupSizePixels * 100;
|
|
408
|
+
}
|
|
385
409
|
if (collapsible) {
|
|
386
410
|
if (prevSize > collapsedSize) {
|
|
387
411
|
// Mimic VS COde behavior; collapse a panel if it's smaller than half of its min-size
|
|
388
|
-
if (
|
|
412
|
+
if (nextSize <= minSize / 2 + collapsedSize) {
|
|
389
413
|
return collapsedSize;
|
|
390
414
|
}
|
|
391
415
|
} else {
|
|
@@ -394,14 +418,97 @@ function safeResizePanel(panel, delta, prevSize, event) {
|
|
|
394
418
|
// Keyboard events should expand a collapsed panel to the min size,
|
|
395
419
|
// but mouse events should wait until the panel has reached its min size
|
|
396
420
|
// to avoid a visual flickering when dragging between collapsed and min size.
|
|
397
|
-
if (
|
|
421
|
+
if (nextSize < minSize) {
|
|
398
422
|
return collapsedSize;
|
|
399
423
|
}
|
|
400
424
|
}
|
|
401
425
|
}
|
|
402
426
|
}
|
|
403
|
-
|
|
404
|
-
|
|
427
|
+
return Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSize));
|
|
428
|
+
}
|
|
429
|
+
function validatePanelProps(units, panelData) {
|
|
430
|
+
const {
|
|
431
|
+
collapsible,
|
|
432
|
+
defaultSize,
|
|
433
|
+
maxSize,
|
|
434
|
+
minSize
|
|
435
|
+
} = panelData.current;
|
|
436
|
+
|
|
437
|
+
// Basic props validation
|
|
438
|
+
if (minSize < 0 || units === "percentages" && minSize > 100) {
|
|
439
|
+
panelData.current.minSize = 0;
|
|
440
|
+
}
|
|
441
|
+
if (maxSize != null) {
|
|
442
|
+
if (maxSize < 0 || units === "percentages" && maxSize > 100) {
|
|
443
|
+
panelData.current.maxSize = null;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
if (defaultSize !== null) {
|
|
447
|
+
if (defaultSize < 0 || units === "percentages" && defaultSize > 100) {
|
|
448
|
+
panelData.current.defaultSize = null;
|
|
449
|
+
} else if (defaultSize < minSize && !collapsible) {
|
|
450
|
+
panelData.current.defaultSize = minSize;
|
|
451
|
+
} else if (maxSize != null && defaultSize > maxSize) {
|
|
452
|
+
panelData.current.defaultSize = maxSize;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
function validatePanelGroupLayout({
|
|
457
|
+
groupId,
|
|
458
|
+
panels,
|
|
459
|
+
nextSizes,
|
|
460
|
+
prevSizes,
|
|
461
|
+
units
|
|
462
|
+
}) {
|
|
463
|
+
// Clone because this method modifies
|
|
464
|
+
nextSizes = [...nextSizes];
|
|
465
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
466
|
+
const groupSizePixels = units === "pixels" ? getAvailableGroupSizePixels(groupId) : NaN;
|
|
467
|
+
let remainingSize = 0;
|
|
468
|
+
|
|
469
|
+
// First, check all of the proposed sizes against the min/max constraints
|
|
470
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
471
|
+
const panel = panelsArray[index];
|
|
472
|
+
const prevSize = prevSizes[index];
|
|
473
|
+
const nextSize = nextSizes[index];
|
|
474
|
+
const safeNextSize = safeResizePanel(units, groupSizePixels, panel, prevSize, nextSize);
|
|
475
|
+
if (nextSize != safeNextSize) {
|
|
476
|
+
remainingSize += nextSize - safeNextSize;
|
|
477
|
+
nextSizes[index] = safeNextSize;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// If there is additional, left over space, assign it to any panel(s) that permits it
|
|
482
|
+
// (It's not worth taking multiple additional passes to evenly distribute)
|
|
483
|
+
if (remainingSize.toFixed(3) !== "0.000") {
|
|
484
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
485
|
+
const panel = panelsArray[index];
|
|
486
|
+
let {
|
|
487
|
+
maxSize,
|
|
488
|
+
minSize
|
|
489
|
+
} = panel.current;
|
|
490
|
+
if (units === "pixels") {
|
|
491
|
+
minSize = minSize / groupSizePixels * 100;
|
|
492
|
+
if (maxSize != null) {
|
|
493
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
const size = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSizes[index] + remainingSize));
|
|
497
|
+
if (size !== nextSizes[index]) {
|
|
498
|
+
remainingSize -= size - nextSizes[index];
|
|
499
|
+
nextSizes[index] = size;
|
|
500
|
+
|
|
501
|
+
// Fuzzy comparison to account for imprecise floating point math
|
|
502
|
+
if (Math.abs(remainingSize).toFixed(3) === "0.000") {
|
|
503
|
+
break;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// If we still have remainder, the requested layout wasn't valid and we should warn about it
|
|
510
|
+
if (remainingSize.toFixed(3) !== "0.000") ;
|
|
511
|
+
return nextSizes;
|
|
405
512
|
}
|
|
406
513
|
|
|
407
514
|
function assert(expectedCondition, message = "Assertion failed!") {
|
|
@@ -427,6 +534,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
427
534
|
panels
|
|
428
535
|
} = committedValuesRef.current;
|
|
429
536
|
const groupElement = getPanelGroup(groupId);
|
|
537
|
+
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
430
538
|
const {
|
|
431
539
|
height,
|
|
432
540
|
width
|
|
@@ -439,23 +547,28 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
439
547
|
if (idBefore == null || idAfter == null) {
|
|
440
548
|
return () => {};
|
|
441
549
|
}
|
|
442
|
-
let
|
|
443
|
-
let
|
|
550
|
+
let currentMinSize = 0;
|
|
551
|
+
let currentMaxSize = 100;
|
|
444
552
|
let totalMinSize = 0;
|
|
445
553
|
let totalMaxSize = 0;
|
|
446
554
|
|
|
447
555
|
// A panel's effective min/max sizes also need to account for other panel's sizes.
|
|
448
556
|
panelsArray.forEach(panelData => {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
557
|
+
const {
|
|
558
|
+
id,
|
|
559
|
+
maxSize,
|
|
560
|
+
minSize
|
|
561
|
+
} = panelData.current;
|
|
562
|
+
if (id === idBefore) {
|
|
563
|
+
currentMinSize = minSize;
|
|
564
|
+
currentMaxSize = maxSize != null ? maxSize : 100;
|
|
452
565
|
} else {
|
|
453
|
-
totalMinSize +=
|
|
454
|
-
totalMaxSize +=
|
|
566
|
+
totalMinSize += minSize;
|
|
567
|
+
totalMaxSize += maxSize != null ? maxSize : 100;
|
|
455
568
|
}
|
|
456
569
|
});
|
|
457
|
-
const ariaValueMax = Math.min(
|
|
458
|
-
const ariaValueMin = Math.max(
|
|
570
|
+
const ariaValueMax = Math.min(currentMaxSize, 100 - totalMinSize);
|
|
571
|
+
const ariaValueMin = Math.max(currentMinSize, (panelsArray.length - 1) * 100 - totalMaxSize);
|
|
459
572
|
const flexGrow = getFlexGrow(panels, idBefore, sizes);
|
|
460
573
|
handle.setAttribute("aria-valuemax", "" + Math.round(ariaValueMax));
|
|
461
574
|
handle.setAttribute("aria-valuemin", "" + Math.round(ariaValueMin));
|
|
@@ -479,7 +592,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
479
592
|
} else {
|
|
480
593
|
delta = -(direction === "horizontal" ? width : height);
|
|
481
594
|
}
|
|
482
|
-
const nextSizes = adjustByDelta(event,
|
|
595
|
+
const nextSizes = adjustByDelta(event, committedValuesRef.current, idBefore, idAfter, delta, sizes, panelSizeBeforeCollapse.current, null);
|
|
483
596
|
if (sizes !== nextSizes) {
|
|
484
597
|
setSizes(nextSizes);
|
|
485
598
|
}
|
|
@@ -786,9 +899,6 @@ const defaultStorage = {
|
|
|
786
899
|
// * dragHandleRect, sizes:
|
|
787
900
|
// When resizing is done via mouse/touch event– some initial state is stored
|
|
788
901
|
// so that any panels that contract will also expand if drag direction is reversed.
|
|
789
|
-
// TODO
|
|
790
|
-
// Within an active drag, remember original positions to refine more easily on expand.
|
|
791
|
-
// Look at what the Chrome devtools Sources does.
|
|
792
902
|
function PanelGroupWithForwardedRef({
|
|
793
903
|
autoSaveId,
|
|
794
904
|
children = null,
|
|
@@ -800,7 +910,8 @@ function PanelGroupWithForwardedRef({
|
|
|
800
910
|
onLayout,
|
|
801
911
|
storage = defaultStorage,
|
|
802
912
|
style: styleFromProps = {},
|
|
803
|
-
tagName: Type = "div"
|
|
913
|
+
tagName: Type = "div",
|
|
914
|
+
units = "percentages"
|
|
804
915
|
}) {
|
|
805
916
|
const groupId = useUniqueId(idFromProps);
|
|
806
917
|
const [activeHandleId, setActiveHandleId] = useState(null);
|
|
@@ -813,6 +924,7 @@ function PanelGroupWithForwardedRef({
|
|
|
813
924
|
useRef({
|
|
814
925
|
didLogDefaultSizeWarning: false,
|
|
815
926
|
didLogIdAndOrderWarning: false,
|
|
927
|
+
didLogInvalidLayoutWarning: false,
|
|
816
928
|
prevPanelIds: []
|
|
817
929
|
});
|
|
818
930
|
|
|
@@ -835,28 +947,52 @@ function PanelGroupWithForwardedRef({
|
|
|
835
947
|
// Store committed values to avoid unnecessarily re-running memoization/effects functions.
|
|
836
948
|
const committedValuesRef = useRef({
|
|
837
949
|
direction,
|
|
950
|
+
id: groupId,
|
|
838
951
|
panels,
|
|
839
|
-
sizes
|
|
952
|
+
sizes,
|
|
953
|
+
units
|
|
840
954
|
});
|
|
841
955
|
useImperativeHandle(forwardedRef, () => ({
|
|
842
|
-
|
|
956
|
+
getId: () => groupId,
|
|
957
|
+
getLayout: unitsFromParams => {
|
|
843
958
|
const {
|
|
844
|
-
sizes
|
|
959
|
+
sizes,
|
|
960
|
+
units: unitsFromProps
|
|
845
961
|
} = committedValuesRef.current;
|
|
846
|
-
|
|
962
|
+
const units = unitsFromParams ?? unitsFromProps;
|
|
963
|
+
if (units === "pixels") {
|
|
964
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
965
|
+
return sizes.map(size => size / 100 * groupSizePixels);
|
|
966
|
+
} else {
|
|
967
|
+
return sizes;
|
|
968
|
+
}
|
|
847
969
|
},
|
|
848
|
-
setLayout: sizes => {
|
|
849
|
-
const total = sizes.reduce((accumulated, current) => accumulated + current, 0);
|
|
850
|
-
assert(total === 100, "Panel sizes must add up to 100%");
|
|
970
|
+
setLayout: (sizes, unitsFromParams) => {
|
|
851
971
|
const {
|
|
852
|
-
|
|
972
|
+
id: groupId,
|
|
973
|
+
panels,
|
|
974
|
+
sizes: prevSizes,
|
|
975
|
+
units
|
|
853
976
|
} = committedValuesRef.current;
|
|
977
|
+
if ((unitsFromParams || units) === "pixels") {
|
|
978
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
979
|
+
sizes = sizes.map(size => size / groupSizePixels * 100);
|
|
980
|
+
}
|
|
854
981
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
855
982
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
856
|
-
|
|
857
|
-
|
|
983
|
+
const nextSizes = validatePanelGroupLayout({
|
|
984
|
+
groupId,
|
|
985
|
+
panels,
|
|
986
|
+
nextSizes: sizes,
|
|
987
|
+
prevSizes,
|
|
988
|
+
units
|
|
989
|
+
});
|
|
990
|
+
if (!areEqual(prevSizes, nextSizes)) {
|
|
991
|
+
setSizes(nextSizes);
|
|
992
|
+
callPanelCallbacks(panelsArray, nextSizes, panelIdToLastNotifiedSizeMap);
|
|
993
|
+
}
|
|
858
994
|
}
|
|
859
|
-
}), []);
|
|
995
|
+
}), [groupId]);
|
|
860
996
|
useWindowSplitterPanelGroupBehavior({
|
|
861
997
|
committedValuesRef,
|
|
862
998
|
groupId,
|
|
@@ -907,6 +1043,22 @@ function PanelGroupWithForwardedRef({
|
|
|
907
1043
|
debounceMap[autoSaveId](autoSaveId, panelsArray, sizes, storage);
|
|
908
1044
|
}
|
|
909
1045
|
}, [autoSaveId, panels, sizes, storage]);
|
|
1046
|
+
const getPanelSize = useCallback((id, unitsFromParams) => {
|
|
1047
|
+
const {
|
|
1048
|
+
panels,
|
|
1049
|
+
units: unitsFromProps
|
|
1050
|
+
} = committedValuesRef.current;
|
|
1051
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
1052
|
+
const index = panelsArray.findIndex(panel => panel.current.id === id);
|
|
1053
|
+
const size = sizes[index];
|
|
1054
|
+
const units = unitsFromParams ?? unitsFromProps;
|
|
1055
|
+
if (units === "pixels") {
|
|
1056
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1057
|
+
return size / 100 * groupSizePixels;
|
|
1058
|
+
} else {
|
|
1059
|
+
return size;
|
|
1060
|
+
}
|
|
1061
|
+
}, [groupId, sizes]);
|
|
910
1062
|
const getPanelStyle = useCallback((id, defaultSize) => {
|
|
911
1063
|
const {
|
|
912
1064
|
panels
|
|
@@ -937,6 +1089,10 @@ function PanelGroupWithForwardedRef({
|
|
|
937
1089
|
};
|
|
938
1090
|
}, [activeHandleId, disablePointerEventsDuringResize, sizes]);
|
|
939
1091
|
const registerPanel = useCallback((id, panelRef) => {
|
|
1092
|
+
const {
|
|
1093
|
+
units
|
|
1094
|
+
} = committedValuesRef.current;
|
|
1095
|
+
validatePanelProps(units, panelRef);
|
|
940
1096
|
setPanels(prevPanels => {
|
|
941
1097
|
if (prevPanels.has(id)) {
|
|
942
1098
|
return prevPanels;
|
|
@@ -973,7 +1129,10 @@ function PanelGroupWithForwardedRef({
|
|
|
973
1129
|
}
|
|
974
1130
|
const size = isHorizontal ? rect.width : rect.height;
|
|
975
1131
|
const delta = movement / size * 100;
|
|
976
|
-
|
|
1132
|
+
|
|
1133
|
+
// If a validateLayout method has been provided
|
|
1134
|
+
// it's important to use it before updating the mouse cursor
|
|
1135
|
+
const nextSizes = adjustByDelta(event, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, initialDragStateRef.current);
|
|
977
1136
|
const sizesChanged = !areEqual(prevSizes, nextSizes);
|
|
978
1137
|
|
|
979
1138
|
// Don't update cursor for resizes triggered by keyboard interactions.
|
|
@@ -1000,6 +1159,8 @@ function PanelGroupWithForwardedRef({
|
|
|
1000
1159
|
}
|
|
1001
1160
|
if (sizesChanged) {
|
|
1002
1161
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1162
|
+
|
|
1163
|
+
// It's okay to bypass in this case because we already validated above
|
|
1003
1164
|
setSizes(nextSizes);
|
|
1004
1165
|
|
|
1005
1166
|
// If resize change handlers have been declared, this is the time to call them.
|
|
@@ -1053,7 +1214,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1053
1214
|
}
|
|
1054
1215
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1055
1216
|
const delta = isLastPanel ? currentSize : collapsedSize - currentSize;
|
|
1056
|
-
const nextSizes = adjustByDelta(null,
|
|
1217
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1057
1218
|
if (prevSizes !== nextSizes) {
|
|
1058
1219
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1059
1220
|
setSizes(nextSizes);
|
|
@@ -1096,7 +1257,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1096
1257
|
}
|
|
1097
1258
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1098
1259
|
const delta = isLastPanel ? collapsedSize - sizeBeforeCollapse : sizeBeforeCollapse;
|
|
1099
|
-
const nextSizes = adjustByDelta(null,
|
|
1260
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1100
1261
|
if (prevSizes !== nextSizes) {
|
|
1101
1262
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1102
1263
|
setSizes(nextSizes);
|
|
@@ -1106,21 +1267,34 @@ function PanelGroupWithForwardedRef({
|
|
|
1106
1267
|
callPanelCallbacks(panelsArray, nextSizes, panelIdToLastNotifiedSizeMap);
|
|
1107
1268
|
}
|
|
1108
1269
|
}, []);
|
|
1109
|
-
const resizePanel = useCallback((id, nextSize) => {
|
|
1270
|
+
const resizePanel = useCallback((id, nextSize, unitsFromParams) => {
|
|
1110
1271
|
const {
|
|
1272
|
+
id: groupId,
|
|
1111
1273
|
panels,
|
|
1112
|
-
sizes: prevSizes
|
|
1274
|
+
sizes: prevSizes,
|
|
1275
|
+
units
|
|
1113
1276
|
} = committedValuesRef.current;
|
|
1277
|
+
if ((unitsFromParams || units) === "pixels") {
|
|
1278
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1279
|
+
nextSize = nextSize / groupSizePixels * 100;
|
|
1280
|
+
}
|
|
1114
1281
|
const panel = panels.get(id);
|
|
1115
1282
|
if (panel == null) {
|
|
1116
1283
|
return;
|
|
1117
1284
|
}
|
|
1118
|
-
|
|
1285
|
+
let {
|
|
1119
1286
|
collapsedSize,
|
|
1120
1287
|
collapsible,
|
|
1121
1288
|
maxSize,
|
|
1122
1289
|
minSize
|
|
1123
1290
|
} = panel.current;
|
|
1291
|
+
if (units === "pixels") {
|
|
1292
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1293
|
+
minSize = minSize / groupSizePixels * 100;
|
|
1294
|
+
if (maxSize != null) {
|
|
1295
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1124
1298
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
1125
1299
|
const index = panelsArray.indexOf(panel);
|
|
1126
1300
|
if (index < 0) {
|
|
@@ -1131,7 +1305,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1131
1305
|
return;
|
|
1132
1306
|
}
|
|
1133
1307
|
if (collapsible && nextSize === collapsedSize) ; else {
|
|
1134
|
-
nextSize = Math.min(maxSize, Math.max(minSize, nextSize));
|
|
1308
|
+
nextSize = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSize));
|
|
1135
1309
|
}
|
|
1136
1310
|
const [idBefore, idAfter] = getBeforeAndAfterIds(id, panelsArray);
|
|
1137
1311
|
if (idBefore == null || idAfter == null) {
|
|
@@ -1139,7 +1313,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1139
1313
|
}
|
|
1140
1314
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1141
1315
|
const delta = isLastPanel ? currentSize - nextSize : nextSize - currentSize;
|
|
1142
|
-
const nextSizes = adjustByDelta(null,
|
|
1316
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1143
1317
|
if (prevSizes !== nextSizes) {
|
|
1144
1318
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1145
1319
|
setSizes(nextSizes);
|
|
@@ -1154,6 +1328,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1154
1328
|
collapsePanel,
|
|
1155
1329
|
direction,
|
|
1156
1330
|
expandPanel,
|
|
1331
|
+
getPanelSize,
|
|
1157
1332
|
getPanelStyle,
|
|
1158
1333
|
groupId,
|
|
1159
1334
|
registerPanel,
|
|
@@ -1175,8 +1350,9 @@ function PanelGroupWithForwardedRef({
|
|
|
1175
1350
|
setActiveHandleId(null);
|
|
1176
1351
|
initialDragStateRef.current = null;
|
|
1177
1352
|
},
|
|
1353
|
+
units,
|
|
1178
1354
|
unregisterPanel
|
|
1179
|
-
}), [activeHandleId, collapsePanel, direction, expandPanel, getPanelStyle, groupId, registerPanel, registerResizeHandle, resizePanel, unregisterPanel]);
|
|
1355
|
+
}), [activeHandleId, collapsePanel, direction, expandPanel, getPanelSize, getPanelStyle, groupId, registerPanel, registerResizeHandle, resizePanel, units, unregisterPanel]);
|
|
1180
1356
|
const style = {
|
|
1181
1357
|
display: "flex",
|
|
1182
1358
|
flexDirection: direction === "horizontal" ? "row" : "column",
|
|
@@ -1191,6 +1367,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1191
1367
|
"data-panel-group": "",
|
|
1192
1368
|
"data-panel-group-direction": direction,
|
|
1193
1369
|
"data-panel-group-id": groupId,
|
|
1370
|
+
"data-panel-group-units": units,
|
|
1194
1371
|
style: {
|
|
1195
1372
|
...style,
|
|
1196
1373
|
...styleFromProps
|
|
@@ -1343,3 +1520,4 @@ PanelResizeHandle.displayName = "PanelResizeHandle";
|
|
|
1343
1520
|
exports.Panel = Panel;
|
|
1344
1521
|
exports.PanelGroup = PanelGroup;
|
|
1345
1522
|
exports.PanelResizeHandle = PanelResizeHandle;
|
|
1523
|
+
exports.getAvailableGroupSizePixels = getAvailableGroupSizePixels;
|