@mantine/hooks
Version:
A collection of 50+ hooks for state and UI management
55 lines (54 loc) • 1.87 kB
JavaScript
"use client";
import { useCallbackRef } from "../utils/use-callback-ref/use-callback-ref.mjs";
import { useCallback, useEffect, useRef, useState } from "react";
//#region packages/@mantine/hooks/src/use-focus-within/use-focus-within.ts
function containsRelatedTarget(event) {
if (event.currentTarget instanceof HTMLElement && event.relatedTarget instanceof HTMLElement) return event.currentTarget.contains(event.relatedTarget);
return false;
}
function useFocusWithin({ onBlur, onFocus } = {}) {
const [focused, setFocused] = useState(false);
const focusedRef = useRef(false);
const previousNode = useRef(null);
const onFocusRef = useCallbackRef(onFocus);
const onBlurRef = useCallbackRef(onBlur);
const _setFocused = useCallback((value) => {
setFocused(value);
focusedRef.current = value;
}, []);
const handleFocusIn = useCallback((event) => {
if (!focusedRef.current) {
_setFocused(true);
onFocusRef(event);
}
}, []);
const handleFocusOut = useCallback((event) => {
if (focusedRef.current && !containsRelatedTarget(event)) {
_setFocused(false);
onBlurRef(event);
}
}, []);
const callbackRef = useCallback((node) => {
if (!node) return;
if (previousNode.current) {
previousNode.current.removeEventListener("focusin", handleFocusIn);
previousNode.current.removeEventListener("focusout", handleFocusOut);
}
node.addEventListener("focusin", handleFocusIn);
node.addEventListener("focusout", handleFocusOut);
previousNode.current = node;
}, [handleFocusIn, handleFocusOut]);
useEffect(() => () => {
if (previousNode.current) {
previousNode.current.removeEventListener("focusin", handleFocusIn);
previousNode.current.removeEventListener("focusout", handleFocusOut);
}
}, []);
return {
ref: callbackRef,
focused
};
}
//#endregion
export { useFocusWithin };
//# sourceMappingURL=use-focus-within.mjs.map