Mirror: React hooks for accessible, common web interactions. UI super powers without the UI.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Rename useDialogDismiss to useDismissable and add focusLoss option

+25 -3
+25 -3
src/useDialogDismiss.ts src/useDismissable.ts
··· 5 5 6 6 const usePriority = makePriorityHook(); 7 7 8 - export function useDialogDismiss<T extends HTMLElement>( 8 + export interface DismissableOptions { 9 + focusLoss?: boolean; 10 + } 11 + 12 + export function useDismissable<T extends HTMLElement>( 9 13 ref: Ref<T>, 10 - onDismiss: () => void 14 + onDismiss: () => void, 15 + options?: DismissableOptions 11 16 ) { 17 + const focusLoss = !!(options && options.focusLoss); 12 18 const hasPriority = usePriority(ref); 13 19 14 20 useLayoutEffect(() => { 15 21 if (!ref.current || !hasPriority) return; 16 22 23 + function onFocusOut(event: FocusEvent) { 24 + if (event.defaultPrevented) return; 25 + 26 + const { target, relatedTarget } = event; 27 + if ( 28 + contains(ref.current, target) && 29 + !contains(ref.current, relatedTarget) 30 + ) { 31 + onDismiss(); 32 + } 33 + } 34 + 17 35 function onKey(event: KeyboardEvent) { 18 36 if (!event.isComposing && event.code === 'Escape') { 19 37 // The current dialog can be dismissed by pressing escape if it either has focus ··· 41 59 } 42 60 } 43 61 62 + if (focusLoss) document.body.addEventListener('focusout', onFocusOut); 63 + 44 64 document.addEventListener('mousedown', onClick); 45 65 document.addEventListener('touchstart', onClick); 46 66 document.addEventListener('keydown', onKey); 47 67 48 68 return () => { 69 + if (focusLoss) document.body.removeEventListener('focusout', onFocusOut); 70 + 49 71 document.removeEventListener('mousedown', onClick); 50 72 document.removeEventListener('touchstart', onClick); 51 73 document.removeEventListener('keydown', onKey); 52 74 }; 53 - }, [ref, hasPriority, onDismiss]); 75 + }, [ref, hasPriority, focusLoss, onDismiss]); 54 76 }