import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import * as React from "react";
import { createPortal } from "react-dom";
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
import { cn } from "../../lib/utils";
const ContextMenuRootContext = React.createContext(null);
function useContextMenuRoot() {
    const ctx = React.useContext(ContextMenuRootContext);
    if (!ctx)
        throw new Error("ContextMenu components must be used within ContextMenu");
    return ctx;
}
function ContextMenu({ children }) {
    const [position, setPosition] = React.useState(null);
    const containersRef = React.useRef(new Set());
    const isOpen = position !== null;
    const openAt = React.useCallback((pos) => {
        setPosition(pos);
    }, []);
    const close = React.useCallback(() => {
        setPosition(null);
    }, []);
    const registerContainer = React.useCallback((el) => {
        if (el)
            containersRef.current.add(el);
    }, []);
    const unregisterContainer = React.useCallback((el) => {
        if (el)
            containersRef.current.delete(el);
    }, []);
    React.useEffect(() => {
        if (!isOpen)
            return;
        const handleKeyDown = (e) => {
            if (e.key === "Escape")
                close();
        };
        const handlePointerDown = (e) => {
            const target = e.target;
            let inside = false;
            containersRef.current.forEach((el) => {
                if (el.contains(target))
                    inside = true;
            });
            if (!inside)
                close();
        };
        window.addEventListener("keydown", handleKeyDown, true);
        // Use bubble phase so capture-phase handlers inside the menu can stop propagation
        window.addEventListener("pointerdown", handlePointerDown);
        // Also listen for click events so synthetic clicks (e.g., forwarded from iframes) close the menu
        window.addEventListener("click", handlePointerDown);
        return () => {
            window.removeEventListener("keydown", handleKeyDown, true);
            window.removeEventListener("pointerdown", handlePointerDown);
            window.removeEventListener("click", handlePointerDown);
        };
    }, [isOpen, close]);
    const value = React.useMemo(() => ({
        isOpen,
        position,
        openAt,
        close,
        registerContainer,
        unregisterContainer,
    }), [isOpen, position, openAt, close, registerContainer, unregisterContainer]);
    return (_jsx(ContextMenuRootContext.Provider, { value: value, children: _jsx("div", { "data-slot": "context-menu", "data-testid": "context-menu", children: children }) }));
}
function ContextMenuTrigger({ asChild, children, ...rest }) {
    const { openAt } = useContextMenuRoot();
    const onContextMenu = (e) => {
        if (rest.onContextMenu)
            rest.onContextMenu(e);
        e.preventDefault();
        e.stopPropagation();
        openAt({ x: e.clientX, y: e.clientY });
    };
    if (asChild && React.isValidElement(children)) {
        const childOnContextMenu = children.props?.onContextMenu;
        const composedOnContextMenu = (e) => {
            if (childOnContextMenu)
                childOnContextMenu(e);
            onContextMenu(e);
        };
        return React.cloneElement(children, {
            ...rest,
            onContextMenu: composedOnContextMenu,
        });
    }
    return (_jsx("span", { "data-slot": "context-menu-trigger", "data-testid": "context-menu-trigger", onContextMenu: onContextMenu, ...rest, children: children }));
}
function ContextMenuGroup({ children, className, }) {
    return (_jsx("div", { "data-slot": "context-menu-group", "data-testid": "context-menu-group", className: className, children: children }));
}
function ContextMenuPortal({ children }) {
    return _jsx(_Fragment, { children: children });
}
function ContextMenuContent({ className, children, }) {
    const { isOpen, position, close, registerContainer, unregisterContainer } = useContextMenuRoot();
    const [openSubmenuId, setOpenSubmenuId] = React.useState(null);
    const [adjustedPosition, setAdjustedPosition] = React.useState(null);
    const menuRef = React.useRef(null);
    const contentRefCallback = React.useCallback((el) => {
        menuRef.current = el;
        if (el) {
            registerContainer(el);
        }
    }, [registerContainer]);
    // Calculate adjusted position based on viewport bounds
    React.useEffect(() => {
        if (!isOpen || !position || !menuRef.current) {
            setAdjustedPosition(null);
            return;
        }
        const OFFSET = 1;
        const PADDING = 8;
        const menuRect = menuRef.current.getBoundingClientRect();
        const viewportWidth = window.innerWidth;
        const viewportHeight = window.innerHeight;
        let left = position.x + OFFSET;
        let top = position.y + OFFSET;
        const menuHeight = Math.max(menuRect.height, menuRef.current.scrollHeight);
        const menuWidth = menuRect.width;
        let maxHeight = viewportHeight - PADDING * 2;
        // Check if menu would overflow bottom of viewport
        if (top + menuHeight > viewportHeight - PADDING) {
            // Position above the click point
            top = position.y - menuHeight - OFFSET;
            // Ensure it doesn't go above the viewport
            if (top < PADDING) {
                // Menu is taller than available space, position at top and constrain height
                top = PADDING;
                maxHeight = viewportHeight - PADDING * 2;
            }
            else {
                maxHeight = position.y - OFFSET - PADDING;
            }
        }
        else {
            maxHeight = viewportHeight - top - PADDING;
        }
        // Check if menu would overflow right edge of viewport
        if (left + menuWidth > viewportWidth - PADDING) {
            // Position to the left of the click point
            left = position.x - menuWidth - OFFSET;
            // Ensure it doesn't go off the left edge
            if (left < PADDING) {
                left = PADDING;
            }
        }
        setAdjustedPosition({ left, top, maxHeight });
    }, [isOpen, position, children]);
    if (!isOpen || !position)
        return null;
    const OFFSET = 1;
    const PADDING = 8;
    const defaultLeft = position.x + OFFSET;
    const defaultTop = position.y + OFFSET;
    // Use adjusted position if available, otherwise use default
    // Use a generous maxHeight initially to allow the menu to be measured correctly in useEffect
    const finalPosition = adjustedPosition || {
        left: defaultLeft,
        top: defaultTop,
        maxHeight: window.innerHeight - PADDING * 2,
    };
    const node = (_jsx("div", { ref: contentRefCallback, "data-slot": "context-menu-content", "data-testid": "context-menu-content", className: cn("text-popover-foreground border-border-default z-50 min-w-[9rem] overflow-y-auto rounded-xl border bg-white/95 p-1 font-normal shadow-[0_10px_40px_color-mix(in_srgb,var(--color-neutral-grey-100)_10%,transparent)] backdrop-blur-md", className), style: {
            position: "fixed",
            left: finalPosition.left,
            top: finalPosition.top,
            maxHeight: finalPosition.maxHeight,
            opacity: adjustedPosition ? 1 : 0,
        }, onKeyDownCapture: (e) => {
            if (e.key === "Escape") {
                e.stopPropagation();
                close();
            }
        }, onContextMenu: (e) => {
            e.preventDefault();
            e.stopPropagation();
        }, children: _jsx(SubmenuLevelContext.Provider, { value: { openSubmenuId, setOpenSubmenuId }, children: children }) }));
    return createPortal(node, document.body);
}
function ContextMenuItem({ className, inset, variant = "default", onClick, onSelect, onMouseEnter, onFocus, ...rest }) {
    const { close } = useContextMenuRoot();
    const level = React.useContext(SubmenuLevelContext);
    const disabled = rest.disabled ?? false;
    const executedRef = React.useRef(false);
    const performAction = (e) => {
        if (disabled)
            return;
        if (executedRef.current)
            return;
        executedRef.current = true;
        try {
            if (onClick)
                onClick(e);
            if (onSelect)
                onSelect(e);
            close();
        }
        finally {
            // Reset in next tick so a subsequent distinct click can trigger again
            setTimeout(() => {
                executedRef.current = false;
            }, 0);
        }
    };
    const handleMouseDown = (e) => {
        // Trigger on primary-button press for snappier UX and to avoid external handlers interfering
        if (e.button === 0) {
            performAction(e);
        }
    };
    const handleClick = (e) => {
        // Fallback in case mousedown didn't fire
        performAction(e);
    };
    const handleKeyDown = (e) => {
        if (e.key === "Enter" || e.key === " ") {
            e.preventDefault();
            // Cast to any to reuse performAction signature
            performAction(e);
        }
    };
    const handleMouseEnter = (e) => {
        level?.setOpenSubmenuId(null);
        onMouseEnter?.(e);
    };
    const handleFocus = (e) => {
        level?.setOpenSubmenuId(null);
        onFocus?.(e);
    };
    return (_jsx("div", { role: "menuitem", "data-slot": "context-menu-item", "data-testid": "context-menu-item", "data-inset": inset, "data-variant": variant, "data-disabled": disabled ? "" : undefined, className: cn("group hover:bg-neutral-grey-5/50 focus:bg-neutral-grey-5/50 relative flex cursor-pointer items-center gap-2 rounded-lg px-2 py-1.5 text-[12px] font-medium transition-colors outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:size-3.5 [&_svg]:shrink-0", className), onMouseDown: handleMouseDown, onClick: handleClick, onKeyDown: handleKeyDown, onMouseEnter: handleMouseEnter, onFocus: handleFocus, ...rest }));
}
function ContextMenuCheckboxItem({ className, children, checked, onClick, ...rest }) {
    const { close } = useContextMenuRoot();
    const handle = (e) => {
        if (rest.disabled)
            return;
        if (onClick)
            onClick(e);
        close();
    };
    return (_jsxs("div", { "data-slot": "context-menu-checkbox-item", "data-testid": "context-menu-checkbox-item", "data-disabled": rest.disabled ? "" : undefined, className: cn("hover:text-accent-foreground focus:text-accent-foreground hover:bg-neutral-grey-5 focus:bg-neutral-grey-5 relative flex cursor-pointer items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-xs outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", className), onClick: handle, ...rest, children: [_jsx("span", { className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center", children: checked ? _jsx(CheckIcon, { className: "size-4" }) : null }), children] }));
}
function ContextMenuRadioGroup({ children }) {
    return (_jsx("div", { "data-slot": "context-menu-radio-group", "data-testid": "context-menu-radio-group", children: children }));
}
function ContextMenuRadioItem({ className, children, checked, onClick, ...rest }) {
    const { close } = useContextMenuRoot();
    const handle = (e) => {
        if (rest.disabled)
            return;
        if (onClick)
            onClick(e);
        close();
    };
    return (_jsxs("div", { "data-slot": "context-menu-radio-item", "data-testid": "context-menu-radio-item", "data-disabled": rest.disabled ? "" : undefined, className: cn("hover:text-accent-foreground focus:text-accent-foreground hover:bg-neutral-grey-5 focus:bg-neutral-grey-5 relative flex cursor-pointer items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-xs outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", className), onClick: handle, ...rest, children: [_jsx("span", { className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center", children: checked ? _jsx(CircleIcon, { className: "size-2 fill-current" }) : null }), children] }));
}
function ContextMenuLabel({ className, inset, ...rest }) {
    return (_jsx("div", { "data-slot": "context-menu-label", "data-testid": "context-menu-label", "data-inset": inset, className: cn("text-neutral-grey-50 px-2.5 py-1.5 text-[10px] font-bold tracking-wider", className), ...rest }));
}
function ContextMenuSeparator({ className, ...rest }) {
    return (_jsx("div", { role: "separator", "data-slot": "context-menu-separator", "data-testid": "context-menu-separator", className: cn("bg-border-default -mx-1 my-1 h-px", className), ...rest }));
}
function ContextMenuShortcut({ className, ...rest }) {
    return (_jsx("span", { "data-slot": "context-menu-shortcut", "data-testid": "context-menu-shortcut", className: cn("text-muted-foreground ml-auto text-xs tracking-widest", className), ...rest }));
}
const SubmenuContext = React.createContext(null);
const SubmenuLevelContext = React.createContext(null);
function ContextMenuSub({ children }) {
    const level = React.useContext(SubmenuLevelContext);
    const submenuId = React.useId();
    const [localOpen, setLocalOpen] = React.useState(false);
    const triggerRef = React.useRef(null);
    const isOpen = level ? level.openSubmenuId === submenuId : localOpen;
    const setOpen = React.useCallback((open) => {
        if (level) {
            level.setOpenSubmenuId(open ? submenuId : null);
        }
        else {
            setLocalOpen(open);
        }
    }, [level, submenuId]);
    const value = React.useMemo(() => ({ isOpen, setOpen, triggerRef }), [isOpen, setOpen]);
    return (_jsx(SubmenuContext.Provider, { value: value, children: _jsx("div", { "data-slot": "context-menu-sub", "data-testid": "context-menu-sub", children: children }) }));
}
function useSubmenu() {
    const ctx = React.useContext(SubmenuContext);
    if (!ctx)
        throw new Error("ContextMenuSub components must be used within ContextMenuSub");
    return ctx;
}
function ContextMenuSubTrigger({ className, inset, children, disabled, ...rest }) {
    const { setOpen, triggerRef } = useSubmenu();
    const openSub = (e) => {
        e.stopPropagation();
        if (!disabled)
            setOpen(true);
    };
    return (_jsxs("div", { ref: triggerRef, "data-slot": "context-menu-sub-trigger", "data-testid": "context-menu-sub-trigger", "data-inset": inset, "data-disabled": disabled ? "" : undefined, className: cn("group hover:text-accent-foreground focus:text-accent-foreground hover:bg-neutral-grey-5/50 focus:bg-neutral-grey-5/50 flex cursor-pointer items-center gap-2 rounded-lg px-2 py-1.5 text-[12px] font-medium outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:size-3.5 [&_svg]:shrink-0", className), onMouseEnter: openSub, onClick: openSub, ...rest, children: [children, _jsx(ChevronRightIcon, { className: "ml-auto" })] }));
}
function ContextMenuSubContent({ className, children, }) {
    const { isOpen, setOpen, triggerRef } = useSubmenu();
    const { registerContainer, unregisterContainer } = useContextMenuRoot();
    const [openSubmenuId, setOpenSubmenuId] = React.useState(null);
    const [coords, setCoords] = React.useState({
        left: 0,
        top: 0,
        maxHeight: 0,
    });
    const menuRef = React.useRef(null);
    const subContentRefCallback = React.useCallback((el) => {
        menuRef.current = el;
        if (el) {
            registerContainer(el);
        }
    }, [registerContainer]);
    React.useEffect(() => {
        const trig = triggerRef.current;
        if (!trig || !isOpen)
            return;
        const rect = trig.getBoundingClientRect();
        const viewportHeight = window.innerHeight;
        const viewportWidth = window.innerWidth;
        const PADDING = 8; // Padding from viewport edges
        let left = rect.right;
        let top = rect.top;
        // Get menu dimensions if available
        const menuEl = menuRef.current;
        const menuWidth = menuEl?.offsetWidth || 200;
        // Check if menu would overflow right edge of viewport
        if (left + menuWidth > viewportWidth - PADDING) {
            // Position to the left of the trigger
            left = rect.left - menuWidth;
            // Ensure it doesn't go off the left edge
            if (left < PADDING) {
                left = PADDING;
            }
        }
        // Calculate available height from the top position to viewport bottom
        const availableHeightBelow = viewportHeight - top - PADDING;
        const availableHeightAbove = rect.bottom - PADDING;
        // Calculate max height - use a reasonable portion of viewport
        let maxHeight;
        // If there's not enough space below, try positioning above
        if (availableHeightBelow < 200 &&
            availableHeightAbove > availableHeightBelow) {
            // Position above - align bottom of menu with bottom of trigger
            maxHeight = Math.min(availableHeightAbove, viewportHeight - 2 * PADDING);
            // We'll adjust top after measuring, for now use available height
            top = Math.max(PADDING, rect.bottom - Math.min(maxHeight, availableHeightAbove));
        }
        else {
            // Position below
            maxHeight = availableHeightBelow;
            // Ensure top doesn't go above viewport
            if (top < PADDING) {
                top = PADDING;
                maxHeight = viewportHeight - 2 * PADDING;
            }
        }
        setCoords({ left, top, maxHeight });
    }, [triggerRef.current, isOpen]);
    if (!isOpen)
        return null;
    const node = (_jsx("div", { ref: subContentRefCallback, "data-slot": "context-menu-sub-content", "data-testid": "context-menu-sub-content", className: cn("text-popover-foreground border-border-default z-50 min-w-[9rem] overflow-y-auto rounded-xl border bg-white/95 p-1 font-normal shadow-[0_10px_40px_color-mix(in_srgb,var(--color-neutral-grey-100)_10%,transparent)] backdrop-blur-md", className), style: {
            position: "fixed",
            left: coords.left,
            top: coords.top,
            maxHeight: coords.maxHeight > 0 ? coords.maxHeight : undefined,
        }, onMouseLeave: () => setOpen(false), onMouseEnter: () => setOpen(true), children: _jsx(SubmenuLevelContext.Provider, { value: { openSubmenuId, setOpenSubmenuId }, children: children }) }));
    return createPortal(node, document.body);
}
export { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, };
//# sourceMappingURL=context-menu.js.map