UNPKG

2.13 kBJavaScriptView Raw
1import { useCallback, useRef } from 'react';
2import useEventCallback from './useEventCallback';
3import useMounted from './useMounted';
4
5/**
6 * useFocusManager provides a way to track and manage focus as it moves around
7 * a container element. An `onChange` is fired when focus enters or leaves the
8 * element, but not when it moves around inside the element, similar to
9 * `pointerenter` and `pointerleave` DOM events.
10 *
11 * ```tsx
12 * const [focused, setFocusState] = useState(false)
13 *
14 * const { onBlur, onFocus } = useFocusManager({
15 * onChange: nextFocused => setFocusState(nextFocused)
16 * })
17 *
18 * return (
19 * <div tabIndex="-1" onFocus={onFocus} onBlur={onBlur}>
20 * {String(focused)}
21 * <input />
22 * <input />
23 *
24 * <button>A button</button>
25 * </div>
26 * ```
27 *
28 */
29export default function useFocusManager(opts) {
30 var isMounted = useMounted();
31 var lastFocused = useRef();
32 var handle = useRef();
33 var willHandle = useEventCallback(opts.willHandle);
34 var didHandle = useEventCallback(opts.didHandle);
35 var onChange = useEventCallback(opts.onChange);
36 var isDisabled = useEventCallback(opts.isDisabled);
37 var handleFocusChange = useCallback(function (focused, event) {
38 if (event && event.persist) event.persist();
39 if (willHandle && willHandle(focused, event) === false) return;
40 clearTimeout(handle.current);
41 handle.current = window.setTimeout(function () {
42 if (focused !== lastFocused.current) {
43 if (didHandle) didHandle(focused, event); // only fire a change when unmounted if its a blur
44
45 if (isMounted() || !focused) {
46 lastFocused.current = focused;
47 onChange && onChange(focused, event);
48 }
49 }
50 });
51 }, [isMounted, willHandle, didHandle, onChange, lastFocused]);
52 var handleBlur = useCallback(function (event) {
53 if (!isDisabled()) handleFocusChange(false, event);
54 }, [handleFocusChange, isDisabled]);
55 var handleFocus = useCallback(function (event) {
56 if (!isDisabled()) handleFocusChange(true, event);
57 }, [handleFocusChange, isDisabled]);
58 return {
59 onBlur: handleBlur,
60 onFocus: handleFocus
61 };
62}
\No newline at end of file