'use client';
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { createContext, useContext, useRef } from 'react';
import { Menu } from '@base-ui/react/menu';
import { useMergedRefs } from '@base-ui/utils/useMergedRefs';
import { twToPx } from '@graphprotocol/gds-css';
import { ArrowRightInteractiveIcon, ArrowUpRightInteractiveIcon, CaretRightIcon, CheckIcon, LoadingIcon, MagnifyingGlassIcon, XIcon, } from '@graphprotocol/gds-react/icons';
import { useAutoValue, useControlled, useCSSPropsPolyfill, useCSSState, useGDS, } from "../hooks/index.js";
import { cn, getCSSPropsAttributes, splitProps } from "../utils/index.js";
import { renderAddon } from "./base/Addon.js";
import { ButtonOrLink } from "./base/ButtonOrLink.js";
import { Render } from "./base/Render.js";
import { Button } from "./Button.js";
import { Checkbox } from "./Checkbox.js";
import { MenuMeta } from './Menu.meta.js';
const MenuTriggerContext = createContext(false);
export function MenuRoot({ ref: passedRef, trigger, triggerMode, side, gap, align, alignOffset, matchTriggerWidth, matchTriggerHeight, open: controlledOpen, defaultOpen, onOpenChange, header, footer, label, type, value, defaultValue, onChange, className, style, children, ...props }) {
    const { dirProps } = useGDS();
    const { rootProps, nestedProps } = splitProps(props);
    const portalRef = useRef(null);
    const [cssPropsPolyfillRef, cssPropsPolyfillAttributes, cssProps] = useCSSPropsPolyfill(MenuMeta, {
        side,
        align,
        matchTriggerWidth,
        matchTriggerHeight,
    }, {
        returnPropValues: { side, gap, align, alignOffset, matchTriggerWidth, matchTriggerHeight },
    });
    const isSubmenu = useContext(MenuGroupContext) !== null;
    const MenuRoot = isSubmenu ? Menu.SubmenuRoot : Menu.Root;
    const hasTrigger = trigger !== undefined;
    const triggerElement = (() => {
        if (!hasTrigger)
            return null;
        const renderTrigger = typeof trigger !== 'function'
            ? trigger
            : (renderProps) => {
                // Don't pass event handlers and other potentially too specific props (e.g. `type`)
                const filteredRenderProps = Object.fromEntries(Object.entries(renderProps).filter(([prop]) => prop === 'ref' ||
                    prop === 'id' ||
                    prop === 'className' ||
                    prop.startsWith('aria-') ||
                    prop.startsWith('data-')));
                return trigger(filteredRenderProps, {
                    open,
                    setOpen,
                    openMenu: () => setOpen(true),
                });
            };
        if (isSubmenu) {
            return _jsx(Render, { render: renderTrigger });
        }
        else {
            return (_jsx(Menu.Trigger, { nativeButton: true, openOnHover: triggerMode === 'hover', "data-open-on-hover": triggerMode === 'hover' || undefined, className: `
            u:i:open:data-open-on-hover:state-hover
            u:iii:open:not-data-open-on-hover:state-active
          `, render: renderTrigger }));
        }
    })();
    const [open, setOpen] = useControlled(controlledOpen ?? (!hasTrigger ? true : undefined), defaultOpen ?? false, onOpenChange);
    const initialOpen = useRef(open);
    if (!open) {
        initialOpen.current = false;
    }
    return (_jsx("div", { ref: cssPropsPolyfillRef, "data-is-submenu": isSubmenu || undefined, "data-has-trigger": hasTrigger || undefined, className: cn(`gds-menu root-contents [anchor-scope:all]
        not-data-has-trigger:**:data-base-ui-focus-guard:hidden
        u:rounded-12
        u:data-is-submenu:default-align-offset-[-2]
        u:data-is-submenu:default-gap-3
        u:data-is-submenu:default-side-end`, 
        // Very imperfect workaround for https://bugs.webkit.org/show_bug.cgi?id=301871
        `safari:root-block
        i:safari:not-data-is-submenu:size-max`, className), ...getCSSPropsAttributes(MenuMeta, { side, gap, align, alignOffset, matchTriggerWidth, matchTriggerHeight }, style), ...cssPropsPolyfillAttributes, ...rootProps, children: _jsxs(MenuRoot, { open: open, onOpenChange: (newOpen) => {
                // A menu with no trigger can still be opened/closed by the consumer, but it should not send events
                if (hasTrigger)
                    setOpen(newOpen);
            }, modal: !isSubmenu ? hasTrigger : undefined, closeParentOnEsc: true, children: [_jsx(MenuTriggerContext.Provider, { value: true, children: triggerElement ?? (
                    /**
                     * Base UI doesn't explicitly support menus with no `Menu.Trigger`, `Menu.Portal`, or
                     * `Menu.Positioner`, so we work around it. We render an invisible trigger to satisfy
                     * focus and keyboard expectations (note that it is visible when focused, as an
                     * outline). Then, to ensure the menu is rendered inline and not anchored to that
                     * trigger, we customize the portal container to be a sibling element (with `contents
                     * *:contents` so it's a transparent wrapper), and we apply positioning styles only when
                     * a trigger is provided (see `Menu.Positioner`'s `render` prop below). Finally, to
                     * prevent focus-trapping behavior that assumes a floating menu, we disable `modal` and
                     * hide Base UI’s focus guards with CSS (see root styles above).
                     */
                    _jsxs(_Fragment, { children: [_jsx(Menu.Trigger, { "aria-label": props['aria-label'] ||
                                    (label && typeof label === 'string' ? label : undefined) ||
                                    'Menu', className: `
                  pointer-events-none absolute inset-[anchor(inside)] rounded-inherit [position-anchor:--gds-menu]
                  not-open:hidden
                ` }), _jsx("div", { ref: portalRef, className: "contents *:contents" })] })) }), _jsx(Menu.Portal, { container: !hasTrigger
                        ? portalRef
                        : /**
                           * Specifying `document.body` because while it is the default for top-level menus, a submenu
                           * defaults to using the same portal as its parent, which is not desirable when the parent is
                           * rendered inline (it can cause the submenu to appear behind other elements).
                           */
                            document?.body, children: _jsx(Menu.Positioner, { side: cssProps.side === 'start'
                            ? 'inline-start'
                            : cssProps.side === 'end'
                                ? 'inline-end'
                                : cssProps.side, sideOffset: twToPx(cssProps.gap), align: cssProps.align, alignOffset: twToPx(cssProps.alignOffset), collisionPadding: 8, collisionAvoidance: {
                            side: 'flip',
                            align: 'flip',
                            fallbackAxisSide: cssProps.side === 'start' || cssProps.side === 'end' ? 'end' : 'none',
                        }, "data-has-trigger": hasTrigger || undefined, "data-match-trigger-width": cssProps.matchTriggerWidth || undefined, "data-match-trigger-height": cssProps.matchTriggerHeight || undefined, className: cn(`root-flex
              [--available-height-but-not-too-small:max(var(--available-height),--spacing(16))]
              [anchor-name:--gds-menu]
              has-nested/menu-footer:[--available-height-but-not-too-small:max(var(--available-height),--spacing(32))]
              has-nested/menu-header:[--available-height-but-not-too-small:max(var(--available-height),--spacing(32))]
              u:w-max
              u:max-w-full
              u:rounded-12
              u:data-has-trigger:max-h-(--available-height-but-not-too-small)
              u:data-has-trigger:max-w-(--available-width)
              u:i:data-[match-trigger-height=at-least]:min-h-[min(var(--anchor-height),var(--available-height-but-not-too-small))]
              u:i:data-[match-trigger-height=at-most]:max-h-[min(var(--anchor-height),var(--available-height-but-not-too-small))]
              u:i:data-[match-trigger-height=true]:h-(--anchor-height)
              u:i:data-[match-trigger-width=at-least]:min-w-[min(var(--anchor-width),var(--available-width))]
              u:i:data-[match-trigger-width=at-most]:max-w-[min(var(--anchor-width),var(--available-width))]
              u:i:data-[match-trigger-width=true]:w-(--anchor-width)`, className), ...dirProps, render: (renderProps) => (_jsx("div", { ...renderProps, style: hasTrigger ? renderProps.style : undefined })), children: _jsxs(Menu.Popup, { ref: passedRef, "data-initial-open": initialOpen.current || undefined, className: `
                flex grow origin-(--transform-origin) flex-col overflow-clip rounded-inherit bg-muted outline-0 transition
                data-ending-style:scale-95
                data-ending-style:opacity-0
                data-starting-style:not-data-initial-open:scale-95
                data-starting-style:not-data-initial-open:opacity-0
              `, ...nestedProps, onKeyDown: (event) => {
                                nestedProps.onKeyDown?.(event);
                                /**
                                 * Ensure Shift + Tab doesn't close the menu if there is a previous focusable
                                 * element that is not a menu item (or if the previous focusable element is a menu
                                 * item while the element that is currently focused is not).
                                 */
                                if (event.key === 'Tab' && event.shiftKey) {
                                    const focusableElements = [
                                        ...event.currentTarget.querySelectorAll(`
                      a[href],
                      button:enabled,
                      input:enabled,
                      select:enabled,
                      textarea:enabled,
                      summary,
                      [tabindex]:not([tabindex="-1"]),
                      [contenteditable="true"]
                    `),
                                    ];
                                    const previousElement = focusableElements.reverse().find((element) => {
                                        return (element.compareDocumentPosition(document.activeElement) &
                                            Node.DOCUMENT_POSITION_FOLLOWING);
                                    });
                                    const activeElementIsMenuItem = document.activeElement?.classList.contains('gds-menu-item');
                                    const previousElementIsMenuItem = previousElement?.classList.contains('gds-menu-item');
                                    if ((previousElement && !previousElementIsMenuItem) ||
                                        (!activeElementIsMenuItem && previousElementIsMenuItem)) {
                                        event.preventBaseUIHandler();
                                        return;
                                    }
                                }
                                // If there is a search input in the menu...
                                const searchInput = event.currentTarget.querySelector('input[type="search"]');
                                if (searchInput instanceof HTMLInputElement) {
                                    // If the user typed some text, ensure it goes in the input instead of Base UI focusing the item that matches
                                    if ((event.key.length === 1 && event.key !== ' ') ||
                                        event.key === 'Backspace' ||
                                        event.key === 'ArrowLeft' ||
                                        event.key === 'ArrowRight') {
                                        event.preventBaseUIHandler();
                                        searchInput.focus();
                                    }
                                    else {
                                        const searchInputIsFocused = document.activeElement === searchInput;
                                        const menuItems = [
                                            ...event.currentTarget.querySelectorAll('.gds-menu-item'),
                                        ];
                                        const highlightedMenuItem = menuItems.find((item) => item.matches('[data-highlighted]'));
                                        /**
                                         * If the user pressed the down arrow while the search input is focused and
                                         * there is a single menu item in the results, move the focus to it because it
                                         * may already be highlighted, which would prevent Base UI from focusing it.
                                         */
                                        if (event.key === 'ArrowDown' &&
                                            searchInputIsFocused &&
                                            menuItems.length === 1) {
                                            event.preventBaseUIHandler();
                                            menuItems[0].focus();
                                        }
                                        // Inversely, if the user pressed the up arrow and the focus is on the only menu item, move it back to the search input
                                        else if (event.key === 'ArrowUp' &&
                                            menuItems.length === 1 &&
                                            document.activeElement === menuItems[0]) {
                                            event.preventDefault();
                                            searchInput.focus();
                                        }
                                        // If the user pressed Enter while the search input is focused and a menu item is highlighted, select it
                                        else if (event.key === 'Enter' && searchInputIsFocused && highlightedMenuItem) {
                                            highlightedMenuItem.focus();
                                            window.setTimeout(() => {
                                                highlightedMenuItem.dispatchEvent(new KeyboardEvent('keydown', {
                                                    key: 'Enter',
                                                    code: 'Enter',
                                                    keyCode: 13,
                                                    which: 13,
                                                    bubbles: true,
                                                    cancelable: true,
                                                }));
                                            }, 0);
                                        }
                                    }
                                }
                            }, children: [_jsx("div", { className: "w-58" }), header ? (_jsx("div", { className: "nested/menu-header u:shrink-0 u:border-b u:border-muted u:p-4", children: header })) : null, _jsx("div", { className: "scrollbar-thin grow scroll-p-8 overflow-x-clip overflow-y-auto gradient-mask-y", children: _jsx("div", { className: "overflow-clip p-2", children: _jsxs(MenuGroupContext.Provider, { value: "root", children: [label !== undefined || type !== undefined ? (type === 'radio' ? (_jsx(MenuGroup, { label: label, type: type, value: value, defaultValue: defaultValue, onChange: onChange, children: children })) : (_jsx(MenuGroup, { label: label, type: type, children: children }))) : (children), _jsx("div", { className: "mt-[calc(-2*(--spacing(2))-1px)] not-preceded-by-peer/menu-group:hidden" })] }) }) }), footer ? (_jsx("div", { className: "nested/menu-footer u:shrink-0 u:border-t u:border-muted u:p-4", children: footer })) : null, _jsx("div", { className: "pointer-events-none absolute inset-0 rounded-inherit border border-muted" })] }) }) })] }, `${hasTrigger}-${triggerMode}`) }));
}
MenuRoot.displayName = 'Menu';
const MenuGroupContext = createContext(null);
export function MenuGroup({ label, type = 'plain', value, defaultValue, onChange, className, style, children, ...props }) {
    const groupContext = useContext(MenuGroupContext);
    const isNested = groupContext !== null && groupContext !== 'root';
    if (isNested) {
        throw new Error(`[Menu] Groups cannot be nested, make sure you're not using \`Menu.Group\` in a \`Menu\` with a \`label\` and/or \`type\` prop (implicit group)`);
    }
    return (_jsx(MenuGroupContext.Provider, { value: { type }, children: _jsxs(Menu.Group, { className: cn('peer/menu-group u:-m-2 u:mb-2 u:border-b u:border-muted u:p-2', className), style: style ?? undefined, ...props, render: type === 'radio' ? (_jsx(Menu.RadioGroup, { value: value, defaultValue: defaultValue, ...(onChange !== undefined && { onValueChange: onChange }) })) : (_jsx("div", {})), children: [label ? (_jsx(Menu.GroupLabel, { className: "truncate p-2 text-12 text-muted", children: label })) : null, children] }) }));
}
MenuGroup.displayName = 'Menu.Group';
export function MenuItem({ ref: passedRef, type: passedType, addonBefore: passedAddonBefore, addonAfter: passedAddonAfter, variant, loading, href, target, checked, defaultChecked, onChange, value: passedValue, disabled: passedDisabled, className, children, ...props }) {
    const elementRef = useRef(null);
    const elementPassedRef = useMergedRefs(elementRef, passedRef);
    const autoValue = useAutoValue(children);
    const disabled = (passedDisabled || loading) ?? false;
    const [stateElementPassedRef, state] = useCSSState({
        pointer: undefined,
        focus: undefined,
        checked,
        disabled,
    }, { ref: elementPassedRef });
    const groupContext = useContext(MenuGroupContext);
    const hasAncestorMenuTrigger = useContext(MenuTriggerContext) !== false;
    const type = hasAncestorMenuTrigger
        ? 'submenu-trigger'
        : (passedType ??
            (groupContext !== null && groupContext !== 'root' ? groupContext.type : undefined) ??
            'plain');
    const renderItem = (renderProps) => {
        let addonBefore = passedAddonBefore;
        let addonInside = undefined;
        let addonAfter = passedAddonAfter;
        if (type === 'checkbox') {
            if (addonBefore)
                addonInside = addonBefore;
            addonBefore = (_jsx(Checkbox, { inert: true, "aria-label": "" // Prevent console warning about missing label
                , className: `
            @state-checked/menu-item:state-checked
            @state-indeterminate/menu-item:state-indeterminate
            @state-hover/menu-item:state-hover
            @state-active/menu-item:state-active
            @state-disabled/menu-item:state-idle
            @state-disabled/menu-item:@state-checked/menu-item:state-disabled
          ` }));
        }
        if (type === 'radio') {
            if (addonBefore)
                addonInside = addonBefore;
            addonBefore = _jsx(CheckIcon, { alt: "", className: "@state-unchecked/menu-item:invisible" });
        }
        if (loading) {
            addonAfter = _jsx(LoadingIcon, {});
        }
        if (type === 'submenu-trigger' && addonAfter === undefined) {
            addonAfter = _jsx(CaretRightIcon, { alt: "" });
        }
        if (href !== undefined && addonAfter === undefined) {
            addonAfter = (_jsx(ButtonOrLink.Consumer, { render: (buttonOrLinkState) => buttonOrLinkState?.target === '_blank' ? (_jsx(ArrowUpRightInteractiveIcon, { hiddenByDefault: true })) : (_jsx(ArrowRightInteractiveIcon, { hiddenByDefault: true })) }));
        }
        return (_jsxs(Render, { render: _jsx(ButtonOrLink, { href: href, target: target }), "data-type": type, "data-variant": variant, className: cn(`gds-menu-item root-flex w-full items-center outline-0 select-none u:rounded-6 u:p-2 u:text-16
          u:state-idle
          u:checked:state-checked
          u:indeterminate:state-indeterminate
          u:disabled:pointer-events-none
          u:disabled:state-disabled
          u:data-highlighted:state-hover
          u:data-[variant=danger]:text-status-error-default
          u:ii:not-disabled:active:state-active
          u:ii:data-[type=submenu-trigger]:not-[a]:cursor-default
          u:ii:data-[type=submenu-trigger]:not-[a]:active:state-hover
          ${ /* Disabled styles */''}
          u:*:transition-opacity
          u:disabled:*:opacity-disabled
          u:disabled:*:grayscale`, className), ...renderProps, children: [_jsx("span", { className: `
            absolute inset-0 rounded-inherit opacity-100 filter-none transition
            @state-hover/menu-item:bg-elevated
            @state-active/menu-item:bg-default
            @state-active/menu-item:transition-none
          ` }), addonBefore ? (_jsx(MenuItemAddon, { className: `
              me-2
              has-checkbox:@state-checked/menu-item:opacity-100
              has-checkbox:@state-checked/menu-item:filter-none
            `, children: renderAddon(addonBefore) })) : null, addonInside ? (_jsx(MenuItemAddon, { className: "me-1", children: renderAddon(addonInside) })) : null, _jsx("span", { className: "grow truncate pe-1", children: children || _jsx(_Fragment, { children: "\u00A0" }) }), addonAfter ? (_jsx(MenuItemAddon, { className: "ms-2", children: renderAddon(addonAfter) })) : null] }));
    };
    // Filter out undefined values to satisfy Base UI's `exactOptionalPropertyTypes`
    // TODO: Remove when https://github.com/mui/base-ui/pull/3302 is released
    const definedProps = Object.fromEntries(Object.entries(props).filter(([, value]) => value !== undefined));
    const baseProps = {
        ref: stateElementPassedRef,
        ...state.polyfillAttributes,
        ...definedProps,
    };
    if (type === 'submenu-trigger') {
        return _jsx(Menu.SubmenuTrigger, { nativeButton: true, disabled: disabled, render: renderItem(baseProps) });
    }
    const nativeButton = href === undefined;
    const onKeyDown = (event) => {
        props.onKeyDown?.(event);
        /**
         * Allow Space to activate menu items that are links. This may not be needed in the future (see
         * https://github.com/mui/base-ui/issues/1746).
         */
        if (!event.baseUIHandlerPrevented && event.key === ' ' && href !== undefined) {
            event.preventBaseUIHandler();
            elementRef.current?.click();
        }
    };
    if (type === 'checkbox') {
        return (_jsx(CheckboxItem, { ...baseProps, nativeButton: nativeButton, closeOnClick: false, checked: checked, defaultChecked: defaultChecked, onCheckedChange: onChange, onKeyDown: onKeyDown, disabled: disabled, render: renderItem }));
    }
    if (type === 'radio') {
        return (_jsx(Menu.RadioItem, { ...baseProps, nativeButton: nativeButton, closeOnClick: true, value: passedValue !== undefined ? passedValue : autoValue, onKeyDown: onKeyDown, disabled: disabled, render: renderItem }));
    }
    return (_jsx(Menu.Item, { ...baseProps, nativeButton: nativeButton, onKeyDown: onKeyDown, disabled: disabled, render: renderItem }));
}
MenuItem.displayName = 'Menu.Item';
function MenuItemAddon({ className, children, ...props }) {
    return (_jsx("span", { className: cn('gds-addon root-flex items-center justify-center u:h-(--gds-addon-size) u:min-w-(--gds-addon-size) u:shrink-0 u:addon-medium', className), ...props, children: children }));
}
export function MenuSearch({ ref: passedRef, placeholder: passedPlaceholder, value: controlledValue, defaultValue, onChange, className, ...props }) {
    const inputRef = useRef(null);
    const inputPassedRef = useMergedRefs(inputRef, passedRef);
    const placeholder = passedPlaceholder ?? 'Search';
    const [value, setValue] = useControlled(controlledValue, defaultValue ?? '', onChange);
    return (_jsxs("div", { className: cn('root-flex items-center u:-m-4 u:text-14 u:text-default', className), ...props, children: [_jsx(MagnifyingGlassIcon, { alt: "", className: "absolute inset-y-0 start-3.5 my-auto size-3.5" }), _jsx("input", { ref: inputPassedRef, type: "search", placeholder: placeholder, "aria-label": placeholder, value: value, onChange: (event) => {
                    setValue(event.target.value);
                }, className: "peer -mb-px h-10 w-0 grow ps-8.5 outline-0" }), _jsx("div", { className: "me-1.5 flex size-7 shrink-0 items-center justify-center peer-placeholder-shown:hidden", children: _jsx(Button, { variant: "naked", size: "xsmall", tabIndex: -1, onClick: () => {
                        setValue('');
                        inputRef.current?.focus();
                    }, className: "h-full", children: _jsx(XIcon, { alt: "Clear" }) }) })] }));
}
MenuSearch.displayName = 'Menu.Search';
/**
 * Transparent wrapper for `Menu.CheckboxItem` to support `indeterminate`. This may not be needed in
 * the future (see https://github.com/mui/base-ui/issues/1983).
 */
function CheckboxItem({ checked: controlledChecked, defaultChecked, onCheckedChange, ...props }) {
    const [checked, setChecked] = useControlled(controlledChecked, defaultChecked ?? false, onCheckedChange);
    return (_jsx(Menu.CheckboxItem, { checked: checked === true, "aria-checked": checked === 'indeterminate' ? 'mixed' : checked, onCheckedChange: (newChecked) => setChecked(newChecked), ...props }));
}
//# sourceMappingURL=Menu.parts.js.map