import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useRef, useEffect, forwardRef } from 'react';
import styled, { css } from 'styled-components';
import { meetsContrastGuidelines, mix } from 'polished';
import { defaultThemeProp } from '../../theme';
import { isPositionWithinRect, tryCatch, createClassName } from '../../utils';
import { getActiveColors, getHoverColors, isSolidColor, omitProps, readableColor, readableHue } from '../../styles';
import { useElement, useConsolidatedRef } from '../../hooks';
import Tooltip from '../Tooltip';
import Progress, { StyledProgressRing } from '../Progress';
import { StyledBackdrop } from '../Backdrop';
import { StyledIcon } from '../Icon';
import { StyledPopover } from '../Popover';
const baseStyles = (theme) => {
    const { base: { spacing, animation: { speed, timing: { ease } }, 'disabled-opacity': disabledOpacity }, components: { button: { 'focus-shadow': focusShadow } } } = theme;
    return css `
    text-decoration: none;
    transition-property: background-color, color, border-color, box-shadow, translate;
    transition-duration: calc(0.5 * ${speed});
    transition-timing-function: ${ease};
    cursor: pointer;

    @media (forced-colors: none) {
      outline: none;
    }

    & + & {
      margin-inline-start: ${spacing};
    }

    /* Not able to combine with selector above. Stylis bug? */

    & + ${StyledPopover} + & {
      margin-inline-start: ${spacing};
    }

    &:disabled,
    &[disabled] {
      opacity: ${disabledOpacity};
      cursor: not-allowed;
      pointer-events: none;
    }

    &:enabled:focus,
    &:not([disabled]):focus {
      box-shadow: ${focusShadow};
    }
  `;
};
/* If the background color is not provided, the color will be used for the hover and active styles */
const getFilledButtonStyles = (color, backgroundColor) => ({
    contrastColor: backgroundColor ? color : tryCatch(() => readableColor(color)),
    hoverColors: getHoverColors(backgroundColor || color),
    activeColors: getActiveColors(backgroundColor || color)
});
const getOutlinedButtonStyles = (color, backgroundColor) => {
    // If the background color is not solid, use the readable color for the text
    const fallbackBackground = isSolidColor(backgroundColor) ? backgroundColor : readableColor(color);
    const backgroundUsable = tryCatch(() => meetsContrastGuidelines(color, fallbackBackground).AA);
    const usableColor = backgroundUsable ? color : readableHue(color, backgroundColor);
    const hoverBackgroundColor = tryCatch(() => mix(0.9, backgroundColor, color));
    const activeBackgroundColor = tryCatch(() => mix(0.8, backgroundColor, usableColor));
    return {
        textColor: backgroundUsable ? color : readableColor(color),
        hoverBg: hoverBackgroundColor,
        hoverFg: readableHue(color, hoverBackgroundColor ?? 'transparent'),
        activeBg: tryCatch(() => mix(0.8, backgroundColor, usableColor)),
        activeFg: readableHue(usableColor, activeBackgroundColor ?? 'transparent')
    };
};
export const StyledButton = styled.button.withConfig(omitProps('loading'))(({ variant, icon, loading, compact, theme }) => {
    const { base: { spacing, 'border-radius': baseBorderRadius, palette: { 'primary-background': backgroundColor }, 'hit-area': { 'mouse-min': hitAreaMouse, 'finger-min': hitAreaFinger, 'compact-min': hitAreaCompact }, animation: { speed } }, components: { button: { color, 'foreground-color': foregroundColor, 'secondary-color': secondaryColor, 'secondary-fill-style': fillStyle, padding, 'border-radius': borderRadius, 'border-width': borderWidth, touch: { padding: touchPadding } } } } = theme;
    // Base
    const base = baseStyles(theme);
    // Non-text base
    const nonTextual = css `
      position: relative;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      min-height: ${hitAreaMouse};
      min-width: ${hitAreaMouse};
      border: ${borderWidth} solid transparent;
      border-radius: calc(${baseBorderRadius} * ${borderRadius});
      -webkit-user-select: none;
      user-select: none;
      white-space: nowrap;

      ${!icon &&
        css `
        padding: ${padding};
      `}

      ${icon &&
        css `
        border-radius: calc(${baseBorderRadius} * ${borderRadius});

        > svg {
          display: block;
        }
      `} ${compact &&
        css `
        min-height: ${hitAreaCompact};
        min-width: ${hitAreaCompact};
      `} @media (
        pointer: coarse) {
        border-radius: calc(${baseBorderRadius} * ${borderRadius});

        ${!compact &&
        css `
          min-height: ${hitAreaFinger};
          min-width: ${hitAreaFinger};
        `}

        ${!icon &&
        css `
          padding: ${touchPadding};
        `}
      }

      &:active {
        translate: 0 0.0625rem;
      }
    `;
    // Primary and Secondary-filled
    /* For primary button, use the foreground color as the text color. If foreground is 'auto', then calculate based on background
       For secondary button, always use the secondary color */
    const { contrastColor, hoverColors, activeColors } = variant !== 'primary' || foregroundColor === 'auto'
        ? getFilledButtonStyles(variant === 'primary' ? color : secondaryColor)
        : getFilledButtonStyles(foregroundColor, color);
    const solidButtonStyles = css `
      --button-background-color: ${variant === 'primary' ? color : secondaryColor};
      color: ${contrastColor};
      background-color: ${variant === 'primary' ? color : secondaryColor};

      @media (hover: hover) {
        &:hover {
          background-color: ${hoverColors.background};
          text-decoration: none;
        }
      }

      &:active {
        background-color: ${activeColors.background};
        color: ${activeColors.foreground};
        text-decoration: none;
      }
    `;
    // Secondary-outline
    const secondaryOutlineButtonStyles = getOutlinedButtonStyles(secondaryColor, backgroundColor);
    const secondary = css `
      --button-background-color: ${backgroundColor};
      color: ${secondaryOutlineButtonStyles.textColor};
      background-color: ${backgroundColor};
      border-color: ${secondaryColor};

      @media (hover: hover) {
        &:hover {
          background-color: ${secondaryOutlineButtonStyles.hoverBg};
          text-decoration: none;
        }
      }

      &:active {
        color: ${secondaryOutlineButtonStyles.activeFg};
        background-color: ${secondaryOutlineButtonStyles.activeBg};
        border-color: ${secondaryOutlineButtonStyles.activeFg};
        text-decoration: none;
      }
    `;
    // Simple
    const simpleButtonStyles = getOutlinedButtonStyles(fillStyle === 'outline' ? secondaryColor : color, backgroundColor);
    const simple = css `
      --button-background-color: ${icon ? 'transparent' : backgroundColor};
      color: ${icon ? 'currentColor' : simpleButtonStyles.textColor};
      background-color: ${icon ? 'transparent' : backgroundColor};

      @media (hover: hover) {
        &:hover {
          ${icon &&
        css `
            ::before {
              content: '';
              position: absolute;
              top: calc(${borderWidth} * -1);
              bottom: calc(${borderWidth} * -1);
              left: calc(${borderWidth} * -1);
              right: calc(${borderWidth} * -1);
              border-radius: inherit;
              background-color: currentColor;
              opacity: 0.1;
            }
          `}

          ${!icon &&
        css `
            background-color: ${simpleButtonStyles.hoverBg};
            color: ${simpleButtonStyles.hoverFg};
            border-color: ${simpleButtonStyles.hoverFg};
            text-decoration: none;
          `}
        }

        &:active {
          ${icon &&
        css `
            ::before {
              content: '';
              position: absolute;
              top: calc(${borderWidth} * -1);
              bottom: calc(${borderWidth} * -1);
              left: calc(${borderWidth} * -1);
              right: calc(${borderWidth} * -1);
              border-radius: inherit;
              background-color: currentColor;
              opacity: 0.2;
            }
          `}

          ${!icon &&
        css `
            background-color: ${simpleButtonStyles.activeBg};
            color: ${simpleButtonStyles.activeFg};
            border-color: ${simpleButtonStyles.activeFg};
            text-decoration: none;
          `}
        }
      }
    `;
    return css `
      ${base}
      ${nonTextual}
        ${(variant === 'primary' || (variant === 'secondary' && fillStyle === 'fill')) &&
        solidButtonStyles}
        ${variant === 'secondary' && fillStyle === 'outline' && secondary}
        ${variant === 'simple' && simple}
        ${variant === 'primary' &&
        css `
        font-weight: ${theme.base['font-weight']['semi-bold']};
      `}

        ${loading &&
        css `
        ${StyledBackdrop} {
          background-color: var(--button-background-color);
          border-radius: inherit;
        }

        ${StyledProgressRing} {
          width: 1em;
          height: 1em;

          ${!icon &&
            css `
            margin-inline-end: calc(${spacing} / 2);
          `}
          circle:nth-child(2) {
            animation-duration: calc(${speed} * 2);
          }
        }
      `}
    `;
});
StyledButton.defaultProps = defaultThemeProp;
export const StyledButtonLink = styled.a.withConfig(omitProps('loading'))(({ theme, variant, href }) => {
    const { base: { palette: { 'foreground-color': textVariantColor } }, components: { button: { color: primaryColor, 'secondary-fill-style': fillStyle }, link: { color: linkColor } } } = theme;
    let linkVariantColor = linkColor;
    if (!href && fillStyle === 'solid') {
        linkVariantColor = primaryColor;
    }
    const { background: activeLinkColor } = getActiveColors(linkVariantColor);
    const { background: activeTextColor } = getActiveColors(textVariantColor);
    const base = baseStyles(theme);
    const textual = css `
    background-color: transparent;
    display: inline;
    text-align: start;
    border: none;

    @media (hover: hover) {
      &:hover {
        text-decoration: underline;
      }
    }

    > ${StyledIcon} {
      vertical-align: bottom;
    }
  `;
    const link = css `
    color: ${linkVariantColor};

    &:active {
      color: ${activeLinkColor};
    }
  `;
    const text = css `
    color: ${textVariantColor};

    &:active {
      color: ${activeTextColor};
    }
  `;
    return css `
    ${base}
    ${textual}
      ${variant === 'link' && link}
      ${variant === 'text' && text}
  `;
});
StyledButtonLink.defaultProps = defaultThemeProp;
const Button = forwardRef(function Button({ variant = 'secondary', type = 'button', disabled = false, icon = false, compact = false, href, as, forwardedAs, label, 'aria-label': ariaLabel, loading = false, children, className, ...restProps }, ref) {
    const [buttonEl, setButtonEl] = useElement();
    const mouseDownEvent = useRef();
    const mouseDownPosition = useRef();
    const mouseDownTimestamp = useRef();
    const buttonRef = useConsolidatedRef(ref, setButtonEl);
    const isTextual = ['link', 'text'].includes(variant);
    const showProgress = loading && !isTextual;
    const StyledComp = isTextual ? StyledButtonLink : StyledButton;
    const handleClickWithElementShift = (e) => {
        if (buttonRef.current &&
            mouseDownPosition.current &&
            mouseDownTimestamp.current &&
            isPositionWithinRect({ x: e.clientX, y: e.clientY }, mouseDownPosition.current) &&
            Date.now() - mouseDownTimestamp.current < 500) {
            buttonRef.current.click();
        }
    };
    useEffect(() => {
        document.addEventListener('mouseup', handleClickWithElementShift);
        return () => {
            document.removeEventListener('mouseup', handleClickWithElementShift);
            mouseDownEvent.current = undefined;
            mouseDownPosition.current = undefined;
            mouseDownTimestamp.current = undefined;
        };
    }, []);
    return (_jsxs(_Fragment, { children: [_jsxs(StyledComp, { ...restProps, ref: buttonRef, as: as || (href ? 'a' : 'button'), forwardedAs: forwardedAs || (href ? 'a' : 'button'), className: createClassName('button', className, { variant, icon, compact, loading }), variant: variant, icon: icon, compact: compact, type: href ? undefined : type, href: href, disabled: disabled && !href, loading: showProgress, "aria-label": ariaLabel || label, onMouseDown: (e) => {
                    restProps.onMouseDown?.(e);
                    e.persist();
                    mouseDownEvent.current = e;
                    mouseDownPosition.current = e.currentTarget.getBoundingClientRect();
                    mouseDownTimestamp.current = Date.now();
                }, onMouseUp: (e) => {
                    const shouldFocus = mouseDownEvent.current && !mouseDownEvent.current.defaultPrevented;
                    mouseDownEvent.current = undefined;
                    mouseDownPosition.current = undefined;
                    mouseDownTimestamp.current = undefined;
                    if (shouldFocus && buttonRef.current !== document.activeElement) {
                        buttonRef.current?.focus();
                    }
                    return restProps.onMouseUp?.(e);
                }, children: [showProgress && _jsx(Progress, { variant: 'ring', placement: 'inline' }), !icon || !showProgress ? children : null] }), buttonEl && label && (_jsx(Tooltip, { target: buttonEl, showDelay: 'none', hideDelay: 'none', describeTarget: false, children: label }))] }));
});
export default Button;
//# sourceMappingURL=Button.js.map