-
Notifications
You must be signed in to change notification settings - Fork 3.5k
/
resizeView.tsx
99 lines (96 loc) · 3.76 KB
/
resizeView.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { GlassPane } from './glassPane';
import { useMeasure } from '../uiUtils';
const fillStyle: React.CSSProperties = {
position: 'absolute',
top: 0,
right: 0,
bottom: 0,
left: 0,
};
export const ResizeView: React.FC<{
orientation: 'horizontal' | 'vertical',
offsets: number[],
setOffsets: (offsets: number[]) => void,
resizerColor: string,
resizerWidth: number,
minColumnWidth?: number,
}> = ({ orientation, offsets, setOffsets, resizerColor, resizerWidth, minColumnWidth }) => {
const minGap = minColumnWidth || 0;
const [resizing, setResizing] = React.useState<{ clientX: number, clientY: number, offset: number, index: number } | null>(null);
const [measure, ref] = useMeasure<HTMLDivElement>();
const dividerStyle: React.CSSProperties = {
position: 'absolute',
right: orientation === 'horizontal' ? undefined : 0,
bottom: orientation === 'horizontal' ? 0 : undefined,
width: orientation === 'horizontal' ? 7 : undefined,
height: orientation === 'horizontal' ? undefined : 7,
borderTopWidth: orientation === 'horizontal' ? undefined : (7 - resizerWidth) / 2,
borderRightWidth: orientation === 'horizontal' ? (7 - resizerWidth) / 2 : undefined,
borderBottomWidth: orientation === 'horizontal' ? undefined : (7 - resizerWidth) / 2,
borderLeftWidth: orientation === 'horizontal' ? (7 - resizerWidth) / 2 : undefined,
borderColor: 'transparent',
borderStyle: 'solid',
cursor: orientation === 'horizontal' ? 'ew-resize' : 'ns-resize',
};
return <div
style={{
position: 'absolute',
top: 0,
right: 0,
bottom: 0,
left: -(7 - resizerWidth) / 2,
zIndex: 100, // Above the content, but below the film strip hover.
pointerEvents: 'none',
}}
ref={ref}>
{!!resizing && <GlassPane
cursor={orientation === 'horizontal' ? 'ew-resize' : 'ns-resize'}
onPaneMouseUp={() => setResizing(null)}
onPaneMouseMove={event => {
if (!event.buttons) {
setResizing(null);
} else if (resizing) {
const delta = orientation === 'horizontal' ? event.clientX - resizing.clientX : event.clientY - resizing.clientY;
const newOffset = resizing.offset + delta;
const previous = resizing.index > 0 ? offsets[resizing.index - 1] : 0;
const next = orientation === 'horizontal' ? measure.width : measure.height;
const constrainedDelta = Math.min(Math.max(previous + minGap, newOffset), next - minGap) - offsets[resizing.index];
for (let i = resizing.index; i < offsets.length; ++i)
offsets[i] = offsets[i] + constrainedDelta;
setOffsets([...offsets]);
}
}}
/>}
{offsets.map((offset, index) => {
return <div
style={{
...dividerStyle,
top: orientation === 'horizontal' ? 0 : offset,
left: orientation === 'horizontal' ? offset : 0,
pointerEvents: 'initial',
}}
onMouseDown={event => setResizing({ clientX: event.clientX, clientY: event.clientY, offset, index })}>
<div style={{
...fillStyle,
background: resizerColor,
}}></div>
</div>;
})}
</div>;
};