@axeptio/design-system
Version:
Design System for Axeptio
469 lines (421 loc) • 11 kB
JSX
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;