import * as React from 'react'; import { useEventCallback, elementContains } from '@fluentui/react-utilities'; /** * Name of the custom event */ export const MENU_ENTER_EVENT = 'fuimenuenter'; /** * This hook works similarly to @see useOnClickOutside * * Problem: Trying to behave the same as system menus: * When the mouse leaves a stack of nested menus the stack should not dismiss. * However if the mouse leaves a stack of menus and enters a parent menu all its children menu should dismiss. * * We don't use the native mouseenter event because it would trigger too many times in the document * Instead, dispatch custom DOM event from the menu so that it can bubble * Each nested menu can use the listener to check if the event is from a child or parent menu */ export const useOnMenuMouseEnter = (options)=>{ const { refs, callback, element, disabled } = options; // Keep mouse event here because this is essentially a custom 'mouseenter' event const listener = useEventCallback((ev)=>{ const popoverRef = refs[0]; const someMenuPopover = ev.target; var _popoverRef_current; // someMenu is a child -> will always be contained because of vParents // someMenu is a parent -> will always not be contained because no vParent // someMenu is the current popover -> it will contain itself const isOutsidePopover = !elementContains((_popoverRef_current = popoverRef.current) !== null && _popoverRef_current !== void 0 ? _popoverRef_current : null, someMenuPopover); if (isOutsidePopover && !disabled) { callback(ev); } }); React.useEffect(()=>{ // eslint-disable-next-line eqeqeq if (element == null) { return; } if (!disabled) { element.addEventListener(MENU_ENTER_EVENT, listener); } return ()=>{ element.removeEventListener(MENU_ENTER_EVENT, listener); }; }, [ listener, element, disabled ]); }; /** * Dispatches the custom MouseEvent enter event. Similar to calling `el.click()` * @param el - element for the event target * @param nativeEvent - the native mouse event this is mapped to */ export const dispatchMenuEnterEvent = (el, nativeEvent)=>{ el.dispatchEvent(new CustomEvent(MENU_ENTER_EVENT, { bubbles: true, detail: { nativeEvent } })); };