"use client";
import { jsx as _jsx } from "react/jsx-runtime";
import { cnb } from "cnbuilder";
import { forwardRef, useEffect, useRef } from "react";
import { useFocusContainer } from "../focus/useFocusContainer.js";
import { useUserInteractionMode } from "../interaction/UserInteractionModeProvider.js";
import { useAppSize } from "../media-queries/AppSizeProvider.js";
import { Portal } from "../portal/Portal.js";
import { useFixedPositioning } from "../positioning/useFixedPositioning.js";
import { useScrollLock } from "../scroll/useScrollLock.js";
import { useScaleTransition } from "../transition/useScaleTransition.js";
import { useEnsuredId } from "../useEnsuredId.js";
import { MenuConfigurationProvider, useMenuConfiguration } from "./MenuConfigurationProvider.js";
import { MenuSheet } from "./MenuSheet.js";
import { MenuWidget } from "./MenuWidget.js";
import { useMenuBarContext } from "./useMenuBarProvider.js";
import { getDefaultAnchor } from "./utils.js";
const noop = ()=>{
// do nothing
};
/**
 * **Client Component**
 *
 * This component should generally only be used to implement context menus with
 * the `useContextMenu` hook. Otherwise, the `DropdownMenu` component should be
 * used.
 *
 * @see The `useContextMenu` hook for an example.
 *
 * @remarks
 * \@since 5.0.0
 * \@since 6.0.0 Updated this component to implement all the `Menu`
 * functionality instead of requiring the `useMenu` hook and `MenuWidget`
 * component. In addition, the `renderAsSheet` behavior has been moved into this
 * implementation so that the `MenuRenderer` is no longer required and context
 * menus can appear as a `Sheet`.
 */ export const Menu = /*#__PURE__*/ forwardRef(function Menu(props, propRef) {
    const { id: propId, style: propStyle, role = "menu", children, horizontal: _horizontal, sheetHeader: _sheetHeader, sheetFooter: _sheetFooter, renderAsSheet: _renderAsSheet, sheetPosition: _sheetPosition, sheetVerticalSize: _sheetVerticalSize, sheetProps, sheetStyle, sheetClassName, menuStyle, menuClassName, disableElevation = false, temporary = true, tabIndex = -1, fixedTo, className, classNames, timeout, appear, enter, exit, onEnter, onEntering = noop, onEntered = noop, onExit, onExiting, onExited = noop, onKeyDown = noop, listProps, listStyle, listClassName, visible, onRequestClose, floating, anchor, closeOnResize = false, closeOnScroll = false, preventScroll = false, vwMargin, vhMargin, xMargin, yMargin, width, transformOrigin = true, preventOverlap, disableSwapping, disableVHBounds, initialX, initialY, getFixedPositionOptions, disablePortal: propDisablePortal, disableTransition, ...remaining } = props;
    const { "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy } = props;
    const id = useEnsuredId(propId, "menu");
    const { root, menubar, menuitem, activeId, animatedOnceRef, hoverTimeoutRef, disableHoverMode } = useMenuBarContext();
    const { horizontal, sheetHeader, sheetFooter, renderAsSheet, sheetPosition, sheetVerticalSize } = useMenuConfiguration(props);
    const { isPhone } = useAppSize();
    const isSheet = renderAsSheet === true || renderAsSheet === "phone" && isPhone;
    const entered = useRef(false);
    const cancelUnmountFocus = useRef(false);
    const hideWithoutRefocus = ()=>{
        cancelUnmountFocus.current = true;
        onRequestClose();
    };
    const mode = useUserInteractionMode();
    const mouse = mode === "mouse";
    const { eventHandlers, transitionOptions } = useFocusContainer({
        nodeRef: propRef,
        activate: visible,
        onKeyDown (event) {
            onKeyDown(event);
            // when a menu is within a sheet, it should not trigger the custom
            // keyboard behavior
            if (isSheet) {
                return;
            }
            switch(event.key){
                case "Escape":
                    // prevent parent components that have an "Escape" keypress event
                    // from being triggered as well
                    event.stopPropagation();
                    disableHoverMode();
                    onRequestClose();
                    break;
                case "Tab":
                    // since menus are portalled, tab index is kinda broke so just close
                    // the menu instead of doing default tab behavior
                    event.preventDefault();
                    if (!menuitem) {
                        // pressing the tab key should still cascade close all menus
                        event.stopPropagation();
                    }
                    disableHoverMode();
                    onRequestClose();
                    break;
                case "ArrowUp":
                    if (!root && menuitem && horizontal) {
                        event.stopPropagation();
                        event.preventDefault();
                        onRequestClose();
                    }
                    break;
                case "ArrowLeft":
                    if (!root && menuitem && !horizontal) {
                        event.stopPropagation();
                        event.preventDefault();
                        onRequestClose();
                    }
                    break;
            }
        },
        onEntering (appearing) {
            onEntering(appearing);
            entered.current = true;
        },
        onEntered (appearing) {
            onEntered(appearing);
            entered.current = true;
            cancelUnmountFocus.current = false;
            animatedOnceRef.current = true;
        },
        onExited () {
            onExited();
            entered.current = false;
        },
        onExiting,
        disableTransition,
        isFocusTypeDisabled (type) {
            if (role === "listbox") {
                return !isSheet;
            }
            if (type === "keyboard") {
                return isSheet;
            }
            const isHoverDisabled = mouse && hoverTimeoutRef.current === 0;
            if (type === "mount") {
                return isHoverDisabled;
            }
            return isHoverDisabled || cancelUnmountFocus.current || root && !!activeId && id !== activeId;
        }
    });
    const { ref, style, callbacks } = useFixedPositioning({
        ...transitionOptions,
        onEnter,
        style: isSheet ? propStyle : menuStyle,
        fixedTo,
        anchor: getDefaultAnchor({
            anchor,
            menubar,
            floating,
            menuitem: !root && menuitem,
            horizontal
        }),
        vwMargin,
        vhMargin,
        xMargin,
        yMargin,
        width,
        transformOrigin,
        preventOverlap,
        disableSwapping,
        disableVHBounds,
        initialX,
        initialY,
        getFixedPositionOptions,
        onResize: closeOnResize ? hideWithoutRefocus : undefined,
        onScroll (_event, data) {
            if (!data.visible || closeOnScroll) {
                hideWithoutRefocus();
            }
        }
    });
    const { rendered, disablePortal, elementProps } = useScaleTransition({
        nodeRef: ref,
        className: cnb(!isSheet && menuClassName, className),
        transitionIn: visible,
        vertical: !horizontal,
        temporary,
        timeout: isSheet || disableTransition ? 0 : timeout,
        classNames,
        appear,
        enter,
        exit,
        onExit,
        onExiting: transitionOptions.onExiting,
        exitedHidden: true,
        ...callbacks
    });
    useScrollLock(visible && preventScroll);
    // need to make sure that the useEffect does not refire for hiding on click
    // events because of the `window.requestAnimationFrame`. It'll make it so
    // that menu items that update state are unable to close when clicked
    const hide = useRef(onRequestClose);
    useEffect(()=>{
        hide.current = onRequestClose;
    });
    useEffect(()=>{
        if (!visible) {
            return;
        }
        const callback = (event)=>{
            // this is required for when the transition is disabled
            if (!entered.current) {
                return;
            }
            // if the user clicks outside of the menu to close it, the toggle button
            // should not be focused. instead the nearest focusable element from the
            // click event should be focused when Tab or Shift + tab is pressed
            cancelUnmountFocus.current = !(event.target instanceof HTMLElement) || !event.target.closest(`[role="${role}"]`);
            // this won't be called if `event.stopPropagation()` is called
            hide.current();
            disableHoverMode();
        };
        // wait an animation frame so the initial click event that caused the menu
        // to become visible does not immediately close the menu
        const frame = window.requestAnimationFrame(()=>{
            window.addEventListener("click", callback);
        });
        return ()=>{
            window.cancelAnimationFrame(frame);
            window.removeEventListener("click", callback);
        };
    }, [
        disableHoverMode,
        role,
        visible
    ]);
    return /*#__PURE__*/ _jsx(MenuConfigurationProvider, {
        horizontal: horizontal,
        renderAsSheet: renderAsSheet,
        sheetFooter: sheetFooter,
        sheetHeader: sheetHeader,
        sheetPosition: sheetPosition,
        sheetVerticalSize: sheetVerticalSize,
        children: /*#__PURE__*/ _jsx(MenuSheet, {
            "aria-label": ariaLabel,
            "aria-labelledby": ariaLabelledBy,
            header: sheetHeader,
            footer: sheetFooter,
            position: sheetPosition,
            verticalSize: sheetVerticalSize,
            visible: visible,
            enabled: isSheet,
            onRequestClose: onRequestClose,
            style: sheetStyle,
            className: sheetClassName,
            disablePortal: propDisablePortal,
            temporary: temporary,
            disableTransition: disableTransition,
            ...sheetProps,
            children: /*#__PURE__*/ _jsx(Portal, {
                disabled: isSheet || (propDisablePortal ?? disablePortal),
                children: (rendered || isSheet) && /*#__PURE__*/ _jsx(MenuWidget, {
                    ...remaining,
                    ...elementProps,
                    ...eventHandlers,
                    id: id,
                    role: role,
                    style: isSheet ? propStyle : style,
                    isSheet: isSheet,
                    tabIndex: tabIndex,
                    horizontal: horizontal,
                    listProps: listProps,
                    listStyle: listStyle,
                    listClassName: listClassName,
                    disableElevation: disableElevation,
                    cancelUnmountFocus: cancelUnmountFocus,
                    children: children
                })
            })
        })
    });
});

//# sourceMappingURL=Menu.js.map