react-resizable-panels 0.0.22 → 0.0.24
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 +8 -0
- package/README.md +12 -10
- package/dist/react-resizable-panels.d.ts +32 -7
- package/dist/react-resizable-panels.d.ts.map +1 -1
- package/dist/react-resizable-panels.js +103 -54
- package/dist/react-resizable-panels.js.map +1 -1
- package/dist/react-resizable-panels.module.js +102 -53
- package/dist/react-resizable-panels.module.js.map +1 -1
- package/package.json +1 -1
- package/src/{Panel.tsx → Panel.ts} +58 -40
- package/src/{PanelGroup.tsx → PanelGroup.ts} +54 -23
- package/src/{PanelResizeHandle.tsx → PanelResizeHandle.ts} +44 -44
- package/src/hooks/useWindowSplitterBehavior.ts +19 -7
- package/src/types.ts +6 -0
- package/src/utils/coordinates.ts +2 -10
- package/src/utils/group.ts +31 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
createElement,
|
|
2
3
|
CSSProperties,
|
|
3
4
|
ElementType,
|
|
4
5
|
MouseEvent,
|
|
@@ -16,6 +17,15 @@ import { useWindowSplitterResizeHandlerBehavior } from "./hooks/useWindowSplitte
|
|
|
16
17
|
import { PanelGroupContext } from "./PanelContexts";
|
|
17
18
|
import type { ResizeHandler, ResizeEvent } from "./types";
|
|
18
19
|
|
|
20
|
+
export type PanelResizeHandleProps = {
|
|
21
|
+
children?: ReactNode;
|
|
22
|
+
className?: string;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
id?: string | null;
|
|
25
|
+
style?: CSSProperties;
|
|
26
|
+
tagName?: ElementType;
|
|
27
|
+
};
|
|
28
|
+
|
|
19
29
|
export default function PanelResizeHandle({
|
|
20
30
|
children = null,
|
|
21
31
|
className: classNameFromProps = "",
|
|
@@ -23,14 +33,7 @@ export default function PanelResizeHandle({
|
|
|
23
33
|
id: idFromProps = null,
|
|
24
34
|
style: styleFromProps = {},
|
|
25
35
|
tagName: Type = "div",
|
|
26
|
-
}: {
|
|
27
|
-
children?: ReactNode;
|
|
28
|
-
className?: string;
|
|
29
|
-
disabled?: boolean;
|
|
30
|
-
id?: string | null;
|
|
31
|
-
style?: CSSProperties;
|
|
32
|
-
tagName?: ElementType;
|
|
33
|
-
}) {
|
|
36
|
+
}: PanelResizeHandleProps) {
|
|
34
37
|
const divElementRef = useRef<HTMLDivElement>(null);
|
|
35
38
|
|
|
36
39
|
const panelGroupContext = useContext(PanelGroupContext);
|
|
@@ -89,19 +92,19 @@ export default function PanelResizeHandle({
|
|
|
89
92
|
};
|
|
90
93
|
|
|
91
94
|
document.body.addEventListener("contextmenu", stopDraggingAndBlur);
|
|
92
|
-
document.body.addEventListener("mouseleave", stopDraggingAndBlur);
|
|
93
95
|
document.body.addEventListener("mousemove", onMove);
|
|
94
96
|
document.body.addEventListener("touchmove", onMove);
|
|
95
|
-
|
|
97
|
+
window.addEventListener("mouseup", stopDraggingAndBlur);
|
|
98
|
+
window.addEventListener("touchend", stopDraggingAndBlur);
|
|
96
99
|
|
|
97
100
|
return () => {
|
|
98
101
|
document.body.style.cursor = "";
|
|
99
102
|
|
|
100
103
|
document.body.removeEventListener("contextmenu", stopDraggingAndBlur);
|
|
101
|
-
document.body.removeEventListener("mouseleave", stopDraggingAndBlur);
|
|
102
104
|
document.body.removeEventListener("mousemove", onMove);
|
|
103
105
|
document.body.removeEventListener("touchmove", onMove);
|
|
104
|
-
|
|
106
|
+
window.removeEventListener("mouseup", stopDraggingAndBlur);
|
|
107
|
+
window.removeEventListener("touchend", stopDraggingAndBlur);
|
|
105
108
|
};
|
|
106
109
|
}, [direction, disabled, isDragging, resizeHandler, stopDraggingAndBlur]);
|
|
107
110
|
|
|
@@ -117,38 +120,35 @@ export default function PanelResizeHandle({
|
|
|
117
120
|
userSelect: "none",
|
|
118
121
|
};
|
|
119
122
|
|
|
120
|
-
return (
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
{children}
|
|
150
|
-
</Type>
|
|
151
|
-
);
|
|
123
|
+
return createElement(Type, {
|
|
124
|
+
children,
|
|
125
|
+
className: classNameFromProps,
|
|
126
|
+
"data-resize-handle-active": isDragging
|
|
127
|
+
? "pointer"
|
|
128
|
+
: isFocused
|
|
129
|
+
? "keyboard"
|
|
130
|
+
: undefined,
|
|
131
|
+
"data-panel-group-direction": direction,
|
|
132
|
+
"data-panel-group-id": groupId,
|
|
133
|
+
"data-panel-resize-handle-enabled": !disabled,
|
|
134
|
+
"data-panel-resize-handle-id": resizeHandleId,
|
|
135
|
+
onBlur: () => setIsFocused(false),
|
|
136
|
+
onFocus: () => setIsFocused(true),
|
|
137
|
+
onMouseDown: (event: MouseEvent) =>
|
|
138
|
+
startDragging(resizeHandleId, event.nativeEvent),
|
|
139
|
+
onMouseUp: stopDraggingAndBlur,
|
|
140
|
+
onTouchCancel: stopDraggingAndBlur,
|
|
141
|
+
onTouchEnd: stopDraggingAndBlur,
|
|
142
|
+
onTouchStart: (event: TouchEvent) =>
|
|
143
|
+
startDragging(resizeHandleId, event.nativeEvent),
|
|
144
|
+
ref: divElementRef,
|
|
145
|
+
role: "separator",
|
|
146
|
+
style: {
|
|
147
|
+
...style,
|
|
148
|
+
...styleFromProps,
|
|
149
|
+
},
|
|
150
|
+
tabIndex: 0,
|
|
151
|
+
});
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
// Workaround for Parcel scope hoisting (which renames objects/functions).
|
|
@@ -51,15 +51,27 @@ export function useWindowSplitterPanelGroupBehavior({
|
|
|
51
51
|
return () => {};
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
let minSize = 0;
|
|
55
|
+
let maxSize = 100;
|
|
56
|
+
let totalMinSize = 0;
|
|
57
|
+
let totalMaxSize = 0;
|
|
58
|
+
|
|
59
|
+
// A panel's effective min/max sizes also need to account for other panel's sizes.
|
|
60
|
+
panelsArray.forEach((panelData) => {
|
|
61
|
+
if (panelData.id === idBefore) {
|
|
62
|
+
maxSize = panelData.maxSize;
|
|
63
|
+
minSize = panelData.minSize;
|
|
64
|
+
} else {
|
|
65
|
+
totalMinSize += panelData.minSize;
|
|
66
|
+
totalMaxSize += panelData.maxSize;
|
|
57
67
|
}
|
|
58
|
-
|
|
59
|
-
}, 100);
|
|
68
|
+
});
|
|
60
69
|
|
|
61
|
-
const
|
|
62
|
-
|
|
70
|
+
const ariaValueMax = Math.min(maxSize, 100 - totalMinSize);
|
|
71
|
+
const ariaValueMin = Math.max(
|
|
72
|
+
minSize,
|
|
73
|
+
(panelsArray.length - 1) * 100 - totalMaxSize
|
|
74
|
+
);
|
|
63
75
|
|
|
64
76
|
const flexGrow = getFlexGrow(panels, idBefore, sizes);
|
|
65
77
|
|
package/src/types.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
import { RefObject } from "react";
|
|
2
|
+
|
|
1
3
|
export type Direction = "horizontal" | "vertical";
|
|
2
4
|
|
|
5
|
+
export type PanelOnResize = (size: number) => void;
|
|
6
|
+
|
|
3
7
|
export type PanelData = {
|
|
4
8
|
defaultSize: number;
|
|
5
9
|
id: string;
|
|
10
|
+
maxSize: number;
|
|
6
11
|
minSize: number;
|
|
12
|
+
onResizeRef: RefObject<PanelOnResize | null>;
|
|
7
13
|
order: number | null;
|
|
8
14
|
};
|
|
9
15
|
|
package/src/utils/coordinates.ts
CHANGED
|
@@ -64,17 +64,9 @@ export function getMovement(
|
|
|
64
64
|
case "ArrowUp":
|
|
65
65
|
return isHorizontal ? 0 : -delta;
|
|
66
66
|
case "End":
|
|
67
|
-
|
|
68
|
-
return size;
|
|
69
|
-
} else {
|
|
70
|
-
return size;
|
|
71
|
-
}
|
|
67
|
+
return size;
|
|
72
68
|
case "Home":
|
|
73
|
-
|
|
74
|
-
return -size;
|
|
75
|
-
} else {
|
|
76
|
-
return -size;
|
|
77
|
-
}
|
|
69
|
+
return -size;
|
|
78
70
|
}
|
|
79
71
|
} else {
|
|
80
72
|
return getDragOffset(event, handleId, direction, initialOffset);
|
package/src/utils/group.ts
CHANGED
|
@@ -25,12 +25,29 @@ export function adjustByDelta(
|
|
|
25
25
|
//
|
|
26
26
|
// A positive delta means the panel immediately before the resizer should "expand".
|
|
27
27
|
// This is accomplished by shrinking/contracting (and shifting) one or more of the panels after the resizer.
|
|
28
|
+
|
|
29
|
+
// Max-bounds check the panel being expanded first.
|
|
30
|
+
{
|
|
31
|
+
const pivotId = delta < 0 ? idAfter : idBefore;
|
|
32
|
+
const index = panelsArray.findIndex((panel) => panel.id === pivotId);
|
|
33
|
+
const panel = panelsArray[index];
|
|
34
|
+
const prevSize = prevSizes[index];
|
|
35
|
+
|
|
36
|
+
const nextSize = safeResizePanel(panel, Math.abs(delta), prevSize);
|
|
37
|
+
if (prevSize === nextSize) {
|
|
38
|
+
return prevSizes;
|
|
39
|
+
} else {
|
|
40
|
+
delta = delta < 0 ? prevSize - nextSize : nextSize - prevSize;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
28
44
|
let pivotId = delta < 0 ? idBefore : idAfter;
|
|
29
45
|
let index = panelsArray.findIndex((panel) => panel.id === pivotId);
|
|
30
46
|
while (true) {
|
|
31
47
|
const panel = panelsArray[index];
|
|
32
48
|
const prevSize = prevSizes[index];
|
|
33
|
-
|
|
49
|
+
|
|
50
|
+
const nextSize = safeResizePanel(panel, 0 - Math.abs(delta), prevSize);
|
|
34
51
|
if (prevSize !== nextSize) {
|
|
35
52
|
deltaApplied += prevSize - nextSize;
|
|
36
53
|
|
|
@@ -154,3 +171,16 @@ export function panelsMapToSortedArray(
|
|
|
154
171
|
): PanelData[] {
|
|
155
172
|
return Array.from(panels.values()).sort((a, b) => a.order - b.order);
|
|
156
173
|
}
|
|
174
|
+
|
|
175
|
+
function safeResizePanel(
|
|
176
|
+
panel: PanelData,
|
|
177
|
+
delta: number,
|
|
178
|
+
prevSize: number
|
|
179
|
+
): number {
|
|
180
|
+
const nextSizeUnsafe = prevSize + delta;
|
|
181
|
+
const nextSize = Math.min(
|
|
182
|
+
panel.maxSize,
|
|
183
|
+
Math.max(panel.minSize, nextSizeUnsafe)
|
|
184
|
+
);
|
|
185
|
+
return nextSize;
|
|
186
|
+
}
|