-
Notifications
You must be signed in to change notification settings - Fork 53
Expand file tree
/
Copy pathPointerCapture.tsx
More file actions
116 lines (103 loc) · 3.4 KB
/
PointerCapture.tsx
File metadata and controls
116 lines (103 loc) · 3.4 KB
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import React from 'react';
import noop from 'lodash/noop';
import { MOUSE_PRIMARY } from '../../constants';
export enum Status {
dragging = 'dragging',
drawing = 'drawing',
init = 'init',
}
export type PointerCaptureRef = HTMLDivElement;
export type Props = {
children?: React.ReactNode;
className?: string;
onDrawStart: (x: number, y: number) => void;
onDrawStop: () => void;
onDrawUpdate: (x: number, y: number) => void;
onMouseOut?: () => void;
onMouseOver?: () => void;
status: Status;
};
function PointerCapture(props: Props, ref: React.Ref<PointerCaptureRef>): JSX.Element {
const {
children,
className,
onDrawStart,
onDrawStop,
onDrawUpdate,
onMouseOut = noop,
onMouseOver = noop,
status,
...rest
} = props;
// Event Handlers
const handleClick = (event: React.MouseEvent): void => {
event.preventDefault();
event.stopPropagation();
};
const handleMouseDown = ({ button, clientX, clientY }: React.MouseEvent): void => {
if (button !== MOUSE_PRIMARY) {
return;
}
onDrawStart(clientX, clientY);
};
const handleMouseOut = (): void => {
onMouseOut();
};
const handleMouseOver = (): void => {
onMouseOver();
};
const handleTouchCancel = (): void => {
onDrawStop();
};
const handleTouchEnd = (): void => {
onDrawStop();
};
const handleTouchMove = ({ targetTouches }: React.TouchEvent): void => {
onDrawUpdate(targetTouches[0].clientX, targetTouches[0].clientY);
};
const handleTouchStart = ({ targetTouches }: React.TouchEvent): void => {
onDrawStart(targetTouches[0].clientX, targetTouches[0].clientY);
};
React.useEffect(() => {
const handleMouseMove = ({ button, clientX, clientY }: MouseEvent): void => {
if (button !== MOUSE_PRIMARY || status === Status.init) {
return;
}
onDrawUpdate(clientX, clientY);
};
const handleMouseUp = (): void => {
onDrawStop();
};
// Document-level mousemove and mouseup event listeners allow the creator component to respond even if
// the cursor leaves the drawing area before the mouse button is released, which finishes the shape
if (status !== Status.init) {
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
}
return () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
}, [onDrawStop, onDrawUpdate, status]);
return (
// eslint-disable-next-line jsx-a11y/mouse-events-have-key-events
<div
ref={ref}
className={className}
onClick={handleClick}
onMouseDown={handleMouseDown}
onMouseOut={handleMouseOut}
onMouseOver={handleMouseOver}
onTouchCancel={handleTouchCancel}
onTouchEnd={handleTouchEnd}
onTouchMove={handleTouchMove}
onTouchStart={handleTouchStart}
role="presentation"
{...rest}
>
{children}
</div>
);
}
export { PointerCapture as PointerCaptureBase };
export default React.forwardRef(PointerCapture);