Skip to content

Instantly share code, notes, and snippets.

@jhefreyzz
Created December 9, 2019 15:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jhefreyzz/617f4d3dcebd130f85184370442fa3ee to your computer and use it in GitHub Desktop.
Save jhefreyzz/617f4d3dcebd130f85184370442fa3ee to your computer and use it in GitHub Desktop.
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