( props: AriaSubmenuTriggerProps, state: SubmenuTriggerState, ref: RefObject<FocusableElement | null> )
| 86 | * @param ref - Ref to the submenu trigger element. |
| 87 | */ |
| 88 | export function useSubmenuTrigger<T>( |
| 89 | props: AriaSubmenuTriggerProps, |
| 90 | state: SubmenuTriggerState, |
| 91 | ref: RefObject<FocusableElement | null> |
| 92 | ): SubmenuTriggerAria<T> { |
| 93 | let { |
| 94 | parentMenuRef, |
| 95 | submenuRef, |
| 96 | type = 'menu', |
| 97 | isDisabled, |
| 98 | delay = 200, |
| 99 | shouldUseVirtualFocus |
| 100 | } = props; |
| 101 | let submenuTriggerId = useId(); |
| 102 | let overlayId = useId(); |
| 103 | let {direction} = useLocale(); |
| 104 | let openTimeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined); |
| 105 | let cancelOpenTimeout = useCallback(() => { |
| 106 | if (openTimeout.current) { |
| 107 | clearTimeout(openTimeout.current); |
| 108 | openTimeout.current = undefined; |
| 109 | } |
| 110 | }, [openTimeout]); |
| 111 | |
| 112 | let onSubmenuOpen = useCallback( |
| 113 | (focusStrategy?: FocusStrategy) => { |
| 114 | cancelOpenTimeout(); |
| 115 | state.open(focusStrategy); |
| 116 | }, |
| 117 | [state, cancelOpenTimeout] |
| 118 | ); |
| 119 | |
| 120 | let onSubmenuClose = useCallback(() => { |
| 121 | cancelOpenTimeout(); |
| 122 | state.close(); |
| 123 | }, [state, cancelOpenTimeout]); |
| 124 | |
| 125 | useLayoutEffect(() => { |
| 126 | return () => { |
| 127 | cancelOpenTimeout(); |
| 128 | }; |
| 129 | }, [cancelOpenTimeout]); |
| 130 | |
| 131 | let {keyboardProps} = useKeyboard({ |
| 132 | shortcuts: { |
| 133 | ArrowLeft: e => { |
| 134 | // If focus is not within the menu, assume virtual focus is being used. |
| 135 | // This means some other input element is also within the popover, so we shouldn't close the menu. |
| 136 | if (!isFocusWithin(e.currentTarget)) { |
| 137 | return false; |
| 138 | } |
| 139 | if (direction === 'ltr' && nodeContains(e.currentTarget, getEventTarget(e) as Element)) { |
| 140 | onSubmenuClose(); |
| 141 | if (!shouldUseVirtualFocus && ref.current) { |
| 142 | focusWithoutScrolling(ref.current); |
| 143 | } |
| 144 | return; |
| 145 | } |
no test coverage detected