react-resizable-panels 0.0.53 → 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 +33 -0
- package/dist/declarations/src/Panel.d.ts +6 -5
- package/dist/declarations/src/PanelGroup.d.ts +8 -4
- package/dist/declarations/src/PanelResizeHandle.d.ts +5 -2
- package/dist/declarations/src/index.d.ts +9 -8
- package/dist/declarations/src/types.d.ts +4 -2
- package/dist/declarations/src/utils/group.d.ts +29 -0
- package/dist/react-resizable-panels.browser.cjs.js +1709 -0
- package/dist/react-resizable-panels.browser.cjs.mjs +6 -0
- package/dist/react-resizable-panels.browser.development.cjs.js +1764 -0
- package/dist/react-resizable-panels.browser.development.cjs.mjs +6 -0
- package/dist/react-resizable-panels.browser.development.esm.js +1737 -0
- package/dist/react-resizable-panels.browser.esm.js +1682 -0
- package/dist/react-resizable-panels.cjs.js +395 -126
- 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 +452 -135
- package/dist/react-resizable-panels.development.cjs.mjs +6 -0
- package/dist/react-resizable-panels.development.esm.js +452 -136
- package/dist/react-resizable-panels.development.node.cjs.js +1579 -0
- package/dist/react-resizable-panels.development.node.cjs.mjs +6 -0
- package/dist/react-resizable-panels.development.node.esm.js +1552 -0
- package/dist/react-resizable-panels.esm.js +395 -127
- package/dist/react-resizable-panels.esm.js.map +1 -0
- package/dist/react-resizable-panels.node.cjs.js +1523 -0
- package/dist/react-resizable-panels.node.cjs.mjs +6 -0
- package/dist/react-resizable-panels.node.esm.js +1496 -0
- package/package.json +26 -1
- package/src/Panel.ts +37 -37
- package/src/PanelContexts.ts +5 -6
- package/src/PanelGroup.ts +269 -121
- package/src/PanelResizeHandle.ts +1 -4
- package/src/env-conditions/browser.ts +1 -0
- package/src/env-conditions/node.ts +1 -0
- package/src/env-conditions/unknown.ts +1 -0
- package/src/hooks/useIsomorphicEffect.ts +2 -9
- package/src/hooks/useWindowSplitterBehavior.ts +14 -11
- package/src/index.ts +11 -3
- package/src/types.ts +3 -1
- package/src/utils/group.ts +327 -28
- package/src/utils/ssr.ts +0 -7
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
+
const isBrowser = typeof window !== "undefined";
|
|
4
|
+
|
|
3
5
|
// This module exists to work around Webpack issue https://github.com/webpack/webpack/issues/14814
|
|
4
6
|
|
|
5
7
|
// eslint-disable-next-line no-restricted-imports
|
|
@@ -21,8 +23,7 @@ const {
|
|
|
21
23
|
// `toString()` prevents bundlers from trying to `import { useId } from 'react'`
|
|
22
24
|
const useId = React["useId".toString()];
|
|
23
25
|
|
|
24
|
-
const
|
|
25
|
-
const useIsomorphicLayoutEffect = canUseEffectHooks ? useLayoutEffect : () => {};
|
|
26
|
+
const useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : () => {};
|
|
26
27
|
|
|
27
28
|
const wrappedUseId = typeof useId === "function" ? useId : () => null;
|
|
28
29
|
let counter = 0;
|
|
@@ -36,10 +37,6 @@ function useUniqueId(idFromParams = null) {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
const PanelGroupContext = createContext(null);
|
|
39
|
-
|
|
40
|
-
// Workaround for Parcel scope hoisting (which renames objects/functions).
|
|
41
|
-
// Casting to :any is required to avoid corrupting the generated TypeScript types.
|
|
42
|
-
// See github.com/parcel-bundler/parcel/issues/8724
|
|
43
40
|
PanelGroupContext.displayName = "PanelGroupContext";
|
|
44
41
|
|
|
45
42
|
function PanelWithForwardedRef({
|
|
@@ -50,8 +47,8 @@ function PanelWithForwardedRef({
|
|
|
50
47
|
defaultSize = null,
|
|
51
48
|
forwardedRef,
|
|
52
49
|
id: idFromProps = null,
|
|
53
|
-
maxSize =
|
|
54
|
-
minSize
|
|
50
|
+
maxSize = null,
|
|
51
|
+
minSize,
|
|
55
52
|
onCollapse = null,
|
|
56
53
|
onResize = null,
|
|
57
54
|
order = null,
|
|
@@ -66,11 +63,22 @@ function PanelWithForwardedRef({
|
|
|
66
63
|
const {
|
|
67
64
|
collapsePanel,
|
|
68
65
|
expandPanel,
|
|
66
|
+
getPanelSize,
|
|
69
67
|
getPanelStyle,
|
|
70
68
|
registerPanel,
|
|
71
69
|
resizePanel,
|
|
70
|
+
units,
|
|
72
71
|
unregisterPanel
|
|
73
72
|
} = context;
|
|
73
|
+
if (minSize == null) {
|
|
74
|
+
if (units === "percentages") {
|
|
75
|
+
// Mimics legacy default value for percentage based panel groups
|
|
76
|
+
minSize = 10;
|
|
77
|
+
} else {
|
|
78
|
+
// There is no meaningful minimum pixel default we can provide
|
|
79
|
+
minSize = 0;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
74
82
|
|
|
75
83
|
// Use a ref to guard against users passing inline props
|
|
76
84
|
const callbacksRef = useRef({
|
|
@@ -81,22 +89,6 @@ function PanelWithForwardedRef({
|
|
|
81
89
|
callbacksRef.current.onCollapse = onCollapse;
|
|
82
90
|
callbacksRef.current.onResize = onResize;
|
|
83
91
|
});
|
|
84
|
-
|
|
85
|
-
// Basic props validation
|
|
86
|
-
if (minSize < 0 || minSize > 100) {
|
|
87
|
-
throw Error(`Panel minSize must be between 0 and 100, but was ${minSize}`);
|
|
88
|
-
} else if (maxSize < 0 || maxSize > 100) {
|
|
89
|
-
throw Error(`Panel maxSize must be between 0 and 100, but was ${maxSize}`);
|
|
90
|
-
} else {
|
|
91
|
-
if (defaultSize !== null) {
|
|
92
|
-
if (defaultSize < 0 || defaultSize > 100) {
|
|
93
|
-
throw Error(`Panel defaultSize must be between 0 and 100, but was ${defaultSize}`);
|
|
94
|
-
} else if (minSize > defaultSize && !collapsible) {
|
|
95
|
-
console.error(`Panel minSize ${minSize} cannot be greater than defaultSize ${defaultSize}`);
|
|
96
|
-
defaultSize = minSize;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
92
|
const style = getPanelStyle(panelId, defaultSize);
|
|
101
93
|
const committedValuesRef = useRef({
|
|
102
94
|
size: parseSizeFromStyle(style)
|
|
@@ -107,6 +99,7 @@ function PanelWithForwardedRef({
|
|
|
107
99
|
collapsible,
|
|
108
100
|
defaultSize,
|
|
109
101
|
id: panelId,
|
|
102
|
+
idWasAutoGenerated: idFromProps == null,
|
|
110
103
|
maxSize,
|
|
111
104
|
minSize,
|
|
112
105
|
order
|
|
@@ -118,6 +111,7 @@ function PanelWithForwardedRef({
|
|
|
118
111
|
panelDataRef.current.collapsible = collapsible;
|
|
119
112
|
panelDataRef.current.defaultSize = defaultSize;
|
|
120
113
|
panelDataRef.current.id = panelId;
|
|
114
|
+
panelDataRef.current.idWasAutoGenerated = idFromProps == null;
|
|
121
115
|
panelDataRef.current.maxSize = maxSize;
|
|
122
116
|
panelDataRef.current.minSize = minSize;
|
|
123
117
|
panelDataRef.current.order = order;
|
|
@@ -134,11 +128,14 @@ function PanelWithForwardedRef({
|
|
|
134
128
|
getCollapsed() {
|
|
135
129
|
return committedValuesRef.current.size === 0;
|
|
136
130
|
},
|
|
137
|
-
|
|
138
|
-
return
|
|
131
|
+
getId() {
|
|
132
|
+
return panelId;
|
|
139
133
|
},
|
|
140
|
-
|
|
141
|
-
|
|
134
|
+
getSize(units) {
|
|
135
|
+
return getPanelSize(panelId, units);
|
|
136
|
+
},
|
|
137
|
+
resize: (percentage, units) => resizePanel(panelId, percentage, units)
|
|
138
|
+
}), [collapsePanel, expandPanel, getPanelSize, panelId, resizePanel]);
|
|
142
139
|
return createElement(Type, {
|
|
143
140
|
children,
|
|
144
141
|
className: classNameFromProps,
|
|
@@ -157,10 +154,6 @@ const Panel = forwardRef((props, ref) => createElement(PanelWithForwardedRef, {
|
|
|
157
154
|
...props,
|
|
158
155
|
forwardedRef: ref
|
|
159
156
|
}));
|
|
160
|
-
|
|
161
|
-
// Workaround for Parcel scope hoisting (which renames objects/functions).
|
|
162
|
-
// Casting to :any is required to avoid corrupting the generated TypeScript types.
|
|
163
|
-
// See github.com/parcel-bundler/parcel/issues/8724
|
|
164
157
|
PanelWithForwardedRef.displayName = "Panel";
|
|
165
158
|
Panel.displayName = "forwardRef(Panel)";
|
|
166
159
|
|
|
@@ -178,7 +171,13 @@ function parseSizeFromStyle(style) {
|
|
|
178
171
|
|
|
179
172
|
const PRECISION = 10;
|
|
180
173
|
|
|
181
|
-
function adjustByDelta(event,
|
|
174
|
+
function adjustByDelta(event, committedValues, idBefore, idAfter, deltaPixels, prevSizes, panelSizeBeforeCollapse, initialDragState) {
|
|
175
|
+
const {
|
|
176
|
+
id: groupId,
|
|
177
|
+
panels,
|
|
178
|
+
units
|
|
179
|
+
} = committedValues;
|
|
180
|
+
const groupSizePixels = units === "pixels" ? getAvailableGroupSizePixels(groupId) : NaN;
|
|
182
181
|
const {
|
|
183
182
|
sizes: initialSizes
|
|
184
183
|
} = initialDragState || {};
|
|
@@ -186,9 +185,6 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
186
185
|
// If we're resizing by mouse or touch, use the initial sizes as a base.
|
|
187
186
|
// This has the benefit of causing force-collapsed panels to spring back open if drag is reversed.
|
|
188
187
|
const baseSizes = initialSizes || prevSizes;
|
|
189
|
-
if (delta === 0) {
|
|
190
|
-
return baseSizes;
|
|
191
|
-
}
|
|
192
188
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
193
189
|
const nextSizes = baseSizes.concat();
|
|
194
190
|
let deltaApplied = 0;
|
|
@@ -203,11 +199,11 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
203
199
|
|
|
204
200
|
// Max-bounds check the panel being expanded first.
|
|
205
201
|
{
|
|
206
|
-
const pivotId =
|
|
202
|
+
const pivotId = deltaPixels < 0 ? idAfter : idBefore;
|
|
207
203
|
const index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
208
204
|
const panel = panelsArray[index];
|
|
209
205
|
const baseSize = baseSizes[index];
|
|
210
|
-
const nextSize = safeResizePanel(panel, Math.abs(
|
|
206
|
+
const nextSize = safeResizePanel(units, groupSizePixels, panel, baseSize, baseSize + Math.abs(deltaPixels), event);
|
|
211
207
|
if (baseSize === nextSize) {
|
|
212
208
|
// If there's no room for the pivot panel to grow, we can ignore this drag update.
|
|
213
209
|
return baseSizes;
|
|
@@ -215,29 +211,29 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
215
211
|
if (nextSize === 0 && baseSize > 0) {
|
|
216
212
|
panelSizeBeforeCollapse.set(pivotId, baseSize);
|
|
217
213
|
}
|
|
218
|
-
|
|
214
|
+
deltaPixels = deltaPixels < 0 ? baseSize - nextSize : nextSize - baseSize;
|
|
219
215
|
}
|
|
220
216
|
}
|
|
221
|
-
let pivotId =
|
|
217
|
+
let pivotId = deltaPixels < 0 ? idBefore : idAfter;
|
|
222
218
|
let index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
223
219
|
while (true) {
|
|
224
220
|
const panel = panelsArray[index];
|
|
225
221
|
const baseSize = baseSizes[index];
|
|
226
|
-
const deltaRemaining = Math.abs(
|
|
227
|
-
const nextSize = safeResizePanel(panel,
|
|
222
|
+
const deltaRemaining = Math.abs(deltaPixels) - Math.abs(deltaApplied);
|
|
223
|
+
const nextSize = safeResizePanel(units, groupSizePixels, panel, baseSize, baseSize - deltaRemaining, event);
|
|
228
224
|
if (baseSize !== nextSize) {
|
|
229
225
|
if (nextSize === 0 && baseSize > 0) {
|
|
230
226
|
panelSizeBeforeCollapse.set(panel.current.id, baseSize);
|
|
231
227
|
}
|
|
232
228
|
deltaApplied += baseSize - nextSize;
|
|
233
229
|
nextSizes[index] = nextSize;
|
|
234
|
-
if (deltaApplied.toPrecision(PRECISION).localeCompare(Math.abs(
|
|
230
|
+
if (deltaApplied.toPrecision(PRECISION).localeCompare(Math.abs(deltaPixels).toPrecision(PRECISION), undefined, {
|
|
235
231
|
numeric: true
|
|
236
232
|
}) >= 0) {
|
|
237
233
|
break;
|
|
238
234
|
}
|
|
239
235
|
}
|
|
240
|
-
if (
|
|
236
|
+
if (deltaPixels < 0) {
|
|
241
237
|
if (--index < 0) {
|
|
242
238
|
break;
|
|
243
239
|
}
|
|
@@ -255,7 +251,7 @@ function adjustByDelta(event, panels, idBefore, idAfter, delta, prevSizes, panel
|
|
|
255
251
|
}
|
|
256
252
|
|
|
257
253
|
// Adjust the pivot panel before, but only by the amount that surrounding panels were able to shrink/contract.
|
|
258
|
-
pivotId =
|
|
254
|
+
pivotId = deltaPixels < 0 ? idAfter : idBefore;
|
|
259
255
|
index = panelsArray.findIndex(panel => panel.current.id === pivotId);
|
|
260
256
|
nextSizes[index] = baseSizes[index] + deltaApplied;
|
|
261
257
|
return nextSizes;
|
|
@@ -294,6 +290,93 @@ function callPanelCallbacks(panelsArray, sizes, panelIdToLastNotifiedSizeMap) {
|
|
|
294
290
|
}
|
|
295
291
|
});
|
|
296
292
|
}
|
|
293
|
+
function calculateDefaultLayout({
|
|
294
|
+
groupId,
|
|
295
|
+
panels,
|
|
296
|
+
units
|
|
297
|
+
}) {
|
|
298
|
+
const groupSizePixels = units === "pixels" ? getAvailableGroupSizePixels(groupId) : NaN;
|
|
299
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
300
|
+
const sizes = Array(panelsArray.length);
|
|
301
|
+
let numPanelsWithSizes = 0;
|
|
302
|
+
let remainingSize = 100;
|
|
303
|
+
|
|
304
|
+
// Assigning default sizes requires a couple of passes:
|
|
305
|
+
// First, all panels with defaultSize should be set as-is
|
|
306
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
307
|
+
const panel = panelsArray[index];
|
|
308
|
+
const {
|
|
309
|
+
defaultSize
|
|
310
|
+
} = panel.current;
|
|
311
|
+
if (defaultSize != null) {
|
|
312
|
+
numPanelsWithSizes++;
|
|
313
|
+
sizes[index] = units === "pixels" ? defaultSize / groupSizePixels * 100 : defaultSize;
|
|
314
|
+
remainingSize -= sizes[index];
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Remaining total size should be distributed evenly between panels
|
|
319
|
+
// This may require two passes, depending on min/max constraints
|
|
320
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
321
|
+
const panel = panelsArray[index];
|
|
322
|
+
let {
|
|
323
|
+
defaultSize,
|
|
324
|
+
id,
|
|
325
|
+
maxSize,
|
|
326
|
+
minSize
|
|
327
|
+
} = panel.current;
|
|
328
|
+
if (defaultSize != null) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
if (units === "pixels") {
|
|
332
|
+
minSize = minSize / groupSizePixels * 100;
|
|
333
|
+
if (maxSize != null) {
|
|
334
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const remainingPanels = panelsArray.length - numPanelsWithSizes;
|
|
338
|
+
const size = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, remainingSize / remainingPanels));
|
|
339
|
+
sizes[index] = size;
|
|
340
|
+
numPanelsWithSizes++;
|
|
341
|
+
remainingSize -= size;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// If there is additional, left over space, assign it to any panel(s) that permits it
|
|
345
|
+
// (It's not worth taking multiple additional passes to evenly distribute)
|
|
346
|
+
if (remainingSize !== 0) {
|
|
347
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
348
|
+
const panel = panelsArray[index];
|
|
349
|
+
let {
|
|
350
|
+
maxSize,
|
|
351
|
+
minSize
|
|
352
|
+
} = panel.current;
|
|
353
|
+
if (units === "pixels") {
|
|
354
|
+
minSize = minSize / groupSizePixels * 100;
|
|
355
|
+
if (maxSize != null) {
|
|
356
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
const size = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, sizes[index] + remainingSize));
|
|
360
|
+
if (size !== sizes[index]) {
|
|
361
|
+
remainingSize -= size - sizes[index];
|
|
362
|
+
sizes[index] = size;
|
|
363
|
+
|
|
364
|
+
// Fuzzy comparison to account for imprecise floating point math
|
|
365
|
+
if (Math.abs(remainingSize).toFixed(3) === "0.000") {
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Finally, if there is still left-over size, log an error
|
|
373
|
+
if (Math.abs(remainingSize).toFixed(3) !== "0.000") {
|
|
374
|
+
{
|
|
375
|
+
console.error(`Invalid panel group configuration; default panel sizes should total 100% but was ${(100 - remainingSize).toFixed(1)}%. This can cause the cursor to become misaligned while dragging.`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return sizes;
|
|
379
|
+
}
|
|
297
380
|
function getBeforeAndAfterIds(id, panelsArray) {
|
|
298
381
|
if (panelsArray.length < 2) {
|
|
299
382
|
return [null, null];
|
|
@@ -307,6 +390,23 @@ function getBeforeAndAfterIds(id, panelsArray) {
|
|
|
307
390
|
const idAfter = isLastPanel ? id : panelsArray[index + 1].current.id;
|
|
308
391
|
return [idBefore, idAfter];
|
|
309
392
|
}
|
|
393
|
+
function getAvailableGroupSizePixels(groupId) {
|
|
394
|
+
const panelGroupElement = getPanelGroup(groupId);
|
|
395
|
+
if (panelGroupElement == null) {
|
|
396
|
+
return NaN;
|
|
397
|
+
}
|
|
398
|
+
const direction = panelGroupElement.getAttribute("data-panel-group-direction");
|
|
399
|
+
const resizeHandles = getResizeHandlesForGroup(groupId);
|
|
400
|
+
if (direction === "horizontal") {
|
|
401
|
+
return panelGroupElement.offsetWidth - resizeHandles.reduce((accumulated, handle) => {
|
|
402
|
+
return accumulated + handle.offsetWidth;
|
|
403
|
+
}, 0);
|
|
404
|
+
} else {
|
|
405
|
+
return panelGroupElement.offsetHeight - resizeHandles.reduce((accumulated, handle) => {
|
|
406
|
+
return accumulated + handle.offsetHeight;
|
|
407
|
+
}, 0);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
310
410
|
|
|
311
411
|
// This method returns a number between 1 and 100 representing
|
|
312
412
|
// the % of the group's overall space this panel should occupy.
|
|
@@ -377,18 +477,24 @@ function panelsMapToSortedArray(panels) {
|
|
|
377
477
|
}
|
|
378
478
|
});
|
|
379
479
|
}
|
|
380
|
-
function safeResizePanel(
|
|
381
|
-
|
|
382
|
-
const {
|
|
480
|
+
function safeResizePanel(units, groupSizePixels, panel, prevSize, nextSize, event = null) {
|
|
481
|
+
let {
|
|
383
482
|
collapsedSize,
|
|
384
483
|
collapsible,
|
|
385
484
|
maxSize,
|
|
386
485
|
minSize
|
|
387
486
|
} = panel.current;
|
|
487
|
+
if (units === "pixels") {
|
|
488
|
+
collapsedSize = collapsedSize / groupSizePixels * 100;
|
|
489
|
+
if (maxSize != null) {
|
|
490
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
491
|
+
}
|
|
492
|
+
minSize = minSize / groupSizePixels * 100;
|
|
493
|
+
}
|
|
388
494
|
if (collapsible) {
|
|
389
495
|
if (prevSize > collapsedSize) {
|
|
390
496
|
// Mimic VS COde behavior; collapse a panel if it's smaller than half of its min-size
|
|
391
|
-
if (
|
|
497
|
+
if (nextSize <= minSize / 2 + collapsedSize) {
|
|
392
498
|
return collapsedSize;
|
|
393
499
|
}
|
|
394
500
|
} else {
|
|
@@ -397,14 +503,119 @@ function safeResizePanel(panel, delta, prevSize, event) {
|
|
|
397
503
|
// Keyboard events should expand a collapsed panel to the min size,
|
|
398
504
|
// but mouse events should wait until the panel has reached its min size
|
|
399
505
|
// to avoid a visual flickering when dragging between collapsed and min size.
|
|
400
|
-
if (
|
|
506
|
+
if (nextSize < minSize) {
|
|
401
507
|
return collapsedSize;
|
|
402
508
|
}
|
|
403
509
|
}
|
|
404
510
|
}
|
|
405
511
|
}
|
|
406
|
-
|
|
407
|
-
|
|
512
|
+
return Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSize));
|
|
513
|
+
}
|
|
514
|
+
function validatePanelProps(units, panelData) {
|
|
515
|
+
const {
|
|
516
|
+
collapsible,
|
|
517
|
+
defaultSize,
|
|
518
|
+
maxSize,
|
|
519
|
+
minSize
|
|
520
|
+
} = panelData.current;
|
|
521
|
+
|
|
522
|
+
// Basic props validation
|
|
523
|
+
if (minSize < 0 || units === "percentages" && minSize > 100) {
|
|
524
|
+
{
|
|
525
|
+
console.error(`Invalid Panel minSize provided, ${minSize}`);
|
|
526
|
+
}
|
|
527
|
+
panelData.current.minSize = 0;
|
|
528
|
+
}
|
|
529
|
+
if (maxSize != null) {
|
|
530
|
+
if (maxSize < 0 || units === "percentages" && maxSize > 100) {
|
|
531
|
+
{
|
|
532
|
+
console.error(`Invalid Panel maxSize provided, ${maxSize}`);
|
|
533
|
+
}
|
|
534
|
+
panelData.current.maxSize = null;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (defaultSize !== null) {
|
|
538
|
+
if (defaultSize < 0 || units === "percentages" && defaultSize > 100) {
|
|
539
|
+
{
|
|
540
|
+
console.error(`Invalid Panel defaultSize provided, ${defaultSize}`);
|
|
541
|
+
}
|
|
542
|
+
panelData.current.defaultSize = null;
|
|
543
|
+
} else if (defaultSize < minSize && !collapsible) {
|
|
544
|
+
{
|
|
545
|
+
console.error(`Panel minSize (${minSize}) cannot be greater than defaultSize (${defaultSize})`);
|
|
546
|
+
}
|
|
547
|
+
panelData.current.defaultSize = minSize;
|
|
548
|
+
} else if (maxSize != null && defaultSize > maxSize) {
|
|
549
|
+
{
|
|
550
|
+
console.error(`Panel maxSize (${maxSize}) cannot be less than defaultSize (${defaultSize})`);
|
|
551
|
+
}
|
|
552
|
+
panelData.current.defaultSize = maxSize;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
function validatePanelGroupLayout({
|
|
557
|
+
groupId,
|
|
558
|
+
panels,
|
|
559
|
+
nextSizes,
|
|
560
|
+
prevSizes,
|
|
561
|
+
units
|
|
562
|
+
}) {
|
|
563
|
+
// Clone because this method modifies
|
|
564
|
+
nextSizes = [...nextSizes];
|
|
565
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
566
|
+
const groupSizePixels = units === "pixels" ? getAvailableGroupSizePixels(groupId) : NaN;
|
|
567
|
+
let remainingSize = 0;
|
|
568
|
+
|
|
569
|
+
// First, check all of the proposed sizes against the min/max constraints
|
|
570
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
571
|
+
const panel = panelsArray[index];
|
|
572
|
+
const prevSize = prevSizes[index];
|
|
573
|
+
const nextSize = nextSizes[index];
|
|
574
|
+
const safeNextSize = safeResizePanel(units, groupSizePixels, panel, prevSize, nextSize);
|
|
575
|
+
if (nextSize != safeNextSize) {
|
|
576
|
+
remainingSize += nextSize - safeNextSize;
|
|
577
|
+
nextSizes[index] = safeNextSize;
|
|
578
|
+
{
|
|
579
|
+
console.error(`Invalid size (${nextSize}) specified for Panel "${panel.current.id}" given the panel's min/max size constraints`);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// If there is additional, left over space, assign it to any panel(s) that permits it
|
|
585
|
+
// (It's not worth taking multiple additional passes to evenly distribute)
|
|
586
|
+
if (remainingSize.toFixed(3) !== "0.000") {
|
|
587
|
+
for (let index = 0; index < panelsArray.length; index++) {
|
|
588
|
+
const panel = panelsArray[index];
|
|
589
|
+
let {
|
|
590
|
+
maxSize,
|
|
591
|
+
minSize
|
|
592
|
+
} = panel.current;
|
|
593
|
+
if (units === "pixels") {
|
|
594
|
+
minSize = minSize / groupSizePixels * 100;
|
|
595
|
+
if (maxSize != null) {
|
|
596
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
const size = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSizes[index] + remainingSize));
|
|
600
|
+
if (size !== nextSizes[index]) {
|
|
601
|
+
remainingSize -= size - nextSizes[index];
|
|
602
|
+
nextSizes[index] = size;
|
|
603
|
+
|
|
604
|
+
// Fuzzy comparison to account for imprecise floating point math
|
|
605
|
+
if (Math.abs(remainingSize).toFixed(3) === "0.000") {
|
|
606
|
+
break;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// If we still have remainder, the requested layout wasn't valid and we should warn about it
|
|
613
|
+
if (remainingSize.toFixed(3) !== "0.000") {
|
|
614
|
+
{
|
|
615
|
+
console.error(`"Invalid panel group configuration; default panel sizes should total 100% but was ${100 - remainingSize}%`);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
return nextSizes;
|
|
408
619
|
}
|
|
409
620
|
|
|
410
621
|
function assert(expectedCondition, message = "Assertion failed!") {
|
|
@@ -430,6 +641,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
430
641
|
panels
|
|
431
642
|
} = committedValuesRef.current;
|
|
432
643
|
const groupElement = getPanelGroup(groupId);
|
|
644
|
+
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
433
645
|
const {
|
|
434
646
|
height,
|
|
435
647
|
width
|
|
@@ -442,23 +654,28 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
442
654
|
if (idBefore == null || idAfter == null) {
|
|
443
655
|
return () => {};
|
|
444
656
|
}
|
|
445
|
-
let
|
|
446
|
-
let
|
|
657
|
+
let currentMinSize = 0;
|
|
658
|
+
let currentMaxSize = 100;
|
|
447
659
|
let totalMinSize = 0;
|
|
448
660
|
let totalMaxSize = 0;
|
|
449
661
|
|
|
450
662
|
// A panel's effective min/max sizes also need to account for other panel's sizes.
|
|
451
663
|
panelsArray.forEach(panelData => {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
664
|
+
const {
|
|
665
|
+
id,
|
|
666
|
+
maxSize,
|
|
667
|
+
minSize
|
|
668
|
+
} = panelData.current;
|
|
669
|
+
if (id === idBefore) {
|
|
670
|
+
currentMinSize = minSize;
|
|
671
|
+
currentMaxSize = maxSize != null ? maxSize : 100;
|
|
455
672
|
} else {
|
|
456
|
-
totalMinSize +=
|
|
457
|
-
totalMaxSize +=
|
|
673
|
+
totalMinSize += minSize;
|
|
674
|
+
totalMaxSize += maxSize != null ? maxSize : 100;
|
|
458
675
|
}
|
|
459
676
|
});
|
|
460
|
-
const ariaValueMax = Math.min(
|
|
461
|
-
const ariaValueMin = Math.max(
|
|
677
|
+
const ariaValueMax = Math.min(currentMaxSize, 100 - totalMinSize);
|
|
678
|
+
const ariaValueMin = Math.max(currentMinSize, (panelsArray.length - 1) * 100 - totalMaxSize);
|
|
462
679
|
const flexGrow = getFlexGrow(panels, idBefore, sizes);
|
|
463
680
|
handle.setAttribute("aria-valuemax", "" + Math.round(ariaValueMax));
|
|
464
681
|
handle.setAttribute("aria-valuemin", "" + Math.round(ariaValueMin));
|
|
@@ -482,7 +699,7 @@ function useWindowSplitterPanelGroupBehavior({
|
|
|
482
699
|
} else {
|
|
483
700
|
delta = -(direction === "horizontal" ? width : height);
|
|
484
701
|
}
|
|
485
|
-
const nextSizes = adjustByDelta(event,
|
|
702
|
+
const nextSizes = adjustByDelta(event, committedValuesRef.current, idBefore, idAfter, delta, sizes, panelSizeBeforeCollapse.current, null);
|
|
486
703
|
if (sizes !== nextSizes) {
|
|
487
704
|
setSizes(nextSizes);
|
|
488
705
|
}
|
|
@@ -754,13 +971,6 @@ function savePanelGroupLayout(autoSaveId, panels, sizes, storage) {
|
|
|
754
971
|
}
|
|
755
972
|
}
|
|
756
973
|
|
|
757
|
-
function isServerRendering() {
|
|
758
|
-
try {
|
|
759
|
-
return typeof window === undefined;
|
|
760
|
-
} catch (error) {}
|
|
761
|
-
return true;
|
|
762
|
-
}
|
|
763
|
-
|
|
764
974
|
const debounceMap = {};
|
|
765
975
|
|
|
766
976
|
// PanelGroup might be rendering in a server-side environment where localStorage is not available
|
|
@@ -804,9 +1014,6 @@ const defaultStorage = {
|
|
|
804
1014
|
// * dragHandleRect, sizes:
|
|
805
1015
|
// When resizing is done via mouse/touch event– some initial state is stored
|
|
806
1016
|
// so that any panels that contract will also expand if drag direction is reversed.
|
|
807
|
-
// TODO
|
|
808
|
-
// Within an active drag, remember original positions to refine more easily on expand.
|
|
809
|
-
// Look at what the Chrome devtools Sources does.
|
|
810
1017
|
function PanelGroupWithForwardedRef({
|
|
811
1018
|
autoSaveId,
|
|
812
1019
|
children = null,
|
|
@@ -818,7 +1025,8 @@ function PanelGroupWithForwardedRef({
|
|
|
818
1025
|
onLayout,
|
|
819
1026
|
storage = defaultStorage,
|
|
820
1027
|
style: styleFromProps = {},
|
|
821
|
-
tagName: Type = "div"
|
|
1028
|
+
tagName: Type = "div",
|
|
1029
|
+
units = "percentages"
|
|
822
1030
|
}) {
|
|
823
1031
|
const groupId = useUniqueId(idFromProps);
|
|
824
1032
|
const [activeHandleId, setActiveHandleId] = useState(null);
|
|
@@ -828,6 +1036,12 @@ function PanelGroupWithForwardedRef({
|
|
|
828
1036
|
// We store the initial Panel sizes in this ref, and apply move deltas to them instead of to the current sizes.
|
|
829
1037
|
// This has the benefit of causing force-collapsed panels to spring back open if drag is reversed.
|
|
830
1038
|
const initialDragStateRef = useRef(null);
|
|
1039
|
+
const devWarningsRef = useRef({
|
|
1040
|
+
didLogDefaultSizeWarning: false,
|
|
1041
|
+
didLogIdAndOrderWarning: false,
|
|
1042
|
+
didLogInvalidLayoutWarning: false,
|
|
1043
|
+
prevPanelIds: []
|
|
1044
|
+
});
|
|
831
1045
|
|
|
832
1046
|
// Use a ref to guard against users passing inline props
|
|
833
1047
|
const callbacksRef = useRef({
|
|
@@ -848,32 +1062,58 @@ function PanelGroupWithForwardedRef({
|
|
|
848
1062
|
// Store committed values to avoid unnecessarily re-running memoization/effects functions.
|
|
849
1063
|
const committedValuesRef = useRef({
|
|
850
1064
|
direction,
|
|
1065
|
+
id: groupId,
|
|
851
1066
|
panels,
|
|
852
|
-
sizes
|
|
1067
|
+
sizes,
|
|
1068
|
+
units
|
|
853
1069
|
});
|
|
854
1070
|
useImperativeHandle(forwardedRef, () => ({
|
|
855
|
-
|
|
1071
|
+
getId: () => groupId,
|
|
1072
|
+
getLayout: unitsFromParams => {
|
|
856
1073
|
const {
|
|
857
|
-
sizes
|
|
1074
|
+
sizes,
|
|
1075
|
+
units: unitsFromProps
|
|
858
1076
|
} = committedValuesRef.current;
|
|
859
|
-
|
|
1077
|
+
const units = unitsFromParams ?? unitsFromProps;
|
|
1078
|
+
if (units === "pixels") {
|
|
1079
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1080
|
+
return sizes.map(size => size / 100 * groupSizePixels);
|
|
1081
|
+
} else {
|
|
1082
|
+
return sizes;
|
|
1083
|
+
}
|
|
860
1084
|
},
|
|
861
|
-
setLayout: sizes => {
|
|
862
|
-
const total = sizes.reduce((accumulated, current) => accumulated + current, 0);
|
|
863
|
-
assert(total === 100, "Panel sizes must add up to 100%");
|
|
1085
|
+
setLayout: (sizes, unitsFromParams) => {
|
|
864
1086
|
const {
|
|
865
|
-
|
|
1087
|
+
id: groupId,
|
|
1088
|
+
panels,
|
|
1089
|
+
sizes: prevSizes,
|
|
1090
|
+
units
|
|
866
1091
|
} = committedValuesRef.current;
|
|
1092
|
+
if ((unitsFromParams || units) === "pixels") {
|
|
1093
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1094
|
+
sizes = sizes.map(size => size / groupSizePixels * 100);
|
|
1095
|
+
}
|
|
867
1096
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
868
1097
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
869
|
-
|
|
870
|
-
|
|
1098
|
+
const nextSizes = validatePanelGroupLayout({
|
|
1099
|
+
groupId,
|
|
1100
|
+
panels,
|
|
1101
|
+
nextSizes: sizes,
|
|
1102
|
+
prevSizes,
|
|
1103
|
+
units
|
|
1104
|
+
});
|
|
1105
|
+
if (!areEqual(prevSizes, nextSizes)) {
|
|
1106
|
+
setSizes(nextSizes);
|
|
1107
|
+
callPanelCallbacks(panelsArray, nextSizes, panelIdToLastNotifiedSizeMap);
|
|
1108
|
+
}
|
|
871
1109
|
}
|
|
872
|
-
}), []);
|
|
1110
|
+
}), [groupId]);
|
|
873
1111
|
useIsomorphicLayoutEffect(() => {
|
|
874
1112
|
committedValuesRef.current.direction = direction;
|
|
1113
|
+
committedValuesRef.current.id = groupId;
|
|
875
1114
|
committedValuesRef.current.panels = panels;
|
|
876
1115
|
committedValuesRef.current.sizes = sizes;
|
|
1116
|
+
committedValuesRef.current.units = units;
|
|
877
1117
|
});
|
|
878
1118
|
useWindowSplitterPanelGroupBehavior({
|
|
879
1119
|
committedValuesRef,
|
|
@@ -915,7 +1155,11 @@ function PanelGroupWithForwardedRef({
|
|
|
915
1155
|
// Compute the initial sizes based on default weights.
|
|
916
1156
|
// This assumes that panels register during initial mount (no conditional rendering)!
|
|
917
1157
|
useIsomorphicLayoutEffect(() => {
|
|
918
|
-
const
|
|
1158
|
+
const {
|
|
1159
|
+
id: groupId,
|
|
1160
|
+
sizes,
|
|
1161
|
+
units
|
|
1162
|
+
} = committedValuesRef.current;
|
|
919
1163
|
if (sizes.length === panels.size) {
|
|
920
1164
|
// Only compute (or restore) default sizes once per panel configuration.
|
|
921
1165
|
return;
|
|
@@ -929,39 +1173,23 @@ function PanelGroupWithForwardedRef({
|
|
|
929
1173
|
defaultSizes = loadPanelLayout(autoSaveId, panelsArray, storage);
|
|
930
1174
|
}
|
|
931
1175
|
if (defaultSizes != null) {
|
|
932
|
-
|
|
1176
|
+
// Validate saved sizes in case something has changed since last render
|
|
1177
|
+
// e.g. for pixel groups, this could be the size of the window
|
|
1178
|
+
const validatedSizes = validatePanelGroupLayout({
|
|
1179
|
+
groupId,
|
|
1180
|
+
panels,
|
|
1181
|
+
nextSizes: defaultSizes,
|
|
1182
|
+
prevSizes: defaultSizes,
|
|
1183
|
+
units
|
|
1184
|
+
});
|
|
1185
|
+
setSizes(validatedSizes);
|
|
933
1186
|
} else {
|
|
934
|
-
const
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
// TODO
|
|
940
|
-
// Implicit default size calculations below do not account for inferred min/max size values.
|
|
941
|
-
// e.g. if Panel A has a maxSize of 40 then Panels A and B can't both have an implicit default size of 50.
|
|
942
|
-
// For now, these logic edge cases are left to the user to handle via props.
|
|
943
|
-
|
|
944
|
-
panelsArray.forEach(panel => {
|
|
945
|
-
totalMinSize += panel.current.minSize;
|
|
946
|
-
if (panel.current.defaultSize === null) {
|
|
947
|
-
panelsWithNullDefaultSize++;
|
|
948
|
-
} else {
|
|
949
|
-
totalDefaultSize += panel.current.defaultSize;
|
|
950
|
-
}
|
|
1187
|
+
const sizes = calculateDefaultLayout({
|
|
1188
|
+
groupId,
|
|
1189
|
+
panels,
|
|
1190
|
+
units
|
|
951
1191
|
});
|
|
952
|
-
|
|
953
|
-
throw new Error(`Default panel sizes cannot exceed 100%`);
|
|
954
|
-
} else if (panelsArray.length > 1 && panelsWithNullDefaultSize === 0 && totalDefaultSize !== 100) {
|
|
955
|
-
throw new Error(`Invalid default sizes specified for panels`);
|
|
956
|
-
} else if (totalMinSize > 100) {
|
|
957
|
-
throw new Error(`Minimum panel sizes cannot exceed 100%`);
|
|
958
|
-
}
|
|
959
|
-
setSizes(panelsArray.map(panel => {
|
|
960
|
-
if (panel.current.defaultSize === null) {
|
|
961
|
-
return (100 - totalDefaultSize) / panelsWithNullDefaultSize;
|
|
962
|
-
}
|
|
963
|
-
return panel.current.defaultSize;
|
|
964
|
-
}));
|
|
1192
|
+
setSizes(sizes);
|
|
965
1193
|
}
|
|
966
1194
|
}, [autoSaveId, panels, storage]);
|
|
967
1195
|
useEffect(() => {
|
|
@@ -978,7 +1206,69 @@ function PanelGroupWithForwardedRef({
|
|
|
978
1206
|
}
|
|
979
1207
|
debounceMap[autoSaveId](autoSaveId, panelsArray, sizes, storage);
|
|
980
1208
|
}
|
|
1209
|
+
{
|
|
1210
|
+
const {
|
|
1211
|
+
didLogIdAndOrderWarning,
|
|
1212
|
+
prevPanelIds
|
|
1213
|
+
} = devWarningsRef.current;
|
|
1214
|
+
if (!didLogIdAndOrderWarning) {
|
|
1215
|
+
const {
|
|
1216
|
+
panels
|
|
1217
|
+
} = committedValuesRef.current;
|
|
1218
|
+
const panelIds = Array.from(panels.keys());
|
|
1219
|
+
devWarningsRef.current.prevPanelIds = panelIds;
|
|
1220
|
+
const panelsHaveChanged = prevPanelIds.length > 0 && !areEqual(prevPanelIds, panelIds);
|
|
1221
|
+
if (panelsHaveChanged) {
|
|
1222
|
+
if (Array.from(panels.values()).find(panel => panel.current.idWasAutoGenerated || panel.current.order == null)) {
|
|
1223
|
+
devWarningsRef.current.didLogIdAndOrderWarning = true;
|
|
1224
|
+
console.warn(`WARNING: Panel id and order props recommended when panels are dynamically rendered`);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
981
1229
|
}, [autoSaveId, panels, sizes, storage]);
|
|
1230
|
+
useIsomorphicLayoutEffect(() => {
|
|
1231
|
+
// Pixel panel constraints need to be reassessed after a group resize
|
|
1232
|
+
// We can avoid the ResizeObserver overhead for relative layouts
|
|
1233
|
+
if (units === "pixels") {
|
|
1234
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
1235
|
+
const {
|
|
1236
|
+
panels,
|
|
1237
|
+
sizes: prevSizes
|
|
1238
|
+
} = committedValuesRef.current;
|
|
1239
|
+
const nextSizes = validatePanelGroupLayout({
|
|
1240
|
+
groupId,
|
|
1241
|
+
panels,
|
|
1242
|
+
nextSizes: prevSizes,
|
|
1243
|
+
prevSizes,
|
|
1244
|
+
units
|
|
1245
|
+
});
|
|
1246
|
+
if (!areEqual(prevSizes, nextSizes)) {
|
|
1247
|
+
setSizes(nextSizes);
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
resizeObserver.observe(getPanelGroup(groupId));
|
|
1251
|
+
return () => {
|
|
1252
|
+
resizeObserver.disconnect();
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
}, [groupId, units]);
|
|
1256
|
+
const getPanelSize = useCallback((id, unitsFromParams) => {
|
|
1257
|
+
const {
|
|
1258
|
+
panels,
|
|
1259
|
+
units: unitsFromProps
|
|
1260
|
+
} = committedValuesRef.current;
|
|
1261
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
1262
|
+
const index = panelsArray.findIndex(panel => panel.current.id === id);
|
|
1263
|
+
const size = sizes[index];
|
|
1264
|
+
const units = unitsFromParams ?? unitsFromProps;
|
|
1265
|
+
if (units === "pixels") {
|
|
1266
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1267
|
+
return size / 100 * groupSizePixels;
|
|
1268
|
+
} else {
|
|
1269
|
+
return size;
|
|
1270
|
+
}
|
|
1271
|
+
}, [groupId, sizes]);
|
|
982
1272
|
const getPanelStyle = useCallback((id, defaultSize) => {
|
|
983
1273
|
const {
|
|
984
1274
|
panels
|
|
@@ -989,8 +1279,11 @@ function PanelGroupWithForwardedRef({
|
|
|
989
1279
|
// At this point the best we can do is render everything with the same size.
|
|
990
1280
|
if (panels.size === 0) {
|
|
991
1281
|
{
|
|
992
|
-
if (
|
|
993
|
-
|
|
1282
|
+
if (!devWarningsRef.current.didLogDefaultSizeWarning) {
|
|
1283
|
+
if (!isBrowser && defaultSize == null) {
|
|
1284
|
+
devWarningsRef.current.didLogDefaultSizeWarning = true;
|
|
1285
|
+
console.warn(`WARNING: Panel defaultSize prop recommended to avoid layout shift after server rendering`);
|
|
1286
|
+
}
|
|
994
1287
|
}
|
|
995
1288
|
}
|
|
996
1289
|
return {
|
|
@@ -1014,6 +1307,10 @@ function PanelGroupWithForwardedRef({
|
|
|
1014
1307
|
};
|
|
1015
1308
|
}, [activeHandleId, disablePointerEventsDuringResize, sizes]);
|
|
1016
1309
|
const registerPanel = useCallback((id, panelRef) => {
|
|
1310
|
+
const {
|
|
1311
|
+
units
|
|
1312
|
+
} = committedValuesRef.current;
|
|
1313
|
+
validatePanelProps(units, panelRef);
|
|
1017
1314
|
setPanels(prevPanels => {
|
|
1018
1315
|
if (prevPanels.has(id)) {
|
|
1019
1316
|
return prevPanels;
|
|
@@ -1050,7 +1347,10 @@ function PanelGroupWithForwardedRef({
|
|
|
1050
1347
|
}
|
|
1051
1348
|
const size = isHorizontal ? rect.width : rect.height;
|
|
1052
1349
|
const delta = movement / size * 100;
|
|
1053
|
-
|
|
1350
|
+
|
|
1351
|
+
// If a validateLayout method has been provided
|
|
1352
|
+
// it's important to use it before updating the mouse cursor
|
|
1353
|
+
const nextSizes = adjustByDelta(event, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, initialDragStateRef.current);
|
|
1054
1354
|
const sizesChanged = !areEqual(prevSizes, nextSizes);
|
|
1055
1355
|
|
|
1056
1356
|
// Don't update cursor for resizes triggered by keyboard interactions.
|
|
@@ -1077,6 +1377,8 @@ function PanelGroupWithForwardedRef({
|
|
|
1077
1377
|
}
|
|
1078
1378
|
if (sizesChanged) {
|
|
1079
1379
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1380
|
+
|
|
1381
|
+
// It's okay to bypass in this case because we already validated above
|
|
1080
1382
|
setSizes(nextSizes);
|
|
1081
1383
|
|
|
1082
1384
|
// If resize change handlers have been declared, this is the time to call them.
|
|
@@ -1130,7 +1432,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1130
1432
|
}
|
|
1131
1433
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1132
1434
|
const delta = isLastPanel ? currentSize : collapsedSize - currentSize;
|
|
1133
|
-
const nextSizes = adjustByDelta(null,
|
|
1435
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1134
1436
|
if (prevSizes !== nextSizes) {
|
|
1135
1437
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1136
1438
|
setSizes(nextSizes);
|
|
@@ -1173,7 +1475,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1173
1475
|
}
|
|
1174
1476
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1175
1477
|
const delta = isLastPanel ? collapsedSize - sizeBeforeCollapse : sizeBeforeCollapse;
|
|
1176
|
-
const nextSizes = adjustByDelta(null,
|
|
1478
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1177
1479
|
if (prevSizes !== nextSizes) {
|
|
1178
1480
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1179
1481
|
setSizes(nextSizes);
|
|
@@ -1183,21 +1485,34 @@ function PanelGroupWithForwardedRef({
|
|
|
1183
1485
|
callPanelCallbacks(panelsArray, nextSizes, panelIdToLastNotifiedSizeMap);
|
|
1184
1486
|
}
|
|
1185
1487
|
}, []);
|
|
1186
|
-
const resizePanel = useCallback((id, nextSize) => {
|
|
1488
|
+
const resizePanel = useCallback((id, nextSize, unitsFromParams) => {
|
|
1187
1489
|
const {
|
|
1490
|
+
id: groupId,
|
|
1188
1491
|
panels,
|
|
1189
|
-
sizes: prevSizes
|
|
1492
|
+
sizes: prevSizes,
|
|
1493
|
+
units
|
|
1190
1494
|
} = committedValuesRef.current;
|
|
1495
|
+
if ((unitsFromParams || units) === "pixels") {
|
|
1496
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1497
|
+
nextSize = nextSize / groupSizePixels * 100;
|
|
1498
|
+
}
|
|
1191
1499
|
const panel = panels.get(id);
|
|
1192
1500
|
if (panel == null) {
|
|
1193
1501
|
return;
|
|
1194
1502
|
}
|
|
1195
|
-
|
|
1503
|
+
let {
|
|
1196
1504
|
collapsedSize,
|
|
1197
1505
|
collapsible,
|
|
1198
1506
|
maxSize,
|
|
1199
1507
|
minSize
|
|
1200
1508
|
} = panel.current;
|
|
1509
|
+
if (units === "pixels") {
|
|
1510
|
+
const groupSizePixels = getAvailableGroupSizePixels(groupId);
|
|
1511
|
+
minSize = minSize / groupSizePixels * 100;
|
|
1512
|
+
if (maxSize != null) {
|
|
1513
|
+
maxSize = maxSize / groupSizePixels * 100;
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1201
1516
|
const panelsArray = panelsMapToSortedArray(panels);
|
|
1202
1517
|
const index = panelsArray.indexOf(panel);
|
|
1203
1518
|
if (index < 0) {
|
|
@@ -1208,7 +1523,13 @@ function PanelGroupWithForwardedRef({
|
|
|
1208
1523
|
return;
|
|
1209
1524
|
}
|
|
1210
1525
|
if (collapsible && nextSize === collapsedSize) ; else {
|
|
1211
|
-
|
|
1526
|
+
const unsafeNextSize = nextSize;
|
|
1527
|
+
nextSize = Math.min(maxSize != null ? maxSize : 100, Math.max(minSize, nextSize));
|
|
1528
|
+
{
|
|
1529
|
+
if (unsafeNextSize !== nextSize) {
|
|
1530
|
+
console.error(`Invalid size (${unsafeNextSize}) specified for Panel "${panel.current.id}" given the panel's min/max size constraints`);
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1212
1533
|
}
|
|
1213
1534
|
const [idBefore, idAfter] = getBeforeAndAfterIds(id, panelsArray);
|
|
1214
1535
|
if (idBefore == null || idAfter == null) {
|
|
@@ -1216,7 +1537,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1216
1537
|
}
|
|
1217
1538
|
const isLastPanel = index === panelsArray.length - 1;
|
|
1218
1539
|
const delta = isLastPanel ? currentSize - nextSize : nextSize - currentSize;
|
|
1219
|
-
const nextSizes = adjustByDelta(null,
|
|
1540
|
+
const nextSizes = adjustByDelta(null, committedValuesRef.current, idBefore, idAfter, delta, prevSizes, panelSizeBeforeCollapse.current, null);
|
|
1220
1541
|
if (prevSizes !== nextSizes) {
|
|
1221
1542
|
const panelIdToLastNotifiedSizeMap = panelIdToLastNotifiedSizeMapRef.current;
|
|
1222
1543
|
setSizes(nextSizes);
|
|
@@ -1231,6 +1552,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1231
1552
|
collapsePanel,
|
|
1232
1553
|
direction,
|
|
1233
1554
|
expandPanel,
|
|
1555
|
+
getPanelSize,
|
|
1234
1556
|
getPanelStyle,
|
|
1235
1557
|
groupId,
|
|
1236
1558
|
registerPanel,
|
|
@@ -1252,8 +1574,9 @@ function PanelGroupWithForwardedRef({
|
|
|
1252
1574
|
setActiveHandleId(null);
|
|
1253
1575
|
initialDragStateRef.current = null;
|
|
1254
1576
|
},
|
|
1577
|
+
units,
|
|
1255
1578
|
unregisterPanel
|
|
1256
|
-
}), [activeHandleId, collapsePanel, direction, expandPanel, getPanelStyle, groupId, registerPanel, registerResizeHandle, resizePanel, unregisterPanel]);
|
|
1579
|
+
}), [activeHandleId, collapsePanel, direction, expandPanel, getPanelSize, getPanelStyle, groupId, registerPanel, registerResizeHandle, resizePanel, units, unregisterPanel]);
|
|
1257
1580
|
const style = {
|
|
1258
1581
|
display: "flex",
|
|
1259
1582
|
flexDirection: direction === "horizontal" ? "row" : "column",
|
|
@@ -1268,6 +1591,7 @@ function PanelGroupWithForwardedRef({
|
|
|
1268
1591
|
"data-panel-group": "",
|
|
1269
1592
|
"data-panel-group-direction": direction,
|
|
1270
1593
|
"data-panel-group-id": groupId,
|
|
1594
|
+
"data-panel-group-units": units,
|
|
1271
1595
|
style: {
|
|
1272
1596
|
...style,
|
|
1273
1597
|
...styleFromProps
|
|
@@ -1280,10 +1604,6 @@ const PanelGroup = forwardRef((props, ref) => createElement(PanelGroupWithForwar
|
|
|
1280
1604
|
...props,
|
|
1281
1605
|
forwardedRef: ref
|
|
1282
1606
|
}));
|
|
1283
|
-
|
|
1284
|
-
// Workaround for Parcel scope hoisting (which renames objects/functions).
|
|
1285
|
-
// Casting to :any is required to avoid corrupting the generated TypeScript types.
|
|
1286
|
-
// See github.com/parcel-bundler/parcel/issues/8724
|
|
1287
1607
|
PanelGroupWithForwardedRef.displayName = "PanelGroup";
|
|
1288
1608
|
PanelGroup.displayName = "forwardRef(PanelGroup)";
|
|
1289
1609
|
|
|
@@ -1419,10 +1739,6 @@ function PanelResizeHandle({
|
|
|
1419
1739
|
tabIndex: 0
|
|
1420
1740
|
});
|
|
1421
1741
|
}
|
|
1422
|
-
|
|
1423
|
-
// Workaround for Parcel scope hoisting (which renames objects/functions).
|
|
1424
|
-
// Casting to :any is required to avoid corrupting the generated TypeScript types.
|
|
1425
|
-
// See github.com/parcel-bundler/parcel/issues/8724
|
|
1426
1742
|
PanelResizeHandle.displayName = "PanelResizeHandle";
|
|
1427
1743
|
|
|
1428
|
-
export { Panel, PanelGroup, PanelResizeHandle };
|
|
1744
|
+
export { Panel, PanelGroup, PanelResizeHandle, getAvailableGroupSizePixels };
|