Skip to content

Commit

Permalink
Feature/add button full width prop (#129)
Browse files Browse the repository at this point in the history
* Add fullWidth prop (WIP)

* Add Full Button Width story buttons

* Update button width styling when fullWidth prop is added

* Update snapshots

* Add fullWidth button to readme

* Add fullWidth to prop table

* Rename fullWidth to isFullWidth

* Add ESLint fix for stories error, resolve markdown file extension

* Add small fix for loading fullWidth icon button height issue

* Add Loader styling for button when full width

* Add TODO re: Loader component

* Expand on isFullWidth prop table note to mention mobile style preference
  • Loading branch information
michaeljaltamirano authored Jul 8, 2019
1 parent 9cff986 commit f6bb1e2
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 38 deletions.
8 changes: 6 additions & 2 deletions .storybook/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,16 @@ function removeDefaultStorybookSvgRule(config) {
);
}

module.exports = ({ config }) => {
module.exports = webpackSettings => {
// ESLint fix for `Resolve error: Cannot destructure property" `config` of 'undefined' or 'null'` in /stories/**/index.js files.
if (!webpackSettings) return {};
const { config } = webpackSettings;

removeDefaultStorybookSvgRule(config);

config.resolve = {
modules: [path.resolve(__dirname, '..'), 'node_modules'],
extensions: ['.js', '.jsx'],
extensions: ['.js', '.jsx', '.md'],
};

const customRules = [
Expand Down
31 changes: 21 additions & 10 deletions docs/button/button.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { CheckmarkIcon } from 'radiance-ui/lib/icons';
<Button buttonType="tertiary">Tertiary Button</Button>
<Button buttonType="quaternary">Quaternary Button</Button>
<Button disabled>Disabled Button</Button>
<Button isFullWidth>Full Width Button</Button>

<Button isLoading>Primary Loading</Button>
<Button isLoading buttonType="secondary">
Expand All @@ -24,6 +25,9 @@ import { CheckmarkIcon } from 'radiance-ui/lib/icons';
<Button buttonType="quaternary" isLoading>
Quaternary Loading
</Button>
<Button isFullWidth isLoading>
Full Width Loading
</Button>
</Button.Container>

<Button.Container>
Expand All @@ -37,10 +41,13 @@ import { CheckmarkIcon } from 'radiance-ui/lib/icons';
<Button buttonType="quaternary" icon={<CheckmarkIcon />}>
Quaternary Button
</Button>

<Button disabled icon={<CheckmarkIcon />}>
Disabled Button
</Button>
<Button isFullWidth icon={<CheckmarkIcon />}>
Full Width Button
</Button>

<Button isLoading icon={<CheckmarkIcon />}>
Primary Loading
</Button>
Expand All @@ -53,6 +60,9 @@ import { CheckmarkIcon } from 'radiance-ui/lib/icons';
<Button isLoading buttonType="quaternary" icon={<CheckmarkIcon />}>
Quaternary Loading
</Button>
<Button isLoading isFullWidth icon={<CheckmarkIcon />}>
Full Width Loading
</Button>
</Button.Container>
</React.Fragment>;
```
Expand All @@ -61,15 +71,16 @@ import { CheckmarkIcon } from 'radiance-ui/lib/icons';

### Proptypes

| prop | propType | required | default | description |
| ---------- | -------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- |
| buttonType | string | no | primary | Determines the button's main style theme. Must be one of `primary`, `secondary`, `tertiary`, `quaternary`. |
| children | node | yes | - | node to be rendered inside the button. Recommended to be the button text |
| disabled | bool | no | false | when disabled, click listener will not be called and the UI will look disabled |
| icon | node | no | null | icon to render in the button. Recommended to use one of Radiance's icons |
| isLoading | bool | no | false | renders loading state and prevents click listener from being called |
| onClick | func | no | () => {} | callback function called on click of the button |
| textColor | string | no | '' | color (as a string) that will override existing text, icon, and loading colors for the button (except when disabled is true) |
| prop | propType | required | default | description |
| ----------- | -------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- |
| buttonType | string | no | primary | Determines the button's main style theme. Must be one of `primary`, `secondary`, `tertiary`, `quaternary`. |
| children | node | yes | - | node to be rendered inside the button. Recommended to be the button text |
| disabled | bool | no | false | when disabled, click listener will not be called and the UI will look disabled |
| icon | node | no | null | icon to render in the button. Recommended to use one of Radiance's icons |
| isLoading | bool | no | false | renders loading state and prevents click listener from being called |
| onClick | func | no | () => {} | callback function called on click of the button |
| textColor | string | no | '' | color (as a string) that will override existing text, icon, and loading colors for the button (except when disabled is true) |
| isFullWidth | bool | no | false | adjusts the default button styles so that the button takes the full width of the container. Intended for mobile-use only. |

### Notes

Expand Down
10 changes: 5 additions & 5 deletions src/shared-components/button/__snapshots__/test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -110,24 +110,24 @@ exports[`<Button /> UI snapshots renders with props 1`] = `
cursor: pointer;
display: block;
margin: 0;
max-width: 325px;
min-height: 52px;
min-width: 208px;
opacity: 1;
padding: 0 1.5rem;
position: relative;
-webkit-transition: all 350ms ease-in-out;
transition: all 350ms ease-in-out;
-webkit-text-decoration: none;
text-decoration: none;
width: -webkit-max-content;
width: -moz-max-content;
width: max-content;
background-color: #ededf0;
border-color: #ededf0;
color: #c3c0cd;
cursor: not-allowed;
fill: #c3c0cd;
min-width: 208px;
max-width: 325px;
width: -webkit-max-content;
width: -moz-max-content;
width: max-content;
}
.emotion-6:hover {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,23 @@ exports[`<LinkButton/> UI snapshots renders with props 1`] = `
cursor: pointer;
display: block;
margin: 0;
max-width: 325px;
min-height: 52px;
min-width: 208px;
opacity: 1;
padding: 0 1.5rem;
position: relative;
-webkit-transition: all 350ms ease-in-out;
transition: all 350ms ease-in-out;
-webkit-text-decoration: none;
text-decoration: none;
width: -webkit-max-content;
width: -moz-max-content;
width: max-content;
background-color: #332e54;
border-color: #332e54;
color: #ffffff;
fill: #ffffff;
min-width: 208px;
max-width: 325px;
width: -webkit-max-content;
width: -moz-max-content;
width: max-content;
}
.emotion-4:hover {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,24 +128,24 @@ exports[`<RoundButton /> UI snapshots renders with props 1`] = `
cursor: pointer;
display: block;
margin: 0;
max-width: 325px;
min-height: 52px;
min-width: 208px;
opacity: 1;
padding: 0 1.5rem;
position: relative;
-webkit-transition: all 350ms ease-in-out;
transition: all 350ms ease-in-out;
-webkit-text-decoration: none;
text-decoration: none;
width: -webkit-max-content;
width: -moz-max-content;
width: max-content;
background-color: #ededf0;
border-color: #ededf0;
color: #c3c0cd;
cursor: not-allowed;
fill: #c3c0cd;
min-width: 208px;
max-width: 325px;
width: -webkit-max-content;
width: -moz-max-content;
width: max-content;
border-radius: 50%;
max-width: unset;
min-height: unset;
Expand Down
13 changes: 12 additions & 1 deletion src/shared-components/button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const isLoadingPropFunction = (props, propName, componentName) => {
}
};

// TODO: Move <Loader /> to be sibling of <ButtonContents /> for more consistent
// loading animation spacing
class Button extends React.Component {
static Container = Container;

Expand All @@ -36,6 +38,7 @@ class Button extends React.Component {
isLoading: PropTypes.bool,
icon: PropTypes.node,
textColor: PropTypes.string,
isFullWidth: PropTypes.bool,
};

static defaultProps = {
Expand All @@ -44,6 +47,7 @@ class Button extends React.Component {
isLoading: false,
onClick() {},
textColor: '',
isFullWidth: false,
};

render() {
Expand All @@ -56,6 +60,7 @@ class Button extends React.Component {
isLoading,
icon,
textColor,
isFullWidth,
...rest
} = this.props;

Expand All @@ -71,9 +76,14 @@ class Button extends React.Component {
isLoading={loadingVal}
type="button"
textColor={textColor}
isFullWidth={isFullWidth}
{...rest}
>
<ButtonContents isLoading={loadingVal} hasIcon={!!icon}>
<ButtonContents
isLoading={loadingVal}
hasIcon={!!icon}
isFullWidth={isFullWidth}
>
{icon}
<ButtonText
isLoading={loadingVal}
Expand All @@ -90,6 +100,7 @@ class Button extends React.Component {
disabled={disabled}
buttonType={buttonType}
textColor={textColor}
isFullWidth={isFullWidth}
/>
</ButtonBase>
);
Expand Down
15 changes: 12 additions & 3 deletions src/shared-components/button/shared-components/loader/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@ import PropTypes from 'prop-types';

import ButtonLoader from './style';

const Loader = ({ isLoading, disabled, buttonType, className, textColor }) => (
const Loader = ({
buttonType,
className,
disabled,
isFullWidth,
isLoading,
textColor,
}) => (
<ButtonLoader
isLoading={isLoading}
disabled={disabled}
buttonType={buttonType}
className={className}
textColor={textColor}
isFullWidth={isFullWidth}
>
<div>
<span />
Expand All @@ -20,8 +28,6 @@ const Loader = ({ isLoading, disabled, buttonType, className, textColor }) => (
);

Loader.propTypes = {
isLoading: PropTypes.bool,
disabled: PropTypes.bool,
buttonType: PropTypes.oneOf([
'primary',
'secondary',
Expand All @@ -30,6 +36,9 @@ Loader.propTypes = {
'action',
]),
className: PropTypes.string,
disabled: PropTypes.bool,
isFullWidth: PropTypes.bool,
isLoading: PropTypes.bool,
textColor: PropTypes.string,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const ButtonLoader = styled.div`
right: 0;
top: 0;
margin-top: -6px;
width: 38px;
width: ${({ isFullWidth }) => (isFullWidth ? `25%` : `38px`)};
opacity: ${({ isLoading }) => (isLoading ? 1 : 0)};
& span {
Expand Down
26 changes: 22 additions & 4 deletions src/shared-components/button/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export const baseButtonStyles = ({
buttonType,
isLoading,
textColor,
isFullWidth,
}) => css`
${TYPOGRAPHY_STYLE.button};
appearance: none;
Expand All @@ -127,15 +128,12 @@ export const baseButtonStyles = ({
cursor: pointer;
display: block;
margin: 0;
max-width: 325px;
min-height: 52px;
min-width: 208px;
opacity: 1;
padding: 0 ${SPACER.large};
position: relative;
transition: all ${ANIMATION.defaultTiming} ease-in-out;
text-decoration: none;
width: max-content;
&:hover {
transition: all ${ANIMATION.defaultTiming} ease-in-out;
Expand All @@ -155,12 +153,32 @@ export const baseButtonStyles = ({
color: ${textColor};
fill: ${textColor};
`};
${isFullWidth
? `
width: 100%;
`
: `
min-width: 208px;
max-width: 325px;
width: max-content;
`};
`;

export const ButtonBase = styled.button(baseButtonStyles);

// align-items conditional fixes slight button height misalignment for truthy scenario
// See screenshot in: https://github.com/PocketDerm/radiance-ui/pull/129#issue-292994081
export const ButtonContents = styled.div`
align-items: center;
align-items: ${({ hasIcon, isFullWidth, isLoading }) => {
if (isFullWidth && isLoading && hasIcon) {
return 'baseline';
}
return 'center';
}};
display: flex;
height: 100%;
justify-content: center;
Expand Down
13 changes: 11 additions & 2 deletions stories/button/button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import { text, select, boolean } from '@storybook/addon-knobs';
import { withDocs } from 'storybook-readme';
import { action } from '@storybook/addon-actions';
import { css } from '@emotion/core';

import ButtonReadme from 'docs/button/button.md';
import ButtonReadme from 'docs/button/button';
import { CheckmarkIcon } from 'src/svgs/icons';
import { Button, Typography } from 'src/shared-components';
import { SPACER } from 'src/constants';
Expand All @@ -30,6 +29,7 @@ const ButtonStory = withDocs(ButtonReadme, () => (
<Button buttonType="tertiary">Tertiary Button</Button>
<Button buttonType="quaternary">Quaternary Button</Button>
<Button disabled>Disabled Button</Button>
<Button isFullWidth>Full Width Button</Button>

<Button isLoading>Primary Loading</Button>
<Button isLoading buttonType="secondary">
Expand All @@ -41,6 +41,9 @@ const ButtonStory = withDocs(ButtonReadme, () => (
<Button buttonType="quaternary" isLoading>
Quaternary Loading
</Button>
<Button isFullWidth isLoading>
Full Width Loading
</Button>
</Button.Container>

<Button.Container
Expand Down Expand Up @@ -70,6 +73,9 @@ const ButtonStory = withDocs(ButtonReadme, () => (
<Button disabled icon={<CheckmarkIcon />}>
Disabled Button
</Button>
<Button isFullWidth icon={<CheckmarkIcon />}>
Full Width Button
</Button>

<Button isLoading icon={<CheckmarkIcon />}>
Primary Loading
Expand All @@ -83,6 +89,9 @@ const ButtonStory = withDocs(ButtonReadme, () => (
<Button isLoading buttonType="quaternary" icon={<CheckmarkIcon />}>
Quaternary Loading
</Button>
<Button isLoading isFullWidth icon={<CheckmarkIcon />}>
Full Width Loading
</Button>
</Button.Container>
<Typography.Heading
css={css`
Expand Down

0 comments on commit f6bb1e2

Please sign in to comment.