'use client';
import { jsx as _jsx } from "react/jsx-runtime";
import { createContext, isValidElement, useContext, useMemo, useRef, useState, } from 'react';
import { useMergedRefs } from '@base-ui/utils/useMergedRefs';
import { mergeProps } from '@react-aria/utils';
import { useButton } from 'react-aria';
import { cn } from "../../utils/index.js";
import { Render } from "./Render.js";
const ButtonOrLinkContext = createContext(null);
export function useAncestorButtonOrLink() {
    return useContext(ButtonOrLinkContext);
}
const memoizedWithContextComponents = new Map();
function withContext(Element) {
    const cached = memoizedWithContextComponents.get(Element);
    if (cached)
        return cached;
    const newWithContextComponent = ({ buttonOrLinkState, ...props }) => (_jsx(ButtonOrLinkContext.Provider, { value: buttonOrLinkState, children: _jsx(Element, { ...props }) }));
    memoizedWithContextComponents.set(Element, newWithContextComponent);
    return newWithContextComponent;
}
const ButtonWithContext = withContext('button');
const SpanButtonWithContext = withContext(SpanButton);
const AnchorWithContext = withContext('a');
const RenderWithContext = withContext(Render);
const ButtonOrLinkConfigContext = createContext(null);
/**
 * Renders a link (`a` or custom `linkComponent`) if `href` is passed. Otherwise, renders a `button`
 * (or a `span` that behaves like a button if `inline` is true).
 */
