Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 0 additions & 98 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
"prop-types": "^15.7.2",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
"sass-loader": "^9.0.2",
"style-loader": "^1.2.1",
"stylelint": "^13.6.1"
Expand Down
18 changes: 11 additions & 7 deletions src/components/Button/Button.docs.mdx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { Story, Preview, Props } from '@storybook/addon-docs/blocks';
import Button, { ButtonLink } from './Button';
import Button, { ButtonLabel } from './Button';

# Button

Presents the user with an action to take, such as a form submission or promotional call-to-action.

Use the `Button` component when presenting the user with an action that affects the current page, such as submitting a form or dismissing a modal. This component renders an HTML `<button>` tag.

Use the `ButtonLink` component when linking to another page. This component renders an HTML `<a>` tag.
Use the `ButtonLabel` component when you want a component that is styled like a button, without the `<button>` wrapper, e.g. for use in a link. This component renders a `<span>` tag only.

## Usage

Expand All @@ -16,21 +16,25 @@ import { Button } from '@quartz/interface/src/components';
```

```js
import { ButtonLink } from '@quartz/interface/src/components';
import { ButtonLabel } from '@quartz/interface/src/components';
```

## Props

<Props of={Button} />

### ButtonLabel

<Props of={ButtonLabel} />

## Usage guidelines

- **Do** use the `Button` component for actions that change something on the page, such as form submissions or toggling content visibility.
- **Do** use the `ButtonLink` component to link to another page or as an anchor link to a piece of content on the same page.
- **Do** use the `ButtonLabel` component to link to another page or as an anchor link to a piece of content on the same page.
- **Do** use icons when needed using `props.children`
- **Do** use the primary variant for affirmative calls to action, such as agreeing to a confirmation or submitting a form.
- **Do** use the secondary variant for negative calls to action, such as declining a confirmation or cancelling an action.
- **Do not** use the Button component to link to another page, use `ButtonLink` instead.
- **Do not** use the Button component to link to another page, use `ButtonLabel` and wrap it in an `<a>` tag instead.
- **Do not** pass content into `props.children` that modifies the color, spacing, font size, font family, font weight, or font style of the label.
- **Do not** intentionally misuse primary and secondary variants to create UX dark patterns.

Expand Down Expand Up @@ -64,9 +68,9 @@ import { ButtonLink } from '@quartz/interface/src/components';
<Story id="button--inline-warning" />
</Preview>

### ButtonLink
### ButtonLabel

<Preview>
<Story id="button--link" />
<Story id="button--label-only" />
</Preview>

88 changes: 50 additions & 38 deletions src/components/Button/Button.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,47 @@ import PropTypes from 'prop-types';
import classnames from 'classnames/bind';
import styles from './Button.scss';
import Spinner from '../Spinner/Spinner';
import Link from '../Link/Link';

const cx = classnames.bind( styles );

const ButtonLabel = ( {
children,
inline,
variant,
} ) => <span className={cx( 'label', `variant-${variant}`, { block: !inline } )}>{children}</span>;

ButtonLabel.propTypes = {
/**
* Child nodes to be rendered as the label for the button. Maps to
* the button element’s innerHTML.
*/
children: PropTypes.node.isRequired,
/**
* Whether the label should be purely textual, e.g. for use in a
* paragraph of text.
*/
inline: PropTypes.bool.isRequired,
/**
* Visual variations of the button.
*/
variant: PropTypes.oneOf( [
'primary',
'secondary',
'warning',
] ).isRequired,
};

ButtonLabel.defaultProps = {
inline: false,
variant: 'primary',
};

const Button = ( {
ariaChecked,
children,
ariaDescribedBy,
disabled,
inactive,
inline,
loading,
on,
onClick,
Expand All @@ -23,21 +54,23 @@ const Button = ( {
<button
aria-checked={ariaChecked}
aria-describedby={ariaDescribedBy}
className={cx(
`variant-${variant}`,
{
inactive: inactive || disabled,
loading,
}
)}
className={cx( 'button', { block: !inline } )}
disabled={disabled || loading}
on={on}
onClick={onClick}
role={role}
type={type}
>
{loading && <Spinner />}
<span className={cx( 'label', { loading } )}>{children}</span>
<ButtonLabel variant={variant} inline={inline}>
{
loading && (
<div className={styles.spinner}>
<Spinner />
</div>
)
}
<span className={cx( 'label-text', { loading } )}>{children}</span>
</ButtonLabel>
</button>
);

Expand All @@ -63,12 +96,10 @@ Button.propTypes = {
*/
disabled: PropTypes.bool.isRequired,
/**
* Toggles the same visual state as `props.disabled`, but without
* affecting the interactivity of the button. Use this when you want
* to indicate that a form's contents are invalid, but still
* submissible.
* Whether the button should be purely textual, e.g. for use in a
* paragraph of text.
*/
inactive: PropTypes.bool.isRequired,
inline: PropTypes.bool.isRequired,
/**
* Visually replaces `props.children` with the Spinner component. Use
* when waiting for an action to complete in response to a user
Expand Down Expand Up @@ -108,36 +139,17 @@ Button.propTypes = {
*/
type: PropTypes.oneOf( [ 'submit', 'button' ] ).isRequired,
/**
* Visual variations of the button.
* Visual variations of the button. See `ButtonLabel.propTypes.variant`
*/
variant: PropTypes.oneOf( [
'inline',
'primary',
'secondary',
'warning-inline',
'warning',
] ).isRequired,
variant: PropTypes.string,
};

Button.defaultProps = {
disabled: false,
inactive: false,
loading: false,
onClick: () => {},
type: 'button',
variant: 'primary',
};

const ButtonLink = ( { children, variant, ...props } ) => <Link className={cx( `variant-${variant}` )} {...props}>{children}</Link>;

ButtonLink.propTypes = {
children: PropTypes.node.isRequired,
variant: PropTypes.string.isRequired,
};

ButtonLink.defaultProps = {
variant: 'primary',
};

export { ButtonLink };
export { ButtonLabel };
export default Button;
Loading