react-resizable-panels 0.0.28 → 0.0.29
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 +6 -0
- package/README.md +8 -0
- package/dist/react-resizable-panels.d.ts +12 -4
- package/dist/react-resizable-panels.d.ts.map +1 -1
- package/dist/react-resizable-panels.js +139 -24
- package/dist/react-resizable-panels.js.map +1 -1
- package/dist/react-resizable-panels.module.js +138 -23
- package/dist/react-resizable-panels.module.js.map +1 -1
- package/package.json +1 -1
- package/src/Panel.ts +42 -7
- package/src/PanelContexts.ts +3 -0
- package/src/PanelGroup.ts +157 -20
- package/src/PanelResizeHandle.ts +1 -1
- package/src/hooks/useIsomorphicEffect.ts +9 -2
- package/src/index.ts +18 -4
- package/src/utils/group.ts +46 -0
package/src/PanelGroup.ts
CHANGED
|
@@ -16,6 +16,8 @@ import { loadPanelLayout, savePanelGroupLayout } from "./utils/serialization";
|
|
|
16
16
|
import { getDragOffset, getMovement } from "./utils/coordinates";
|
|
17
17
|
import {
|
|
18
18
|
adjustByDelta,
|
|
19
|
+
callPanelCallbacks,
|
|
20
|
+
getBeforeAndAfterIds,
|
|
19
21
|
getFlexGrow,
|
|
20
22
|
getPanelGroup,
|
|
21
23
|
getResizeHandlePanelIds,
|
|
@@ -48,7 +50,7 @@ export type PanelGroupProps = {
|
|
|
48
50
|
tagName?: ElementType;
|
|
49
51
|
};
|
|
50
52
|
|
|
51
|
-
export
|
|
53
|
+
export function PanelGroup({
|
|
52
54
|
autoSaveId,
|
|
53
55
|
children = null,
|
|
54
56
|
className: classNameFromProps = "",
|
|
@@ -67,6 +69,9 @@ export default function PanelGroup({
|
|
|
67
69
|
|
|
68
70
|
const dragOffsetRef = useRef<number>(0);
|
|
69
71
|
|
|
72
|
+
// Used to support imperative collapse/expand API.
|
|
73
|
+
const panelSizeBeforeCollapse = useRef<Map<string, number>>(new Map());
|
|
74
|
+
|
|
70
75
|
// Store committed values to avoid unnecessarily re-running memoization/effects functions.
|
|
71
76
|
const committedValuesRef = useRef<CommittedValues>({
|
|
72
77
|
direction,
|
|
@@ -191,9 +196,13 @@ export default function PanelGroup({
|
|
|
191
196
|
|
|
192
197
|
// Without this, Panel sizes may be unintentionally overridden by their content.
|
|
193
198
|
overflow: "hidden",
|
|
199
|
+
|
|
200
|
+
// Disable pointer events inside of a panel during resize.
|
|
201
|
+
// This avoid edge cases like nested iframes.
|
|
202
|
+
pointerEvents: activeHandleId !== null ? "none" : undefined,
|
|
194
203
|
};
|
|
195
204
|
},
|
|
196
|
-
[direction, sizes]
|
|
205
|
+
[activeHandleId, direction, sizes]
|
|
197
206
|
);
|
|
198
207
|
|
|
199
208
|
const registerPanel = useCallback((id: string, panel: PanelData) => {
|
|
@@ -275,24 +284,7 @@ export default function PanelGroup({
|
|
|
275
284
|
setGlobalCursorStyle(isHorizontal ? "horizontal" : "vertical");
|
|
276
285
|
|
|
277
286
|
// If resize change handlers have been declared, this is the time to call them.
|
|
278
|
-
|
|
279
|
-
const prevSize = prevSizes[index];
|
|
280
|
-
if (prevSize !== nextSize) {
|
|
281
|
-
const { onCollapse, onResize } =
|
|
282
|
-
panelsArray[index].callbacksRef.current;
|
|
283
|
-
if (onResize) {
|
|
284
|
-
onResize(nextSize);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
if (onCollapse) {
|
|
288
|
-
if (prevSize === 0 && nextSize !== 0) {
|
|
289
|
-
onCollapse(false);
|
|
290
|
-
} else if (prevSize !== 0 && nextSize === 0) {
|
|
291
|
-
onCollapse(true);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
});
|
|
287
|
+
callPanelCallbacks(panelsArray, prevSizes, nextSizes);
|
|
296
288
|
|
|
297
289
|
setSizes(nextSizes);
|
|
298
290
|
}
|
|
@@ -316,14 +308,156 @@ export default function PanelGroup({
|
|
|
316
308
|
});
|
|
317
309
|
}, []);
|
|
318
310
|
|
|
311
|
+
const collapsePanel = useCallback((id: string) => {
|
|
312
|
+
const { panels, sizes: prevSizes } = committedValuesRef.current;
|
|
313
|
+
|
|
314
|
+
const panel = panels.get(id);
|
|
315
|
+
if (panel == null || !panel.collapsible) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
320
|
+
|
|
321
|
+
const index = panelsArray.indexOf(panel);
|
|
322
|
+
if (index < 0) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const currentSize = prevSizes[index];
|
|
327
|
+
if (currentSize === 0) {
|
|
328
|
+
// Panel is already collapsed.
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
panelSizeBeforeCollapse.current.set(id, currentSize);
|
|
333
|
+
|
|
334
|
+
const [idBefore, idAfter] = getBeforeAndAfterIds(id, panelsArray);
|
|
335
|
+
if (idBefore == null || idAfter == null) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const isLastPanel = index === panelsArray.length - 1;
|
|
340
|
+
const delta = isLastPanel ? currentSize : 0 - currentSize;
|
|
341
|
+
|
|
342
|
+
const nextSizes = adjustByDelta(
|
|
343
|
+
panels,
|
|
344
|
+
idBefore,
|
|
345
|
+
idAfter,
|
|
346
|
+
delta,
|
|
347
|
+
prevSizes
|
|
348
|
+
);
|
|
349
|
+
if (prevSizes !== nextSizes) {
|
|
350
|
+
// If resize change handlers have been declared, this is the time to call them.
|
|
351
|
+
callPanelCallbacks(panelsArray, prevSizes, nextSizes);
|
|
352
|
+
|
|
353
|
+
setSizes(nextSizes);
|
|
354
|
+
}
|
|
355
|
+
}, []);
|
|
356
|
+
|
|
357
|
+
const expandPanel = useCallback((id: string) => {
|
|
358
|
+
const { panels, sizes: prevSizes } = committedValuesRef.current;
|
|
359
|
+
|
|
360
|
+
const panel = panels.get(id);
|
|
361
|
+
if (panel == null) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const sizeBeforeCollapse =
|
|
366
|
+
panelSizeBeforeCollapse.current.get(id) || panel.minSize;
|
|
367
|
+
if (!sizeBeforeCollapse) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
372
|
+
|
|
373
|
+
const index = panelsArray.indexOf(panel);
|
|
374
|
+
if (index < 0) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const currentSize = prevSizes[index];
|
|
379
|
+
if (currentSize !== 0) {
|
|
380
|
+
// Panel is already expanded.
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const [idBefore, idAfter] = getBeforeAndAfterIds(id, panelsArray);
|
|
385
|
+
if (idBefore == null || idAfter == null) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const isLastPanel = index === panelsArray.length - 1;
|
|
390
|
+
const delta = isLastPanel ? 0 - sizeBeforeCollapse : sizeBeforeCollapse;
|
|
391
|
+
|
|
392
|
+
const nextSizes = adjustByDelta(
|
|
393
|
+
panels,
|
|
394
|
+
idBefore,
|
|
395
|
+
idAfter,
|
|
396
|
+
delta,
|
|
397
|
+
prevSizes
|
|
398
|
+
);
|
|
399
|
+
if (prevSizes !== nextSizes) {
|
|
400
|
+
// If resize change handlers have been declared, this is the time to call them.
|
|
401
|
+
callPanelCallbacks(panelsArray, prevSizes, nextSizes);
|
|
402
|
+
|
|
403
|
+
setSizes(nextSizes);
|
|
404
|
+
}
|
|
405
|
+
}, []);
|
|
406
|
+
|
|
407
|
+
const resizePanel = useCallback((id: string, nextSize: number) => {
|
|
408
|
+
const { panels, sizes: prevSizes } = committedValuesRef.current;
|
|
409
|
+
|
|
410
|
+
const panel = panels.get(id);
|
|
411
|
+
if (panel == null) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const panelsArray = panelsMapToSortedArray(panels);
|
|
416
|
+
|
|
417
|
+
const index = panelsArray.indexOf(panel);
|
|
418
|
+
if (index < 0) {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const currentSize = prevSizes[index];
|
|
423
|
+
if (currentSize === nextSize) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const [idBefore, idAfter] = getBeforeAndAfterIds(id, panelsArray);
|
|
428
|
+
if (idBefore == null || idAfter == null) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const isLastPanel = index === panelsArray.length - 1;
|
|
433
|
+
const delta = isLastPanel ? currentSize - nextSize : nextSize - currentSize;
|
|
434
|
+
|
|
435
|
+
const nextSizes = adjustByDelta(
|
|
436
|
+
panels,
|
|
437
|
+
idBefore,
|
|
438
|
+
idAfter,
|
|
439
|
+
delta,
|
|
440
|
+
prevSizes
|
|
441
|
+
);
|
|
442
|
+
if (prevSizes !== nextSizes) {
|
|
443
|
+
// If resize change handlers have been declared, this is the time to call them.
|
|
444
|
+
callPanelCallbacks(panelsArray, prevSizes, nextSizes);
|
|
445
|
+
|
|
446
|
+
setSizes(nextSizes);
|
|
447
|
+
}
|
|
448
|
+
}, []);
|
|
449
|
+
|
|
319
450
|
const context = useMemo(
|
|
320
451
|
() => ({
|
|
321
452
|
activeHandleId,
|
|
453
|
+
collapsePanel,
|
|
322
454
|
direction,
|
|
455
|
+
expandPanel,
|
|
323
456
|
getPanelStyle,
|
|
324
457
|
groupId,
|
|
325
458
|
registerPanel,
|
|
326
459
|
registerResizeHandle,
|
|
460
|
+
resizePanel,
|
|
327
461
|
startDragging: (id: string, event: ResizeEvent) => {
|
|
328
462
|
setActiveHandleId(id);
|
|
329
463
|
|
|
@@ -337,11 +471,14 @@ export default function PanelGroup({
|
|
|
337
471
|
}),
|
|
338
472
|
[
|
|
339
473
|
activeHandleId,
|
|
474
|
+
collapsePanel,
|
|
340
475
|
direction,
|
|
476
|
+
expandPanel,
|
|
341
477
|
getPanelStyle,
|
|
342
478
|
groupId,
|
|
343
479
|
registerPanel,
|
|
344
480
|
registerResizeHandle,
|
|
481
|
+
resizePanel,
|
|
345
482
|
unregisterPanel,
|
|
346
483
|
]
|
|
347
484
|
);
|
package/src/PanelResizeHandle.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { useEffect, useLayoutEffect } from "react";
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
typeof window !== "undefined"
|
|
3
|
+
const canUseEffectHooks = !!(
|
|
4
|
+
typeof window !== "undefined" &&
|
|
5
|
+
typeof window.document !== "undefined" &&
|
|
6
|
+
typeof window.document.createElement !== "undefined"
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
const useIsomorphicLayoutEffect = canUseEffectHooks
|
|
10
|
+
? useLayoutEffect
|
|
11
|
+
: () => {};
|
|
5
12
|
|
|
6
13
|
export default useIsomorphicLayoutEffect;
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
|
-
import Panel from "./Panel";
|
|
2
|
-
import PanelGroup from "./PanelGroup";
|
|
3
|
-
import PanelResizeHandle from "./PanelResizeHandle";
|
|
1
|
+
import { Panel } from "./Panel";
|
|
2
|
+
import { PanelGroup } from "./PanelGroup";
|
|
3
|
+
import { PanelResizeHandle } from "./PanelResizeHandle";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import type { ImperativePanelHandle, PanelProps } from "./Panel";
|
|
6
|
+
import type { PanelGroupProps } from "./PanelGroup";
|
|
7
|
+
import type { PanelResizeHandleProps } from "./PanelResizeHandle";
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
Panel,
|
|
11
|
+
PanelGroup,
|
|
12
|
+
PanelResizeHandle,
|
|
13
|
+
|
|
14
|
+
// TypeScript types
|
|
15
|
+
ImperativePanelHandle,
|
|
16
|
+
PanelGroupProps,
|
|
17
|
+
PanelProps,
|
|
18
|
+
PanelResizeHandleProps,
|
|
19
|
+
};
|
package/src/utils/group.ts
CHANGED
|
@@ -83,6 +83,52 @@ export function adjustByDelta(
|
|
|
83
83
|
return nextSizes;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
export function callPanelCallbacks(
|
|
87
|
+
panelsArray: PanelData[],
|
|
88
|
+
prevSizes: number[],
|
|
89
|
+
nextSizes: number[]
|
|
90
|
+
) {
|
|
91
|
+
nextSizes.forEach((nextSize, index) => {
|
|
92
|
+
const prevSize = prevSizes[index];
|
|
93
|
+
if (prevSize !== nextSize) {
|
|
94
|
+
const { callbacksRef } = panelsArray[index];
|
|
95
|
+
const { onCollapse, onResize } = callbacksRef.current;
|
|
96
|
+
|
|
97
|
+
if (onResize) {
|
|
98
|
+
onResize(nextSize);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (onCollapse) {
|
|
102
|
+
if (prevSize === 0 && nextSize !== 0) {
|
|
103
|
+
onCollapse(false);
|
|
104
|
+
} else if (prevSize !== 0 && nextSize === 0) {
|
|
105
|
+
onCollapse(true);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function getBeforeAndAfterIds(
|
|
113
|
+
id: string,
|
|
114
|
+
panelsArray: PanelData[]
|
|
115
|
+
): [idBefore: string | null, idAFter: string | null] {
|
|
116
|
+
if (panelsArray.length < 2) {
|
|
117
|
+
return [null, null];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const index = panelsArray.findIndex((panel) => panel.id === id);
|
|
121
|
+
if (index < 0) {
|
|
122
|
+
return [null, null];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const isLastPanel = index === panelsArray.length - 1;
|
|
126
|
+
const idBefore = isLastPanel ? panelsArray[index - 1].id : id;
|
|
127
|
+
const idAfter = isLastPanel ? id : panelsArray[index + 1].id;
|
|
128
|
+
|
|
129
|
+
return [idBefore, idAfter];
|
|
130
|
+
}
|
|
131
|
+
|
|
86
132
|
// This method returns a number between 1 and 100 representing
|
|
87
133
|
// the % of the group's overall space this panel should occupy.
|
|
88
134
|
export function getFlexGrow(
|