Skip to content

Commit

Permalink
feat: add stateful button (#413)
Browse files Browse the repository at this point in the history
* feat: add async action button component

* docs: add documentation for async button

* fix: rename to StatefulButton and add component export
  • Loading branch information
abutterworth committed Apr 5, 2019
1 parent 2ac0705 commit d1ed714
Show file tree
Hide file tree
Showing 10 changed files with 653 additions and 0 deletions.
198 changes: 198 additions & 0 deletions .storybook/__snapshots__/Storyshots.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,204 @@ exports[`Storyshots Basics|MailtoLink with subject and body 1`] = `
</a>
`;

exports[`Storyshots Basics|StatefulButton basic usage 1`] = `
<div>
<button
aria-live="assertive"
className="btn pgn__stateful-btn pgn__stateful-btn-state-default btn-primary mr-2"
disabled={false}
onBlur={[Function]}
onClick={[Function]}
onKeyDown={[Function]}
type="button"
>
<span
className="d-flex align-items-center justify-content-center"
>
Saved
</span>
</button>
<button
aria-live="assertive"
className="btn pgn__stateful-btn pgn__stateful-btn-state-pending btn-primary mr-2 disabled"
disabled={true}
onBlur={[Function]}
onClick={[Function]}
onKeyDown={[Function]}
type="button"
>
<span
className="d-flex align-items-center justify-content-center"
>
<span
className="pgn__stateful-btn-icon"
>
<span
aria-hidden={true}
className="icon fa fa-spinner fa-spin"
id="Icon1"
/>
</span>
Saving
</span>
</button>
<button
aria-live="assertive"
className="btn pgn__stateful-btn pgn__stateful-btn-state-complete btn-primary mr-2 disabled"
disabled={true}
onBlur={[Function]}
onClick={[Function]}
onKeyDown={[Function]}
type="button"
>
<span
className="d-flex align-items-center justify-content-center"
>
<span
className="pgn__stateful-btn-icon"
>
<span
aria-hidden={true}
className="icon fa fa-check-circle"
id="Icon1"
/>
</span>
Saved
</span>
</button>
</div>
`;

exports[`Storyshots Basics|StatefulButton custom icons and disable during state 1`] = `
Array [
<button
aria-live="assertive"
className="btn pgn__stateful-btn pgn__stateful-btn-state-default btn-primary mr-2"
disabled={false}
onBlur={[Function]}
onClick={[Function]}
onKeyDown={[Function]}
type="button"
>
<span
className="d-flex align-items-center justify-content-center"
>
<span
className="pgn__stateful-btn-icon"
>
<span
aria-hidden={true}
className="fa fa-download"
id="Icon1"
/>
</span>
Download
</span>
</button>,
<button
aria-live="assertive"
className="btn pgn__stateful-btn pgn__stateful-btn-state-pending btn-primary mr-2 disabled"
disabled={true}
onBlur={[Function]}
onClick={[Function]}
onKeyDown={[Function]}
type="button"
>
<span
className="d-flex align-items-center justify-content-center"
>
<span
className="pgn__stateful-btn-icon"
>
<span
aria-hidden={true}
className="fa fa-spinner fa-spin"
id="Icon1"
/>
</span>
Downloading
</span>
</button>,
<button
aria-live="assertive"
className="btn pgn__stateful-btn pgn__stateful-btn-state-complete btn-primary mr-2"
disabled={false}
onBlur={[Function]}
onClick={[Function]}
onKeyDown={[Function]}
type="button"
>
<span
className="d-flex align-items-center justify-content-center"
>
<span
className="pgn__stateful-btn-icon"
>
<span
aria-hidden={true}
className="fa fa-check"
id="Icon1"
/>
</span>
Downloaded
</span>
</button>,
]
`;

exports[`Storyshots Basics|StatefulButton custom states 1`] = `
Array [
<button
aria-live="assertive"
className="btn pgn__stateful-btn pgn__stateful-btn-state-unedited btn-primary mr-2 disabled"
disabled={true}
onBlur={[Function]}
onClick={[Function]}
onKeyDown={[Function]}
type="button"
>
<span
className="d-flex align-items-center justify-content-center"
>
<span
className="pgn__stateful-btn-icon"
>
<span
aria-hidden={true}
className="fa fa-save"
id="Icon1"
/>
</span>
Save (no changes)
</span>
</button>,
<button
aria-live="assertive"
className="btn pgn__stateful-btn pgn__stateful-btn-state-edited btn-primary mr-2"
disabled={false}
onBlur={[Function]}
onClick={[Function]}
onKeyDown={[Function]}
type="button"
>
<span
className="d-flex align-items-center justify-content-center"
>
<span
className="pgn__stateful-btn-icon"
>
<span
aria-hidden={true}
className="fa fa-save"
id="Icon1"
/>
</span>
Save Changes
</span>
</button>,
]
`;

exports[`Storyshots Collapsible basic usage with resizing 1`] = `
<div>
<div
Expand Down
8 changes: 8 additions & 0 deletions .storybook/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import { addParameters, addDecorator, configure } from '@storybook/react';
import { setConsoleOptions } from '@storybook/addon-console';
import { withInfo } from '@storybook/addon-info';
import { SyntaxHighlighter } from '@storybook/components';

// Style applied to all stories
import "./style.scss";
Expand All @@ -21,6 +22,13 @@ addParameters({
inline: true,
header: false,
source: true,
components: {
code: function({language, code}) {
return (
<SyntaxHighlighter language="jsx" format={false} copyable={false}>{code}</SyntaxHighlighter>
);
},
}
},
});

Expand Down
35 changes: 35 additions & 0 deletions src/StatefulButton/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Stateful Button

A button that can display different states. Each state has:

- A label (required)
- An icon
- an option to be disabled

These are controlled by the props `labels`, `icons`, and `disabledStates`.

Button states can be whatever you want them to be, but default icons exist for:

- `pending`, `complete`, and `error`.

Control the state with the `state` prop. Example usage:

```jsx
<StatefulButton
state="pending"
labels={{
default: 'Download',
pending: 'Downloading',
complete: 'Downloaded',
}}
icons={{
default: <Icon className="fa fa-download" />,
pending: <Icon className="fa fa-spinner fa-spin" />,
complete: <Icon className="fa fa-check" />,
}}
disabledStates=['pending']
className='btn-primary mr-2'
/>
```

All other props sent to this component will be passed through to the underlying Button component.
3 changes: 3 additions & 0 deletions src/StatefulButton/StatefulButton.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.pgn__stateful-btn-icon {
margin-right: .5em;
}
69 changes: 69 additions & 0 deletions src/StatefulButton/StatefulButton.stories.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from 'react';
import { storiesOf } from '@storybook/react';

import StatefulButton from './index';
import Icon from '../Icon';
import README from './README.md';

storiesOf('Basics|StatefulButton', module)
.addParameters({ info: { text: README } })
.add('basic usage', () => {
const props = {
labels: {
default: 'Saved',
pending: 'Saving',
complete: 'Saved',
},
className: 'btn-primary mr-2',
};
return (
<div>
<StatefulButton {...props} />
<StatefulButton state="pending" {...props} />
<StatefulButton state="complete" {...props} />
</div>
);
})
.add('custom icons and disable during state', () => {
const downloadButtonProps = {
labels: {
default: 'Download',
pending: 'Downloading',
complete: 'Downloaded',
},
icons: {
default: <Icon className="fa fa-download" />,
pending: <Icon className="fa fa-spinner fa-spin" />,
complete: <Icon className="fa fa-check" />,
},
disabledStates: ['pending'],
className: 'btn-primary mr-2',
};
return (
<React.Fragment>
<StatefulButton state="default" {...downloadButtonProps} />
<StatefulButton state="pending" {...downloadButtonProps} />
<StatefulButton state="complete" {...downloadButtonProps} />
</React.Fragment>
);
})
.add('custom states', () => {
const buttonProps = {
labels: {
unedited: 'Save (no changes)',
edited: 'Save Changes',
},
icons: {
unedited: <Icon className="fa fa-save" />,
edited: <Icon className="fa fa-save" />,
},
disabledStates: ['unedited'],
className: 'btn-primary mr-2',
};
return (
<React.Fragment>
<StatefulButton state="unedited" {...buttonProps} />
<StatefulButton state="edited" {...buttonProps} />
</React.Fragment>
);
});
Loading

0 comments on commit d1ed714

Please sign in to comment.