{"version":3,"sources":["../src/components/Menu/useMenu.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n  useControllableState,\n  useEventCallback,\n  useFirstMount,\n  useId,\n  useMergedRefs,\n  useTimeout,\n} from '@fluentui/react-utilities';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport { MENU_ENTER_EVENT } from '@fluentui/react-menu';\nimport type {\n  PositioningShorthandValue,\n  PositioningVirtualElement,\n  SetVirtualMouseTarget,\n} from '@fluentui/react-positioning';\n\nimport { useMenuContext } from './menuContext';\nimport { useHasParentMenuList } from './menuListPresenceContext';\nimport { usePositioning, resolvePositioningShorthand } from '../../positioning';\nimport type { MenuOpenChangeData, MenuOpenEvent, MenuProps, MenuState } from './Menu.types';\n\nexport const useMenu = (props: MenuProps): MenuState => {\n  const isSubmenu = useIsSubmenu();\n  const {\n    hoverDelay = 500,\n    inline = false,\n    hasCheckmarks = false,\n    hasIcons = false,\n    closeOnScroll = false,\n    openOnContext = false,\n    persistOnItemClick = false,\n    openOnHover = isSubmenu,\n    defaultCheckedValues,\n    mountNode = null,\n  } = props;\n\n  const triggerId = useId('menu');\n  const [contextTarget, setContextTarget] = useContextTargetState();\n\n  const triggerRef = React.useRef<HTMLElement | null>(null);\n  const menuPopoverRef = React.useRef<HTMLElement | null>(null);\n\n  const children = React.Children.toArray(props.children) as React.ReactElement[];\n\n  if (process.env.NODE_ENV !== 'production') {\n    if (children.length === 0) {\n      // eslint-disable-next-line no-console\n      console.warn('Menu must contain at least one child');\n    }\n\n    if (children.length > 2) {\n      // eslint-disable-next-line no-console\n      console.warn('Menu must contain at most two children');\n    }\n  }\n\n  let menuTrigger: React.ReactElement | undefined = undefined;\n  let menuPopover: React.ReactElement | undefined = undefined;\n  if (children.length === 2) {\n    menuTrigger = children[0];\n    menuPopover = children[1];\n  } else if (children.length === 1) {\n    menuPopover = children[0];\n  }\n\n  const [open, setOpen] = useMenuOpenState({\n    hoverDelay,\n    setContextTarget,\n    // eslint-disable-next-line @typescript-eslint/no-deprecated\n    triggerRef: triggerRef as React.MutableRefObject<HTMLElement | null>,\n    // eslint-disable-next-line @typescript-eslint/no-deprecated\n    menuPopoverRef: menuPopoverRef as React.MutableRefObject<HTMLElement | null>,\n    open: props.open,\n    defaultOpen: props.defaultOpen,\n    onOpenChange: props.onOpenChange,\n  });\n\n  const [checkedValues, onCheckedValueChange] = useMenuSelectableState({\n    checkedValues: props.checkedValues,\n    defaultCheckedValues,\n    onCheckedValueChange: props.onCheckedValueChange,\n  });\n\n  const resolvedPositioning = resolvePositioningShorthand(props.positioning);\n  const positioningOptions = {\n    position: isSubmenu ? 'after' : 'below',\n    align: isSubmenu ? 'top' : 'start',\n    target: openOnContext ? contextTarget : undefined,\n    fallbackPositions: isSubmenu ? SUBMENU_FALLBACK_POSITIONS : undefined,\n    ...resolvedPositioning,\n  } as const;\n\n  const { targetRef, containerRef } = usePositioning(positioningOptions);\n\n  // eslint-disable-next-line @typescript-eslint/no-deprecated\n  const mergedTriggerRef = useMergedRefs(triggerRef, targetRef) as React.MutableRefObject<HTMLElement | null>;\n  // prettier-ignore\n  // eslint-disable-next-line @typescript-eslint/no-deprecated\n  const mergedMenuPopoverRef = useMergedRefs(menuPopoverRef, containerRef) as React.MutableRefObject<HTMLElement | null>;\n\n  return {\n    inline,\n    hoverDelay,\n    triggerId,\n    isSubmenu,\n    openOnHover,\n    contextTarget,\n    setContextTarget,\n    hasCheckmarks,\n    hasIcons,\n    closeOnScroll,\n    menuTrigger,\n    menuPopover,\n    mountNode,\n    triggerRef: mergedTriggerRef,\n    menuPopoverRef: mergedMenuPopoverRef,\n    openOnContext,\n    open,\n    setOpen,\n    checkedValues,\n    onCheckedValueChange,\n    persistOnItemClick,\n  } as MenuState;\n};\n\nconst SUBMENU_FALLBACK_POSITIONS: PositioningShorthandValue[] = [\n  'after',\n  'after-bottom',\n  'before-top',\n  'before',\n  'before-bottom',\n  'above',\n];\n\nconst useIsSubmenu = (): boolean => {\n  const parentIsSubmenu = useMenuContext(ctx => ctx.isSubmenu);\n  const hasParentMenuList = useHasParentMenuList();\n  return parentIsSubmenu || hasParentMenuList;\n};\n\nconst useContextTargetState = (): [PositioningVirtualElement | undefined, SetVirtualMouseTarget] => {\n  const [virtualElement, setVirtualElement] = React.useState<PositioningVirtualElement | undefined>(undefined);\n  const setContextTarget: SetVirtualMouseTarget = useEventCallback(event => {\n    if (event === undefined || event === null) {\n      setVirtualElement(undefined);\n      return;\n    }\n\n    const mouseEvent = event instanceof MouseEvent ? event : event.nativeEvent;\n\n    if (process.env.NODE_ENV !== 'production' && !(mouseEvent instanceof MouseEvent)) {\n      // eslint-disable-next-line no-console\n      console.error('Menu contextTarget should only be set from a MouseEvent');\n    }\n\n    setVirtualElement(createVirtualElementFromClick(mouseEvent));\n  });\n\n  return [virtualElement, setContextTarget];\n};\n\nconst createVirtualElementFromClick = (nativeEvent: MouseEvent): PositioningVirtualElement => {\n  const left = nativeEvent.clientX;\n  const top = nativeEvent.clientY;\n  const right = left + 1;\n  const bottom = top + 1;\n\n  return {\n    getBoundingClientRect() {\n      return { left, top, right, bottom, x: left, y: top, height: 1, width: 1 };\n    },\n  };\n};\n\nconst useMenuSelectableState = (\n  props: Pick<MenuProps, 'checkedValues' | 'defaultCheckedValues' | 'onCheckedValueChange'>,\n) => {\n  const [checkedValues, setCheckedValues] = useControllableState({\n    state: props.checkedValues,\n    defaultState: props.defaultCheckedValues,\n    initialState: {},\n  });\n\n  const onCheckedValueChange: MenuState['onCheckedValueChange'] = useEventCallback((e, { name, checkedItems }) => {\n    props.onCheckedValueChange?.(e, { name, checkedItems });\n\n    setCheckedValues(currentValue => ({\n      ...currentValue,\n      [name]: checkedItems,\n    }));\n  });\n\n  return [checkedValues, onCheckedValueChange] as const;\n};\n\nconst useMenuOpenState = (\n  state: {\n    hoverDelay: number;\n    setContextTarget: SetVirtualMouseTarget;\n    // eslint-disable-next-line @typescript-eslint/no-deprecated\n    triggerRef: React.MutableRefObject<HTMLElement | null>;\n    // eslint-disable-next-line @typescript-eslint/no-deprecated\n    menuPopoverRef: React.MutableRefObject<HTMLElement | null>;\n  } & Pick<MenuProps, 'open' | 'defaultOpen' | 'onOpenChange'>,\n) => {\n  const { targetDocument } = useFluent();\n  const parentSetOpen = useMenuContext(ctx => ctx.setOpen);\n  const onOpenChange: MenuProps['onOpenChange'] = useEventCallback((e, data) => state.onOpenChange?.(e, data));\n\n  const enteringTriggerRef = React.useRef(false);\n\n  const [open, setOpenState] = useControllableState({\n    state: state.open,\n    defaultState: state.defaultOpen,\n    initialState: false,\n  });\n\n  const trySetOpen = useEventCallback((e: MenuOpenEvent, data: MenuOpenChangeData) => {\n    const event = e instanceof CustomEvent && e.type === MENU_ENTER_EVENT ? e.detail.nativeEvent : e;\n    onOpenChange?.(event, { ...data });\n    if (data.open && e.type === 'contextmenu') {\n      state.setContextTarget(e as React.MouseEvent);\n    }\n\n    if (!data.open) {\n      state.setContextTarget(undefined);\n    }\n\n    if (data.bubble) {\n      parentSetOpen(e, { ...data });\n    }\n\n    setOpenState(data.open);\n  });\n\n  const [setOpenTimeout, clearOpenTimeout] = useTimeout();\n\n  const setOpen = useEventCallback((e: MenuOpenEvent, data: MenuOpenChangeData & { ignoreHoverDelay?: boolean }) => {\n    clearOpenTimeout();\n    if (!(e instanceof Event) && e.persist) {\n      // < React 17 still uses pooled synthetic events\n      e.persist();\n    }\n\n    const shouldUseDelay =\n      !data.ignoreHoverDelay &&\n      (e.type === 'mouseleave' || e.type === 'mouseover' || e.type === 'mousemove' || e.type === MENU_ENTER_EVENT);\n\n    if (shouldUseDelay) {\n      if (state.triggerRef.current?.contains(e.target as HTMLElement)) {\n        enteringTriggerRef.current = e.type === 'mouseover' || e.type === 'mousemove';\n      }\n\n      setOpenTimeout(() => trySetOpen(e, data), state.hoverDelay);\n    } else {\n      trySetOpen(e, data);\n    }\n  });\n\n  const firstMount = useFirstMount();\n\n  React.useEffect(() => {\n    if (open || firstMount) {\n      return;\n    }\n\n    if (\n      targetDocument?.activeElement === targetDocument?.body ||\n      state.menuPopoverRef.current?.contains(targetDocument?.activeElement ?? null)\n    ) {\n      state.triggerRef.current?.focus();\n    }\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [open, targetDocument, state.menuPopoverRef, state.triggerRef]);\n\n  return [open, setOpen] as const;\n};\n"],"names":["useMenu","props","isSubmenu","useIsSubmenu","hoverDelay","inline","hasCheckmarks","hasIcons","closeOnScroll","openOnContext","persistOnItemClick","openOnHover","defaultCheckedValues","mountNode","triggerId","useId","contextTarget","setContextTarget","useContextTargetState","triggerRef","React","useRef","menuPopoverRef","children","Children","toArray","process","env","NODE_ENV","length","console","warn","menuTrigger","undefined","menuPopover","open","setOpen","useMenuOpenState","defaultOpen","onOpenChange","checkedValues","onCheckedValueChange","useMenuSelectableState","resolvedPositioning","resolvePositioningShorthand","positioning","positioningOptions","position","align","target","fallbackPositions","SUBMENU_FALLBACK_POSITIONS","targetRef","containerRef","usePositioning","mergedTriggerRef","useMergedRefs","mergedMenuPopoverRef","parentIsSubmenu","useMenuContext","ctx","hasParentMenuList","useHasParentMenuList","virtualElement","setVirtualElement","useState","useEventCallback","event","mouseEvent","MouseEvent","nativeEvent","error","createVirtualElementFromClick","left","clientX","top","clientY","right","bottom","getBoundingClientRect","x","y","height","width","setCheckedValues","useControllableState","state","defaultState","initialState","e","name","checkedItems","currentValue","targetDocument","useFluent","parentSetOpen","data","enteringTriggerRef","setOpenState","trySetOpen","CustomEvent","type","MENU_ENTER_EVENT","detail","bubble","setOpenTimeout","clearOpenTimeout","useTimeout","Event","persist","shouldUseDelay","ignoreHoverDelay","current","contains","firstMount","useFirstMount","useEffect","activeElement","body","focus"],"mappings":"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"}