export const ButtonOrLinkRoot = (passedProps) => {
    const ancestorButtonOrLink = useAncestorButtonOrLink();
    if (ancestorButtonOrLink) {
        throw new Error('[ButtonOrLink] Trying to render a nested `ButtonOrLink`');
    }
    const config = useContext(ButtonOrLinkConfigContext);
    const transformProps = config?.transformProps ?? ((props) => props);
    const props = transformProps({
        ...passedProps,
        onClick: passedProps.onClick || config?.onClick
            ? (event) => {
                passedProps.onClick?.(event);
                if (event.isPropagationStopped())
                    return;
                config?.onClick?.(event, passedProps);
            }
            : undefined,
    });
    const { disabled = false, inline = false, linkComponent: passedLinkComponent, render: passedRender, className: passedClassName, children, ...specificProps } = props;
    const manuallyDisabledEventProps = {
        onClick: undefined,
        onMouseDown: undefined,
        onMouseUp: undefined,
        onPointerDown: undefined,
        onPointerUp: undefined,
        onTouchStart: undefined,
        onTouchEnd: undefined,
        onKeyDown: undefined,
        onKeyUp: undefined,
    };
    const render = (Element, renderProps, buttonOrLinkState, extraElementProps) => {
        const elementProps = { buttonOrLinkState, ...extraElementProps };
        const renderState = {
            ...buttonOrLinkState,
            Element,
            elementProps,
        };
        return passedRender ? (passedRender(renderProps, renderState)) : (_jsx(Element, { ...renderProps, ...elementProps }));
    };
    const className = cn('gds-button-or-link', passedClassName);
    if (props.href === undefined) {
        const { role = 'button', type = 'button', checked, defaultChecked, href: _href, target: _target, ...remainingProps } = specificProps;
        if (defaultChecked !== undefined) {
            // oxlint-disable-next-line no-console
            console.warn('[ButtonOrLink] `defaultChecked` is not supported; use a controlled `checked` prop instead, or wrap `ButtonOrLink` in a component that manages the uncontrolled state');
        }
        const checkedAttribute = checked === undefined
            ? {}
            : ((checked) => {
                if ((role === 'option' || role === 'tab' || role === 'row' || role === 'gridcell') &&
                    checked !== 'indeterminate') {
                    return { 'aria-selected': Boolean(checked) };
                }
                const checkedOrMixed = checked === 'indeterminate' ? 'mixed' : Boolean(checked);
                if (role === 'button') {
                    return { 'aria-pressed': checkedOrMixed };
                }
                return { 'aria-checked': checkedOrMixed };
            })(checked);
        const buttonProps = {
            role,
            type: disabled === 'focusable' ? 'button' : type,
            disabled: disabled === true,
            'aria-disabled': disabled === 'focusable' || undefined,
            ...checkedAttribute,
            className,
            children,
            ...remainingProps,
            ...((disabled === 'focusable' || (disabled && inline)) && manuallyDisabledEventProps),
        };
        const buttonOrLinkState = {
            category: 'button',
            role,
            disabled,
            type,
            checked,
        };
        return render(inline ? SpanButtonWithContext : ButtonWithContext, buttonProps, buttonOrLinkState);
    }
    const { href, target, role = 'link', rel = target === '_blank' ? 'noopener noreferrer' : undefined, type: _type, checked: _checked, defaultChecked: _defaultChecked, ...remainingProps } = specificProps;
    let linkProps = {
        role: disabled || role !== 'link' ? role : undefined,
        href: !disabled ? href : undefined,
        target: !disabled ? target : undefined,
        rel: !disabled ? rel : undefined,
        tabIndex: disabled === 'focusable' ? 0 : undefined,
        'aria-disabled': Boolean(disabled) || undefined,
        className,
        children,
        ...remainingProps,
        ...(disabled && manuallyDisabledEventProps),
        // Prevent scrolling the page when Space is pressed while a link is focused
        onKeyDown: (event) => {
            if (event.key === ' ')
                event.preventDefault();
            if (!disabled)
                remainingProps.onKeyDown?.(event);
        },
    };
    let linkComponent = null;
    if (passedLinkComponent) {
        if (typeof passedLinkComponent === 'object' && 'component' in passedLinkComponent) {
            const useForDisabledLinks = passedLinkComponent.useForDisabledLinks ?? false;
            if (!disabled || useForDisabledLinks) {
                linkComponent = passedLinkComponent.component;
                if (passedLinkComponent.props) {
                    linkProps = passedLinkComponent.props(linkProps);
                }
            }
        }
        else if (!disabled) {
            linkComponent = passedLinkComponent;
        }
    }
    const buttonOrLinkState = {
        category: 'link',
        role,
        disabled,
        href,
        target,
    };
    if (isValidElement(linkComponent)) {
        return render(RenderWithContext, linkProps, buttonOrLinkState, { render: linkComponent });
    }
    return render(linkComponent && linkComponent !== 'a' ? withContext(linkComponent) : AnchorWithContext, linkProps, buttonOrLinkState);
};
ButtonOrLinkRoot.displayName = 'ButtonOrLink';
export const ButtonOrLinkConfig = ({ onClick: passedOnClick, transformProps: passedTransformProps, children, }) => {
    const ancestorConfig = useContext(ButtonOrLinkConfigContext);
    const onClick = passedOnClick && ancestorConfig?.onClick
        ? (() => {
            const ancestorOnClick = ancestorConfig.onClick;
            return (event, props) => {
                passedOnClick(event, props);
                if (event.isPropagationStopped())
                    return;
                ancestorOnClick(event, props);
            };
        })()
        : (passedOnClick ?? ancestorConfig?.onClick);
    const transformProps = passedTransformProps && ancestorConfig?.transformProps
        ? (() => {
            const ancestorTransformProps = ancestorConfig.transformProps;
            return (props) => {
                return ancestorTransformProps(passedTransformProps(props));
            };
        })()
        : (passedTransformProps ?? ancestorConfig?.transformProps);
    const buttonOrLinkConfigContextValue = useMemo(() => {
        if (!onClick && !transformProps)
            return null;
        return { onClick, transformProps };
    }, [onClick, transformProps]);
    return (_jsx(ButtonOrLinkConfigContext.Provider, { value: buttonOrLinkConfigContextValue, children: children }));
};
ButtonOrLinkConfig.displayName = 'ButtonOrLink.Config';
export function ButtonOrLinkConsumer({ render }) {
    const state = useAncestorButtonOrLink();
    return render(state);
}
ButtonOrLinkConsumer.displayName = 'ButtonOrLink.Consumer';
function SpanButton({ ref: passedRef, type = 'button', disabled = false, onClick, children, ...props }) {
    const spanRef = useRef(null);
    const spanPassedRef = useMergedRefs(spanRef, passedRef);
    const [active, setActive] = useState(false);
    const { buttonProps } = useButton({
        type,
        isDisabled: disabled,
        elementType: 'span',
        onPress: (event) => {
            event.target.dispatchEvent(new MouseEvent('click', {
                altKey: event.altKey,
                ctrlKey: event.ctrlKey,
                metaKey: event.metaKey,
                shiftKey: event.shiftKey,
                relatedTarget: event.target,
                bubbles: true,
                cancelable: true,
            }));
        },
        onPressStart: (event) => {
            if (event.pointerType === 'keyboard')
                setActive(true);
        },
        onPressEnd: () => {
            if (active)
                setActive(false);
        },
    }, spanRef);
    return (_jsx("span", { ref: spanPassedRef, "data-gds-exposed-pointer": active ? 'active' : undefined, ...mergeProps(props, {
            ...buttonProps,
            onClick: (event) => {
                onClick?.(event);
                /**
                 * Prevent toggling a `<input type="checkbox">` or `<input type="radio">` when clicking on
                 * a button inside the input's `<label>`.
                 */
                event.preventDefault();
            },
        }), children: children }));
}
//# sourceMappingURL=ButtonOrLink.parts.js.map