@yamada-ui/react
Version:
React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion
84 lines (80 loc) • 2.82 kB
JavaScript
"use client";
import { useUpdateEffect } from "../../utils/effect.js";
import { isRefObject } from "../../utils/ref.js";
import { utils_exports } from "../../utils/index.js";
import { useEventListener } from "../use-event-listener/index.js";
import { useCallback, useRef } from "react";
//#region src/hooks/use-focus/index.ts
/**
* `useFocusOnShow` is a custom hook that focuses on the target element when it is shown.
*
* @see https://yamada-ui.com/docs/hooks/use-focus-on-show
*/
const useFocusOnShow = (refOrEl, { focusTarget: focusRefOrEl, preventScroll, shouldFocus, visible } = {
preventScroll: true,
shouldFocus: false
}) => {
const trulyShouldFocus = shouldFocus && visible;
const focused = useRef(false);
const getTarget = useCallback(() => {
return isRefObject(refOrEl) ? refOrEl.current : refOrEl;
}, [refOrEl]);
const getFocusTarget = useCallback(() => {
return isRefObject(focusRefOrEl) ? focusRefOrEl.current : focusRefOrEl;
}, [focusRefOrEl]);
const onFocus = useCallback(() => {
const target = getTarget();
if (!target || !trulyShouldFocus || focused.current) return;
if (target.contains(document.activeElement)) return;
const focusTarget = getFocusTarget();
if (focusTarget) requestAnimationFrame(() => {
focusTarget.focus({ preventScroll });
focused.current = true;
});
else {
const firstFocusable = (0, utils_exports.getFirstFocusableElement)(target);
if (firstFocusable) requestAnimationFrame(() => {
firstFocusable.focus({ preventScroll });
focused.current = true;
});
else requestAnimationFrame(() => {
target.focus({ preventScroll });
focused.current = true;
});
}
}, [
getTarget,
trulyShouldFocus,
getFocusTarget,
preventScroll
]);
useUpdateEffect(() => {
focused.current = !trulyShouldFocus;
}, [trulyShouldFocus]);
useUpdateEffect(() => {
requestAnimationFrame(onFocus);
}, [onFocus]);
useEventListener(getTarget, "transitionend", onFocus);
};
/**
* `useFocusOnPointerDown` is a custom hook that focuses on the target element when it is clicked.
*
* @see https://yamada-ui.com/docs/hooks/use-focus-on-pointer-down
*/
const useFocusOnPointerDown = ({ ref, elements, enabled }) => {
useEventListener(() => (0, utils_exports.getDocument)(ref.current), "pointerdown", (ev) => {
if (!(0, utils_exports.isSafari)() || !enabled) return;
const target = ev.target;
const validTarget = (elements ?? [ref]).some((elOrRef) => {
const el = isRefObject(elOrRef) ? elOrRef.current : elOrRef;
return el?.contains(target) || el === target;
});
if ((0, utils_exports.getActiveElement)((0, utils_exports.getDocument)(ref.current)) !== target && validTarget) {
ev.preventDefault();
target.focus();
}
});
};
//#endregion
export { useFocusOnPointerDown, useFocusOnShow };
//# sourceMappingURL=index.js.map