/
HoverModeProvider.tsx
131 lines (119 loc) · 3.27 KB
/
HoverModeProvider.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
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
import {
ReactElement,
ReactNode,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { useOnUnmount } from "../useOnUnmount";
import {
DEFAULT_HOVER_MODE_DEACTIVATION_TIME,
DEFAULT_HOVER_MODE_VISIBLE_IN_TIME,
} from "./constants";
import {
HoverModeContext,
HoverModeContextProvider,
} from "./useHoverModeContext";
/** @remarks \@since 2.8.0 */
export interface HoverModeConfiguration {
/**
* Boolean if the hover mode functionality should be disabled.
*
* @defaultValue `false`
*/
disabled?: boolean;
/**
* The amount of time (in ms) the user must hover an element before the hover
* mode is enabled and the visibility is set to `true`.
*
* @defaultValue {@link DEFAULT_HOVER_MODE_VISIBLE_IN_TIME}
*/
defaultVisibleInTime?: number;
/**
* The amount of time (in ms) the user must not hover any element connected to
* the hover mode.
*
* @defaultValue {@link DEFAULT_HOVER_MODE_DEACTIVATION_TIME}
*/
deactivateTime?: number;
}
/** @remarks \@since 2.8.0 */
export interface HoverModeProviderProps extends HoverModeConfiguration {
children: ReactNode;
}
/**
* This component should normally be mounted near the root of your app to enable
* hover mode for child components. However, it can also be used at other levels
* if hover mode functionality should not carry over between two different parts
* of the screen.
*
* @example
* Separating Hover Mode
* ```tsx
* export default function Example(): ReactElement {
* return (
* <>
* <HoverModeProvider>
* <HeaderActions />
* </HoverModeProvider>
* <HoverModeProvider>
* <MainContent />
* </HoverModeProvider>
* </>
* );
* }
* ```
*
* @remarks \@since 2.8.0
*/
export function HoverModeProvider({
children,
disabled = false,
defaultVisibleInTime = DEFAULT_HOVER_MODE_VISIBLE_IN_TIME,
deactivateTime = DEFAULT_HOVER_MODE_DEACTIVATION_TIME,
}: HoverModeProviderProps): ReactElement {
const [visibleInTime, setVisibleInTime] = useState(defaultVisibleInTime);
const timeoutRef = useRef<number>();
const enableHoverMode = useCallback(() => {
if (disabled) {
return;
}
window.clearTimeout(timeoutRef.current);
setVisibleInTime(0);
}, [disabled]);
const disableHoverMode = useCallback(() => {
window.clearTimeout(timeoutRef.current);
setVisibleInTime(defaultVisibleInTime);
}, [defaultVisibleInTime]);
const startDisableTimer = useCallback(() => {
window.clearTimeout(timeoutRef.current);
timeoutRef.current = window.setTimeout(() => {
setVisibleInTime(defaultVisibleInTime);
}, deactivateTime);
}, [defaultVisibleInTime, deactivateTime]);
useEffect(() => {
if (disabled) {
window.clearTimeout(timeoutRef.current);
setVisibleInTime(defaultVisibleInTime);
}
}, [disabled, defaultVisibleInTime]);
useOnUnmount(() => {
window.clearTimeout(timeoutRef.current);
});
const context = useMemo<HoverModeContext>(
() => ({
visibleInTime,
enableHoverMode,
disableHoverMode,
startDisableTimer,
}),
[disableHoverMode, enableHoverMode, startDisableTimer, visibleInTime]
);
return (
<HoverModeContextProvider value={context}>
{children}
</HoverModeContextProvider>
);
}