-
-
Notifications
You must be signed in to change notification settings - Fork 303
/
usePressedStates.ts
158 lines (137 loc) · 4.3 KB
/
usePressedStates.ts
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
117
118
119
120
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
150
151
152
153
154
155
156
157
158
import { useCallback, useState } from "react";
import { useRefCache } from "@react-md/utils";
import { MergableRippleHandlers } from "./ripples/types";
interface PressedStatesOptions<E extends HTMLElement = HTMLElement> {
handlers?: MergableRippleHandlers<E>;
disableSpacebarClick?: boolean;
}
interface ReturnValue<E extends HTMLElement> {
pressed: boolean;
handlers: MergableRippleHandlers<E>;
}
/**
* This is a different version of the useRippleStates that will allow you to know
* when a component is being pressed by the user. This is really just a fallback for
* when the ripples are disabled.
*
* This will return an object containing the current pressed state of the element as well
* as all the merged eventHandlers required to trigger the different states.
*
* NOTE: Unlike the ripple effect, this pressed states will not be triggered from
* a programmatic click event.
*/
export default function usePressedStates<E extends HTMLElement = HTMLElement>({
handlers = {},
disableSpacebarClick = false,
}: PressedStatesOptions<E> = {}): ReturnValue<E> {
const [pressed, setPressed] = useState(false);
const ref = useRefCache({ ...handlers, pressed });
const handleKeyDown = useCallback(
(event: React.KeyboardEvent<E>) => {
const { onKeyDown, pressed } = ref.current;
if (onKeyDown) {
onKeyDown(event);
}
const { key } = event;
if (
!pressed &&
(key === "Enter" || (!disableSpacebarClick && key === " "))
) {
setPressed(true);
}
},
// disabled since useRefCache for ref
// eslint-disable-next-line react-hooks/exhaustive-deps
[disableSpacebarClick]
);
const handleKeyUp = useCallback((event: React.KeyboardEvent<E>) => {
const { onKeyUp, pressed } = ref.current;
if (onKeyUp) {
onKeyUp(event);
}
if (pressed) {
setPressed(false);
}
// disabled since useRefCache for ref
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleMouseDown = useCallback((event: React.MouseEvent<E>) => {
const { onMouseDown, pressed } = ref.current;
if (onMouseDown) {
onMouseDown(event);
}
if (!pressed && event.button === 0) {
setPressed(true);
}
// disabled since useRefCache for ref
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleMouseUp = useCallback((event: React.MouseEvent<E>) => {
const { onMouseUp, pressed } = ref.current;
if (onMouseUp) {
onMouseUp(event);
}
if (pressed) {
setPressed(false);
}
// disabled since useRefCache for ref
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleMouseLeave = useCallback((event: React.MouseEvent<E>) => {
const { onMouseLeave, pressed } = ref.current;
if (onMouseLeave) {
onMouseLeave(event);
}
if (pressed) {
setPressed(false);
}
// disabled since useRefCache for ref
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleTouchStart = useCallback((event: React.TouchEvent<E>) => {
const { onTouchStart, pressed } = ref.current;
if (onTouchStart) {
onTouchStart(event);
}
if (!pressed) {
setPressed(true);
}
// disabled since useRefCache for ref
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleTouchMove = useCallback((event: React.TouchEvent<E>) => {
const { onTouchMove, pressed } = ref.current;
if (onTouchMove) {
onTouchMove(event);
}
if (pressed) {
setPressed(false);
}
// disabled since useRefCache for ref
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleTouchEnd = useCallback((event: React.TouchEvent<E>) => {
const { onTouchEnd, pressed } = ref.current;
if (onTouchEnd) {
onTouchEnd(event);
}
if (pressed) {
setPressed(false);
}
// disabled since useRefCache for ref
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return {
pressed,
handlers: {
onKeyDown: handleKeyDown,
onKeyUp: handleKeyUp,
onMouseDown: handleMouseDown,
onMouseUp: handleMouseUp,
onMouseLeave: handleMouseLeave,
onTouchStart: handleTouchStart,
onTouchMove: handleTouchMove,
onTouchEnd: handleTouchEnd,
},
};
}