import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { forwardRef, useState, useCallback } from 'react';
import styled, { css } from 'styled-components';
import { defaultThemeProp } from '../../theme';
import { useConsolidatedRef, useUID, useFocusWithin, useDirection, useTestIds, useEscape, useElement } from '../../hooks';
import Button, { StyledButton } from '../Button';
import Popover, { StyledPopover } from '../Popover';
import Menu from '../Menu';
import Icon, { registerIcon, StyledIcon } from '../Icon';
import * as arrowMicroDownIcon from '../Icon/icons/arrow-micro-down.icon';
import Flex from '../Flex';
import { Count } from '../Badges';
import { getActiveElement, getFocusables, isInstance, withTestIds } from '../../utils';
import { getMenuButtonTestIds } from './MenuButton.test-ids';
registerIcon(arrowMicroDownIcon);
export const StyledMenuButton = styled.button(({ theme: { base: { spacing } } }) => {
    return css `
      gap: ${spacing};
      flex-shrink: 0;
      white-space: nowrap;
      max-width: 100%;

      & + ${StyledPopover} + ${StyledButton} {
        margin-inline-start: ${spacing};
      }
    `;
});
StyledMenuButton.defaultProps = defaultThemeProp;
const StyledMenuButtonText = styled.span `
  text-overflow: ellipsis;
  overflow: hidden;
`;
const StyledMenuButtonChildren = styled.span(({ theme, padIcon }) => {
    const { base: { 'hit-area': { 'mouse-min': hitAreaMouse, 'finger-min': hitAreaFinger } }, components: { icon: { size: { s: iconSize } } } } = theme;
    return css `
    max-width: 100%;

    ${padIcon &&
        css `
      padding-inline-start: calc((${hitAreaMouse} - ${iconSize}) / 2);

      @media (pointer: coarse) {
        padding-inline-start: calc(${hitAreaFinger} - ${iconSize} * 2);
      }
    `}

    ${StyledIcon}:last-child:not(:first-child) {
      /* Offsets the flex gap to make the down arrow appear to trail the text. */
      margin-inline-start: -${theme.base.spacing};
    }
  `;
});
StyledMenuButtonChildren.defaultProps = defaultThemeProp;
const StyledMenuButtonPopover = styled(Popover) `
  min-width: 20ch;
`;
const MenuButton = forwardRef(function MenuButton(props, ref) {
    const uid = useUID();
    const { testId, id = uid, text, menu, popover, onClick, icon, count, iconOnly = false, showArrow, onKeyDown: onKeyDownProp, ...restProps } = props;
    const testIds = useTestIds(testId, getMenuButtonTestIds);
    const [isOpen, setIsOpen] = useState(false);
    const buttonRef = useConsolidatedRef(ref);
    // Force re-render when popoverRef is set, so useFocusWithin has a non-null ref to read
    const [, forceRerender] = useElement(null);
    const popoverRef = useConsolidatedRef(popover?.ref, forceRerender);
    const filterInputRef = useConsolidatedRef(menu?.filterInputProps?.ref);
    const menuRef = useConsolidatedRef(menu?.ref);
    // FIXME: Type assertion required for issue in useFocusWithin generic
    useFocusWithin([popoverRef, buttonRef], useCallback((isFocused) => {
        if (!isFocused)
            setIsOpen(false);
    }, []));
    useEscape(e => {
        if (isOpen) {
            setIsOpen(false);
            e.stopPropagation();
        }
    }, buttonRef);
    useEscape(e => {
        if (isOpen) {
            setIsOpen(false);
            e.stopPropagation();
            buttonRef.current?.focus();
        }
    }, menu?.focusControlEl);
    useEscape(e => {
        if (isOpen) {
            setIsOpen(false);
            e.stopPropagation();
            buttonRef.current?.focus();
        }
    }, filterInputRef);
    const { rtl } = useDirection();
    const onKeyDown = useCallback((e) => {
        onKeyDownProp?.(e);
        if (e.key !== 'Tab' || !menu)
            return;
        const footerEl = menuRef.current?.querySelector('footer');
        if (!footerEl)
            return;
        const tabbingForward = !e.shiftKey;
        if (tabbingForward) {
            const footerFocusables = getFocusables(footerEl);
            if (footerFocusables.length > 0) {
                e.preventDefault();
                footerFocusables[0].focus();
                return;
            }
        }
        setIsOpen(false);
    }, [menu]);
    return (_jsxs(_Fragment, { children: [_jsx(Button, { "data-testid": testIds.root, as: StyledMenuButton, "aria-label": text, ...restProps, id: id, ref: buttonRef, "aria-expanded": isOpen, "aria-haspopup": 'menu', "aria-controls": isOpen ? `${id}-popover` : undefined, label: iconOnly && !isOpen ? text : undefined, onClick: (e) => {
                    // e.detail is 0 when triggered by keyboard.
                    const mouseClick = e.detail > 0;
                    if (isOpen) {
                        if (mouseClick) {
                            // Close the menu if it is open and it is a *mouse* click on the button.
                            setIsOpen(false);
                        }
                    }
                    else {
                        // Open the menu if it's closed, for mouse or keyboard click.
                        setIsOpen(true);
                    }
                    // If the menu is closed or the user mouse clicks.
                    // This avoids Enter key firing onClick when selecting a menu item.
                    if (!isOpen || mouseClick) {
                        onClick?.(e);
                    }
                }, onKeyDown: onKeyDown, icon: iconOnly, children: _jsxs(Flex, { as: StyledMenuButtonChildren, container: { alignItems: 'center', gap: 1 }, padIcon: iconOnly && showArrow, children: [icon && _jsx(Icon, { name: icon }), !iconOnly && (_jsxs(_Fragment, { children: [_jsx(StyledMenuButtonText, { children: text }), typeof count === 'number' && _jsx(Count, { children: count })] })), ((!iconOnly && showArrow === undefined) || showArrow) && (_jsx(Icon, { name: 'arrow-micro-down' }))] }) }), _jsx(StyledMenuButtonPopover, { placement: rtl ? 'bottom-end' : 'bottom-start', hideOnTargetHidden: true, ...popover, id: `${id}-popover`, show: !!menu && isOpen, target: buttonRef.current, ref: popoverRef, onKeyDown: (e) => {
                    if (e.key !== 'Tab' || !buttonRef.current)
                        return;
                    const footerEl = menuRef.current?.querySelector('footer');
                    if (!footerEl || !footerEl?.contains(getActiveElement()))
                        return;
                    const footerFocusables = getFocusables(footerEl);
                    if (isInstance(e.target, HTMLElement)) {
                        const currentIndex = footerFocusables.indexOf(e.target);
                        const tabbingForward = !e.shiftKey;
                        const isLastFocusable = currentIndex === footerFocusables.length - 1;
                        if (tabbingForward && isLastFocusable) {
                            e.preventDefault();
                            const rootNode = buttonRef.current.getRootNode();
                            if (!isInstance(rootNode, Document, ShadowRoot))
                                return;
                            const allFocusables = getFocusables(rootNode);
                            const nextIndex = allFocusables.indexOf(buttonRef.current) + 1;
                            allFocusables[nextIndex]?.focus();
                            setIsOpen(false);
                        }
                        else if (!tabbingForward && currentIndex === 0) {
                            e.preventDefault();
                            buttonRef.current?.focus();
                        }
                    }
                }, children: menu && (_jsx(Menu, { testId: testIds.root, ...menu, ref: menuRef, loading: menu.loading, items: menu.items, onItemClick: (itemId, e) => {
                        // When clicking an item (by mouse or keyboard) and the menu is not multi-select, close the menu.
                        if (menu.mode !== 'multi-select') {
                            setIsOpen(false);
                        }
                        menu.onItemClick?.(itemId, e);
                    }, focusControlEl: menu.focusControlEl || buttonRef.current || undefined })) })] }));
});
export default withTestIds(MenuButton, getMenuButtonTestIds);
//# sourceMappingURL=MenuButton.js.map