export function useFocusTrap()

in src/hooks/useFocusTrap.ts [36:80]


export function useFocusTrap(
  settings?: FocusTrapHookSettings,
  dependencies: React.DependencyList = []
): {containerRef: React.RefObject<HTMLElement>; initialFocusRef: React.RefObject<HTMLElement>} {
  const containerRef = useProvidedRefOrCreate(settings?.containerRef)
  const initialFocusRef = useProvidedRefOrCreate(settings?.initialFocusRef)
  const disabled = settings?.disabled
  const abortController = React.useRef<AbortController>()
  const previousFocusedElement = React.useRef<Element | null>(null)

  // If we are enabling a focus trap and haven't already stored the previously focused element
  // go ahead an do that so we can restore later when the trap is disabled.
  if (!previousFocusedElement.current && !settings?.disabled) {
    previousFocusedElement.current = document.activeElement
  }

  // This function removes the event listeners that enable the focus trap and restores focus
  // to the previously-focused element (if necessary).
  function disableTrap() {
    abortController.current?.abort()
    if (settings?.restoreFocusOnCleanUp && previousFocusedElement.current instanceof HTMLElement) {
      previousFocusedElement.current.focus()
      previousFocusedElement.current = null
    }
  }

  React.useEffect(
    () => {
      if (containerRef.current instanceof HTMLElement) {
        if (!disabled) {
          abortController.current = focusTrap(containerRef.current, initialFocusRef.current ?? undefined)
          return () => {
            disableTrap()
          }
        } else {
          disableTrap()
        }
      }
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [containerRef, initialFocusRef, disabled, ...dependencies]
  )

  return {containerRef, initialFocusRef}
}