src/hooks/useOverlay.tsx (35 lines of code) (raw):
import {useOnOutsideClick, TouchOrMouseEvent} from './useOnOutsideClick'
import {useOpenAndCloseFocus} from './useOpenAndCloseFocus'
import {useOnEscapePress} from './useOnEscapePress'
import {useProvidedRefOrCreate} from './useProvidedRefOrCreate'
export type UseOverlaySettings = {
ignoreClickRefs?: React.RefObject<HTMLElement>[]
initialFocusRef?: React.RefObject<HTMLElement>
returnFocusRef: React.RefObject<HTMLElement>
onEscape: (e: KeyboardEvent) => void
onClickOutside: (e: TouchOrMouseEvent) => void
overlayRef?: React.RefObject<HTMLDivElement>
preventFocusOnOpen?: boolean
}
export type OverlayReturnProps = {
ref: React.RefObject<HTMLDivElement>
}
export const useOverlay = ({
overlayRef: _overlayRef,
returnFocusRef,
initialFocusRef,
onEscape,
ignoreClickRefs,
onClickOutside,
preventFocusOnOpen
}: UseOverlaySettings): OverlayReturnProps => {
const overlayRef = useProvidedRefOrCreate<HTMLDivElement>(_overlayRef)
useOpenAndCloseFocus({containerRef: overlayRef, returnFocusRef, initialFocusRef, preventFocusOnOpen})
useOnOutsideClick({containerRef: overlayRef, ignoreClickRefs, onClickOutside})
/** Don't bubble Escape event up the tree */
const onEscapeWithStoppedPropagation: UseOverlaySettings['onEscape'] = event => {
event.stopPropagation()
onEscape(event)
}
useOnEscapePress(onEscapeWithStoppedPropagation, undefined, overlayRef)
return {ref: overlayRef}
}