blockstack-ui
Version:
Blockstack UI components built with css-in-js and styled-system.
179 lines (163 loc) • 3.86 kB
JavaScript
import React from 'react'
import { Flex, Type } from '../../'
import { Hover, Active } from 'react-powerplug'
import epitath from 'epitath'
import PropTypes from 'prop-types'
/**
* Handle our sizes
*/
const handleSize = ({ size, hovered, bg, ...rest }) => {
if (size === 'small') {
return {
...rest,
height: 'auto',
py: 1,
px: 3,
typeProps: {
...rest.typeProps,
fontSize: '12px',
fontWeight: 500
},
bg: hovered ? 'blue.light' : 'transparent',
color: 'blue.dark',
borderColor: hovered ? 'blue.dark' : 'blue.mid',
boxShadow: hovered ? 'general' : 'none',
border: '1px solid',
flexGrow: [1, 0, 0],
ml: [0, 2, 2],
mr: [2, 0, 0]
}
}
return { ...rest, size, bg, hovered }
}
/**
* Inverts the colors to white
*/
const handleInvert = ({ invert, hovered, active, disabled, ...rest }) =>
invert
? {
...rest,
bg: 'white',
color: rest.bg
}
: rest
/**
* Makes a button outlined
*/
const handleOutline = ({ outline, ...rest }) =>
outline
? {
...rest,
bg: 'transparent',
borderColor: rest.bg,
color: rest.bg
}
: rest
/**
* This removes any props we don't want passed along to the final component/dom element
*/
const cleanProps = ({ hovered, active, outline, invert, ...rest }) => rest
const propFn = (props) =>
cleanProps(handleSize(handleOutline(handleInvert(props))))
const Button = epitath(function*({
children,
disabled,
icon: Icon,
outline,
invert,
style,
bg,
...rest
}) {
const { active, bind: activeBind } = yield <Active />
const { hovered, bind: hoverBind } = yield <Hover />
const bind = { ...activeBind, ...hoverBind }
const defaultProps = {
is: 'button',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
px: 5,
height: '48px',
borderColor: 'transparent',
bg: bg ? bg : hovered ? 'blue' : 'blue.dark',
color: 'white',
border: 2,
borderRadius: 50,
boxShadow: hovered ? 'button.hover' : 'button',
fontWeight: 'semibold',
variant: 'default',
fontSize: 2,
typeProps: {
fontSize: 2
}
}
const {
typeProps: { typeStyle, ...typeProps },
...props
} = propFn({
...defaultProps,
hovered: hovered ? 'true' : undefined,
active: active ? 'true' : undefined,
outline,
invert,
...rest
})
const buttonProps = {
style: {
...style,
textDecoration: 'none',
cursor: !disabled && hovered ? 'pointer' : undefined,
transition: '.34s all cubic-bezier(.19,1,.22,1)',
transform: active ? 'translateY(2px)' : 'none',
outline: 'none'
},
...props,
...bind
}
const labelProps = {
...typeProps,
style: {
...typeStyle,
whiteSpace: 'nowrap',
pointerEvents: 'none',
userSelect: 'none',
transform: 'translateY(-1px)'
},
display: 'inline-block'
}
const IconComponent = ({ borderColor, color, ...p }) =>
Icon ? (
<Flex
alignItems="center"
justifyContent="center"
color={outline ? borderColor : invert ? color : 'blue.accent'}
pl={2}
style={{ pointerEvents: 'none' }}
>
<Icon
color="currentColor"
size="1.2rem"
style={{
display: 'block'
}}
/>
</Flex>
) : null
return (
<Flex flexShrink={0} {...buttonProps}>
<Type {...labelProps}>{children}</Type>
<IconComponent {...buttonProps} />
</Flex>
)
})
const Buttons = (props) => <Flex {...props} />
Buttons.defaultProps = {
justifyContent: 'space-evenly'
}
Button.propTypes = {
outline: PropTypes.bool,
invert: PropTypes.bool,
size: PropTypes.oneOf(['small'])
}
export { Button, Buttons }