Created
December 9, 2019 15:57
-
-
Save jhefreyzz/617f4d3dcebd130f85184370442fa3ee to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import { Link } from 'react-router-dom' | |
import styled, { | |
css, | |
ThemedCssFunction, | |
DefaultTheme, | |
FlattenInterpolation, | |
ThemeProps, | |
ThemedStyledProps | |
} from 'styled-components' | |
import {ifNotProp} from "styled-tools" | |
import getPaletteColor from '../../utils/getPaletteColor' | |
import Icon from './Icon' | |
interface StyleProperty { | |
name?: string | |
style?: | |
| FlattenInterpolation<ThemeProps<DefaultTheme>> | |
| FlattenInterpolation<ThemedCssFunction<DefaultTheme>> | |
} | |
const sizes: StyleProperty[] = [ | |
{ | |
name: 'XSmall', | |
style: css` | |
height: 32px; | |
font-size: 14px; | |
padding: 0 16px; | |
` | |
}, | |
{ | |
name: 'Small', | |
style: css` | |
height: 40px; | |
font-size: 16px; | |
padding: 0 16px; | |
` | |
}, | |
{ | |
name: 'Medium', | |
style: css` | |
height: 48px; | |
font-size: 16px; | |
padding: 0 16px; | |
` | |
}, | |
{ | |
name: 'Large', | |
style: css` | |
height: 56px; | |
font-size: 20px; | |
padding: 0 24px; | |
` | |
} | |
] | |
const variants: StyleProperty[] = [ | |
{ | |
name: 'LightGrey', | |
style: css` | |
color: ${getPaletteColor('shades', 600)}; | |
background: ${getPaletteColor('shades', 200)}; | |
box-shadow: 0 1px 0 0 ${getPaletteColor('shades', 300)}; | |
&:hover, | |
&:focus { | |
background: ${getPaletteColor('shades', 300)}; | |
box-shadow: 0 1px 0 0 ${getPaletteColor('shades', 400)}; | |
} | |
&:active { | |
background: ${getPaletteColor('shades', 400)}; | |
color: ${getPaletteColor('shades', 0)}; | |
transition: background 0s ease; | |
} | |
` | |
}, | |
{ | |
name: 'DarkGrey', | |
style: css` | |
color: ${getPaletteColor('shades', 0)}; | |
background: ${getPaletteColor('shades', 600)}; | |
box-shadow: 0 1px 0 0 ${getPaletteColor('shades', 700)}; | |
&:hover, | |
&:focus { | |
background: ${getPaletteColor('shades', 700)}; | |
box-shadow: 0 1px 0 0 ${getPaletteColor('shades', 900)}; | |
} | |
&:active { | |
background: ${getPaletteColor('shades', 900)}; | |
transition: background 0s ease; | |
} | |
` | |
}, | |
{ | |
name: 'Green', | |
style: css` | |
color: ${getPaletteColor('shades', 0)}; | |
background: ${getPaletteColor('green', 600)}; | |
box-shadow: 0 1px 0 0 ${getPaletteColor('green', 700)}; | |
&:hover, | |
&:focus { | |
background: ${getPaletteColor('green', 700)}; | |
box-shadow: 0 1px 0 0 ${getPaletteColor('green', 800)}; | |
} | |
&:active { | |
background: ${getPaletteColor('green', 800)}; | |
transition: background 0s ease; | |
} | |
` | |
}, | |
{ | |
name: 'Blue', | |
style: css` | |
color: ${getPaletteColor('shades', 0)}; | |
background: ${getPaletteColor('blue', 500)}; | |
box-shadow: 0 1px 0 0 ${getPaletteColor('blue', 600)}; | |
&:hover, | |
&:focus { | |
background: ${getPaletteColor('blue', 600)}; | |
box-shadow: 0 1px 0 0 ${getPaletteColor('blue', 700)}; | |
} | |
&:active { | |
background: ${getPaletteColor('blue', 700)}; | |
transition: background 0s ease; | |
} | |
` | |
}, | |
{ | |
name: 'Red', | |
style: css` | |
color: ${getPaletteColor('shades', 0)}; | |
background: ${getPaletteColor('red', 500)}; | |
box-shadow: 0 1px 0 0 ${getPaletteColor('red', 700)}; | |
&:hover, | |
&:focus { | |
background: ${getPaletteColor('red', 600)}; | |
box-shadow: 0 1px 0 0 ${getPaletteColor('red', 800)}; | |
} | |
&:active { | |
background: ${getPaletteColor('red', 800)}; | |
transition: background 0s ease; | |
} | |
` | |
} | |
] | |
const getVariantStyle = ({ | |
variant, | |
iconButton | |
}: { | |
variant: StyleProperty | |
iconButton: string | |
}) => { | |
if (iconButton) { | |
return null | |
} | |
const existVariant = variants.find(({ name }) => name === variant) | |
return existVariant ? existVariant.style : null | |
} | |
const getSizeStyle = ({ size }: { size: StyleProperty }) => { | |
const existSize = sizes.find(sizeInner => sizeInner.name === size.name) | |
return existSize ? existSize.style : null | |
} | |
const getIconButtonStyles = () => { | |
return css` | |
min-width: 32px; | |
height: 32px; | |
padding: ${ifNotProp('hasIconText', 0)}; | |
justify-content: center; | |
color: #fff; | |
background: rgba(255, 255, 255, 0.2); | |
&:hover, | |
&:focus { | |
background: rgba(255, 255, 255, 0.4); | |
} | |
&:active { | |
background: rgba(255, 255, 255, 0.6); | |
transition: background 0s ease; | |
} | |
` | |
} | |
const StyledButton = styled.button<ThemedStyledProps<any, any>>` | |
border-radius: 3px; | |
border: none; | |
outline: none; | |
cursor: pointer; | |
user-select: none; | |
display: inline-flex; | |
align-items: center; | |
justify-content: center; | |
font-weight: 700; | |
white-space: nowrap; | |
transition: background 0.3s ease, box-shadow 0.3s ease, opacity 0.3s ease, | |
color 0.3s ease; | |
&[disabled] { | |
pointer-events: none; | |
color: #a5acb0; | |
background: #f9f9f9; | |
box-shadow: none; | |
transition: all 50ms ease; | |
} | |
${getVariantStyle}; | |
${getSizeStyle}; | |
${getIconButtonStyles}; | |
` | |
const StyledLink = StyledButton.withComponent(Link) | |
const Button = ({ children, icon, iconText, to, ...props }: ButtonProps) => { | |
const isIconButton = !children | |
const buttonIcon = icon && ( | |
<Icon hasText={Boolean(children) || Boolean(iconText)} name={icon} /> | |
) | |
if (isIconButton) { | |
delete props.variant | |
} | |
return to ? ( | |
<StyledLink hasIconText={Boolean(iconText)} {...props}> | |
{buttonIcon} | |
{iconText} | |
{children} | |
</StyledLink> | |
) : ( | |
<StyledButton | |
iconButton={isIconButton} | |
hasIconText={Boolean(iconText)} | |
{...props} | |
> | |
{buttonIcon} | |
{iconText} | |
{children} | |
</StyledButton> | |
) | |
} | |
type ButtonProps = { | |
children?: string | |
icon?: string | |
iconText?: string | |
to?: string | object | |
variant?: 'Blue' | 'DarkGrey' | 'Green' | 'LightGrey' | 'Red' | |
size?: 'Large' | 'Medium' | 'Small' | 'XSmall' | |
[key: string]: any | |
} | |
Button.defaultProps = { | |
variant: 'LightGrey', | |
size: 'XSmall' | |
} | |
export default Button |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment