Skip to content

Commit

Permalink
feat: implement button variants
Browse files Browse the repository at this point in the history
  • Loading branch information
vickonrails committed Apr 3, 2021
1 parent 00ce37c commit 10135a9
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 24 deletions.
11 changes: 7 additions & 4 deletions example/src/App.tsx
Expand Up @@ -23,13 +23,16 @@ const App = () => {
return (
<ThemeProvider theme={customTheme}>
<div className='container btn-group'>
<Button variant='primary' size='sm'>
Text
<Button buttonType='solid' variant='primary' shape='round'>
Button Text
</Button>
<Button variant='primary' size='md'>
<Button variant='error' buttonType='ghost' shape='round' size='lg'>
Something
</Button>
<Button variant='primary' size='lg'>
<Button variant='success' buttonType='outline' size='sm'>
Something
</Button>
<Button variant='warning' buttonType='link'>
Something
</Button>
</div>
Expand Down
8 changes: 8 additions & 0 deletions src/.eslintrc
@@ -1,5 +1,13 @@
{
"env": {
"jest": true
},
"rules": {
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
]
}
}
8 changes: 4 additions & 4 deletions src/components/button/Readme.md
Expand Up @@ -30,18 +30,18 @@ function App() {
## Todo

- [x] size
- [ ] shape
- [x] shape
- [ ] prefix & suffix
- [ ] trim
- [ ] variant
- [x] variant
- [ ] loading
- [ ] disabled
- [ ] write tests

## Tests suites

- [ ] should render correctly
- [ ] should render empty button without errors
- [x] should render correctly
- [x] should render empty button without errors
- [ ] should render a spinner when `loading` is set to `true`
- [ ] should not be clickable when button is loading
- [ ] should render a link when `type` is set to link
Expand Down
66 changes: 54 additions & 12 deletions src/components/button/button.tsx
Expand Up @@ -2,29 +2,31 @@ import React from 'react'
import styled from '@emotion/styled'
import { css } from '@emotion/react'
import { theme } from '../theme'
import { getButtonShape } from '../../utils/button'

const Button: React.FC<ButtonProps> = ({ loading, shape, type, ...props }) => {
const Button: React.FC<ButtonProps> = ({ loading, ...props }) => {
return <StyledButton {...props}>{props.children}</StyledButton>
}

type Type = 'submit' | 'button' | 'reset'
export type Size = 'sm' | 'md' | 'lg'
type Shape = 'round' | 'border' | 'square'
type Variant = 'primary' | 'secondary' | 'warning' | 'error' | 'link' | 'ghost'
export type ButtonShape = 'round' | 'curve' | 'square'
type ButtonType = 'solid' | 'outline' | 'link' | 'ghost'
type Variant = 'primary' | 'warning' | 'error' | 'success'

interface ButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
/**
* default type of button. Can be submit, button, reset
*/
type?: Type

buttonType?: ButtonType
/**
* size of button. Can be sm, lg, md
*/
size?: Size
/**
* shape of the button. can be round, border, square
*/
shape?: Shape
shape?: ButtonShape
/**
* trim text on button if more than specified length
*/
Expand Down Expand Up @@ -59,6 +61,8 @@ const BaseButton = css`
cursor: pointer;
border: none;
border-radius: ${theme.borders.sm};
color: inherit;
border: 1px solid ${theme.colors.gray[3]};
`

const ButtonSize = ({ size }: ButtonProps) =>
Expand All @@ -68,23 +72,61 @@ const ButtonSize = ({ size }: ButtonProps) =>
`

const ButtonVariant = ({ variant }: ButtonProps) =>
variant === 'primary' &&
variant &&
css`
color: ${theme.colors.white};
background: ${theme.components.buttonTheme.variants[variant]};
transition: background, transform, border, color;
transition-duration: 0.2s;
&:hover {
background: inherit;
border: 1px solid ${theme.components.buttonTheme.variants[variant]};
color: ${theme.components.buttonTheme.variants[variant]};
}
&:active {
background: ${theme.colors.gray[4]};
color: ${theme.components.buttonTheme.variants[variant]};
}
&:focus {
outline: none;
box-shadow: 0 0 0 3px ${theme.colors.blue[100]};
transform: translateY(-1px);
}
`

const ButtonType = ({ buttonType, variant }: ButtonProps) =>
buttonType &&
css`
background: ${buttonType === 'outline' && 'inherit'};
color: ${buttonType === 'outline' &&
`${
variant ? theme.components.buttonTheme.variants[variant] : `currentColor`
} `};
border: ${buttonType === 'outline' && `1px solid currentColor`};
`

const ButtonShape = ({ shape }: ButtonProps) =>
shape &&
css`
border-radius: ${getButtonShape(shape)};
`

const StyledButton = styled.button<ButtonProps>`
const StyledButton = styled('button')<ButtonProps>`
${BaseButton};
${ButtonSize};
${ButtonVariant};
${ButtonType};
${ButtonShape};
`

Button.defaultProps = {
type: 'submit',
size: 'md',
shape: 'border',
variant: 'secondary',
shape: 'curve',
buttonType: 'solid',
variant: 'primary',
loading: false
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/theme/borders.ts
@@ -1,6 +1,6 @@
const border = {
sm: '4px',
circle: '50%'
full: '10000px'
}

export type BorderProps = typeof border
Expand Down
9 changes: 6 additions & 3 deletions src/components/theme/components/button.theme.ts
Expand Up @@ -4,11 +4,14 @@ import { spacing } from '../spacing'

const buttonTheme = {
variants: {
primary: colors.primary
primary: colors.primary,
error: colors.red[400],
success: colors.green[500],
warning: colors.yellow[500]
},
borders: {
round: borders.sm,
circle: borders.circle
round: borders.full,
curve: borders.sm
},
size: {
sm: `${spacing['x-small']} ${spacing.small}`,
Expand Down
12 changes: 12 additions & 0 deletions src/utils/button.ts
@@ -0,0 +1,12 @@
import { ButtonShape, theme } from '../components'

export const getButtonShape = (shape: ButtonShape): string => {
switch (shape) {
case 'curve':
return theme.components.buttonTheme.borders.curve
case 'round':
return theme.components.buttonTheme.borders.round
case 'square':
return `0`
}
}

0 comments on commit 10135a9

Please sign in to comment.