define(["require", "exports", "tslib", "react", "./ContextualMenu.types", "../../common/DirectionalHint", "../../FocusZone", "../../Utilities", "../../utilities/contextualMenu/index", "../../Callout", "./ContextualMenuItem", "./ContextualMenuItemWrapper/index", "../../Styling", "./ContextualMenu.classNames", "@fluentui/react-hooks", "../../ResponsiveMode", "../../utilities/MenuContext/index"], function (require, exports, tslib_1, React, ContextualMenu_types_1, DirectionalHint_1, FocusZone_1, Utilities_1, index_1, Callout_1, ContextualMenuItem_1, index_2, Styling_1, ContextualMenu_classNames_1, react_hooks_1, ResponsiveMode_1, index_3) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.ContextualMenuBase = exports.canAnyMenuItemsCheck = exports.getSubmenuItems = void 0;
    var getClassNames = Utilities_1.classNamesFunction();
    var getContextualMenuItemClassNames = Utilities_1.classNamesFunction();
    // The default ContextualMenu properties have no items and beak, the default submenu direction is right and top.
    var DEFAULT_PROPS = {
        items: [],
        shouldFocusOnMount: true,
        gapSpace: 0,
        directionalHint: DirectionalHint_1.DirectionalHint.bottomAutoEdge,
        beakWidth: 16,
    };
    function getSubmenuItems(item, options) {
        var target = options === null || options === void 0 ? void 0 : options.target;
        // eslint-disable-next-line deprecation/deprecation
        var items = item.subMenuProps ? item.subMenuProps.items : item.items;
        if (items) {
            var overrideItems = [];
            for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
                var subItem = items_1[_i];
                if (subItem.preferMenuTargetAsEventTarget) {
                    // For sub-items which need an overridden target, intercept `onClick`
                    var onClick = subItem.onClick, contextItem = tslib_1.__rest(subItem, ["onClick"]);
                    overrideItems.push(tslib_1.__assign(tslib_1.__assign({}, contextItem), { onClick: getOnClickWithOverrideTarget(onClick, target) }));
                }
                else {
                    overrideItems.push(subItem);
                }
            }
            return overrideItems;
        }
    }
    exports.getSubmenuItems = getSubmenuItems;
    /**
     * Returns true if a list of menu items can contain a checkbox
     */
    function canAnyMenuItemsCheck(items) {
        return items.some(function (item) {
            if (item.canCheck) {
                return true;
            }
            // If the item is a section, check if any of the items in the section can check.
            if (item.sectionProps && item.sectionProps.items.some(function (submenuItem) { return submenuItem.canCheck === true; })) {
                return true;
            }
            return false;
        });
    }
    exports.canAnyMenuItemsCheck = canAnyMenuItemsCheck;
    var NavigationIdleDelay = 250; /* ms */
    var COMPONENT_NAME = 'ContextualMenu';
    var _getMenuItemStylesFunction = Utilities_1.memoizeFunction(function () {
        var styles = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            styles[_i] = arguments[_i];
        }
        return function (styleProps) {
            return Styling_1.concatStyleSetsWithProps.apply(void 0, tslib_1.__spreadArray([styleProps, ContextualMenu_classNames_1.getItemStyles], styles));
        };
    });
    //#region Custom hooks
    function useVisibility(props, targetWindow) {
        var _a = props.hidden, hidden = _a === void 0 ? false : _a, onMenuDismissed = props.onMenuDismissed, onMenuOpened = props.onMenuOpened;
        var previousHidden = react_hooks_1.usePrevious(hidden);
        var onMenuOpenedRef = React.useRef(onMenuOpened);
        var onMenuClosedRef = React.useRef(onMenuDismissed);
        var propsRef = React.useRef(props);
        onMenuOpenedRef.current = onMenuOpened;
        onMenuClosedRef.current = onMenuDismissed;
        propsRef.current = props;
        React.useEffect(function () {
            var _a, _b;
            // Don't issue dismissed callbacks on initial mount
            if (hidden && previousHidden === false) {
                (_a = onMenuClosedRef.current) === null || _a === void 0 ? void 0 : _a.call(onMenuClosedRef, propsRef.current);
            }
            else if (!hidden && previousHidden !== false) {
                (_b = onMenuOpenedRef.current) === null || _b === void 0 ? void 0 : _b.call(onMenuOpenedRef, propsRef.current);
            }
        }, [hidden, previousHidden]);
        // Issue onDismissedCallback on unmount
        React.useEffect(function () { return function () { var _a; return (_a = onMenuClosedRef.current) === null || _a === void 0 ? void 0 : _a.call(onMenuClosedRef, propsRef.current); }; }, []);
    }
    function useSubMenuState(_a, dismiss) {
        var hidden = _a.hidden, items = _a.items, theme = _a.theme, className = _a.className, id = _a.id, menuTarget = _a.target;
        var _b = React.useState(), expandedMenuItemKey = _b[0], setExpandedMenuItemKey = _b[1];
        var _c = React.useState(), submenuTarget = _c[0], setSubmenuTarget = _c[1];
        /** True if the menu was expanded by mouse click OR hover (as opposed to by keyboard) */
        var _d = React.useState(), shouldFocusOnContainer = _d[0], setShouldFocusOnContainer = _d[1];
        var subMenuId = react_hooks_1.useId(COMPONENT_NAME, id);
        var closeSubMenu = React.useCallback(function () {
            setShouldFocusOnContainer(undefined);
            setExpandedMenuItemKey(undefined);
            setSubmenuTarget(undefined);
        }, []);
        var openSubMenu = React.useCallback(function (_a, target, focusContainer) {
            var submenuItemKey = _a.key;
            if (expandedMenuItemKey === submenuItemKey) {
                return;
            }
            target.focus();
            setShouldFocusOnContainer(focusContainer);
            setExpandedMenuItemKey(submenuItemKey);
            setSubmenuTarget(target);
        }, [expandedMenuItemKey]);
        React.useEffect(function () {
            if (hidden) {
                closeSubMenu();
            }
        }, [hidden, closeSubMenu]);
        var onSubMenuDismiss = useOnSubmenuDismiss(dismiss, closeSubMenu);
        var getSubmenuProps = function () {
            var item = findItemByKeyFromItems(expandedMenuItemKey, items);
            var submenuProps = null;
            if (item) {
                submenuProps = {
                    items: getSubmenuItems(item, { target: menuTarget }),
                    target: submenuTarget,
                    onDismiss: onSubMenuDismiss,
                    isSubMenu: true,
                    id: subMenuId,
                    shouldFocusOnMount: true,
                    shouldFocusOnContainer: shouldFocusOnContainer,
                    directionalHint: Utilities_1.getRTL(theme) ? DirectionalHint_1.DirectionalHint.leftTopEdge : DirectionalHint_1.DirectionalHint.rightTopEdge,
                    className: className,
                    gapSpace: 0,
                    isBeakVisible: false,
                };
                if (item.subMenuProps) {
                    Utilities_1.assign(submenuProps, item.subMenuProps);
                }
                if (item.preferMenuTargetAsEventTarget) {
                    var onItemClick = item.onItemClick;
                    submenuProps.onItemClick = getOnClickWithOverrideTarget(onItemClick, menuTarget);
                }
            }
            return submenuProps;
        };
        return [expandedMenuItemKey, openSubMenu, getSubmenuProps, onSubMenuDismiss];
    }
    function useShouldUpdateFocusOnMouseMove(_a) {
        var delayUpdateFocusOnHover = _a.delayUpdateFocusOnHover, hidden = _a.hidden;
        var shouldUpdateFocusOnMouseEvent = React.useRef(!delayUpdateFocusOnHover);
        var gotMouseMove = React.useRef(false);
        React.useEffect(function () {
            shouldUpdateFocusOnMouseEvent.current = !delayUpdateFocusOnHover;
            gotMouseMove.current = hidden ? false : !delayUpdateFocusOnHover && gotMouseMove.current;
        }, [delayUpdateFocusOnHover, hidden]);
        var onMenuFocusCapture = React.useCallback(function () {
            if (delayUpdateFocusOnHover) {
                shouldUpdateFocusOnMouseEvent.current = false;
            }
        }, [delayUpdateFocusOnHover]);
        return [shouldUpdateFocusOnMouseEvent, gotMouseMove, onMenuFocusCapture];
    }
    function usePreviousActiveElement(_a, targetWindow) {
        var hidden = _a.hidden, onRestoreFocus = _a.onRestoreFocus;
        var previousActiveElement = React.useRef();
        var activeElement = targetWindow ? Utilities_1.getActiveElement(targetWindow === null || targetWindow === void 0 ? void 0 : targetWindow.document) : undefined;
        var tryFocusPreviousActiveElement = React.useCallback(function (options) {
            var _a, _b;
            if (onRestoreFocus) {
                onRestoreFocus(options);
            }
            else if (options === null || options === void 0 ? void 0 : options.documentContainsFocus) {
                // Make sure that the focus method actually exists
                // In some cases the object might exist but not be a real element.
                // This is primarily for IE 11 and should be removed once IE 11 is no longer in use.
                (_b = (_a = previousActiveElement.current) === null || _a === void 0 ? void 0 : _a.focus) === null || _b === void 0 ? void 0 : _b.call(_a);
            }
        }, [onRestoreFocus]);
        react_hooks_1.useIsomorphicLayoutEffect(function () {
            var _a;
            if (!hidden) {
                previousActiveElement.current = activeElement;
            }
            else if (previousActiveElement.current) {
                tryFocusPreviousActiveElement({
                    originalElement: previousActiveElement.current,
                    containsFocus: true,
                    documentContainsFocus: ((_a = Utilities_1.getDocument()) === null || _a === void 0 ? void 0 : _a.hasFocus()) || false,
                });
                previousActiveElement.current = undefined;
            }
        }, [hidden, activeElement, tryFocusPreviousActiveElement]);
        return [tryFocusPreviousActiveElement];
    }
    function useKeyHandlers(_a, dismiss, hostElement, openSubMenu) {
        var theme = _a.theme, isSubMenu = _a.isSubMenu, _b = _a.focusZoneProps, _c = _b === void 0 ? {} : _b, checkForNoWrap = _c.checkForNoWrap, _d = _c.direction, focusZoneDirection = _d === void 0 ? FocusZone_1.FocusZoneDirection.vertical : _d;
        /** True if the most recent keydown event was for alt (option) or meta (command). */
        var lastKeyDownWasAltOrMeta = React.useRef();
        /**
         * Calls `shouldHandleKey` to determine whether the keyboard event should be handled;
         * if so, stops event propagation and dismisses menu(s).
         * @param ev - The keyboard event.
         * @param shouldHandleKey - Returns whether we should handle this keyboard event.
         * @param dismissAllMenus - If true, dismiss all menus. Otherwise, dismiss only the current menu.
         * Only does anything if `shouldHandleKey` returns true.
         * @returns Whether the event was handled.
         */
        var keyHandler = function (ev, shouldHandleKey, dismissAllMenus) {
            var handled = false;
            if (shouldHandleKey(ev)) {
                dismiss(ev, dismissAllMenus);
                ev.preventDefault();
                ev.stopPropagation();
                handled = true;
            }
            return handled;
        };
        /**
         * Checks if the submenu should be closed
         */
        var shouldCloseSubMenu = function (ev) {
            var submenuCloseKey = Utilities_1.getRTL(theme) ? Utilities_1.KeyCodes.right : Utilities_1.KeyCodes.left;
            // eslint-disable-next-line deprecation/deprecation
            if (ev.which !== submenuCloseKey || !isSubMenu) {
                return false;
            }
            return !!(focusZoneDirection === FocusZone_1.FocusZoneDirection.vertical ||
                (checkForNoWrap && !Utilities_1.shouldWrapFocus(ev.target, 'data-no-horizontal-wrap')));
        };
        var shouldHandleKeyDown = function (ev) {
            return (
            // eslint-disable-next-line deprecation/deprecation
            ev.which === Utilities_1.KeyCodes.escape ||
                shouldCloseSubMenu(ev) ||
                // eslint-disable-next-line deprecation/deprecation
                (ev.which === Utilities_1.KeyCodes.up && (ev.altKey || ev.metaKey)));
        };
        var onKeyDown = function (ev) {
            // Take note if we are processing an alt (option) or meta (command) keydown.
            // See comment in shouldHandleKeyUp for reasoning.
            lastKeyDownWasAltOrMeta.current = isAltOrMeta(ev);
            // On Mac, pressing escape dismisses all levels of native context menus
            // eslint-disable-next-line deprecation/deprecation
            var dismissAllMenus = ev.which === Utilities_1.KeyCodes.escape && (Utilities_1.isMac() || Utilities_1.isIOS());
            return keyHandler(ev, shouldHandleKeyDown, dismissAllMenus);
        };
        /**
         * We close the menu on key up only if ALL of the following are true:
         * - Most recent key down was alt or meta (command)
         * - The alt/meta key down was NOT followed by some other key (such as down/up arrow to
         *   expand/collapse the menu)
         * - We're not on a Mac (or iOS)
         *
         * This is because on Windows, pressing alt moves focus to the application menu bar or similar,
         * closing any open context menus. There is not a similar behavior on Macs.
         */
        var shouldHandleKeyUp = function (ev) {
            var keyPressIsAltOrMetaAlone = lastKeyDownWasAltOrMeta.current && isAltOrMeta(ev);
            lastKeyDownWasAltOrMeta.current = false;
            return !!keyPressIsAltOrMetaAlone && !(Utilities_1.isIOS() || Utilities_1.isMac());
        };
        var onKeyUp = function (ev) {
            return keyHandler(ev, shouldHandleKeyUp, true /* dismissAllMenus */);
        };
        var onMenuKeyDown = function (ev) {
            // Mark as handled if onKeyDown returns true (for handling collapse cases)
            // or if we are attempting to expand a submenu
            var handled = onKeyDown(ev);
            if (handled || !hostElement.current) {
                return;
            }
            // If we have a modifier key being pressed, we do not want to move focus.
            // Otherwise, handle up and down keys.
            var hasModifier = !!(ev.altKey || ev.metaKey);
            // eslint-disable-next-line deprecation/deprecation
            var isUp = ev.which === Utilities_1.KeyCodes.up;
            // eslint-disable-next-line deprecation/deprecation
            var isDown = ev.which === Utilities_1.KeyCodes.down;
            if (!hasModifier && (isUp || isDown)) {
                var elementToFocus = isUp
                    ? Utilities_1.getLastFocusable(hostElement.current, hostElement.current.lastChild, true)
                    : Utilities_1.getFirstFocusable(hostElement.current, hostElement.current.firstChild, true);
                if (elementToFocus) {
                    elementToFocus.focus();
                    ev.preventDefault();
                    ev.stopPropagation();
                }
            }
        };
        var onItemKeyDown = function (item, ev) {
            var openKey = Utilities_1.getRTL(theme) ? Utilities_1.KeyCodes.left : Utilities_1.KeyCodes.right;
            if (!item.disabled &&
                // eslint-disable-next-line deprecation/deprecation
                (ev.which === openKey || ev.which === Utilities_1.KeyCodes.enter || (ev.which === Utilities_1.KeyCodes.down && (ev.altKey || ev.metaKey)))) {
                openSubMenu(item, ev.currentTarget);
                ev.preventDefault();
            }
        };
        return [onKeyDown, onKeyUp, onMenuKeyDown, onItemKeyDown];
    }
    function useScrollHandler(asyncTracker) {
        var isScrollIdle = React.useRef(true);
        var scrollIdleTimeoutId = React.useRef();
        /**
         * Scroll handler for the callout to make sure the mouse events
         * for updating focus are not interacting during scroll
         */
        var onScroll = function () {
            if (!isScrollIdle.current && scrollIdleTimeoutId.current !== undefined) {
                asyncTracker.clearTimeout(scrollIdleTimeoutId.current);
                scrollIdleTimeoutId.current = undefined;
            }
            else {
                isScrollIdle.current = false;
            }
            scrollIdleTimeoutId.current = asyncTracker.setTimeout(function () {
                isScrollIdle.current = true;
            }, NavigationIdleDelay);
        };
        return [onScroll, isScrollIdle];
    }
    function useOnSubmenuDismiss(dismiss, closeSubMenu) {
        var isMountedRef = React.useRef(false);
        React.useEffect(function () {
            isMountedRef.current = true;
            return function () {
                isMountedRef.current = false;
            };
        }, []);
        /**
         * This function is called ASYNCHRONOUSLY, and so there is a chance it is called
         * after the component is unmounted. The isMountedRef is added to prevent
         * from calling setState() after unmount. Do NOT copy this pattern in synchronous
         * code.
         */
        var onSubMenuDismiss = function (ev, dismissAll) {
            if (dismissAll) {
                dismiss(ev, dismissAll);
            }
            else if (isMountedRef.current) {
                closeSubMenu();
            }
        };
        return onSubMenuDismiss;
    }
    function useSubmenuEnterTimer(_a, asyncTracker) {
        var _b = _a.subMenuHoverDelay, subMenuHoverDelay = _b === void 0 ? NavigationIdleDelay : _b;
        var enterTimerRef = React.useRef(undefined);
        var cancelSubMenuTimer = function () {
            if (enterTimerRef.current !== undefined) {
                asyncTracker.clearTimeout(enterTimerRef.current);
                enterTimerRef.current = undefined;
            }
        };
        var startSubmenuTimer = function (onTimerExpired) {
            enterTimerRef.current = asyncTracker.setTimeout(function () {
                onTimerExpired();
                cancelSubMenuTimer();
            }, subMenuHoverDelay);
        };
        return [cancelSubMenuTimer, startSubmenuTimer, enterTimerRef];
    }
    function useMouseHandlers(props, isScrollIdle, subMenuEntryTimer, targetWindow, shouldUpdateFocusOnMouseEvent, gotMouseMove, expandedMenuItemKey, hostElement, startSubmenuTimer, cancelSubMenuTimer, openSubMenu, onSubMenuDismiss, dismiss) {
        var menuTarget = props.target;
        var onItemMouseEnterBase = function (item, ev, target) {
            if (shouldUpdateFocusOnMouseEvent.current) {
                gotMouseMove.current = true;
            }
            if (shouldIgnoreMouseEvent()) {
                return;
            }
            updateFocusOnMouseEvent(item, ev, target);
        };
        var onItemMouseMoveBase = function (item, ev, target) {
            var targetElement = ev.currentTarget;
            // Always do this check to make sure we record a mouseMove if needed (even if we are timed out)
            if (shouldUpdateFocusOnMouseEvent.current) {
                gotMouseMove.current = true;
            }
            else {
                return;
            }
            if (!isScrollIdle.current ||
                subMenuEntryTimer.current !== undefined ||
                targetElement === (targetWindow ? Utilities_1.getActiveElement(targetWindow === null || targetWindow === void 0 ? void 0 : targetWindow.document) : undefined)) {
                return;
            }
            updateFocusOnMouseEvent(item, ev, target);
        };
        var shouldIgnoreMouseEvent = function () {
            return !isScrollIdle.current || !gotMouseMove.current;
        };
        var onMouseItemLeave = function (item, ev) {
            var _a;
            if (shouldIgnoreMouseEvent()) {
                return;
            }
            cancelSubMenuTimer();
            if (expandedMenuItemKey !== undefined) {
                return;
            }
            /**
             * IE11 focus() method forces parents to scroll to top of element.
             * Edge and IE expose a setActive() function for focusable divs that
             * sets the page focus but does not scroll the parent element.
             */
            if (hostElement.current.setActive) {
                try {
                    hostElement.current.setActive();
                }
                catch (e) {
                    /* no-op */
                }
            }
            else {
                (_a = hostElement.current) === null || _a === void 0 ? void 0 : _a.focus();
            }
        };
        /**
         * Handles updating focus when mouseEnter or mouseMove fire.
         * As part of updating focus, This function will also update
         * the expand/collapse state accordingly.
         */
        var updateFocusOnMouseEvent = function (item, ev, target) {
            var targetElement = target ? target : ev.currentTarget;
            if (item.key === expandedMenuItemKey) {
                return;
            }
            cancelSubMenuTimer();
            // If the menu is not expanded we can update focus without any delay
            if (expandedMenuItemKey === undefined) {
                targetElement.focus();
            }
            // Delay updating expanding/dismissing the submenu
            // and only set focus if we have not already done so
            if (index_1.hasSubmenu(item)) {
                ev.stopPropagation();
                startSubmenuTimer(function () {
                    targetElement.focus();
                    openSubMenu(item, targetElement, true);
                });
            }
            else {
                startSubmenuTimer(function () {
                    onSubMenuDismiss(ev);
                    targetElement.focus();
                });
            }
        };
        var onItemClick = function (item, ev) {
            onItemClickBase(item, ev, ev.currentTarget);
        };
        var onItemClickBase = function (item, ev, target) {
            var items = getSubmenuItems(item, { target: menuTarget });
            // Cancel an async menu item hover timeout action from being taken and instead
            // just trigger the click event instead.
            cancelSubMenuTimer();
            if (!index_1.hasSubmenu(item) && (!items || !items.length)) {
                // This is an item without a menu. Click it.
                executeItemClick(item, ev);
            }
            else {
                if (item.key !== expandedMenuItemKey) {
                    // This has a collapsed sub menu. Expand it.
                    // focus on the container by default when the menu is opened with a click event
                    // this differentiates from a keyboard interaction triggering the click event
                    var shouldFocusOnContainer = typeof props.shouldFocusOnContainer === 'boolean'
                        ? props.shouldFocusOnContainer
                        : ev.nativeEvent.pointerType === 'mouse';
                    openSubMenu(item, target, shouldFocusOnContainer);
                }
            }
            ev.stopPropagation();
            ev.preventDefault();
        };
        var onAnchorClick = function (item, ev) {
            executeItemClick(item, ev);
            ev.stopPropagation();
        };
        var executeItemClick = function (item, ev) {
            if (item.disabled || item.isDisabled) {
                return;
            }
            if (item.preferMenuTargetAsEventTarget) {
                overrideTarget(ev, menuTarget);
            }
            var shouldDismiss = false;
            if (item.onClick) {
                shouldDismiss = !!item.onClick(ev, item);
            }
            else if (props.onItemClick) {
                shouldDismiss = !!props.onItemClick(ev, item);
            }
            if (shouldDismiss || !ev.defaultPrevented) {
                dismiss(ev, true);
            }
        };
        return [
            onItemMouseEnterBase,
            onItemMouseMoveBase,
            onMouseItemLeave,
            onItemClick,
            onAnchorClick,
            executeItemClick,
            onItemClickBase,
        ];
    }
    //#endregion
    exports.ContextualMenuBase = React.memo(React.forwardRef(function (propsWithoutDefaults, forwardedRef) {
        var _a;
        var _b = Utilities_1.getPropsWithDefaults(DEFAULT_PROPS, propsWithoutDefaults), ref = _b.ref, props = tslib_1.__rest(_b, ["ref"]);
        var hostElement = React.useRef(null);
        var asyncTracker = react_hooks_1.useAsync();
        var menuId = react_hooks_1.useId(COMPONENT_NAME, props.id);
        react_hooks_1.useWarnings({
            name: COMPONENT_NAME,
            props: props,
            deprecations: {
                getMenuClassNames: 'styles',
            },
        });
        var dismiss = function (ev, dismissAll) { var _a; return (_a = props.onDismiss) === null || _a === void 0 ? void 0 : _a.call(props, ev, dismissAll); };
        var _c = react_hooks_1.useTarget(props.target, hostElement), targetRef = _c[0], targetWindow = _c[1];
        var tryFocusPreviousActiveElement = usePreviousActiveElement(props, targetWindow)[0];
        var _d = useSubMenuState(props, dismiss), expandedMenuItemKey = _d[0], openSubMenu = _d[1], getSubmenuProps = _d[2], onSubMenuDismiss = _d[3];
        var _e = useShouldUpdateFocusOnMouseMove(props), shouldUpdateFocusOnMouseEvent = _e[0], gotMouseMove = _e[1], onMenuFocusCapture = _e[2];
        var _f = useScrollHandler(asyncTracker), onScroll = _f[0], isScrollIdle = _f[1];
        var _g = useSubmenuEnterTimer(props, asyncTracker), cancelSubMenuTimer = _g[0], startSubmenuTimer = _g[1], subMenuEntryTimer = _g[2];
        var responsiveMode = ResponsiveMode_1.useResponsiveMode(hostElement, props.responsiveMode);
        useVisibility(props, targetWindow);
        var _h = useKeyHandlers(props, dismiss, hostElement, openSubMenu), onKeyDown = _h[0], onKeyUp = _h[1], onMenuKeyDown = _h[2], onItemKeyDown = _h[3];
        var _j = useMouseHandlers(props, isScrollIdle, subMenuEntryTimer, targetWindow, shouldUpdateFocusOnMouseEvent, gotMouseMove, expandedMenuItemKey, hostElement, startSubmenuTimer, cancelSubMenuTimer, openSubMenu, onSubMenuDismiss, dismiss), onItemMouseEnterBase = _j[0], onItemMouseMoveBase = _j[1], onMouseItemLeave = _j[2], onItemClick = _j[3], onAnchorClick = _j[4], executeItemClick = _j[5], onItemClickBase = _j[6];
        //#region Render helpers
        var onDefaultRenderMenuList = function (menuListProps, 
        // eslint-disable-next-line deprecation/deprecation
        menuClassNames, defaultRender) {
            var indexCorrection = 0;
            var items = menuListProps.items, totalItemCount = menuListProps.totalItemCount, hasCheckmarks = menuListProps.hasCheckmarks, hasIcons = menuListProps.hasIcons;
            return (React.createElement("ul", { className: menuClassNames.list, onKeyDown: onKeyDown, onKeyUp: onKeyUp, role: 'presentation' }, items.map(function (item, index) {
                var menuItem = renderMenuItem(item, index, indexCorrection, totalItemCount, hasCheckmarks, hasIcons, menuClassNames);
                if (item.itemType !== ContextualMenu_types_1.ContextualMenuItemType.Divider && item.itemType !== ContextualMenu_types_1.ContextualMenuItemType.Header) {
                    var indexIncrease = item.customOnRenderListLength ? item.customOnRenderListLength : 1;
                    indexCorrection += indexIncrease;
                }
                return menuItem;
            })));
        };
        var renderFocusZone = function (children, adjustedFocusZoneProps) {
            var _a = props.focusZoneAs, ChildrenRenderer = _a === void 0 ? FocusZone_1.FocusZone : _a;
            return React.createElement(ChildrenRenderer, tslib_1.__assign({}, adjustedFocusZoneProps), children);
        };
        /**
         * !!!IMPORTANT!!! Avoid mutating `item: IContextualMenuItem` argument. It will
         * cause the menu items to always re-render because the component update is based on shallow comparison.
         */
        var renderMenuItem = function (item, index, focusableElementIndex, totalItemCount, hasCheckmarks, hasIcons, 
        // eslint-disable-next-line deprecation/deprecation
        menuClassNames) {
            var _a;
            var renderedItems = [];
            var iconProps = item.iconProps || { iconName: 'None' };
            var getItemClassNames = item.getItemClassNames, // eslint-disable-line deprecation/deprecation
            itemProps = item.itemProps;
            var styles = itemProps ? itemProps.styles : undefined;
            // We only send a dividerClassName when the item to be rendered is a divider.
            // For all other cases, the default divider style is used.
            var dividerClassName = item.itemType === ContextualMenu_types_1.ContextualMenuItemType.Divider ? item.className : undefined;
            var subMenuIconClassName = item.submenuIconProps ? item.submenuIconProps.className : '';
            // eslint-disable-next-line deprecation/deprecation
            var itemClassNames;
            // IContextualMenuItem#getItemClassNames for backwards compatibility
            // otherwise uses mergeStyles for class names.
            if (getItemClassNames) {
                itemClassNames = getItemClassNames(props.theme, index_1.isItemDisabled(item), expandedMenuItemKey === item.key, !!index_1.getIsChecked(item), !!item.href, iconProps.iconName !== 'None', item.className, dividerClassName, iconProps.className, subMenuIconClassName, item.primaryDisabled);
            }
            else {
                var itemStyleProps = {
                    theme: props.theme,
                    disabled: index_1.isItemDisabled(item),
                    expanded: expandedMenuItemKey === item.key,
                    checked: !!index_1.getIsChecked(item),
                    isAnchorLink: !!item.href,
                    knownIcon: iconProps.iconName !== 'None',
                    itemClassName: item.className,
                    dividerClassName: dividerClassName,
                    iconClassName: iconProps.className,
                    subMenuClassName: subMenuIconClassName,
                    primaryDisabled: item.primaryDisabled,
                };
                // We need to generate default styles then override if styles are provided
                // since the ContextualMenu currently handles item classNames.
                itemClassNames = getContextualMenuItemClassNames(_getMenuItemStylesFunction((_a = menuClassNames.subComponentStyles) === null || _a === void 0 ? void 0 : _a.menuItem, styles), itemStyleProps);
            }
            // eslint-disable-next-line deprecation/deprecation
            if (item.text === '-' || item.name === '-') {
                item.itemType = ContextualMenu_types_1.ContextualMenuItemType.Divider;
            }
            switch (item.itemType) {
                case ContextualMenu_types_1.ContextualMenuItemType.Divider:
                    renderedItems.push(renderSeparator(index, itemClassNames));
                    break;
                case ContextualMenu_types_1.ContextualMenuItemType.Header:
                    renderedItems.push(renderSeparator(index, itemClassNames));
                    var headerItem = renderHeaderMenuItem(item, itemClassNames, menuClassNames, index, hasCheckmarks, hasIcons);
                    renderedItems.push(renderListItem(headerItem, item.key || index, itemClassNames, item.title));
                    break;
                case ContextualMenu_types_1.ContextualMenuItemType.Section:
                    renderedItems.push(renderSectionItem(item, itemClassNames, menuClassNames, index, hasCheckmarks, hasIcons));
                    break;
                default:
                    var defaultRenderNormalItem = function () {
                        return renderNormalItem(item, itemClassNames, index, focusableElementIndex, totalItemCount, hasCheckmarks, hasIcons);
                    };
                    var menuItem = props.onRenderContextualMenuItem
                        ? props.onRenderContextualMenuItem(item, defaultRenderNormalItem)
                        : defaultRenderNormalItem();
                    renderedItems.push(renderListItem(menuItem, item.key || index, itemClassNames, item.title));
                    break;
            }
            // Since multiple nodes *could* be rendered, wrap them all in a fragment with this item's key.
            // This ensures the reconciler handles multi-item output per-node correctly and does not re-mount content.
            return React.createElement(React.Fragment, { key: item.key }, renderedItems);
        };
        var defaultMenuItemRenderer = function (item, 
        // eslint-disable-next-line deprecation/deprecation
        menuClassNames) {
            var index = item.index, focusableElementIndex = item.focusableElementIndex, totalItemCount = item.totalItemCount, hasCheckmarks = item.hasCheckmarks, hasIcons = item.hasIcons;
            return renderMenuItem(item, index, focusableElementIndex, totalItemCount, hasCheckmarks, hasIcons, menuClassNames);
        };
        var renderSectionItem = function (sectionItem, 
        // eslint-disable-next-line deprecation/deprecation
        itemClassNames, 
        // eslint-disable-next-line deprecation/deprecation
        menuClassNames, index, hasCheckmarks, hasIcons) {
            var sectionProps = sectionItem.sectionProps;
            if (!sectionProps) {
                return;
            }
            var headerItem;
            var groupProps;
            if (sectionProps.title) {
                var headerContextualMenuItem = undefined;
                var ariaLabelledby = '';
                if (typeof sectionProps.title === 'string') {
                    // Since title is a user-facing string, it needs to be stripped
                    // of whitespace in order to build a valid element ID
                    var id_1 = menuId + sectionProps.title.replace(/\s/g, '');
                    headerContextualMenuItem = {
                        key: "section-" + sectionProps.title + "-title",
                        itemType: ContextualMenu_types_1.ContextualMenuItemType.Header,
                        text: sectionProps.title,
                        id: id_1,
                    };
                    ariaLabelledby = id_1;
                }
                else {
                    var id_2 = sectionProps.title.id || menuId + sectionProps.title.key.replace(/\s/g, '');
                    headerContextualMenuItem = tslib_1.__assign(tslib_1.__assign({}, sectionProps.title), { id: id_2 });
                    ariaLabelledby = id_2;
                }
                if (headerContextualMenuItem) {
                    groupProps = {
                        role: 'group',
                        'aria-labelledby': ariaLabelledby,
                    };
                    headerItem = renderHeaderMenuItem(headerContextualMenuItem, itemClassNames, menuClassNames, index, hasCheckmarks, hasIcons);
                }
            }
            if (sectionProps.items && sectionProps.items.length > 0) {
                return (React.createElement("li", { role: "presentation", key: sectionProps.key || sectionItem.key || "section-" + index },
                    React.createElement("div", tslib_1.__assign({}, groupProps),
                        React.createElement("ul", { className: menuClassNames.list, role: "presentation" },
                            sectionProps.topDivider && renderSeparator(index, itemClassNames, true, true),
                            headerItem && renderListItem(headerItem, sectionItem.key || index, itemClassNames, sectionItem.title),
                            sectionProps.items.map(function (contextualMenuItem, itemsIndex) {
                                return renderMenuItem(contextualMenuItem, itemsIndex, itemsIndex, sectionProps.items.length, hasCheckmarks, hasIcons, menuClassNames);
                            }),
                            sectionProps.bottomDivider && renderSeparator(index, itemClassNames, false, true)))));
            }
        };
        var renderListItem = function (content, key, classNames, // eslint-disable-line deprecation/deprecation
        title) {
            return (React.createElement("li", { role: "presentation", title: title, key: key, className: classNames.item }, content));
        };
        var renderSeparator = function (index, classNames, // eslint-disable-line deprecation/deprecation
        top, fromSection) {
            if (fromSection || index > 0) {
                return (React.createElement("li", { role: "separator", key: 'separator-' + index + (top === undefined ? '' : top ? '-top' : '-bottom'), className: classNames.divider, "aria-hidden": "true" }));
            }
            return null;
        };
        var renderNormalItem = function (item, classNames, // eslint-disable-line deprecation/deprecation
        index, focusableElementIndex, totalItemCount, hasCheckmarks, hasIcons) {
            if (item.onRender) {
                return item.onRender(tslib_1.__assign({ 'aria-posinset': focusableElementIndex + 1, 'aria-setsize': totalItemCount }, item), dismiss);
            }
            var contextualMenuItemAs = props.contextualMenuItemAs;
            var commonProps = {
                item: item,
                classNames: classNames,
                index: index,
                focusableElementIndex: focusableElementIndex,
                totalItemCount: totalItemCount,
                hasCheckmarks: hasCheckmarks,
                hasIcons: hasIcons,
                contextualMenuItemAs: contextualMenuItemAs,
                onItemMouseEnter: onItemMouseEnterBase,
                onItemMouseLeave: onMouseItemLeave,
                onItemMouseMove: onItemMouseMoveBase,
                onItemMouseDown: onItemMouseDown,
                executeItemClick: executeItemClick,
                onItemKeyDown: onItemKeyDown,
                expandedMenuItemKey: expandedMenuItemKey,
                openSubMenu: openSubMenu,
                dismissSubMenu: onSubMenuDismiss,
                dismissMenu: dismiss,
            };
            if (item.href) {
                return React.createElement(index_2.ContextualMenuAnchor, tslib_1.__assign({}, commonProps, { onItemClick: onAnchorClick }));
            }
            if (item.split && index_1.hasSubmenu(item)) {
                return (React.createElement(index_2.ContextualMenuSplitButton, tslib_1.__assign({}, commonProps, { onItemClick: onItemClick, onItemClickBase: onItemClickBase, onTap: cancelSubMenuTimer })));
            }
            return React.createElement(index_2.ContextualMenuButton, tslib_1.__assign({}, commonProps, { onItemClick: onItemClick, onItemClickBase: onItemClickBase }));
        };
        var renderHeaderMenuItem = function (item, 
        // eslint-disable-next-line deprecation/deprecation
        itemClassNames, 
        // eslint-disable-next-line deprecation/deprecation
        menuClassNames, index, hasCheckmarks, hasIcons) {
            var _a = props.contextualMenuItemAs, ChildrenRenderer = _a === void 0 ? ContextualMenuItem_1.ContextualMenuItem : _a;
            var itemProps = item.itemProps, id = item.id;
            var divHtmlProperties = itemProps && Utilities_1.getNativeProps(itemProps, Utilities_1.divProperties);
            return (
            // eslint-disable-next-line deprecation/deprecation
            React.createElement("div", tslib_1.__assign({ id: id, className: menuClassNames.header }, divHtmlProperties, { style: item.style }),
                React.createElement(ChildrenRenderer, tslib_1.__assign({ item: item, classNames: itemClassNames, index: index, onCheckmarkClick: hasCheckmarks ? onItemClick : undefined, hasIcons: hasIcons }, itemProps))));
        };
        //#endregion
        //#region Main render
        var isBeakVisible = props.isBeakVisible;
        var items = props.items, labelElementId = props.labelElementId, id = props.id, className = props.className, beakWidth = props.beakWidth, directionalHint = props.directionalHint, directionalHintForRTL = props.directionalHintForRTL, alignTargetEdge = props.alignTargetEdge, gapSpace = props.gapSpace, coverTarget = props.coverTarget, ariaLabel = props.ariaLabel, doNotLayer = props.doNotLayer, target = props.target, bounds = props.bounds, useTargetWidth = props.useTargetWidth, useTargetAsMinWidth = props.useTargetAsMinWidth, directionalHintFixed = props.directionalHintFixed, shouldFocusOnMount = props.shouldFocusOnMount, shouldFocusOnContainer = props.shouldFocusOnContainer, title = props.title, styles = props.styles, theme = props.theme, calloutProps = props.calloutProps, _k = props.onRenderSubMenu, onRenderSubMenu = _k === void 0 ? onDefaultRenderSubMenu : _k, _l = props.onRenderMenuList, onRenderMenuList = _l === void 0 ? function (menuListProps, defaultRender) { return onDefaultRenderMenuList(menuListProps, classNames, defaultRender); } : _l, focusZoneProps = props.focusZoneProps, 
        // eslint-disable-next-line deprecation/deprecation
        getMenuClassNames = props.getMenuClassNames;
        var classNames = getMenuClassNames
            ? getMenuClassNames(theme, className)
            : getClassNames(styles, {
                theme: theme,
                className: className,
            });
        var hasIcons = itemsHaveIcons(items);
        function itemsHaveIcons(contextualMenuItems) {
            for (var _i = 0, contextualMenuItems_1 = contextualMenuItems; _i < contextualMenuItems_1.length; _i++) {
                var item = contextualMenuItems_1[_i];
                if (item.iconProps) {
                    return true;
                }
                if (item.itemType === ContextualMenu_types_1.ContextualMenuItemType.Section &&
                    item.sectionProps &&
                    itemsHaveIcons(item.sectionProps.items)) {
                    return true;
                }
            }
            return false;
        }
        var adjustedFocusZoneProps = tslib_1.__assign(tslib_1.__assign({ direction: FocusZone_1.FocusZoneDirection.vertical, handleTabKey: FocusZone_1.FocusZoneTabbableElements.all, isCircularNavigation: true }, focusZoneProps), { className: Utilities_1.css(classNames.root, (_a = props.focusZoneProps) === null || _a === void 0 ? void 0 : _a.className) });
        var hasCheckmarks = canAnyMenuItemsCheck(items);
        var submenuProps = expandedMenuItemKey && props.hidden !== true ? getSubmenuProps() : null;
        isBeakVisible = isBeakVisible === undefined ? responsiveMode <= ResponsiveMode_1.ResponsiveMode.medium : isBeakVisible;
        /**
         * When useTargetWidth is true, get the width of the target element and apply it for the context menu container
         */
        var contextMenuStyle;
        var targetAsHtmlElement = targetRef.current;
        if ((useTargetWidth || useTargetAsMinWidth) && targetAsHtmlElement && targetAsHtmlElement.offsetWidth) {
            var targetBoundingRect = targetAsHtmlElement.getBoundingClientRect();
            var targetWidth = targetBoundingRect.width - 2; /* Accounts for 1px border */
            if (useTargetWidth) {
                contextMenuStyle = {
                    width: targetWidth,
                };
            }
            else if (useTargetAsMinWidth) {
                contextMenuStyle = {
                    minWidth: targetWidth,
                };
            }
        }
        // The menu should only return if items were provided, if no items were provided then it should not appear.
        if (items && items.length > 0) {
            var totalItemCount_1 = 0;
            for (var _i = 0, items_2 = items; _i < items_2.length; _i++) {
                var item = items_2[_i];
                if (item.itemType !== ContextualMenu_types_1.ContextualMenuItemType.Divider && item.itemType !== ContextualMenu_types_1.ContextualMenuItemType.Header) {
                    var itemCount = item.customOnRenderListLength ? item.customOnRenderListLength : 1;
                    totalItemCount_1 += itemCount;
                }
            }
            var calloutStyles_1 = classNames.subComponentStyles
                ? classNames.subComponentStyles.callout
                : undefined;
            return (React.createElement(index_3.MenuContext.Consumer, null, function (menuContext) { return (React.createElement(Callout_1.Callout, tslib_1.__assign({ styles: calloutStyles_1, onRestoreFocus: tryFocusPreviousActiveElement }, calloutProps, { target: target || menuContext.target, isBeakVisible: isBeakVisible, beakWidth: beakWidth, directionalHint: directionalHint, directionalHintForRTL: directionalHintForRTL, gapSpace: gapSpace, coverTarget: coverTarget, doNotLayer: doNotLayer, className: Utilities_1.css('ms-ContextualMenu-Callout', calloutProps && calloutProps.className), setInitialFocus: shouldFocusOnMount, onDismiss: props.onDismiss || menuContext.onDismiss, onScroll: onScroll, bounds: bounds, directionalHintFixed: directionalHintFixed, alignTargetEdge: alignTargetEdge, hidden: props.hidden || menuContext.hidden, ref: forwardedRef }),
                React.createElement("div", { style: contextMenuStyle, ref: hostElement, id: id, className: classNames.container, tabIndex: shouldFocusOnContainer ? 0 : -1, onKeyDown: onMenuKeyDown, onKeyUp: onKeyUp, onFocusCapture: onMenuFocusCapture, "aria-label": ariaLabel, "aria-labelledby": labelElementId, role: 'menu' },
                    title && React.createElement("div", { className: classNames.title },
                        " ",
                        title,
                        " "),
                    items && items.length
                        ? renderFocusZone(onRenderMenuList({
                            ariaLabel: ariaLabel,
                            items: items,
                            totalItemCount: totalItemCount_1,
                            hasCheckmarks: hasCheckmarks,
                            hasIcons: hasIcons,
                            defaultMenuItemRenderer: function (item) {
                                return defaultMenuItemRenderer(item, classNames);
                            },
                            labelElementId: labelElementId,
                        }, function (menuListProps, defaultRender) { return onDefaultRenderMenuList(menuListProps, classNames, defaultRender); }), adjustedFocusZoneProps)
                        : null,
                    submenuProps && onRenderSubMenu(submenuProps, onDefaultRenderSubMenu)))); }));
        }
        else {
            return null;
        }
        //#endregion
    }), function (prevProps, newProps) {
        if (!newProps.shouldUpdateWhenHidden && prevProps.hidden && newProps.hidden) {
            // Do not update when hidden.
            return true;
        }
        return Utilities_1.shallowCompare(prevProps, newProps);
    });
    exports.ContextualMenuBase.displayName = 'ContextualMenuBase';
    /**
     * Returns true if the key for the event is alt (Mac option) or meta (Mac command).
     */
    function isAltOrMeta(ev) {
        // eslint-disable-next-line deprecation/deprecation
        return ev.which === Utilities_1.KeyCodes.alt || ev.key === 'Meta';
    }
    function onItemMouseDown(item, ev) {
        var _a;
        (_a = item.onMouseDown) === null || _a === void 0 ? void 0 : _a.call(item, item, ev);
    }
    function onDefaultRenderSubMenu(subMenuProps, defaultRender) {
        throw Error('ContextualMenuBase: onRenderSubMenu callback is null or undefined. ' +
            'Please ensure to set `onRenderSubMenu` property either manually or with `styled` helper.');
    }
    /**
     * Returns the item that matches a given key if any.
     * @param key - The key of the item to match
     * @param items - The items to look for the key
     */
    function findItemByKeyFromItems(key, items) {
        for (var _i = 0, items_3 = items; _i < items_3.length; _i++) {
            var item = items_3[_i];
            if (item.itemType === ContextualMenu_types_1.ContextualMenuItemType.Section && item.sectionProps) {
                var match = findItemByKeyFromItems(key, item.sectionProps.items);
                if (match) {
                    return match;
                }
            }
            else if (item.key && item.key === key) {
                return item;
            }
        }
    }
    function getOnClickWithOverrideTarget(onClick, target) {
        return onClick
            ? function (ev, item) {
                overrideTarget(ev, target);
                return onClick(ev, item);
            }
            : onClick;
    }
    function overrideTarget(ev, target) {
        if (ev && target) {
            ev.persist();
            if (target instanceof Event) {
                ev.target = target.target;
            }
            else if (target instanceof Element) {
                ev.target = target;
            }
        }
    }
});
//# sourceMappingURL=ContextualMenu.base.js.map