import React, {forwardRef, AnchorHTMLAttributes, ButtonHTMLAttributes} from 'react' import {styled, cssRule} from '@karma.run/react' import {themeMiddleware, Theme} from '../style/themeContext' import { FontSize, TransitionDuration, Spacing, BorderWidth, hexToRgba, WidthProps, MarginProps, FlexChildProps, extractStyleProps } from '../style/helpers' import {IconElement, Icon} from '../data/icon' export type ButtonVariant = 'default' | 'outlined' | 'text' export type ButtonColor = 'default' | 'primary' | 'secondary' interface ButtonStyleProps extends WidthProps, MarginProps, FlexChildProps { disabled?: boolean variant: ButtonVariant color: ButtonColor theme: Theme } function getMainColor({color, disabled, theme}: ButtonStyleProps) { if (disabled) return theme.colors.grayLight switch (color) { case 'primary': return theme.colors.primary case 'secondary': return theme.colors.action case 'default': return theme.colors.grayDark } } function getActiveMainColor({color, theme}: ButtonStyleProps) { switch (color) { case 'primary': return theme.colors.primaryDark case 'secondary': return theme.colors.actionDark case 'default': return theme.colors.dark } } function getTextColor(props: ButtonStyleProps) { const {variant, disabled, theme} = props switch (variant) { case 'outlined': case 'text': if (disabled) return theme.colors.grayLight return getMainColor(props) case 'default': if (disabled) return theme.colors.gray return theme.colors.white } } function getActiveTextColor(props: ButtonStyleProps) { const {variant, theme} = props switch (variant) { case 'outlined': return getActiveMainColor(props) case 'text': case 'default': return theme.colors.white } } const ButtonStyle = cssRule(props => { const {color, variant, disabled, theme, ...styleProps} = props const backgroundColor = getMainColor(props) const activeBackgroundColor = getActiveMainColor(props) const textColor = getTextColor(props) const activeTextColor = getActiveTextColor(props) return { _className: process.env.NODE_ENV !== 'production' ? 'Button' : undefined, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', paddingTop: Spacing.ExtraSmall, paddingBottom: Spacing.ExtraSmall, paddingLeft: Spacing.Small, paddingRight: Spacing.Small, cursor: disabled ? 'default' : 'pointer', fontSize: FontSize.Medium, borderRadius: Spacing.ExtraSmall, color: textColor, fontFamily: 'inherit', textAlign: 'center', lineHeight: 1.2, fill: textColor, borderWidth: BorderWidth.Small, borderStyle: 'solid', borderColor: variant === 'outlined' ? backgroundColor : 'transparent', backgroundColor: variant === 'default' ? backgroundColor : 'transparent', pointerEvents: disabled ? 'none' : undefined, transitionProperty: 'color background-color box-shadow', transitionTimingFunction: 'ease-in', transitionDuration: TransitionDuration.Fast, ...styleProps, ':link': { color: textColor }, ':visited': { color: textColor }, ':hover': { color: activeTextColor, borderColor: variant === 'outlined' ? activeBackgroundColor : undefined, backgroundColor: variant === 'outlined' ? undefined : activeBackgroundColor, fill: activeTextColor }, ':active': { color: theme.colors.grayLight, backgroundColor: activeBackgroundColor, fill: theme.colors.grayLight, boxShadow: `0 0 15px 0 ${hexToRgba(activeBackgroundColor, 0.6)}` }, ':focus': { outline: 'none', boxShadow: `0 0 10px 0 ${hexToRgba(backgroundColor, 0.6)}` } } }) export interface BaseButtonProps extends WidthProps, MarginProps, FlexChildProps { icon?: IconElement label: string disabled?: boolean color?: ButtonColor variant?: ButtonVariant outlined?: boolean } export type ButtonProps = BaseButtonProps & ButtonHTMLAttributes export type LinkButtonProps = BaseButtonProps & AnchorHTMLAttributes const ButtonElement = styled('button', ButtonStyle, themeMiddleware) const LinkButtonElement = styled('a', ButtonStyle, themeMiddleware) const ButtonIcon = styled('span', () => ({ _className: process.env.NODE_ENV !== 'production' ? 'ButtonIcon' : undefined, marginRight: Spacing.Tiny, marginLeft: -Spacing.Tiny })) export const Button = forwardRef(function Button( {icon, label, disabled, color = 'default', variant = 'default', ...props}, ref ) { const [styleProps, elementProps] = extractStyleProps(props) return ( {icon && ( )} {label} ) }) export const LinkButton = forwardRef(function LinkButton( {icon, label, disabled, color = 'default', variant = 'default', ...props}, ref ) { const [styleProps, elementProps] = extractStyleProps(props) return ( {icon && ( )} {label} ) })