Skip to content

Commit

Permalink
15087: Add Button Base
Browse files Browse the repository at this point in the history
add button constants

button base updates

base button docs update

add iconprops base button

update block doc on button
  • Loading branch information
garrettbear committed Sep 29, 2022
1 parent f3465c9 commit ada30f7
Show file tree
Hide file tree
Showing 11 changed files with 579 additions and 1 deletion.
126 changes: 126 additions & 0 deletions ui/components/component-library/button-base/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs';
import { ButtonBase } from './button-base';

### This is a base component. It should not be used in your feature code directly but as a "base" for other UI components

# ButtonBase

The `ButtonBase` is the base component for buttons.

<Canvas>
<Story id="ui-components-component-library-button-base-button-base-stories-js--default-story" />
</Canvas>

## Props

The `ButtonBase` accepts all props below as well as all [Box](/docs/ui-components-ui-box-box-stories-js--default-story#props) component props

<ArgsTable of={ButtonBase} />

### Size

Use the `size` prop and the `SIZES` object from `./ui/helpers/constants/design-system.js` to change the size of `ButtonBase`. Defaults to `SIZES.MD`

Possible sizes include:

- `SIZES.AUTO` 22px
- `SIZES.SM` 32px
- `SIZES.MD` 40px
- `SIZES.LG` 48px

<Canvas>
<Story id="ui-components-component-library-button-base-button-base-stories-js--size" />
</Canvas>

```jsx
import { SIZES } from '../../../helpers/constants/design-system';
import { ButtonBase } from '../ui/component-library';

<ButtonBase size={SIZES.AUTO} />
<ButtonBase size={SIZES.SM} />
<ButtonBase size={SIZES.MD} />
<ButtonBase size={SIZES.LG} />
```

### Block

Use boolean `block` prop to quickly enable a full width block button

<Canvas>
<Story id="ui-components-component-library-button-base-button-base-stories-js--block" />
</Canvas>

```jsx
import { DISPLAY } from '../../../helpers/constants/design-system';
import { ButtonBase } from '../ui/component-library';

<ButtonBase>Default Button</ButtonBase>
<ButtonBase block>Block Button</ButtonBase>
<ButtonBase display={DISPLAY.BLOCK}>Block Button</ButtonBase>
```

### As

Use the `as` box prop to change the element of `ButtonBase`. Defaults to `button`.

Button `as` options:

- `button`
- `a`

<Canvas>
<Story id="ui-components-component-library-button-base-button-base-stories-js--as" />
</Canvas>

```jsx
import { ButtonBase } from '../ui/component-library';


<ButtonBase as="button">Button Element</ButtonBase>
<ButtonBase as="a" href="#">
Anchor Element
</ButtonBase>
```

### Disabled

Use the boolean `disabled` prop to disable button

<Canvas>
<Story id="ui-components-component-library-button-base-button-base-stories-js--disabled" />
</Canvas>

```jsx
import { ButtonBase } from '../ui/component-library';

<ButtonBase disabled>Disabled Button</ButtonBase>;
```

### Loading

Use the boolean `loading` prop to set loading spinner

<Canvas>
<Story id="ui-components-component-library-button-base-button-base-stories-js--loading" />
</Canvas>

```jsx
import { ButtonBase } from '../ui/component-library';

<ButtonBase loading>Loading Button</ButtonBase>;
```

### Icon

Use the `icon` prop and the `ICON_NAMES` object from `./ui/components/component-library/icon` to select icon.

<Canvas>
<Story id="ui-components-component-library-button-base-button-base-stories-js--icon" />
</Canvas>

```jsx
import { ButtonBase } from '../ui/component-library';
import { ICON_NAMES } from '../icon';

<ButtonBase icon={ICON_NAMES.ADD_SQUARE_FILLED}>Button</ButtonBase>;
```
126 changes: 126 additions & 0 deletions ui/components/component-library/button-base/button-base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';

import Box from '../../ui/box';
import { Icon, ICON_NAMES } from '../icon';
import { Text } from '../text';

import {
ALIGN_ITEMS,
JUSTIFY_CONTENT,
TEXT_COLORS,
TEXT,
SIZES,
FLEX_DIRECTION,
} from '../../../helpers/constants/design-system';
import { BUTTON_SIZES } from './button.constants';

export const ButtonBase = ({
as = 'button',
block,
children,
className,
size = BUTTON_SIZES.MD,
icon,
iconPositionRight,
loading,
disabled,
iconProps,
...props
}) => {
return (
<Box
as={as}
paddingLeft={size === BUTTON_SIZES.AUTO ? 0 : 4}
paddingRight={size === BUTTON_SIZES.AUTO ? 0 : 4}
className={classnames(
'mm-button',
`mm-button--size-${size}`,
{
[`mm-button--loading`]: Boolean(loading),
[`mm-button--disabled`]: Boolean(disabled),
[`mm-button--block`]: Boolean(block),
},
className,
)}
disabled={disabled}
{...props}
>
<Text
as="span"
className="mm-button__content"
alignItems={ALIGN_ITEMS.CENTER}
justifyContent={JUSTIFY_CONTENT.CENTER}
flexDirection={
iconPositionRight ? FLEX_DIRECTION.ROW_REVERSE : FLEX_DIRECTION.ROW
}
gap={2}
variant={size === BUTTON_SIZES.AUTO ? TEXT.INHERIT : TEXT.BODY_MD}
color={TEXT_COLORS.INHERIT}
>
{icon && (
<Icon
name={icon}
size={size === BUTTON_SIZES.AUTO ? SIZES.AUTO : SIZES.SM}
{...iconProps}
/>
)}
{children}
</Text>
{loading && (
<Icon
className="mm-button__icon-loading"
name={ICON_NAMES.LOADING_FILLED}
size={size === BUTTON_SIZES.AUTO ? SIZES.AUTO : SIZES.MD}
/>
)}
</Box>
);
};

ButtonBase.propTypes = {
/**
* The polymorphic `as` prop allows you to change the root HTML element of the Button component between `button` and `a` tag
*/
as: PropTypes.string,
/**
* Boolean prop to quickly activate box prop display block
*/
block: PropTypes.bool,
/**
* The children to be rendered inside the ButtonBase
*/
children: PropTypes.node,
/**
* An additional className to apply to the ButtonBase.
*/
className: PropTypes.string,
/**
* Boolean to disable button
*/
disabled: PropTypes.bool,
/**
* Add icon to left side of button text passing icon name
* The name of the icon to display. Should be one of ICON_NAMES
*/
icon: PropTypes.string, // Can't set PropTypes.oneOf(ICON_NAMES) because ICON_NAMES is an environment variable
/**
* Boolean that when true will position the icon on right of children
* Icon default position left
*/
iconPositionRight: PropTypes.bool,
/**
* Boolean to show loading spinner in button
*/
loading: PropTypes.bool,
/**
* The size of the ButtonBase.
* Possible values could be 'BUTTON_SIZES.XS', 'BUTTON_SIZES.SM', 'BUTTON_SIZES.MD', 'BUTTON_SIZES.LG',
*/
size: PropTypes.oneOf(Object.values(BUTTON_SIZES)),
/**
* ButtonBase accepts all the props from Box
*/
...Box.propTypes,
};
79 changes: 79 additions & 0 deletions ui/components/component-library/button-base/button-base.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
.mm-button {
position: relative;
height: 40px;
padding: 0;
border-radius: 999px;
cursor: pointer;
color: var(--color-text-default);
background-color: #dcdcdc;
vertical-align: middle;
user-select: none;

&:active,
&:hover {
color: var(--color-text-default);
}

&--block {
display: block;
width: 100%;
}

&__content {
height: 100%;
}


&--size-sm {
height: 32px;
}

&--size-md {
height: 40px;
}

&--size-lg {
height: 48px;
}

&--size-auto {
height: auto;
background-color: transparent;
border-radius: 0;
vertical-align: top;
font-family: inherit;
font-weight: inherit;
font-size: inherit;
line-height: inherit;
letter-spacing: inherit;
}

&--loading {
cursor: not-allowed;
}

&--loading .mm-button--content {
color: transparent;
}

&--disabled,
&:disabled {
opacity: 0.3;
cursor: not-allowed;
}

&__icon-loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
animation: spinner 1.2s linear infinite;
}
}



@keyframes spinner {
to { transform: translate(-50%, -50%) rotate(360deg); }
}

Loading

0 comments on commit ada30f7

Please sign in to comment.