UNPKG

3.4 kBJavaScriptView Raw
1import * as React from 'react';
2import { useEventCallback } from '../utils';
3
4const useTouchRipple = props => {
5 const {
6 disabled,
7 disableFocusRipple,
8 disableRipple,
9 disableTouchRipple,
10 focusVisible,
11 rippleRef
12 } = props;
13 React.useEffect(() => {
14 if (focusVisible && !disableFocusRipple && !disableRipple) {
15 rippleRef.current?.pulsate();
16 }
17 }, [rippleRef, focusVisible, disableFocusRipple, disableRipple]);
18
19 function useRippleHandler(rippleAction, skipRippleAction = disableTouchRipple) {
20 return useEventCallback(event => {
21 if (!skipRippleAction && rippleRef.current) {
22 rippleRef.current[rippleAction](event);
23 }
24
25 return true;
26 });
27 }
28
29 const keydownRef = React.useRef(false);
30 const handleKeyDown = useEventCallback(event => {
31 if (!disableFocusRipple && !keydownRef.current && focusVisible && rippleRef.current && event.key === ' ') {
32 keydownRef.current = true;
33 rippleRef.current.stop(event, () => {
34 rippleRef?.current?.start(event);
35 });
36 }
37 });
38 const handleKeyUp = useEventCallback(event => {
39 // calling preventDefault in keyUp on a <button> will not dispatch a click event if Space is pressed
40 // https://codesandbox.io/s/button-keyup-preventdefault-dn7f0
41 if (!disableFocusRipple && event.key === ' ' && rippleRef.current && focusVisible && !event.defaultPrevented) {
42 keydownRef.current = false;
43 rippleRef.current.stop(event, () => {
44 rippleRef?.current?.pulsate(event);
45 });
46 }
47 });
48 const handleBlur = useRippleHandler('stop', false);
49 const handleMouseDown = useRippleHandler('start');
50 const handleContextMenu = useRippleHandler('stop');
51 const handleDragLeave = useRippleHandler('stop');
52 const handleMouseUp = useRippleHandler('stop');
53 const handleMouseLeave = useRippleHandler('stop');
54 const handleTouchStart = useRippleHandler('start');
55 const handleTouchEnd = useRippleHandler('stop');
56 const handleTouchMove = useRippleHandler('stop');
57 const [mountedState, setMountedState] = React.useState(false);
58 React.useEffect(() => {
59 setMountedState(true);
60 }, []);
61 const enableTouchRipple = mountedState && !disableRipple && !disabled;
62 const getRippleHandlers = React.useMemo(() => {
63 const rippleHandlers = {
64 onBlur: handleBlur,
65 onKeyDown: handleKeyDown,
66 onKeyUp: handleKeyUp,
67 onMouseDown: handleMouseDown,
68 onMouseUp: handleMouseUp,
69 onMouseLeave: handleMouseLeave,
70 onContextMenu: handleContextMenu,
71 onDragLeave: handleDragLeave,
72 onTouchStart: handleTouchStart,
73 onTouchEnd: handleTouchEnd,
74 onTouchMove: handleTouchMove
75 };
76 return (otherEvents = {}) => {
77 const eventNames = Object.keys(rippleHandlers);
78 const wrappedEvents = eventNames.map(eventName => ({
79 name: eventName,
80 handler: ev => {
81 otherEvents[eventName]?.(ev);
82 rippleHandlers[eventName](ev);
83 }
84 }));
85 return wrappedEvents.reduce((acc, current) => {
86 acc[current.name] = current.handler;
87 return acc;
88 }, {});
89 };
90 }, [handleBlur, handleKeyDown, handleKeyUp, handleMouseDown, handleMouseUp, handleMouseLeave, handleContextMenu, handleDragLeave, handleTouchStart, handleTouchEnd, handleTouchMove]);
91 return {
92 enableTouchRipple,
93 getRippleHandlers
94 };
95};
96
97export default useTouchRipple;
\No newline at end of file