Skip to content

Commit

Permalink
Add button component
Browse files Browse the repository at this point in the history
  • Loading branch information
Henrique Macedo committed Jan 20, 2021
1 parent 541b86b commit d703d52
Show file tree
Hide file tree
Showing 6 changed files with 315 additions and 1 deletion.
74 changes: 74 additions & 0 deletions src/atoms/button/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, { useEffect } from 'react';
import { Icon, Spinner } from '../..';
import * as Styles from './styles';
import { ButtonColor, ButtonVariant } from './types';

interface ButtonProps {
variant?: ButtonVariant;
circle?: boolean;
color?: ButtonColor;
value?: string;
className?: string;
querySelector?: string;
ariaLabel?: string;
action?:
| ((event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void)
| undefined;
disabled?: boolean;
loading?: boolean;
dataTestId?: string;
eventId?: string;
icon?: string;
}

const Button = (props: ButtonProps) => {
const {
variant = 'solid',
circle = false,
color = 'primary',
value = '',
className = 'button',
querySelector = '.button',
ariaLabel = '',
action = () => {},
disabled = false,
loading = false,
dataTestId = '',
eventId = '',
icon = '',
} = props;

useEffect(() => {
if (!document) return;

const element = document.querySelector(querySelector as any);
if (!element) return;

element.onmousemove = (e: any) => {
const x = e.pageX - e.target?.offsetLeft ?? -0;
const y = e.pageY - e.target?.offsetTop;
e.target?.style.setProperty('--x', `${x}px`);
e.target?.style.setProperty('--y', `${y}px`);
};
}, [querySelector]);

return (
<Styles.ButtonWrapper
variant={variant}
color={color}
circle={circle}
className={className}
value={value}
aria-label={ariaLabel}
onClick={action}
disabled={disabled || loading}
data-testid={dataTestId}
data-event={eventId}
>
{loading ? <Spinner /> : icon ? <Icon icon={icon} /> : null}
{value && <span>{value}</span>}
</Styles.ButtonWrapper>
);
};

export default Button;
176 changes: 176 additions & 0 deletions src/atoms/button/styles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import styled, { css, keyframes } from 'styled-components';
import { ButtonColor, ButtonVariant } from './types';

interface ButtonProps {
variant?: ButtonVariant;
circle?: boolean;
color?: ButtonColor;
value?: String;
}

const live = keyframes`
0% {
background-color: hsl(354, 83%, 54%);
box-shadow: 0 0 10px 0 rgba(40, 40, 40, 0.3);
}
50% {
background-color: var(--red, hsl(354, 83%, 64%));
box-shadow: 0 0 10px 0 rgba(40, 40, 40, 0);
}
100% {
background-color: hsl(354, 83%, 54%);
box-shadow: 0 0 10px 0 rgba(40, 40, 40, 0.3);
}
`;

export const ButtonWrapper = styled.button<ButtonProps>`
--button: var(--green, hsl(186, 62%, 59%));
--txt: var(--white, hsl(0, 0%, 100%));
--hover: hsl(186, 62%, 49%);
border-width: ${(props) => (props.variant === 'outline' ? '3px' : 0)};
border-style: solid;
border-color: var(--button);
border-radius: ${(props) => (props.variant === 'text' ? 0 : '999px')};
background-color: ${(props) =>
props.variant === 'solid' ? 'var(--button)' : 'transparent'};
width: ${(props) =>
props.value ? (props.circle ? '36px' : 'min-content') : '36px'};
height: 36px;
display: flex;
justify-content: center;
align-items: center;
padding: ${(props) => (props.value ? (props.circle ? 0 : '0 20px') : 0)};
text-transform: uppercase;
white-space: nowrap;
transition-duration: 0.3s;
cursor: pointer;
&:hover {
border-color: ${(props) =>
props.variant === 'solid' ? '' : 'var(--hover)'};
background-color: ${(props) =>
props.variant === 'solid' ? 'var(--hover)' : 'transparent'};
span {
color: ${(props) => (props.variant === 'solid' ? '' : 'var(--hover)')};
}
svg {
fill: ${(props) => (props.variant === 'solid' ? '' : 'var(--hover)')};
}
}
&:disabled {
cursor: inherit;
opacity: 0.5;
&:hover {
pointer-events: none;
}
}
> *:not(:last-child) {
margin-right: 5px;
}
.spinner {
border-top-color: ${(props) =>
props.variant === 'solid' ? '' : 'var(--button)'};
}
span {
position: relative;
font-size: 0.75rem;
font-weight: var(--bold, 700);
color: ${(props) =>
props.variant === 'solid' ? 'var(--txt)' : 'var(--button)'};
pointer-events: none;
transition-duration: 0.3s;
}
svg {
width: auto;
min-width: 20px;
height: 20px;
fill: ${(props) =>
props.variant === 'solid' ? 'var(--txt)' : 'var(--button)'};
transition: 0.3s;
}
${(props) =>
props.color === 'danger' &&
css`
--button: var(--red, hsl(354, 83%, 64%));
--hover: hsl(354, 83%, 54%);
`}
${(props) =>
props.color === 'info' &&
css`
--button: var(--grey, hsl(0, 0%, 85%));
--hover: hsl(0, 0%, 75%);
`}
${(props) =>
props.color === 'purple' &&
css`
--button: var(--purple, hsl(256, 55%, 43%));
--hover: hsl(256, 55%, 33%);
`}
${(props) =>
props.color === 'white' &&
css`
--button: var(--white);
--hover: var(--grey);
`}
${(props) =>
props.color === 'black' &&
css`
--button: var(--default, hsl(0, 0%, 16%));
--hover: hsl(0, 0%, 6%);
`}
${(props) =>
props.color === 'magic' &&
css`
position: relative;
background-image: linear-gradient(to bottom right, #ef5867, #5031a8);
height: 60px;
padding: 0 40px;
overflow: hidden;
span {
font-size: 1rem;
font-weight: var(--black, 700);
}
&:before {
--size: 0;
content: '';
position: absolute;
left: var(--x);
top: var(--y);
width: var(--size);
height: var(--size);
background: radial-gradient(circle closest-side, #5031a8, transparent);
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
-webkit-transition: width 0.2s ease, height 0.2s ease;
transition: width 0.2s ease, height 0.2s ease;
}
&:hover:before {
--size: 200px;
}
`}
${(props) =>
props.color === 'live' &&
css`
animation: ${live} 1s infinite;
`}
`;
11 changes: 11 additions & 0 deletions src/atoms/button/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export type ButtonVariant = 'solid' | 'outline' | 'text';

export type ButtonColor =
| 'primary'
| 'danger'
| 'info'
| 'purple'
| 'white'
| 'black'
| 'magic'
| 'live';
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export { default as Checkbox } from './atoms/checkbox';
export { default as Tag } from './atoms/tag';
export { default as Spinner } from './atoms/spinner';
export { default as Icon } from './atoms/icon';
export { default as Button } from './atoms/button';
52 changes: 52 additions & 0 deletions stories/atoms/button.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import { Button } from '../../src';
import icons from '../../src/ions/icons';

export default {
title: 'Atoms/Button',
component: Button,
argTypes: {
color: {
control: {
type: 'select',
options: [
'primary',
'danger',
'info',
'purple',
'white',
'black',
'magic',
'live',
],
},
},
variant: {
control: {
type: 'select',
options: ['solid', 'outline', 'text'],
},
},
icon: {
control: {
type: 'select',
options: Object.keys(icons),
},
},
},
};

export const ButtonComponent = (args) => <Button {...args} />;

ButtonComponent.args = {
value: 'Dummie',
variant: 'solid',
circle: false,
color: 'primary',
className: 'button',
querySelector: '.button',
ariaLabel: 'Dummie Button',
disabled: false,
loading: false,
icon: 'rocket',
};
2 changes: 1 addition & 1 deletion stories/atoms/icon.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ export const IconComponent = (args) => (

IconComponent.args = {
fill: '#000000',
icon: '20px',
icon: 'rocket',
};

0 comments on commit d703d52

Please sign in to comment.