Mirror: React hooks for accessible, common web interactions. UI super powers without the UI.
1import { useLayoutEffect } from './utils/react';
2import { contains } from './utils/element';
3import { makePriorityHook } from './usePriority';
4import { Ref } from './types';
5
6const usePriority = makePriorityHook();
7
8export function useDialogDismiss<T extends HTMLElement>(
9 ref: Ref<T>,
10 onDismiss: () => void
11) {
12 const hasPriority = usePriority(ref);
13
14 useLayoutEffect(() => {
15 if (!hasPriority) return;
16
17 function onKey(event: KeyboardEvent) {
18 if (
19 event.isComposing ||
20 event.defaultPrevented ||
21 event.code !== 'Escape'
22 )
23 return;
24 event.preventDefault();
25 onDismiss();
26 }
27
28 function onClick(event: MouseEvent | TouchEvent) {
29 if (
30 !ref.current ||
31 contains(ref.current, event.target) ||
32 event.defaultPrevented
33 )
34 return;
35 event.preventDefault();
36 onDismiss();
37 }
38
39 document.addEventListener('mousedown', onClick);
40 document.addEventListener('touchstart', onClick);
41 document.addEventListener('keydown', onKey);
42
43 return () => {
44 document.removeEventListener('mousedown', onClick);
45 document.removeEventListener('touchstart', onClick);
46 document.removeEventListener('keydown', onKey);
47 };
48 }, [ref, hasPriority, onDismiss]);
49}