UNPKG

@axeptio/design-system

Version:
469 lines (421 loc) 11 kB
import React from 'react'; import PropTypes from 'prop-types'; import styled, { useTheme } from 'styled-components'; import Icon from '../../Icon'; import Loader from '../../Loader'; const easing = 'cubic-bezier(0.19, 1, 0.22, 1)'; const xSmallPadding = '2px 15px'; const smallPadding = '6px 22px'; const mediumPadding = '12px 22px'; const largePadding = '18px 30px'; export const HoverText = styled.span` z-index: 100; position: absolute; top: 0; left: 0; right: 0; bottom: 0; padding: ${props => props.size === 'xsmall' ? xSmallPadding : props.size === 'small' ? smallPadding : props.size === 'medium' ? mediumPadding : props.size === 'large' ? largePadding : props.link ? largePadding : largePadding}; display: flex; align-items: center; justify-content: center; text-align: center; color: ${props => props.theme.colors.secondary}; opacity: 0; transform: translateY(-100%); transition: all 0.25s ${easing}; pointer-events: none; cursor: ${props => (props.disabled ? 'not-allowed' : 'pointer')}; ${props => props.customBackgroundColorOnHover && `background: ${props.customBackgroundColorOnHover};`} .svg-icon { pointer-events: none; visibility: hidden; opacity: 0; } `; const Root = styled.button` position: relative; font-family: ${props => props.theme.fonts.text}; font-style: normal; font-weight: ${props => (props.link ? 600 : 700)}; font-size: ${props => (props.size === 'large' || props.size === 'medium' ? '18px' : props.size === 'xsmall' ? '10px' : '16px')}; line-height: 1; text-decoration: ${props => (props.link && !props.linkNoUnderline ? 'underline' : 'none')}; text-decoration-color: ${props => props.link && props.theme.colors.grey.v400}; margin: 0; justify-content: center; box-sizing: border-box; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: antialiased; font-smoothing: antialiased; ${props => props.fullWidth && ` width: 100%; `} min-height: ${props => (props.link ? '0px' : props.size === 'xsmall' ? '17px' : '46px')}; min-width: ${props => (props.size === 'xsmall' ? '60px' : 'none')}; background-color: ${props => props.theme.colors.grey.v200}; color: ${props => props.theme.colors.secondary}; overflow: hidden; transform: translate3d(0, 0, 0); transition: all 0.15s ease; .text, .svg-icon { z-index: 1; position: relative; transition: all 0.55s ${easing}; } .text { text-align: center; } &::after { z-index: 10; content: ''; position: absolute; top: -50%; left: -25%; display: block; width: 150%; height: 250%; border-radius: 50%; background: ${props => props.primary ? props.theme.colors.grey.v100 : props.secondary ? props.theme.colors.black : props.theme.colors.grey.v200}; ${props => props.customBackgroundColorOnHover && `background: ${props.customBackgroundColorOnHover};`} pointer-events: none; transform: translateY(-100%); transition: all 0.55s ${easing}; } ${props => props.primary && ` background-color: ${props.theme.colors.primary}; color: ${props.theme.buttons.primary.color}; .svg-icon { fill: ${props.theme.colors.secondary}; stroke: ${props.theme.colors.secondary}; } &::after { background: ${props.theme.colors.secondary}; } `} ${props => props.secondary && ` background-color: ${props.theme.colors.secondary}; color: ${props.theme.colors.white}; .svg-icon { fill: ${props.theme.colors.white}; stroke: ${props.theme.colors.white}; } `}; ${props => props.link && ` color: ${props.theme.colors.black}; background-color: transparent; .svg-icon { fill: ${props.theme.colors.grey.v400}; stroke: ${props.theme.colors.grey.v400}; } &::after { background: transparent; } `} ${props => !props.active && !props.disabled && !props.link && ` @media (hover: hover){ &:hover { color: ${props.theme.colors.secondary}; .svg-icon { z-index: 200; } .text { transform: translateY(80%); } ${HoverText} { opacity: 1; transform: translateY(0); } &::after { transform: translateY(-10%); } } } `}; height: ${props => props.size === 'large' ? '70px' : props.size === 'small' ? '46px' : props.size === 'xsmall' ? '17px' : '58px'}; display: flex; flex-direction: row; align-items: center; padding: ${props => props.size === 'xsmall' ? xSmallPadding : props.size === 'small' ? smallPadding : props.size === 'medium' ? mediumPadding : props.size === 'large' ? largePadding : props.link ? largePadding : largePadding}; border-radius: ${props => props.theme.buttons.primary.borderRadius}; border: none; cursor: ${props => (props.disabled ? 'not-allowed' : 'pointer')}; ${props => props.active && !props.primary && ` box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.35); .svg-icon { fill: ${props.theme.colors.black}; } `}; ${props => props.active && props.primary && ` box-shadow: 0px 0px 0px 2px rgba(255, 206, 67, 0.35); background-color: ${props.theme.colors.secondary}; color: ${props.theme.colors.primary}; .svg-icon { fill: ${props.theme.colors.primary}; stroke: ${props.theme.colors.primary}; } `}; opacity: ${props => (props.disabled ? 0.5 : 1)}; &:active, :focus { ${props => props.primary && !props.disabled && ` box-shadow: 0px 0px 0px 2px rgba(255, 206, 67, 0.35); background-color: ${ props.customBackgroundColorOnHover ? props.customBackgroundColorOnHover : props.theme.colors.secondary }; color: ${props.theme.colors.primary}; .svg-icon { fill: ${props.theme.colors.primary}; stroke: ${props.theme.colors.primary}; } `}; ${props => !props.primary && !props.disabled && ` box-shadow: 0px 0px 0px 2px rgba(255, 255, 255, 0.35); .svg-icon { fill: ${props.theme.colors.black}; } `}; } &:hover { ${props => !props.disabled && !props.active && ` background-color: ${props.theme.colors.grey.v200}; color: ${props.theme.colors.secondary}; `} ${props => !props.disabled && props.primary && ` background-color: ${ props.customBackgroundColorOnHover ? props.customBackgroundColorOnHover : props.theme.colors.secondary }; ${HoverText} { color: ${props.theme.buttons.primary.colorHover}; } .svg-icon { fill: ${props.theme.colors.primary}; stroke: ${props.theme.colors.primary}; } `} ${props => !props.disabled && props.secondary && ` ${HoverText} { color: ${props.theme.colors.white}; } background-color: ${props.customBackgroundColorOnHover ? props.customBackgroundColorOnHover : props.theme.colors.black}; .svg-icon { fill: ${props.theme.colors.black}; } `} ${props => props.link && ` color: ${props => props.theme.secondary} text-decoration-color: ${props.theme.colors.secondary}; background-color: transparent; .text { color: ${props.theme.colors.secondary}; } .svg-icon { fill: ${props.theme.colors.secondary}; stroke: ${props.theme.colors.secondary}; } `} } `; const Link = styled.a` display: flex; align-items: center; color: ${props => props.theme.colors.grey.v400}; `; const Button = ({ primary, secondary, size, children, label, disabled, active, link, linkNoUnderline, iconRight, iconLeft, loading, fullWidth, ...props }) => { const theme = useTheme(); const Content = ({ first, disabled }) => { const iconSize = size === 'xsmall' ? 12 : 24; return ( <> {iconLeft ? <Icon left iconSize={iconSize} name={iconLeft} /> : null} <span className={first ? 'text' : ''} aria-label={label} style={{ cursor: disabled ? 'not-allowed' : 'pointer' }} > {children} </span> {iconRight ? <Icon right iconSize={iconSize} name={iconRight} /> : null} </> ); }; Content.propTypes = { first: PropTypes.bool, disabled: PropTypes.bool }; return ( <Root primary={primary} secondary={secondary} size={size} disabled={disabled || loading} active={active} link={link} linkNoUnderline={linkNoUnderline} fullWidth={fullWidth} onClick={e => (!disabled ? props.onClick(e) : () => null)} customBackgroundColorOnHover={props.customBackgroundColorOnHover} > {loading ? ( <Loader color={primary ? theme.colors.secondary : secondary} size={size === 'xsmall' ? 'xsmall' : 'small'} /> ) : link ? ( <Link> <Content first /> </Link> ) : ( <> <Content first disabled={disabled || loading} /> <HoverText size={size} customBackgroundColorOnHover={props.customBackgroundColorOnHover}> <Content first={false} style={{ pointerEvents: 'auto' }} /> </HoverText> </> )} </Root> ); }; Button.propTypes = { /** * Color */ primary: PropTypes.bool, /** * Color */ secondary: PropTypes.bool, /** * Active */ link: PropTypes.bool, /** * Add text underline */ linkNoUnderline: PropTypes.bool, /** * Active */ active: PropTypes.bool, /** * Active */ loading: PropTypes.bool, /** * disabled */ disabled: PropTypes.bool, /** * full Width */ fullWidth: PropTypes.bool, /** * icon on the left */ iconLeft: PropTypes.oneOf(['ArrowNext', 'Check', 'Download', 'Link']), /** * icon on the right */ iconRight: PropTypes.oneOf(['ArrowNext', 'Check', 'Download', 'Link']), /** * How large should the button be? */ size: PropTypes.oneOf(['xsmall', 'small', 'medium', 'large']), /** * Button contents */ children: PropTypes.any, /** * label for aria */ label: PropTypes.string, /** * Optional click handler */ onClick: PropTypes.func, /** * Optional custom background color (on hover) */ customBackgroundColorOnHover: PropTypes.string }; Button.defaultProps = { primary: false, disabled: false, size: 'medium', onClick: undefined }; export default Button;