UNPKG

2.63 kBJavaScriptView Raw
1"use strict";
2
3exports.__esModule = true;
4exports.default = useFocusManager;
5var _react = require("react");
6var _useEventCallback = _interopRequireDefault(require("./useEventCallback"));
7var _useMounted = _interopRequireDefault(require("./useMounted"));
8function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9/**
10 * useFocusManager provides a way to track and manage focus as it moves around
11 * a container element. An `onChange` is fired when focus enters or leaves the
12 * element, but not when it moves around inside the element, similar to
13 * `pointerenter` and `pointerleave` DOM events.
14 *
15 * ```tsx
16 * const [focused, setFocusState] = useState(false)
17 *
18 * const { onBlur, onFocus } = useFocusManager({
19 * onChange: nextFocused => setFocusState(nextFocused)
20 * })
21 *
22 * return (
23 * <div tabIndex="-1" onFocus={onFocus} onBlur={onBlur}>
24 * {String(focused)}
25 * <input />
26 * <input />
27 *
28 * <button>A button</button>
29 * </div>
30 * ```
31 *
32 * @returns a memoized FocusController containing event handlers
33 */
34function useFocusManager(opts) {
35 const isMounted = (0, _useMounted.default)();
36 const lastFocused = (0, _react.useRef)();
37 const handle = (0, _react.useRef)();
38 const willHandle = (0, _useEventCallback.default)(opts.willHandle);
39 const didHandle = (0, _useEventCallback.default)(opts.didHandle);
40 const onChange = (0, _useEventCallback.default)(opts.onChange);
41 const isDisabled = (0, _useEventCallback.default)(opts.isDisabled);
42 const handleChange = (0, _react.useCallback)((focused, event) => {
43 if (focused !== lastFocused.current) {
44 didHandle == null ? void 0 : didHandle(focused, event);
45
46 // only fire a change when unmounted if its a blur
47 if (isMounted() || !focused) {
48 lastFocused.current = focused;
49 onChange == null ? void 0 : onChange(focused, event);
50 }
51 }
52 }, [isMounted, didHandle, onChange, lastFocused]);
53 const handleFocusChange = (0, _react.useCallback)((focused, event) => {
54 if (isDisabled()) return;
55 if (event && event.persist) event.persist();
56 if ((willHandle == null ? void 0 : willHandle(focused, event)) === false) {
57 return;
58 }
59 clearTimeout(handle.current);
60 if (focused) {
61 handleChange(focused, event);
62 } else {
63 handle.current = window.setTimeout(() => handleChange(focused, event));
64 }
65 }, [willHandle, handleChange]);
66 return (0, _react.useMemo)(() => ({
67 onBlur: event => {
68 handleFocusChange(false, event);
69 },
70 onFocus: event => {
71 handleFocusChange(true, event);
72 }
73 }), [handleFocusChange]);
74}
\No newline at end of file