@gechiui/compose
Version:
GeChiUI higher-order components (HOCs).
76 lines (66 loc) • 2.54 kB
JavaScript
/**
* GeChiUI dependencies
*/
import { useRef, useEffect, useCallback } from '@gechiui/element';
/**
* When opening modals/sidebars/dialogs, the focus
* must move to the opened area and return to the
* previously focused element when closed.
* The current hook implements the returning behavior.
*
* @param {() => void} [onFocusReturn] Overrides the default return behavior.
* @return {import('react').RefCallback<HTMLElement>} Element Ref.
*
* @example
* ```js
* import { useFocusReturn } from '@gechiui/compose';
*
* const WithFocusReturn = () => {
* const ref = useFocusReturn()
* return (
* <div ref={ ref }>
* <Button />
* <Button />
* </div>
* );
* }
* ```
*/
function useFocusReturn(onFocusReturn) {
/** @type {import('react').MutableRefObject<null | HTMLElement>} */
const ref = useRef(null);
/** @type {import('react').MutableRefObject<null | Element>} */
const focusedBeforeMount = useRef(null);
const onFocusReturnRef = useRef(onFocusReturn);
useEffect(() => {
onFocusReturnRef.current = onFocusReturn;
}, [onFocusReturn]);
return useCallback(node => {
if (node) {
// Set ref to be used when unmounting.
ref.current = node; // Only set when the node mounts.
if (focusedBeforeMount.current) {
return;
}
focusedBeforeMount.current = node.ownerDocument.activeElement;
} else if (focusedBeforeMount.current) {
var _ref$current, _ref$current2, _ref$current3;
const isFocused = (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.contains((_ref$current2 = ref.current) === null || _ref$current2 === void 0 ? void 0 : _ref$current2.ownerDocument.activeElement);
if ((_ref$current3 = ref.current) !== null && _ref$current3 !== void 0 && _ref$current3.isConnected && !isFocused) {
return;
} // Defer to the component's own explicit focus return behavior, if
// specified. This allows for support that the `onFocusReturn`
// decides to allow the default behavior to occur under some
// conditions.
if (onFocusReturnRef.current) {
onFocusReturnRef.current();
} else {
var _focusedBeforeMount$c;
/** @type {null | HTMLElement} */
(_focusedBeforeMount$c = focusedBeforeMount.current) === null || _focusedBeforeMount$c === void 0 ? void 0 : _focusedBeforeMount$c.focus();
}
}
}, []);
}
export default useFocusReturn;
//# sourceMappingURL=index.js.map