UNPKG

reblend-ui

Version:

Utilities for creating robust overlay components

70 lines (57 loc) 2.1 kB
import listen from 'dom-helpers/listen'; import ownerDocument from 'dom-helpers/ownerDocument'; import { useEffect } from 'reblendjs'; import { useEventCallback } from 'reblend-hooks'; import useClickOutside, { ClickOutsideOptions, getRefTarget, } from './useClickOutside'; import { isEscKey } from './utils'; const noop = () => {}; export interface RootCloseOptions extends ClickOutsideOptions { disabled?: boolean; } /** * The `useRootClose` hook registers your callback on the document * when rendered. Powers the `<Overlay/>` component. This is used achieve modal * style behavior where your callback is triggered when the user tries to * interact with the rest of the document or hits the `esc` key. * * @param {Ref<HTMLElement>| HTMLElement} ref The element boundary * @param {function} onRootClose * @param {object=} options * @param {boolean=} options.disabled * @param {string=} options.clickTrigger The DOM event name (click, mousedown, etc) to attach listeners on */ function useRootClose( ref: Reblend.Ref<Element> | Element | null | undefined, onRootClose: (e: Event) => void, { disabled, clickTrigger }: RootCloseOptions = {}, ) { const onClose = onRootClose || noop; useClickOutside(ref, onClose, { disabled, clickTrigger }); const handleKeyUp = useEventCallback((e: KeyboardEvent) => { if (isEscKey(e)) { onClose(e); } }); useEffect(() => { if (disabled || ref == null) return undefined; const doc = ownerDocument(getRefTarget(ref)!); // Store the current event to avoid triggering handlers immediately // https://github.com/facebook/react/issues/20074 let currentEvent = (doc.defaultView || window).event; const removeKeyupListener = listen(doc as any, 'keyup', (e) => { // skip if this event is the same as the one running when we added the handlers if (e === currentEvent) { currentEvent = undefined; return; } handleKeyUp(e); }); return () => { removeKeyupListener(); }; }, [ref, disabled, handleKeyUp]); } export default useRootClose;