GoScrobble/web/node_modules/@restart/hooks/esm/useFocusManager.js

62 lines
2.1 KiB
JavaScript
Raw Permalink Normal View History

2022-04-25 02:47:15 +00:00
import { useCallback, useRef } from 'react';
import useEventCallback from './useEventCallback';
import useMounted from './useMounted';
/**
* useFocusManager provides a way to track and manage focus as it moves around
* a container element. An `onChange` is fired when focus enters or leaves the
* element, but not when it moves around inside the element, similar to
* `pointerenter` and `pointerleave` DOM events.
*
* ```tsx
* const [focused, setFocusState] = useState(false)
*
* const { onBlur, onFocus } = useFocusManager({
* onChange: nextFocused => setFocusState(nextFocused)
* })
*
* return (
* <div tabIndex="-1" onFocus={onFocus} onBlur={onBlur}>
* {String(focused)}
* <input />
* <input />
*
* <button>A button</button>
* </div>
* ```
*
*/
export default function useFocusManager(opts) {
var isMounted = useMounted();
var lastFocused = useRef();
var handle = useRef();
var willHandle = useEventCallback(opts.willHandle);
var didHandle = useEventCallback(opts.didHandle);
var onChange = useEventCallback(opts.onChange);
var isDisabled = useEventCallback(opts.isDisabled);
var handleFocusChange = useCallback(function (focused, event) {
if (event && event.persist) event.persist();
if (willHandle && willHandle(focused, event) === false) return;
clearTimeout(handle.current);
handle.current = window.setTimeout(function () {
if (focused !== lastFocused.current) {
if (didHandle) didHandle(focused, event); // only fire a change when unmounted if its a blur
if (isMounted() || !focused) {
lastFocused.current = focused;
onChange && onChange(focused, event);
}
}
});
}, [isMounted, willHandle, didHandle, onChange, lastFocused]);
var handleBlur = useCallback(function (event) {
if (!isDisabled()) handleFocusChange(false, event);
}, [handleFocusChange, isDisabled]);
var handleFocus = useCallback(function (event) {
if (!isDisabled()) handleFocusChange(true, event);
}, [handleFocusChange, isDisabled]);
return {
onBlur: handleBlur,
onFocus: handleFocus
};
}