react-resizable-panels 1.0.10 → 2.0.1
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 +9 -0
- package/README.md +29 -104
- package/dist/declarations/src/PanelResizeHandle.d.ts +3 -1
- package/dist/declarations/src/PanelResizeHandleRegistry.d.ts +20 -0
- package/dist/react-resizable-panels.browser.cjs.js +362 -133
- package/dist/react-resizable-panels.browser.development.cjs.js +362 -133
- package/dist/react-resizable-panels.browser.development.esm.js +362 -133
- package/dist/react-resizable-panels.browser.esm.js +362 -133
- package/dist/react-resizable-panels.cjs.js +362 -133
- package/dist/react-resizable-panels.development.cjs.js +362 -133
- package/dist/react-resizable-panels.development.esm.js +362 -133
- package/dist/react-resizable-panels.development.node.cjs.js +362 -133
- package/dist/react-resizable-panels.development.node.esm.js +362 -133
- package/dist/react-resizable-panels.esm.js +362 -133
- package/dist/react-resizable-panels.node.cjs.js +362 -133
- package/dist/react-resizable-panels.node.esm.js +362 -133
- package/package.json +1 -1
- package/src/PanelGroup.ts +18 -10
- package/src/PanelResizeHandle.ts +64 -82
- package/src/PanelResizeHandleRegistry.ts +263 -0
- package/src/utils/calculateDragOffsetPercentage.ts +1 -1
- package/src/utils/cursor.ts +63 -33
- package/src/utils/events/getResizeEventCoordinates.ts +24 -0
- package/src/utils/events/getResizeEventCursorPosition.ts +14 -0
- package/src/utils/{events.ts → events/index.ts} +1 -1
- package/src/utils/getInputType.ts +5 -0
- package/src/utils/getResizeEventCursorPosition.ts +0 -21
package/src/PanelResizeHandle.ts
CHANGED
|
@@ -5,9 +5,6 @@ import {
|
|
|
5
5
|
HTMLAttributes,
|
|
6
6
|
PropsWithChildren,
|
|
7
7
|
ReactElement,
|
|
8
|
-
MouseEvent as ReactMouseEvent,
|
|
9
|
-
TouchEvent,
|
|
10
|
-
useCallback,
|
|
11
8
|
useContext,
|
|
12
9
|
useEffect,
|
|
13
10
|
useRef,
|
|
@@ -20,8 +17,13 @@ import {
|
|
|
20
17
|
ResizeEvent,
|
|
21
18
|
ResizeHandler,
|
|
22
19
|
} from "./PanelGroupContext";
|
|
20
|
+
import {
|
|
21
|
+
PointerHitAreaMargins,
|
|
22
|
+
registerResizeHandle,
|
|
23
|
+
ResizeHandlerAction,
|
|
24
|
+
ResizeHandlerState,
|
|
25
|
+
} from "./PanelResizeHandleRegistry";
|
|
23
26
|
import { assert } from "./utils/assert";
|
|
24
|
-
import { getCursorStyle } from "./utils/cursor";
|
|
25
27
|
|
|
26
28
|
export type PanelResizeHandleOnDragging = (isDragging: boolean) => void;
|
|
27
29
|
|
|
@@ -32,6 +34,7 @@ export type PanelResizeHandleProps = Omit<
|
|
|
32
34
|
PropsWithChildren<{
|
|
33
35
|
className?: string;
|
|
34
36
|
disabled?: boolean;
|
|
37
|
+
hitAreaMargins?: PointerHitAreaMargins;
|
|
35
38
|
id?: string | null;
|
|
36
39
|
onDragging?: PanelResizeHandleOnDragging;
|
|
37
40
|
style?: CSSProperties;
|
|
@@ -43,6 +46,7 @@ export function PanelResizeHandle({
|
|
|
43
46
|
children = null,
|
|
44
47
|
className: classNameFromProps = "",
|
|
45
48
|
disabled = false,
|
|
49
|
+
hitAreaMargins,
|
|
46
50
|
id: idFromProps,
|
|
47
51
|
onDragging,
|
|
48
52
|
style: styleFromProps = {},
|
|
@@ -69,16 +73,16 @@ export function PanelResizeHandle({
|
|
|
69
73
|
|
|
70
74
|
const {
|
|
71
75
|
direction,
|
|
72
|
-
dragState,
|
|
73
76
|
groupId,
|
|
74
|
-
registerResizeHandle,
|
|
77
|
+
registerResizeHandle: registerResizeHandleWithParentGroup,
|
|
75
78
|
startDragging,
|
|
76
79
|
stopDragging,
|
|
77
80
|
panelGroupElement,
|
|
78
81
|
} = panelGroupContext;
|
|
79
82
|
|
|
80
83
|
const resizeHandleId = useUniqueId(idFromProps);
|
|
81
|
-
|
|
84
|
+
|
|
85
|
+
const [state, setState] = useState<ResizeHandlerState>("inactive");
|
|
82
86
|
|
|
83
87
|
const [isFocused, setIsFocused] = useState(false);
|
|
84
88
|
|
|
@@ -86,67 +90,71 @@ export function PanelResizeHandle({
|
|
|
86
90
|
null
|
|
87
91
|
);
|
|
88
92
|
|
|
89
|
-
const stopDraggingAndBlur = useCallback(() => {
|
|
90
|
-
// Clicking on the drag handle shouldn't leave it focused;
|
|
91
|
-
// That would cause the PanelGroup to think it was still active.
|
|
92
|
-
const element = elementRef.current;
|
|
93
|
-
assert(element);
|
|
94
|
-
element.blur();
|
|
95
|
-
|
|
96
|
-
stopDragging();
|
|
97
|
-
|
|
98
|
-
const { onDragging } = callbacksRef.current;
|
|
99
|
-
if (onDragging) {
|
|
100
|
-
onDragging(false);
|
|
101
|
-
}
|
|
102
|
-
}, [stopDragging]);
|
|
103
|
-
|
|
104
93
|
useEffect(() => {
|
|
105
94
|
if (disabled) {
|
|
106
95
|
setResizeHandler(null);
|
|
107
96
|
} else {
|
|
108
|
-
const resizeHandler =
|
|
97
|
+
const resizeHandler = registerResizeHandleWithParentGroup(resizeHandleId);
|
|
109
98
|
setResizeHandler(() => resizeHandler);
|
|
110
99
|
}
|
|
111
|
-
}, [disabled, resizeHandleId,
|
|
100
|
+
}, [disabled, resizeHandleId, registerResizeHandleWithParentGroup]);
|
|
112
101
|
|
|
113
102
|
useEffect(() => {
|
|
114
|
-
if (disabled || resizeHandler == null
|
|
103
|
+
if (disabled || resizeHandler == null) {
|
|
115
104
|
return;
|
|
116
105
|
}
|
|
117
106
|
|
|
118
|
-
const onMove = (event: ResizeEvent) => {
|
|
119
|
-
resizeHandler(event);
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const onMouseLeave = (event: MouseEvent) => {
|
|
123
|
-
resizeHandler(event);
|
|
124
|
-
};
|
|
125
|
-
|
|
126
107
|
const element = elementRef.current;
|
|
127
108
|
assert(element);
|
|
128
109
|
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
110
|
+
const setResizeHandlerState = (
|
|
111
|
+
action: ResizeHandlerAction,
|
|
112
|
+
state: ResizeHandlerState,
|
|
113
|
+
event: ResizeEvent
|
|
114
|
+
) => {
|
|
115
|
+
setState(state);
|
|
116
|
+
|
|
117
|
+
switch (action) {
|
|
118
|
+
case "down": {
|
|
119
|
+
startDragging(resizeHandleId, event);
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
case "up": {
|
|
123
|
+
stopDragging();
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
switch (state) {
|
|
129
|
+
case "drag": {
|
|
130
|
+
resizeHandler(event);
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
148
134
|
};
|
|
149
|
-
|
|
135
|
+
|
|
136
|
+
return registerResizeHandle(
|
|
137
|
+
resizeHandleId,
|
|
138
|
+
element,
|
|
139
|
+
direction,
|
|
140
|
+
{
|
|
141
|
+
// Coarse inputs (e.g. finger/touch)
|
|
142
|
+
coarse: hitAreaMargins?.coarse ?? 15,
|
|
143
|
+
// Fine inputs (e.g. mouse)
|
|
144
|
+
fine: hitAreaMargins?.fine ?? 5,
|
|
145
|
+
},
|
|
146
|
+
setResizeHandlerState
|
|
147
|
+
);
|
|
148
|
+
}, [
|
|
149
|
+
direction,
|
|
150
|
+
disabled,
|
|
151
|
+
hitAreaMargins,
|
|
152
|
+
registerResizeHandleWithParentGroup,
|
|
153
|
+
resizeHandleId,
|
|
154
|
+
resizeHandler,
|
|
155
|
+
startDragging,
|
|
156
|
+
stopDragging,
|
|
157
|
+
]);
|
|
150
158
|
|
|
151
159
|
useWindowSplitterResizeHandlerBehavior({
|
|
152
160
|
disabled,
|
|
@@ -156,7 +164,6 @@ export function PanelResizeHandle({
|
|
|
156
164
|
});
|
|
157
165
|
|
|
158
166
|
const style: CSSProperties = {
|
|
159
|
-
cursor: getCursorStyle(direction),
|
|
160
167
|
touchAction: "none",
|
|
161
168
|
userSelect: "none",
|
|
162
169
|
};
|
|
@@ -168,29 +175,6 @@ export function PanelResizeHandle({
|
|
|
168
175
|
className: classNameFromProps,
|
|
169
176
|
onBlur: () => setIsFocused(false),
|
|
170
177
|
onFocus: () => setIsFocused(true),
|
|
171
|
-
onMouseDown: (event: ReactMouseEvent) => {
|
|
172
|
-
startDragging(resizeHandleId, event.nativeEvent);
|
|
173
|
-
|
|
174
|
-
const callbacks = callbacksRef.current;
|
|
175
|
-
assert(callbacks);
|
|
176
|
-
const { onDragging } = callbacks;
|
|
177
|
-
if (onDragging) {
|
|
178
|
-
onDragging(true);
|
|
179
|
-
}
|
|
180
|
-
},
|
|
181
|
-
onMouseUp: stopDraggingAndBlur,
|
|
182
|
-
onTouchCancel: stopDraggingAndBlur,
|
|
183
|
-
onTouchEnd: stopDraggingAndBlur,
|
|
184
|
-
onTouchStart: (event: TouchEvent) => {
|
|
185
|
-
startDragging(resizeHandleId, event.nativeEvent);
|
|
186
|
-
|
|
187
|
-
const callbacks = callbacksRef.current;
|
|
188
|
-
assert(callbacks);
|
|
189
|
-
const { onDragging } = callbacks;
|
|
190
|
-
if (onDragging) {
|
|
191
|
-
onDragging(true);
|
|
192
|
-
}
|
|
193
|
-
},
|
|
194
178
|
ref: elementRef,
|
|
195
179
|
role: "separator",
|
|
196
180
|
style: {
|
|
@@ -203,11 +187,9 @@ export function PanelResizeHandle({
|
|
|
203
187
|
"data-panel-group-direction": direction,
|
|
204
188
|
"data-panel-group-id": groupId,
|
|
205
189
|
"data-resize-handle": "",
|
|
206
|
-
"data-resize-handle-active":
|
|
207
|
-
? "pointer"
|
|
208
|
-
|
|
209
|
-
? "keyboard"
|
|
210
|
-
: undefined,
|
|
190
|
+
"data-resize-handle-active":
|
|
191
|
+
state === "drag" ? "pointer" : isFocused ? "keyboard" : undefined,
|
|
192
|
+
"data-resize-handle-state": state,
|
|
211
193
|
"data-panel-resize-handle-enabled": !disabled,
|
|
212
194
|
"data-panel-resize-handle-id": resizeHandleId,
|
|
213
195
|
});
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { Direction, ResizeEvent } from "./types";
|
|
2
|
+
import { resetGlobalCursorStyle, setGlobalCursorStyle } from "./utils/cursor";
|
|
3
|
+
import { getResizeEventCoordinates } from "./utils/events/getResizeEventCoordinates";
|
|
4
|
+
import { getInputType } from "./utils/getInputType";
|
|
5
|
+
|
|
6
|
+
export type ResizeHandlerAction = "down" | "move" | "up";
|
|
7
|
+
export type ResizeHandlerState = "drag" | "hover" | "inactive";
|
|
8
|
+
export type SetResizeHandlerState = (
|
|
9
|
+
action: ResizeHandlerAction,
|
|
10
|
+
state: ResizeHandlerState,
|
|
11
|
+
event: ResizeEvent
|
|
12
|
+
) => void;
|
|
13
|
+
|
|
14
|
+
export type PointerHitAreaMargins = {
|
|
15
|
+
coarse: number;
|
|
16
|
+
fine: number;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type ResizeHandlerData = {
|
|
20
|
+
direction: Direction;
|
|
21
|
+
element: HTMLElement;
|
|
22
|
+
hitAreaMargins: PointerHitAreaMargins;
|
|
23
|
+
setResizeHandlerState: SetResizeHandlerState;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const EXCEEDED_HORIZONTAL_MIN = 0b0001;
|
|
27
|
+
export const EXCEEDED_HORIZONTAL_MAX = 0b0010;
|
|
28
|
+
export const EXCEEDED_VERTICAL_MIN = 0b0100;
|
|
29
|
+
export const EXCEEDED_VERTICAL_MAX = 0b1000;
|
|
30
|
+
|
|
31
|
+
const isCoarsePointer = getInputType() === "coarse";
|
|
32
|
+
|
|
33
|
+
let intersectingHandles: ResizeHandlerData[] = [];
|
|
34
|
+
let isPointerDown = false;
|
|
35
|
+
let ownerDocumentCounts: Map<Document, number> = new Map();
|
|
36
|
+
let panelConstraintFlags: Map<string, number> = new Map();
|
|
37
|
+
|
|
38
|
+
const registeredResizeHandlers = new Set<ResizeHandlerData>();
|
|
39
|
+
|
|
40
|
+
export function registerResizeHandle(
|
|
41
|
+
resizeHandleId: string,
|
|
42
|
+
element: HTMLElement,
|
|
43
|
+
direction: Direction,
|
|
44
|
+
hitAreaMargins: PointerHitAreaMargins,
|
|
45
|
+
setResizeHandlerState: SetResizeHandlerState
|
|
46
|
+
) {
|
|
47
|
+
const { ownerDocument } = element;
|
|
48
|
+
|
|
49
|
+
const data: ResizeHandlerData = {
|
|
50
|
+
direction,
|
|
51
|
+
element,
|
|
52
|
+
hitAreaMargins,
|
|
53
|
+
setResizeHandlerState,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const count = ownerDocumentCounts.get(ownerDocument) ?? 0;
|
|
57
|
+
ownerDocumentCounts.set(ownerDocument, count + 1);
|
|
58
|
+
|
|
59
|
+
registeredResizeHandlers.add(data);
|
|
60
|
+
|
|
61
|
+
updateListeners();
|
|
62
|
+
|
|
63
|
+
return function unregisterResizeHandle() {
|
|
64
|
+
panelConstraintFlags.delete(resizeHandleId);
|
|
65
|
+
registeredResizeHandlers.delete(data);
|
|
66
|
+
|
|
67
|
+
const count = ownerDocumentCounts.get(ownerDocument) ?? 1;
|
|
68
|
+
ownerDocumentCounts.set(ownerDocument, count - 1);
|
|
69
|
+
|
|
70
|
+
updateListeners();
|
|
71
|
+
|
|
72
|
+
if (count === 1) {
|
|
73
|
+
ownerDocumentCounts.delete(ownerDocument);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function handlePointerDown(event: ResizeEvent) {
|
|
79
|
+
const { x, y } = getResizeEventCoordinates(event);
|
|
80
|
+
|
|
81
|
+
isPointerDown = true;
|
|
82
|
+
|
|
83
|
+
recalculateIntersectingHandles({ x, y });
|
|
84
|
+
updateListeners();
|
|
85
|
+
|
|
86
|
+
if (intersectingHandles.length > 0) {
|
|
87
|
+
updateResizeHandlerStates("down", event);
|
|
88
|
+
|
|
89
|
+
event.preventDefault();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function handlePointerMove(event: ResizeEvent) {
|
|
94
|
+
const { x, y } = getResizeEventCoordinates(event);
|
|
95
|
+
|
|
96
|
+
if (isPointerDown) {
|
|
97
|
+
intersectingHandles.forEach((data) => {
|
|
98
|
+
const { setResizeHandlerState } = data;
|
|
99
|
+
|
|
100
|
+
setResizeHandlerState("move", "drag", event);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Update cursor based on return value(s) from active handles
|
|
104
|
+
updateCursor();
|
|
105
|
+
} else {
|
|
106
|
+
recalculateIntersectingHandles({ x, y });
|
|
107
|
+
updateResizeHandlerStates("move", event);
|
|
108
|
+
updateCursor();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (intersectingHandles.length > 0) {
|
|
112
|
+
event.preventDefault();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function handlePointerUp(event: ResizeEvent) {
|
|
117
|
+
const { x, y } = getResizeEventCoordinates(event);
|
|
118
|
+
|
|
119
|
+
panelConstraintFlags.clear();
|
|
120
|
+
isPointerDown = false;
|
|
121
|
+
|
|
122
|
+
if (intersectingHandles.length > 0) {
|
|
123
|
+
event.preventDefault();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
recalculateIntersectingHandles({ x, y });
|
|
127
|
+
updateResizeHandlerStates("up", event);
|
|
128
|
+
updateCursor();
|
|
129
|
+
|
|
130
|
+
updateListeners();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function recalculateIntersectingHandles({ x, y }: { x: number; y: number }) {
|
|
134
|
+
intersectingHandles.splice(0);
|
|
135
|
+
|
|
136
|
+
registeredResizeHandlers.forEach((data) => {
|
|
137
|
+
const { element, hitAreaMargins } = data;
|
|
138
|
+
const { bottom, left, right, top } = element.getBoundingClientRect();
|
|
139
|
+
|
|
140
|
+
const margin = isCoarsePointer
|
|
141
|
+
? hitAreaMargins.coarse
|
|
142
|
+
: hitAreaMargins.fine;
|
|
143
|
+
|
|
144
|
+
const intersects =
|
|
145
|
+
x >= left - margin &&
|
|
146
|
+
x <= right + margin &&
|
|
147
|
+
y >= top - margin &&
|
|
148
|
+
y <= bottom + margin;
|
|
149
|
+
|
|
150
|
+
if (intersects) {
|
|
151
|
+
intersectingHandles.push(data);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function reportConstraintsViolation(
|
|
157
|
+
resizeHandleId: string,
|
|
158
|
+
flag: number
|
|
159
|
+
) {
|
|
160
|
+
panelConstraintFlags.set(resizeHandleId, flag);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function updateCursor() {
|
|
164
|
+
let intersectsHorizontal = false;
|
|
165
|
+
let intersectsVertical = false;
|
|
166
|
+
|
|
167
|
+
intersectingHandles.forEach((data) => {
|
|
168
|
+
const { direction } = data;
|
|
169
|
+
|
|
170
|
+
if (direction === "horizontal") {
|
|
171
|
+
intersectsHorizontal = true;
|
|
172
|
+
} else {
|
|
173
|
+
intersectsVertical = true;
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
let constraintFlags = 0;
|
|
178
|
+
panelConstraintFlags.forEach((flag) => {
|
|
179
|
+
constraintFlags |= flag;
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
if (intersectsHorizontal && intersectsVertical) {
|
|
183
|
+
setGlobalCursorStyle("intersection", constraintFlags);
|
|
184
|
+
} else if (intersectsHorizontal) {
|
|
185
|
+
setGlobalCursorStyle("horizontal", constraintFlags);
|
|
186
|
+
} else if (intersectsVertical) {
|
|
187
|
+
setGlobalCursorStyle("vertical", constraintFlags);
|
|
188
|
+
} else {
|
|
189
|
+
resetGlobalCursorStyle();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function updateListeners() {
|
|
194
|
+
ownerDocumentCounts.forEach((_, ownerDocument) => {
|
|
195
|
+
const { body } = ownerDocument;
|
|
196
|
+
|
|
197
|
+
body.removeEventListener("contextmenu", handlePointerUp);
|
|
198
|
+
body.removeEventListener("mousedown", handlePointerDown);
|
|
199
|
+
body.removeEventListener("mouseleave", handlePointerMove);
|
|
200
|
+
body.removeEventListener("mousemove", handlePointerMove);
|
|
201
|
+
body.removeEventListener("touchmove", handlePointerMove);
|
|
202
|
+
body.removeEventListener("touchstart", handlePointerDown);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
window.removeEventListener("mouseup", handlePointerUp);
|
|
206
|
+
window.removeEventListener("touchcancel", handlePointerUp);
|
|
207
|
+
window.removeEventListener("touchend", handlePointerUp);
|
|
208
|
+
|
|
209
|
+
if (registerResizeHandle.length > 0) {
|
|
210
|
+
if (isPointerDown) {
|
|
211
|
+
if (intersectingHandles.length > 0) {
|
|
212
|
+
ownerDocumentCounts.forEach((count, ownerDocument) => {
|
|
213
|
+
const { body } = ownerDocument;
|
|
214
|
+
|
|
215
|
+
if (count > 0) {
|
|
216
|
+
body.addEventListener("contextmenu", handlePointerUp);
|
|
217
|
+
body.addEventListener("mouseleave", handlePointerMove);
|
|
218
|
+
body.addEventListener("mousemove", handlePointerMove);
|
|
219
|
+
body.addEventListener("touchmove", handlePointerMove, {
|
|
220
|
+
passive: false,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
window.addEventListener("mouseup", handlePointerUp);
|
|
227
|
+
window.addEventListener("touchcancel", handlePointerUp);
|
|
228
|
+
window.addEventListener("touchend", handlePointerUp);
|
|
229
|
+
} else {
|
|
230
|
+
ownerDocumentCounts.forEach((count, ownerDocument) => {
|
|
231
|
+
const { body } = ownerDocument;
|
|
232
|
+
|
|
233
|
+
if (count > 0) {
|
|
234
|
+
body.addEventListener("mousedown", handlePointerDown);
|
|
235
|
+
body.addEventListener("mousemove", handlePointerMove);
|
|
236
|
+
body.addEventListener("touchmove", handlePointerMove, {
|
|
237
|
+
passive: false,
|
|
238
|
+
});
|
|
239
|
+
body.addEventListener("touchstart", handlePointerDown);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function updateResizeHandlerStates(
|
|
247
|
+
action: ResizeHandlerAction,
|
|
248
|
+
event: ResizeEvent
|
|
249
|
+
) {
|
|
250
|
+
registeredResizeHandlers.forEach((data) => {
|
|
251
|
+
const { setResizeHandlerState } = data;
|
|
252
|
+
|
|
253
|
+
if (intersectingHandles.includes(data)) {
|
|
254
|
+
if (isPointerDown) {
|
|
255
|
+
setResizeHandlerState(action, "drag", event);
|
|
256
|
+
} else {
|
|
257
|
+
setResizeHandlerState(action, "hover", event);
|
|
258
|
+
}
|
|
259
|
+
} else {
|
|
260
|
+
setResizeHandlerState(action, "inactive", event);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
}
|
|
@@ -3,7 +3,7 @@ import { Direction } from "../types";
|
|
|
3
3
|
import { assert } from "./assert";
|
|
4
4
|
import { getPanelGroupElement } from "./dom/getPanelGroupElement";
|
|
5
5
|
import { getResizeHandleElement } from "./dom/getResizeHandleElement";
|
|
6
|
-
import { getResizeEventCursorPosition } from "./getResizeEventCursorPosition";
|
|
6
|
+
import { getResizeEventCursorPosition } from "./events/getResizeEventCursorPosition";
|
|
7
7
|
|
|
8
8
|
export function calculateDragOffsetPercentage(
|
|
9
9
|
event: ResizeEvent,
|
package/src/utils/cursor.ts
CHANGED
|
@@ -1,54 +1,84 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
let
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import {
|
|
2
|
+
EXCEEDED_HORIZONTAL_MAX,
|
|
3
|
+
EXCEEDED_HORIZONTAL_MIN,
|
|
4
|
+
EXCEEDED_VERTICAL_MAX,
|
|
5
|
+
EXCEEDED_VERTICAL_MIN,
|
|
6
|
+
} from "../PanelResizeHandleRegistry";
|
|
7
|
+
|
|
8
|
+
type CursorState = "horizontal" | "intersection" | "vertical";
|
|
9
|
+
|
|
10
|
+
let currentCursorStyle: string | null = null;
|
|
11
|
+
let styleElement: HTMLStyleElement | null = null;
|
|
12
|
+
|
|
13
|
+
export function getCursorStyle(
|
|
14
|
+
state: CursorState,
|
|
15
|
+
constraintFlags: number
|
|
16
|
+
): string {
|
|
17
|
+
if (constraintFlags) {
|
|
18
|
+
const horizontalMin = (constraintFlags & EXCEEDED_HORIZONTAL_MIN) !== 0;
|
|
19
|
+
const horizontalMax = (constraintFlags & EXCEEDED_HORIZONTAL_MAX) !== 0;
|
|
20
|
+
const verticalMin = (constraintFlags & EXCEEDED_VERTICAL_MIN) !== 0;
|
|
21
|
+
const verticalMax = (constraintFlags & EXCEEDED_VERTICAL_MAX) !== 0;
|
|
22
|
+
|
|
23
|
+
if (horizontalMin) {
|
|
24
|
+
if (verticalMin) {
|
|
25
|
+
return "se-resize";
|
|
26
|
+
} else if (verticalMax) {
|
|
27
|
+
return "ne-resize";
|
|
28
|
+
} else {
|
|
29
|
+
return "e-resize";
|
|
30
|
+
}
|
|
31
|
+
} else if (horizontalMax) {
|
|
32
|
+
if (verticalMin) {
|
|
33
|
+
return "sw-resize";
|
|
34
|
+
} else if (verticalMax) {
|
|
35
|
+
return "nw-resize";
|
|
36
|
+
} else {
|
|
37
|
+
return "w-resize";
|
|
38
|
+
}
|
|
39
|
+
} else if (verticalMin) {
|
|
40
|
+
return "s-resize";
|
|
41
|
+
} else if (verticalMax) {
|
|
42
|
+
return "n-resize";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
13
46
|
switch (state) {
|
|
14
47
|
case "horizontal":
|
|
15
48
|
return "ew-resize";
|
|
16
|
-
case "
|
|
17
|
-
return "
|
|
18
|
-
case "horizontal-min":
|
|
19
|
-
return "e-resize";
|
|
49
|
+
case "intersection":
|
|
50
|
+
return "move";
|
|
20
51
|
case "vertical":
|
|
21
52
|
return "ns-resize";
|
|
22
|
-
case "vertical-max":
|
|
23
|
-
return "n-resize";
|
|
24
|
-
case "vertical-min":
|
|
25
|
-
return "s-resize";
|
|
26
53
|
}
|
|
27
54
|
}
|
|
28
55
|
|
|
29
56
|
export function resetGlobalCursorStyle() {
|
|
30
|
-
if (
|
|
31
|
-
document.head.removeChild(
|
|
57
|
+
if (styleElement !== null) {
|
|
58
|
+
document.head.removeChild(styleElement);
|
|
32
59
|
|
|
33
|
-
|
|
34
|
-
|
|
60
|
+
currentCursorStyle = null;
|
|
61
|
+
styleElement = null;
|
|
35
62
|
}
|
|
36
63
|
}
|
|
37
64
|
|
|
38
|
-
export function setGlobalCursorStyle(
|
|
39
|
-
|
|
65
|
+
export function setGlobalCursorStyle(
|
|
66
|
+
state: CursorState,
|
|
67
|
+
constraintFlags: number
|
|
68
|
+
) {
|
|
69
|
+
const style = getCursorStyle(state, constraintFlags);
|
|
70
|
+
|
|
71
|
+
if (currentCursorStyle === style) {
|
|
40
72
|
return;
|
|
41
73
|
}
|
|
42
74
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const style = getCursorStyle(state);
|
|
75
|
+
currentCursorStyle = style;
|
|
46
76
|
|
|
47
|
-
if (
|
|
48
|
-
|
|
77
|
+
if (styleElement === null) {
|
|
78
|
+
styleElement = document.createElement("style");
|
|
49
79
|
|
|
50
|
-
document.head.appendChild(
|
|
80
|
+
document.head.appendChild(styleElement);
|
|
51
81
|
}
|
|
52
82
|
|
|
53
|
-
|
|
83
|
+
styleElement.innerHTML = `*{cursor: ${style}!important;}`;
|
|
54
84
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ResizeEvent } from "../../types";
|
|
2
|
+
import { isMouseEvent, isTouchEvent } from ".";
|
|
3
|
+
|
|
4
|
+
export function getResizeEventCoordinates(event: ResizeEvent) {
|
|
5
|
+
if (isMouseEvent(event)) {
|
|
6
|
+
return {
|
|
7
|
+
x: event.pageX,
|
|
8
|
+
y: event.pageY,
|
|
9
|
+
};
|
|
10
|
+
} else if (isTouchEvent(event)) {
|
|
11
|
+
const touch = event.touches[0];
|
|
12
|
+
if (touch && touch.pageX && touch.pageY) {
|
|
13
|
+
return {
|
|
14
|
+
x: touch.pageX,
|
|
15
|
+
y: touch.pageY,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
x: Infinity,
|
|
22
|
+
y: Infinity,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ResizeEvent } from "../../PanelGroupContext";
|
|
2
|
+
import { Direction } from "../../types";
|
|
3
|
+
import { getResizeEventCoordinates } from "./getResizeEventCoordinates";
|
|
4
|
+
|
|
5
|
+
export function getResizeEventCursorPosition(
|
|
6
|
+
direction: Direction,
|
|
7
|
+
event: ResizeEvent
|
|
8
|
+
): number {
|
|
9
|
+
const isHorizontal = direction === "horizontal";
|
|
10
|
+
|
|
11
|
+
const { x, y } = getResizeEventCoordinates(event);
|
|
12
|
+
|
|
13
|
+
return isHorizontal ? x : y;
|
|
14
|
+
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { ResizeEvent } from "../PanelGroupContext";
|
|
2
|
-
import { Direction } from "../types";
|
|
3
|
-
import { assert } from "./assert";
|
|
4
|
-
import { isMouseEvent, isTouchEvent } from "./events";
|
|
5
|
-
|
|
6
|
-
export function getResizeEventCursorPosition(
|
|
7
|
-
direction: Direction,
|
|
8
|
-
event: ResizeEvent
|
|
9
|
-
): number {
|
|
10
|
-
const isHorizontal = direction === "horizontal";
|
|
11
|
-
|
|
12
|
-
if (isMouseEvent(event)) {
|
|
13
|
-
return isHorizontal ? event.clientX : event.clientY;
|
|
14
|
-
} else if (isTouchEvent(event)) {
|
|
15
|
-
const firstTouch = event.touches[0];
|
|
16
|
-
assert(firstTouch);
|
|
17
|
-
return isHorizontal ? firstTouch.screenX : firstTouch.screenY;
|
|
18
|
-
} else {
|
|
19
|
-
throw Error(`Unsupported event type "${event.type}"`);
|
|
20
|
-
}
|
|
21
|
-
}
|