Mirror: React hooks for accessible, common web interactions. UI super powers without the UI.
at main 1.4 kB view raw
1import { isFocusTarget, getActive } from './utils/focus'; 2import { useLayoutEffect } from './utils/react'; 3import { click } from './utils/click'; 4import { contains, isInputElement } from './utils/element'; 5import { makePriorityHook } from './usePriority'; 6import { Ref } from './types'; 7 8const usePriority = makePriorityHook(); 9 10export interface OptionFocusOptions { 11 disabled?: boolean; 12} 13 14export function useOptionFocus<T extends HTMLElement>( 15 ref: Ref<T>, 16 options?: OptionFocusOptions 17) { 18 const disabled = !!(options && options.disabled); 19 const hasPriority = usePriority(ref, disabled); 20 21 useLayoutEffect(() => { 22 const { current: element } = ref; 23 // NOTE: This behaviour isn't necessary for input elements 24 if (!element || disabled || isInputElement(element)) return; 25 26 function onKey(event: KeyboardEvent) { 27 if (!element || event.defaultPrevented || event.isComposing) return; 28 29 const active = getActive(); 30 if (!isFocusTarget(element) || !contains(active, element)) { 31 // Do nothing if the current item is not a target or not focused 32 return; 33 } else if (event.code === 'Space' || event.code === 'Enter') { 34 event.preventDefault(); 35 click(element); 36 } 37 } 38 39 element.addEventListener('keydown', onKey); 40 return () => { 41 element.removeEventListener('keydown', onKey); 42 }; 43 }, [ref.current, disabled, hasPriority]); 44}