react-resizable-panels 0.0.2 → 0.0.3
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 +10 -0
- package/README.md +3 -5
- package/dist/react-resizable-panels.d.ts +8 -9
- package/dist/react-resizable-panels.d.ts.map +1 -1
- package/dist/react-resizable-panels.js +125 -73
- package/dist/react-resizable-panels.js.map +1 -1
- package/dist/react-resizable-panels.module.js +123 -71
- package/dist/react-resizable-panels.module.js.map +1 -1
- package/package.json +4 -12
- package/src/Panel.tsx +20 -7
- package/src/PanelContexts.ts +5 -4
- package/src/PanelGroup.tsx +136 -61
- package/src/PanelResizeHandle.tsx +12 -7
- package/src/index.ts +1 -1
- package/src/types.ts +2 -4
- package/.proxyrc +0 -8
- package/dist/index.8be10522.js +0 -28334
- package/dist/index.8be10522.js.map +0 -1
- package/dist/index.d85b50e4.css +0 -95
- package/dist/index.d85b50e4.css.map +0 -1
- package/dist/index.html +0 -9
- package/tsconfig.json +0 -6
- package/website/demo.tsx +0 -140
- package/website/index.html +0 -9
- package/website/index.tsx +0 -12
- package/website/root.css +0 -15
- package/website/styles.module.css +0 -77
package/src/PanelGroup.tsx
CHANGED
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
} from "react";
|
|
11
11
|
|
|
12
12
|
import { PanelGroupContext } from "./PanelContexts";
|
|
13
|
-
import { Direction,
|
|
13
|
+
import { Direction, PanelData } from "./types";
|
|
14
14
|
|
|
15
15
|
type Props = {
|
|
16
16
|
autoSaveId?: string;
|
|
17
|
-
children
|
|
17
|
+
children?: ReactNode[];
|
|
18
18
|
className?: string;
|
|
19
19
|
direction: Direction;
|
|
20
20
|
height: number;
|
|
@@ -27,8 +27,15 @@ const PRECISION = 5;
|
|
|
27
27
|
// Within an active drag, remember original positions to refine more easily on expand.
|
|
28
28
|
// Look at what the Chrome devtools Sources does.
|
|
29
29
|
|
|
30
|
-
export default function PanelGroup({
|
|
31
|
-
|
|
30
|
+
export default function PanelGroup({
|
|
31
|
+
autoSaveId,
|
|
32
|
+
children = null,
|
|
33
|
+
className = "",
|
|
34
|
+
direction,
|
|
35
|
+
height,
|
|
36
|
+
width,
|
|
37
|
+
}: Props) {
|
|
38
|
+
const [panels, setPanels] = useState<Map<string, PanelData>>(new Map());
|
|
32
39
|
|
|
33
40
|
// 0-1 values representing the relative size of each panel.
|
|
34
41
|
const [sizes, setSizes] = useState<number[]>([]);
|
|
@@ -37,17 +44,20 @@ export default function PanelGroup({ autoSaveId, children, className = "", direc
|
|
|
37
44
|
const committedValuesRef = useRef<{
|
|
38
45
|
direction: Direction;
|
|
39
46
|
height: number;
|
|
47
|
+
panels: Map<string, PanelData>;
|
|
40
48
|
sizes: number[];
|
|
41
49
|
width: number;
|
|
42
50
|
}>({
|
|
43
51
|
direction,
|
|
44
52
|
height,
|
|
53
|
+
panels,
|
|
45
54
|
sizes,
|
|
46
55
|
width,
|
|
47
56
|
});
|
|
48
57
|
useLayoutEffect(() => {
|
|
49
58
|
committedValuesRef.current.direction = direction;
|
|
50
59
|
committedValuesRef.current.height = height;
|
|
60
|
+
committedValuesRef.current.panels = panels;
|
|
51
61
|
committedValuesRef.current.sizes = sizes;
|
|
52
62
|
committedValuesRef.current.width = width;
|
|
53
63
|
});
|
|
@@ -56,45 +66,57 @@ export default function PanelGroup({ autoSaveId, children, className = "", direc
|
|
|
56
66
|
// Compute the initial sizes based on default weights.
|
|
57
67
|
// This assumes that panels register during initial mount (no conditional rendering)!
|
|
58
68
|
useLayoutEffect(() => {
|
|
59
|
-
const panels = panelsRef.current;
|
|
60
69
|
const sizes = committedValuesRef.current.sizes;
|
|
61
|
-
if (sizes.length === panels.
|
|
70
|
+
if (sizes.length === panels.size) {
|
|
62
71
|
return;
|
|
63
72
|
}
|
|
64
73
|
|
|
74
|
+
// TODO [panels]
|
|
75
|
+
// Validate that the total minSize is <= 1.
|
|
76
|
+
|
|
65
77
|
// If this panel has been configured to persist sizing information,
|
|
66
78
|
// default size should be restored from local storage if possible.
|
|
67
79
|
let defaultSizes: number[] | undefined = undefined;
|
|
68
80
|
if (autoSaveId) {
|
|
69
81
|
try {
|
|
70
|
-
const value = localStorage.getItem(
|
|
82
|
+
const value = localStorage.getItem(
|
|
83
|
+
createLocalStorageKey(autoSaveId, panels)
|
|
84
|
+
);
|
|
71
85
|
if (value) {
|
|
72
86
|
defaultSizes = JSON.parse(value);
|
|
73
87
|
}
|
|
74
88
|
} catch (error) {}
|
|
75
89
|
}
|
|
76
90
|
|
|
77
|
-
if (
|
|
91
|
+
if (defaultSizes != null) {
|
|
78
92
|
setSizes(defaultSizes);
|
|
79
93
|
} else {
|
|
80
|
-
const
|
|
94
|
+
const panelsArray: PanelData[] = Array.from(panels.values());
|
|
95
|
+
const totalWeight = panelsArray.reduce((weight, panel) => {
|
|
81
96
|
return weight + panel.defaultSize;
|
|
82
97
|
}, 0);
|
|
83
98
|
|
|
84
|
-
setSizes(
|
|
99
|
+
setSizes(panelsArray.map((panel) => panel.defaultSize / totalWeight));
|
|
85
100
|
}
|
|
86
|
-
}, [autoSaveId]);
|
|
101
|
+
}, [autoSaveId, panels]);
|
|
87
102
|
|
|
88
103
|
useEffect(() => {
|
|
89
|
-
if (autoSaveId
|
|
104
|
+
if (autoSaveId) {
|
|
105
|
+
if (sizes.length === 0 || sizes.length !== panels.size) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
90
109
|
// If this panel has been configured to persist sizing information, save sizes to local storage.
|
|
91
|
-
localStorage.setItem(
|
|
110
|
+
localStorage.setItem(
|
|
111
|
+
createLocalStorageKey(autoSaveId, panels),
|
|
112
|
+
JSON.stringify(sizes)
|
|
113
|
+
);
|
|
92
114
|
}
|
|
93
|
-
}, [autoSaveId, sizes]);
|
|
115
|
+
}, [autoSaveId, panels, sizes]);
|
|
94
116
|
|
|
95
117
|
const getPanelStyle = useCallback(
|
|
96
|
-
(id:
|
|
97
|
-
const panels =
|
|
118
|
+
(id: string): CSSProperties => {
|
|
119
|
+
const { panels } = committedValuesRef.current;
|
|
98
120
|
|
|
99
121
|
const offset = getOffset(panels, id, direction, sizes, height, width);
|
|
100
122
|
const size = getSize(panels, id, direction, sizes, height, width);
|
|
@@ -120,31 +142,64 @@ export default function PanelGroup({ autoSaveId, children, className = "", direc
|
|
|
120
142
|
[direction, height, sizes, width]
|
|
121
143
|
);
|
|
122
144
|
|
|
123
|
-
const registerPanel = useCallback((id:
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
panels.push(panel);
|
|
130
|
-
}, []);
|
|
145
|
+
const registerPanel = useCallback((id: string, panel: PanelData) => {
|
|
146
|
+
setPanels((prevPanels) => {
|
|
147
|
+
if (prevPanels.has(id)) {
|
|
148
|
+
return prevPanels;
|
|
149
|
+
}
|
|
131
150
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
event.preventDefault();
|
|
151
|
+
const nextPanels = new Map(prevPanels);
|
|
152
|
+
nextPanels.set(id, panel);
|
|
135
153
|
|
|
136
|
-
|
|
137
|
-
|
|
154
|
+
return nextPanels;
|
|
155
|
+
});
|
|
156
|
+
}, []);
|
|
138
157
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
158
|
+
const registerResizeHandle = useCallback(
|
|
159
|
+
(idBefore: string, idAfter: string) => {
|
|
160
|
+
return (event: MouseEvent) => {
|
|
161
|
+
event.preventDefault();
|
|
162
|
+
|
|
163
|
+
const {
|
|
164
|
+
direction,
|
|
165
|
+
height,
|
|
166
|
+
panels,
|
|
167
|
+
sizes: prevSizes,
|
|
168
|
+
width,
|
|
169
|
+
} = committedValuesRef.current;
|
|
170
|
+
|
|
171
|
+
const isHorizontal = direction === "horizontal";
|
|
172
|
+
const movement = isHorizontal ? event.movementX : event.movementY;
|
|
173
|
+
const delta = isHorizontal ? movement / width : movement / height;
|
|
174
|
+
|
|
175
|
+
const nextSizes = adjustByDelta(
|
|
176
|
+
panels,
|
|
177
|
+
idBefore,
|
|
178
|
+
idAfter,
|
|
179
|
+
delta,
|
|
180
|
+
prevSizes
|
|
181
|
+
);
|
|
182
|
+
if (prevSizes !== nextSizes) {
|
|
183
|
+
setSizes(nextSizes);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
142
186
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
187
|
+
// TODO [issues/5] Add to Map
|
|
188
|
+
},
|
|
189
|
+
[]
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
const unregisterPanel = useCallback((id: string) => {
|
|
193
|
+
setPanels((prevPanels) => {
|
|
194
|
+
if (!prevPanels.has(id)) {
|
|
195
|
+
return prevPanels;
|
|
146
196
|
}
|
|
147
|
-
|
|
197
|
+
|
|
198
|
+
const nextPanels = new Map(prevPanels);
|
|
199
|
+
nextPanels.delete(id);
|
|
200
|
+
|
|
201
|
+
return nextPanels;
|
|
202
|
+
});
|
|
148
203
|
}, []);
|
|
149
204
|
|
|
150
205
|
const context = useMemo(
|
|
@@ -153,23 +208,28 @@ export default function PanelGroup({ autoSaveId, children, className = "", direc
|
|
|
153
208
|
getPanelStyle,
|
|
154
209
|
registerPanel,
|
|
155
210
|
registerResizeHandle,
|
|
211
|
+
unregisterPanel,
|
|
156
212
|
}),
|
|
157
|
-
[
|
|
213
|
+
[
|
|
214
|
+
direction,
|
|
215
|
+
getPanelStyle,
|
|
216
|
+
registerPanel,
|
|
217
|
+
registerResizeHandle,
|
|
218
|
+
unregisterPanel,
|
|
219
|
+
]
|
|
158
220
|
);
|
|
159
221
|
|
|
160
222
|
return (
|
|
161
223
|
<PanelGroupContext.Provider value={context}>
|
|
162
|
-
<div className={className}>
|
|
163
|
-
{children}
|
|
164
|
-
</div>
|
|
224
|
+
<div className={className}>{children}</div>
|
|
165
225
|
</PanelGroupContext.Provider>
|
|
166
226
|
);
|
|
167
227
|
}
|
|
168
228
|
|
|
169
229
|
function adjustByDelta(
|
|
170
|
-
panels:
|
|
171
|
-
idBefore:
|
|
172
|
-
idAfter:
|
|
230
|
+
panels: Map<string, PanelData>,
|
|
231
|
+
idBefore: string,
|
|
232
|
+
idAfter: string,
|
|
173
233
|
delta: number,
|
|
174
234
|
prevSizes: number[]
|
|
175
235
|
): number[] {
|
|
@@ -177,6 +237,8 @@ function adjustByDelta(
|
|
|
177
237
|
return prevSizes;
|
|
178
238
|
}
|
|
179
239
|
|
|
240
|
+
const panelsArray: PanelData[] = Array.from(panels.values());
|
|
241
|
+
|
|
180
242
|
const nextSizes = prevSizes.concat();
|
|
181
243
|
|
|
182
244
|
let deltaApplied = 0;
|
|
@@ -189,9 +251,9 @@ function adjustByDelta(
|
|
|
189
251
|
// A positive delta means the panel immediately before the resizer should "expand".
|
|
190
252
|
// This is accomplished by shrinking/contracting (and shifting) one or more of the panels after the resizer.
|
|
191
253
|
let pivotId = delta < 0 ? idBefore : idAfter;
|
|
192
|
-
let index =
|
|
254
|
+
let index = panelsArray.findIndex((panel) => panel.id === pivotId);
|
|
193
255
|
while (true) {
|
|
194
|
-
const panel =
|
|
256
|
+
const panel = panelsArray[index];
|
|
195
257
|
const prevSize = prevSizes[index];
|
|
196
258
|
const nextSize = Math.max(prevSize - Math.abs(delta), panel.minSize);
|
|
197
259
|
if (prevSize !== nextSize) {
|
|
@@ -209,7 +271,7 @@ function adjustByDelta(
|
|
|
209
271
|
break;
|
|
210
272
|
}
|
|
211
273
|
} else {
|
|
212
|
-
if (++index >=
|
|
274
|
+
if (++index >= panelsArray.length) {
|
|
213
275
|
break;
|
|
214
276
|
}
|
|
215
277
|
}
|
|
@@ -223,21 +285,32 @@ function adjustByDelta(
|
|
|
223
285
|
|
|
224
286
|
// Adjust the pivot panel before, but only by the amount that surrounding panels were able to shrink/contract.
|
|
225
287
|
pivotId = delta < 0 ? idAfter : idBefore;
|
|
226
|
-
index =
|
|
288
|
+
index = panelsArray.findIndex((panel) => panel.id === pivotId);
|
|
227
289
|
nextSizes[index] = prevSizes[index] + deltaApplied;
|
|
228
290
|
|
|
229
291
|
return nextSizes;
|
|
230
292
|
}
|
|
231
293
|
|
|
294
|
+
function createLocalStorageKey(
|
|
295
|
+
autoSaveId: string,
|
|
296
|
+
panels: Map<string, PanelData>
|
|
297
|
+
): string {
|
|
298
|
+
const panelIds = Array.from(panels.keys()).sort();
|
|
299
|
+
|
|
300
|
+
return `PanelGroup:sizes:${autoSaveId}${panelIds.join("|")}`;
|
|
301
|
+
}
|
|
302
|
+
|
|
232
303
|
function getOffset(
|
|
233
|
-
panels:
|
|
234
|
-
id:
|
|
304
|
+
panels: Map<string, PanelData>,
|
|
305
|
+
id: string,
|
|
235
306
|
direction: Direction,
|
|
236
307
|
sizes: number[],
|
|
237
308
|
height: number,
|
|
238
309
|
width: number
|
|
239
310
|
): number {
|
|
240
|
-
|
|
311
|
+
const panelsArray: PanelData[] = Array.from(panels.values());
|
|
312
|
+
|
|
313
|
+
let index = panelsArray.findIndex((panel) => panel.id === id);
|
|
241
314
|
if (index < 0) {
|
|
242
315
|
return 0;
|
|
243
316
|
}
|
|
@@ -245,7 +318,7 @@ function getOffset(
|
|
|
245
318
|
let scaledOffset = 0;
|
|
246
319
|
|
|
247
320
|
for (index = index - 1; index >= 0; index--) {
|
|
248
|
-
const panel =
|
|
321
|
+
const panel = panelsArray[index];
|
|
249
322
|
scaledOffset += getSize(panels, panel.id, direction, sizes, height, width);
|
|
250
323
|
}
|
|
251
324
|
|
|
@@ -253,24 +326,26 @@ function getOffset(
|
|
|
253
326
|
}
|
|
254
327
|
|
|
255
328
|
function getSize(
|
|
256
|
-
panels:
|
|
257
|
-
id:
|
|
329
|
+
panels: Map<string, PanelData>,
|
|
330
|
+
id: string,
|
|
258
331
|
direction: Direction,
|
|
259
332
|
sizes: number[],
|
|
260
333
|
height: number,
|
|
261
334
|
width: number
|
|
262
335
|
): number {
|
|
263
|
-
const
|
|
336
|
+
const totalSize = direction === "horizontal" ? width : height;
|
|
337
|
+
|
|
338
|
+
if (panels.size === 1) {
|
|
339
|
+
return totalSize;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const panelsArray: PanelData[] = Array.from(panels.values());
|
|
343
|
+
|
|
344
|
+
const index = panelsArray.findIndex((panel) => panel.id === id);
|
|
264
345
|
const size = sizes[index];
|
|
265
346
|
if (size == null) {
|
|
266
347
|
return 0;
|
|
267
348
|
}
|
|
268
349
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if (panels.length === 1) {
|
|
272
|
-
return totalSize;
|
|
273
|
-
} else {
|
|
274
|
-
return Math.round(size * totalSize);
|
|
275
|
-
}
|
|
350
|
+
return Math.round(size * totalSize);
|
|
276
351
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ReactNode, useContext, useEffect, useState } from "react";
|
|
2
2
|
|
|
3
3
|
import { PanelGroupContext } from "./PanelContexts";
|
|
4
|
-
import {
|
|
4
|
+
import { ResizeHandler } from "./types";
|
|
5
5
|
|
|
6
6
|
export default function PanelResizeHandle({
|
|
7
7
|
children = null,
|
|
@@ -13,17 +13,21 @@ export default function PanelResizeHandle({
|
|
|
13
13
|
children?: ReactNode;
|
|
14
14
|
className?: string;
|
|
15
15
|
disabled?: boolean;
|
|
16
|
-
panelAfter:
|
|
17
|
-
panelBefore:
|
|
16
|
+
panelAfter: string;
|
|
17
|
+
panelBefore: string;
|
|
18
18
|
}) {
|
|
19
19
|
const context = useContext(PanelGroupContext);
|
|
20
20
|
if (context === null) {
|
|
21
|
-
throw Error(
|
|
21
|
+
throw Error(
|
|
22
|
+
`PanelResizeHandle components must be rendered within a PanelGroup container`
|
|
23
|
+
);
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
const { direction, registerResizeHandle } = context;
|
|
25
27
|
|
|
26
|
-
const [resizeHandler, setResizeHandler] = useState<ResizeHandler | null>(
|
|
28
|
+
const [resizeHandler, setResizeHandler] = useState<ResizeHandler | null>(
|
|
29
|
+
null
|
|
30
|
+
);
|
|
27
31
|
const [isDragging, setIsDragging] = useState(false);
|
|
28
32
|
|
|
29
33
|
useEffect(() => {
|
|
@@ -39,7 +43,8 @@ export default function PanelResizeHandle({
|
|
|
39
43
|
return;
|
|
40
44
|
}
|
|
41
45
|
|
|
42
|
-
document.body.style.cursor =
|
|
46
|
+
document.body.style.cursor =
|
|
47
|
+
direction === "horizontal" ? "ew-resize" : "ns-resize";
|
|
43
48
|
|
|
44
49
|
const onMouseLeave = (_: MouseEvent) => {
|
|
45
50
|
setIsDragging(false);
|
|
@@ -72,7 +77,7 @@ export default function PanelResizeHandle({
|
|
|
72
77
|
onMouseDown={() => setIsDragging(true)}
|
|
73
78
|
onMouseUp={() => setIsDragging(false)}
|
|
74
79
|
style={{
|
|
75
|
-
cursor: direction ===
|
|
80
|
+
cursor: direction === "horizontal" ? "ew-resize" : "ns-resize",
|
|
76
81
|
}}
|
|
77
82
|
>
|
|
78
83
|
{children}
|
package/src/index.ts
CHANGED
package/src/types.ts
CHANGED