@hakuna-matata-ui/hooks
Version:
React hooks for Chakra components
59 lines (47 loc) • 1.41 kB
text/typescript
import {
contains,
focus,
FocusableElement,
getActiveElement,
isTabbable,
} from "@hakuna-matata-ui/utils"
import { RefObject } from "react"
import { useUpdateEffect } from "./use-update-effect"
export interface UseFocusOnHideOptions {
focusRef: RefObject<FocusableElement>
shouldFocus?: boolean
visible?: boolean
}
function preventReturnFocus(containerRef: React.RefObject<HTMLElement>) {
const el = containerRef.current
if (!el) return false
const activeElement = getActiveElement(el)
if (!activeElement) return false
if (contains(el, activeElement)) return false
if (isTabbable(activeElement)) return true
return false
}
/**
* Popover hook to manage the focus when the popover closes or hides.
*
* We either want to return focus back to the popover trigger or
* let focus proceed normally if user moved to another interactive
* element in the viewport.
*/
export function useFocusOnHide(
containerRef: RefObject<HTMLElement>,
options: UseFocusOnHideOptions,
) {
const { shouldFocus: shouldFocusProp, visible, focusRef } = options
const shouldFocus = shouldFocusProp && !visible
useUpdateEffect(() => {
if (!shouldFocus) return
if (preventReturnFocus(containerRef)) {
return
}
const el = focusRef?.current || containerRef.current
if (el) {
focus(el, { nextTick: true })
}
}, [shouldFocus, containerRef, focusRef])
}