1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Feat/16637/button housekeeping (#16872)

* button housekeeping

* add iconsearch

* fix description

* readme update

* update disabled classnames

* buttonlink disabled class

* add disabled proptypes

* add constant exports

* update disabled style classes

* update snapshot for box pill classname

* add buttonTextProps

* update primarybutton background color to use box props

* update button secondary and link to use box props

* update tests
This commit is contained in:
Garrett Bear 2023-01-13 13:58:09 -08:00 committed by GitHub
parent 214afe1992
commit 1265731344
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 216 additions and 174 deletions

View File

@ -128,17 +128,17 @@ import { ButtonBase } from '../../ui/components/component-library';
<ButtonBase loading>Loading Button</ButtonBase>;
```
### Icon
### Icon Name
Use the `icon` prop and the `ICON_NAMES` object from `./ui/components/component-library` to select icon.
Use the `iconName` prop and the `ICON_NAMES` object from `./ui/components/component-library` to select icon.
<Canvas>
<Story id="ui-components-component-library-button-base-button-base-stories-js--icon" />
<Story id="ui-components-component-library-button-base-button-base-stories-js--iconName" />
</Canvas>
```jsx
import { ButtonBase } from '../../ui/components/component-library';
import { ICON_NAMES } from '../icon';
<ButtonBase icon={ICON_NAMES.ADD_SQUARE_FILLED}>Button</ButtonBase>;
<ButtonBase iconName={ICON_NAMES.ADD_SQUARE_FILLED}>Button</ButtonBase>;
```

View File

@ -3,11 +3,11 @@
exports[`ButtonBase should render button element correctly and match snapshot 1`] = `
<div>
<button
class="box mm-button mm-button--size-md box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center"
class="box mm-button-base mm-button-base--size-md box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-text-default box--background-color-background-alternative box--rounded-pill"
data-testid="button-base"
>
<span
class="box mm-text mm-button__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
class="box mm-text mm-button-base__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
>
Button base
</span>

View File

@ -14,6 +14,8 @@ import {
TEXT,
SIZES,
FLEX_DIRECTION,
BORDER_RADIUS,
COLORS,
} from '../../../helpers/constants/design-system';
import { BUTTON_BASE_SIZES } from './button-base.constants';
@ -24,27 +26,31 @@ export const ButtonBase = ({
className,
href,
size = BUTTON_BASE_SIZES.MD,
icon,
iconName,
iconPositionRight,
loading,
disabled,
iconProps,
buttonTextProps,
...props
}) => {
const Tag = href ? 'a' : as;
return (
<Box
as={Tag}
backgroundColor={COLORS.BACKGROUND_ALTERNATIVE}
color={COLORS.TEXT_DEFAULT}
href={href}
paddingLeft={size === BUTTON_BASE_SIZES.AUTO ? 0 : 4}
paddingRight={size === BUTTON_BASE_SIZES.AUTO ? 0 : 4}
borderRadius={BORDER_RADIUS.PILL}
className={classnames(
'mm-button',
`mm-button--size-${size}`,
'mm-button-base',
`mm-button-base--size-${size}`,
{
'mm-button--loading': loading,
'mm-button--disabled': disabled,
'mm-button--block': block,
'mm-button-base--loading': loading,
'mm-button-base--disabled': disabled,
'mm-button-base--block': block,
},
className,
)}
@ -56,7 +62,7 @@ export const ButtonBase = ({
>
<Text
as="span"
className="mm-button__content"
className="mm-button-base__content"
alignItems={ALIGN_ITEMS.CENTER}
justifyContent={JUSTIFY_CONTENT.CENTER}
flexDirection={
@ -65,10 +71,11 @@ export const ButtonBase = ({
gap={2}
variant={size === BUTTON_BASE_SIZES.AUTO ? TEXT.INHERIT : TEXT.BODY_MD}
color={TEXT_COLORS.INHERIT}
{...buttonTextProps}
>
{icon && (
{iconName && (
<Icon
name={icon}
name={iconName}
size={size === BUTTON_BASE_SIZES.AUTO ? SIZES.AUTO : SIZES.SM}
{...iconProps}
/>
@ -77,7 +84,7 @@ export const ButtonBase = ({
</Text>
{loading && (
<Icon
className="mm-button__icon-loading"
className="mm-button-base__icon-loading"
name={ICON_NAMES.LOADING_FILLED}
size={size === BUTTON_BASE_SIZES.AUTO ? SIZES.AUTO : SIZES.MD}
/>
@ -95,6 +102,10 @@ ButtonBase.propTypes = {
* Boolean prop to quickly activate box prop display block
*/
block: PropTypes.bool,
/**
* Additional props to pass to the Text component that wraps the button children
*/
buttonTextProps: PropTypes.shape(Text.PropTypes),
/**
* The children to be rendered inside the ButtonBase
*/
@ -115,7 +126,7 @@ ButtonBase.propTypes = {
* 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
iconName: 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

View File

@ -1,11 +1,8 @@
.mm-button {
.mm-button-base {
position: relative;
height: 40px;
padding: 0;
border-radius: 999px;
padding: 0; // TODO: remove once https://github.com/MetaMask/metamask-extension/pull/17006 is merged
cursor: pointer;
color: var(--color-text-default);
background-color: var(--brand-colors-grey-grey100);
vertical-align: middle;
user-select: none;
@ -23,7 +20,6 @@
height: 100%;
}
&--size-sm {
height: 32px;
}

View File

@ -167,8 +167,8 @@ Loading.args = {
loading: true,
};
export const Icon = (args) => (
<ButtonBase {...args} icon={ICON_NAMES.ADD_SQUARE_FILLED}>
export const IconName = (args) => (
<ButtonBase {...args} iconName={ICON_NAMES.ADD_SQUARE_FILLED}>
Button
</ButtonBase>
);

View File

@ -11,7 +11,7 @@ describe('ButtonBase', () => {
);
expect(getByText('Button base')).toBeDefined();
expect(container.querySelector('button')).toBeDefined();
expect(getByTestId('button-base')).toHaveClass('mm-button');
expect(getByTestId('button-base')).toHaveClass('mm-button-base');
expect(container).toMatchSnapshot();
});
@ -19,7 +19,7 @@ describe('ButtonBase', () => {
const { getByTestId, container } = render(
<ButtonBase as="a" data-testid="button-base" />,
);
expect(getByTestId('button-base')).toHaveClass('mm-button');
expect(getByTestId('button-base')).toHaveClass('mm-button-base');
const anchor = container.getElementsByTagName('a').length;
expect(anchor).toBe(1);
});
@ -30,7 +30,7 @@ describe('ButtonBase', () => {
Button Base
</ButtonBase>,
);
expect(getByTestId('button-base')).toHaveClass('mm-button');
expect(getByTestId('button-base')).toHaveClass('mm-button-base');
expect(getByTestId('button-base')).toHaveAttribute(
'href',
'https://www.test.com/',
@ -41,7 +41,7 @@ describe('ButtonBase', () => {
it('should render button as block', () => {
const { getByTestId } = render(<ButtonBase block data-testid="block" />);
expect(getByTestId('block')).toHaveClass(`mm-button--block`);
expect(getByTestId('block')).toHaveClass(`mm-button-base--block`);
});
it('should render with different size classes', () => {
@ -66,24 +66,24 @@ describe('ButtonBase', () => {
</>,
);
expect(getByTestId(BUTTON_BASE_SIZES.AUTO)).toHaveClass(
`mm-button--size-${BUTTON_BASE_SIZES.AUTO}`,
`mm-button-base--size-${BUTTON_BASE_SIZES.AUTO}`,
);
expect(getByTestId(BUTTON_BASE_SIZES.SM)).toHaveClass(
`mm-button--size-${BUTTON_BASE_SIZES.SM}`,
`mm-button-base--size-${BUTTON_BASE_SIZES.SM}`,
);
expect(getByTestId(BUTTON_BASE_SIZES.MD)).toHaveClass(
`mm-button--size-${BUTTON_BASE_SIZES.MD}`,
`mm-button-base--size-${BUTTON_BASE_SIZES.MD}`,
);
expect(getByTestId(BUTTON_BASE_SIZES.LG)).toHaveClass(
`mm-button--size-${BUTTON_BASE_SIZES.LG}`,
`mm-button-base--size-${BUTTON_BASE_SIZES.LG}`,
);
});
it('should render with added classname', () => {
const { getByTestId } = render(
<ButtonBase data-testid="classname" className="mm-button--test" />,
<ButtonBase data-testid="classname" className="mm-button-base--test" />,
);
expect(getByTestId('classname')).toHaveClass('mm-button--test');
expect(getByTestId('classname')).toHaveClass('mm-button-base--test');
});
it('should render with different button states', () => {
@ -93,14 +93,14 @@ describe('ButtonBase', () => {
<ButtonBase disabled data-testid="disabled" />
</>,
);
expect(getByTestId('loading')).toHaveClass(`mm-button--loading`);
expect(getByTestId('disabled')).toHaveClass(`mm-button--disabled`);
expect(getByTestId('loading')).toHaveClass(`mm-button-base--loading`);
expect(getByTestId('disabled')).toHaveClass(`mm-button-base--disabled`);
});
it('should render with icon', () => {
const { getByTestId } = render(
<ButtonBase
data-testid="icon"
icon="add-square-filled"
iconName="add-square-filled"
iconProps={{ 'data-testid': 'base-button-icon' }}
/>,
);

View File

@ -35,7 +35,7 @@ Possible sizes include:
```jsx
import { SIZES } from '../../../helpers/constants/design-system';
import { ButtonLink } from '../../ui/components/component-library';
import { ButtonLink } from '../../component-library';
<ButtonLink size={SIZES.AUTO} />
<ButtonLink size={SIZES.SM} />
@ -52,7 +52,7 @@ Use the `danger` boolean prop to change the `ButtonLink` to danger color.
</Canvas>
```jsx
import { ButtonLink } from '../../ui/components/component-library';
import { ButtonLink } from '../../component-library';
<ButtonLink>Normal</ButtonLink>
<ButtonLink danger>Danger</ButtonLink>
@ -60,14 +60,14 @@ import { ButtonLink } from '../../ui/components/component-library';
### Href
When an `href` is passed the tag element will switch to an `anchor`(`a`) tag.
When an `href` prop is passed it will change the element to an anchor(`a`) tag.
<Canvas>
<Story id="ui-components-component-library-button-link-button-link-stories-js--href" />
</Canvas>
```jsx
import { ButtonLink } from '../../ui/components/component-library';
import { ButtonLink } from '../../component-library';
<ButtonLink href="/">Href Example</ButtonLink>;
<ButtonLink href="/">Anchor Element</ButtonLink>;
```

View File

@ -3,11 +3,11 @@
exports[`ButtonLink should render button element correctly 1`] = `
<div>
<button
class="box mm-button mm-button--size-md mm-button-link box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--background-color-transparent"
class="box mm-button-base mm-button-base--size-md mm-button-link box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-primary-default box--background-color-transparent box--rounded-pill"
data-testid="button-link"
>
<span
class="box mm-text mm-button__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
class="box mm-text mm-button-base__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
>
Button Link
</span>

View File

@ -9,6 +9,7 @@ import { BUTTON_LINK_SIZES } from './button-link.constants';
export const ButtonLink = ({
className,
danger,
disabled,
size = BUTTON_LINK_SIZES.MD,
...props
}) => {
@ -16,10 +17,12 @@ export const ButtonLink = ({
<ButtonBase
className={classnames(className, 'mm-button-link', {
'mm-button-link--type-danger': danger,
'mm-button-link--disabled': disabled,
})}
size={size}
color={danger ? COLORS.ERROR_DEFAULT : COLORS.PRIMARY_DEFAULT}
backgroundColor={COLORS.TRANSPARENT}
{...props}
{...{ disabled, ...props }}
/>
);
};
@ -33,6 +36,10 @@ ButtonLink.propTypes = {
* Boolean to change button type to Danger when true
*/
danger: PropTypes.bool,
/**
* Boolean to disable button
*/
disabled: PropTypes.bool,
/**
* Possible size values: 'SIZES.AUTO', 'SIZES.SM'(32px), 'SIZES.MD'(40px), 'SIZES.LG'(48px).
* Default value is 'SIZES.MD'.

View File

@ -1,6 +1,4 @@
.mm-button-link {
color: var(--color-primary-default);
&:hover {
color: var(--color-primary-default);
opacity: 0.5;
@ -11,7 +9,7 @@
opacity: 0.5;
}
&.mm-button--disabled {
&--disabled {
&:hover {
color: var(--color-primary-default);
opacity: 0.3;
@ -23,8 +21,6 @@
}
&--type-danger {
color: var(--color-error-default);
&:hover {
color: var(--color-error-default);
opacity: 0.5;
@ -34,9 +30,9 @@
color: var(--color-error-default);
opacity: 0.5;
}
}
&.mm-button--disabled:hover {
color: var(--color-error-default);
}
&--type-danger#{&}--disabled:hover {
opacity: 0.3;
}
}

View File

@ -149,7 +149,7 @@ export const Danger = (args) => (
</Box>
);
export const Href = (args) => <ButtonLink {...args}>Href Example</ButtonLink>;
export const Href = (args) => <ButtonLink {...args}>Anchor Element</ButtonLink>;
Href.args = {
href: '/metamask',

View File

@ -11,7 +11,7 @@ describe('ButtonLink', () => {
);
expect(getByText('Button Link')).toBeDefined();
expect(container.querySelector('button')).toBeDefined();
expect(getByTestId('button-link')).toHaveClass('mm-button');
expect(getByTestId('button-link')).toHaveClass('mm-button-base');
expect(container).toMatchSnapshot();
});
@ -19,14 +19,14 @@ describe('ButtonLink', () => {
const { getByTestId, container } = render(
<ButtonLink as="a" data-testid="button-link" />,
);
expect(getByTestId('button-link')).toHaveClass('mm-button');
expect(getByTestId('button-link')).toHaveClass('mm-button-base');
const anchor = container.getElementsByTagName('a').length;
expect(anchor).toBe(1);
});
it('should render button as block', () => {
const { getByTestId } = render(<ButtonLink block data-testid="block" />);
expect(getByTestId('block')).toHaveClass(`mm-button--block`);
expect(getByTestId('block')).toHaveClass(`mm-button-base--block`);
});
it('should render with added classname', () => {
@ -46,11 +46,17 @@ describe('ButtonLink', () => {
</>,
);
expect(getByTestId(SIZES.SM)).toHaveClass(`mm-button--size-${SIZES.SM}`);
expect(getByTestId(SIZES.MD)).toHaveClass(`mm-button--size-${SIZES.MD}`);
expect(getByTestId(SIZES.LG)).toHaveClass(`mm-button--size-${SIZES.LG}`);
expect(getByTestId(SIZES.SM)).toHaveClass(
`mm-button-base--size-${SIZES.SM}`,
);
expect(getByTestId(SIZES.MD)).toHaveClass(
`mm-button-base--size-${SIZES.MD}`,
);
expect(getByTestId(SIZES.LG)).toHaveClass(
`mm-button-base--size-${SIZES.LG}`,
);
expect(getByTestId(SIZES.AUTO)).toHaveClass(
`mm-button--size-${SIZES.AUTO}`,
`mm-button-base--size-${SIZES.AUTO}`,
);
});
@ -71,12 +77,12 @@ describe('ButtonLink', () => {
<ButtonLink disabled data-testid="disabled" />
</>,
);
expect(getByTestId('loading')).toHaveClass(`mm-button--loading`);
expect(getByTestId('disabled')).toHaveClass(`mm-button--disabled`);
expect(getByTestId('loading')).toHaveClass(`mm-button-base--loading`);
expect(getByTestId('disabled')).toHaveClass(`mm-button-base--disabled`);
});
it('should render with icon', () => {
const { container } = render(
<ButtonLink data-testid="icon" icon="add-square-filled" />,
<ButtonLink data-testid="icon" iconName="add-square-filled" />,
);
const icons = container.getElementsByClassName('mm-icon').length;

View File

@ -3,11 +3,11 @@
exports[`ButtonPrimary should render button element correctly 1`] = `
<div>
<button
class="box mm-button mm-button--size-md mm-button-primary box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center"
class="box mm-button-base mm-button-base--size-md mm-button-primary box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-primary-inverse box--background-color-primary-default box--rounded-pill"
data-testid="button-primary"
>
<span
class="box mm-text mm-button__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
class="box mm-text mm-button-base__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
>
Button Primary
</span>

View File

@ -3,21 +3,26 @@ import PropTypes from 'prop-types';
import classnames from 'classnames';
import { ButtonBase } from '../button-base';
import { COLORS } from '../../../helpers/constants/design-system';
import { BUTTON_PRIMARY_SIZES } from './button-primary.constants';
export const ButtonPrimary = ({
className,
danger,
disabled,
size = BUTTON_PRIMARY_SIZES.MD,
...props
}) => {
return (
<ButtonBase
backgroundColor={danger ? COLORS.ERROR_DEFAULT : COLORS.PRIMARY_DEFAULT}
color={danger ? COLORS.ERROR_INVERSE : COLORS.PRIMARY_INVERSE}
className={classnames(className, 'mm-button-primary', {
'mm-button-primary--type-danger': danger,
'mm-button-primary--disabled': disabled,
})}
size={size}
{...props}
{...{ disabled, ...props }}
/>
);
};
@ -31,6 +36,10 @@ ButtonPrimary.propTypes = {
* When true, `ButtonPrimary` color becomes Danger.
*/
danger: PropTypes.bool,
/**
* Boolean to disable button
*/
disabled: PropTypes.bool,
/**
* Possible size values: 'SIZES.SM'(32px), 'SIZES.MD'(40px), 'SIZES.LG'(48px).
* Default value is 'SIZES.MD'.

View File

@ -1,7 +1,4 @@
.mm-button-primary {
color: var(--color-primary-inverse);
background-color: var(--color-primary-default);
&:hover {
color: var(--color-primary-inverse);
box-shadow: var(--component-button-primary-shadow);
@ -12,20 +9,8 @@
background-color: var(--color-primary-alternative);
}
&.mm-button--disabled {
&:hover {
box-shadow: none;
}
&:active {
background-color: var(--color-primary-default);
}
}
// Danger type
&--type-danger {
color: var(--color-error-inverse);
background-color: var(--color-error-default);
&:hover {
color: var(--color-error-inverse);
box-shadow: var(--component-button-danger-shadow);
@ -35,9 +20,20 @@
color: var(--color-error-inverse);
background-color: var(--color-error-alternative);
}
}
&.mm-button--disabled:active {
background-color: var(--color-error-default);
// Disabled
&--disabled {
&:hover {
box-shadow: none;
}
&:active {
background-color: var(--color-primary-default);
}
}
// Disabled danger
&--type-danger#{&}--disabled:active {
background-color: var(--color-error-default);
}
}

View File

@ -13,7 +13,7 @@ describe('ButtonPrimary', () => {
);
expect(getByText('Button Primary')).toBeDefined();
expect(container.querySelector('button')).toBeDefined();
expect(getByTestId('button-primary')).toHaveClass('mm-button');
expect(getByTestId('button-primary')).toHaveClass('mm-button-base');
expect(container).toMatchSnapshot();
});
@ -21,14 +21,14 @@ describe('ButtonPrimary', () => {
const { getByTestId, container } = render(
<ButtonPrimary as="a" data-testid="button-primary" />,
);
expect(getByTestId('button-primary')).toHaveClass('mm-button');
expect(getByTestId('button-primary')).toHaveClass('mm-button-base');
const anchor = container.getElementsByTagName('a').length;
expect(anchor).toBe(1);
});
it('should render button as block', () => {
const { getByTestId } = render(<ButtonPrimary block data-testid="block" />);
expect(getByTestId('block')).toHaveClass(`mm-button--block`);
expect(getByTestId('block')).toHaveClass(`mm-button-base--block`);
});
it('should render with added classname', () => {
@ -57,13 +57,13 @@ describe('ButtonPrimary', () => {
);
expect(getByTestId(BUTTON_PRIMARY_SIZES.SM)).toHaveClass(
`mm-button--size-${BUTTON_PRIMARY_SIZES.SM}`,
`mm-button-base--size-${BUTTON_PRIMARY_SIZES.SM}`,
);
expect(getByTestId(BUTTON_PRIMARY_SIZES.MD)).toHaveClass(
`mm-button--size-${BUTTON_PRIMARY_SIZES.MD}`,
`mm-button-base--size-${BUTTON_PRIMARY_SIZES.MD}`,
);
expect(getByTestId(BUTTON_PRIMARY_SIZES.LG)).toHaveClass(
`mm-button--size-${BUTTON_PRIMARY_SIZES.LG}`,
`mm-button-base--size-${BUTTON_PRIMARY_SIZES.LG}`,
);
});
@ -84,12 +84,12 @@ describe('ButtonPrimary', () => {
<ButtonPrimary disabled data-testid="disabled" />
</>,
);
expect(getByTestId('loading')).toHaveClass(`mm-button--loading`);
expect(getByTestId('disabled')).toHaveClass(`mm-button--disabled`);
expect(getByTestId('loading')).toHaveClass(`mm-button-base--loading`);
expect(getByTestId('disabled')).toHaveClass(`mm-button-base--disabled`);
});
it('should render with icon', () => {
const { container } = render(
<ButtonPrimary data-testid="icon" icon="add-square-filled" />,
<ButtonPrimary data-testid="icon" iconName="add-square-filled" />,
);
const icons = container.getElementsByClassName('mm-icon').length;

View File

@ -3,11 +3,11 @@
exports[`ButtonSecondary should render button element correctly 1`] = `
<div>
<button
class="box mm-button mm-button--size-md mm-button-secondary box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center"
class="box mm-button-base mm-button-base--size-md mm-button-secondary box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-primary-default box--background-color-transparent box--rounded-pill box--border-color-primary-default box--border-style-solid box--border-width-1"
data-testid="button-secondary"
>
<span
class="box mm-text mm-button__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
class="box mm-text mm-button-base__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
>
Button Secondary
</span>

View File

@ -3,21 +3,27 @@ import PropTypes from 'prop-types';
import classnames from 'classnames';
import { ButtonBase } from '../button-base';
import { COLORS } from '../../../helpers/constants/design-system';
import { BUTTON_SECONDARY_SIZES } from './button-secondary.constants';
export const ButtonSecondary = ({
className,
danger,
disabled,
size = BUTTON_SECONDARY_SIZES.MD,
...props
}) => {
return (
<ButtonBase
backgroundColor={COLORS.TRANSPARENT}
borderColor={danger ? COLORS.ERROR_DEFAULT : COLORS.PRIMARY_DEFAULT}
color={danger ? COLORS.ERROR_DEFAULT : COLORS.PRIMARY_DEFAULT}
className={classnames(className, 'mm-button-secondary', {
'mm-button-secondary--type-danger': danger,
'mm-button-secondary--disabled': disabled,
})}
size={size}
{...props}
{...{ disabled, ...props }}
/>
);
};
@ -31,6 +37,10 @@ ButtonSecondary.propTypes = {
* When true, ButtonSecondary color becomes Danger.
*/
danger: PropTypes.bool,
/**
* Boolean to disable button
*/
disabled: PropTypes.bool,
/**
* Possible size values: 'SIZES.SM'(32px), 'SIZES.MD'(40px), 'SIZES.LG'(48px).
* Default value is 'SIZES.MD'.

View File

@ -1,8 +1,4 @@
.mm-button-secondary {
color: var(--color-primary-default);
border: 1px solid var(--color-primary-default);
background-color: transparent;
&:hover {
color: var(--color-primary-inverse);
background-color: var(--color-primary-default);
@ -15,18 +11,7 @@
border-color: var(--color-primary-alternative);
}
&.mm-button--disabled {
&:hover {
color: var(--color-primary-default);
box-shadow: none;
background-color: transparent;
}
&:active {
background-color: transparent;
}
}
// Danger type
&--type-danger {
color: var(--color-error-default);
border: 1px solid var(--color-error-default);
@ -43,9 +28,23 @@
background-color: var(--color-error-alternative);
border-color: var(--color-error-alternative);
}
}
&.mm-button--disabled:hover {
color: var(--color-error-default);
// Disabled
&--disabled {
&:hover {
color: var(--color-primary-default);
box-shadow: none;
background-color: transparent;
}
&:active {
background-color: transparent;
}
}
// Disabled danger
&--type-danger#{&}--disabled:hover {
color: var(--color-error-default);
}
}

View File

@ -13,7 +13,7 @@ describe('ButtonSecondary', () => {
);
expect(getByText('Button Secondary')).toBeDefined();
expect(container.querySelector('button')).toBeDefined();
expect(getByTestId('button-secondary')).toHaveClass('mm-button');
expect(getByTestId('button-secondary')).toHaveClass('mm-button-base');
expect(container).toMatchSnapshot();
});
@ -21,7 +21,7 @@ describe('ButtonSecondary', () => {
const { getByTestId, container } = render(
<ButtonSecondary as="a" data-testid="button-secondary" />,
);
expect(getByTestId('button-secondary')).toHaveClass('mm-button');
expect(getByTestId('button-secondary')).toHaveClass('mm-button-base');
const anchor = container.getElementsByTagName('a').length;
expect(anchor).toBe(1);
});
@ -30,7 +30,7 @@ describe('ButtonSecondary', () => {
const { getByTestId } = render(
<ButtonSecondary block data-testid="block" />,
);
expect(getByTestId('block')).toHaveClass(`mm-button--block`);
expect(getByTestId('block')).toHaveClass(`mm-button-base--block`);
});
it('should render with added classname', () => {
@ -59,13 +59,13 @@ describe('ButtonSecondary', () => {
);
expect(getByTestId(BUTTON_SECONDARY_SIZES.SM)).toHaveClass(
`mm-button--size-${BUTTON_SECONDARY_SIZES.SM}`,
`mm-button-base--size-${BUTTON_SECONDARY_SIZES.SM}`,
);
expect(getByTestId(BUTTON_SECONDARY_SIZES.MD)).toHaveClass(
`mm-button--size-${BUTTON_SECONDARY_SIZES.MD}`,
`mm-button-base--size-${BUTTON_SECONDARY_SIZES.MD}`,
);
expect(getByTestId(BUTTON_SECONDARY_SIZES.LG)).toHaveClass(
`mm-button--size-${BUTTON_SECONDARY_SIZES.LG}`,
`mm-button-base--size-${BUTTON_SECONDARY_SIZES.LG}`,
);
});
@ -88,12 +88,12 @@ describe('ButtonSecondary', () => {
<ButtonSecondary disabled data-testid="disabled" />
</>,
);
expect(getByTestId('loading')).toHaveClass(`mm-button--loading`);
expect(getByTestId('disabled')).toHaveClass(`mm-button--disabled`);
expect(getByTestId('loading')).toHaveClass(`mm-button-base--loading`);
expect(getByTestId('disabled')).toHaveClass(`mm-button-base--disabled`);
});
it('should render with icon', () => {
const { container } = render(
<ButtonSecondary data-testid="icon" icon="add-square-filled" />,
<ButtonSecondary data-testid="icon" iconName="add-square-filled" />,
);
const icons = container.getElementsByClassName('mm-icon').length;

View File

@ -1,9 +1,11 @@
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs';
import { Button } from './button';
import { ButtonBase } from '../button-base';
import { ButtonLink } from '../button-link';
# Button
The `Button` is used for user actions it unifies `ButtonPrimary`, `ButtonSecondary` and `ButtonLink`
The `Button` is used for user actions. It unifies `ButtonPrimary`, `ButtonSecondary` and `ButtonLink`.
<Canvas>
<Story id="ui-components-component-library-button-button-stories-js--default-story" />
@ -11,10 +13,18 @@ The `Button` is used for user actions it unifies `ButtonPrimary`, `ButtonSeconda
## Props
The `Button` accepts all props below as well as all [ButtonPrimary](/ui-components-component-library-button-primary-button-primary-stories-js--default-story), [ButtonSecondary](/ui-components-component-library-button-secondary-button-secondary-stories-js--default-story), [ButtonLink](/ui-components-component-library-button-link-button-link-stories-js--default-story), and [Box](/docs/ui-components-ui-box-box-stories-js--default-story#props) component props
The `Button` accepts all props below as well as [Box](/docs/ui-components-ui-box-box-stories-js--default-story#props) component props
<ArgsTable of={Button} />
The `Button` accepts all [ButtonBase](/docs/ui-components-component-library-button-base-button-base-stories-js--default-story) component props
<ArgsTable of={ButtonBase} />
The `Button` accepts all [ButtonPrimary](/docs/ui-components-component-library-button-primary-button-primary-stories-js--default-story), [ButtonSecondary](/docs/ui-components-component-library-button-secondary-button-secondary-stories-js--default-story), and [ButtonLink](/docs/ui-components-component-library-button-link-button-link-stories-js--default-story) component props
<ArgsTable of={ButtonLink} />
### Type
Use the `type` prop and the `BUTTON_TYPES` object from `./button.constants.js` to change the `Button` type.
@ -45,7 +55,7 @@ Optional: `BUTTON_SIZES` from `./button` object can be used instead of `SIZES`.
Possible sizes include:
- `SIZES.AUTO` inherits the font-size of the parent element.
- `SIZES.AUTO` inherits the font-size of the parent element. (Only used for `ButtonLink`)
- `SIZES.SM` 32px
- `SIZES.MD` 40px
- `SIZES.LG` 48px
@ -56,7 +66,7 @@ Possible sizes include:
```jsx
import { SIZES } from '../../../helpers/constants/design-system';
import { Button } from '../ui/component-library/button/button/button';
import { Button } from '../ui/component-library';
<Button size={SIZES.AUTO} />
<Button size={SIZES.SM} />
@ -73,7 +83,7 @@ Use the `danger` boolean prop to change the `Button` to danger color.
</Canvas>
```jsx
import { Button } from '../ui/component-library/button/button/button';
import { Button } from '../ui/component-library';
<Button>Normal</Button>
<Button danger>Danger</Button>
@ -81,16 +91,16 @@ import { Button } from '../ui/component-library/button/button/button';
### Href
When an `href` is passed the tag element will switch to an `anchor`(`a`) tag.
When an `href` prop is passed it will change the element to an anchor(`a`) tag.
<Canvas>
<Story id="ui-components-component-library-button-button-stories-js--href" />
</Canvas>
```jsx
import { Button } from '../ui/component-library/button/button/button';
import { Button } from '../ui/component-library';
<Button href="/">Href Example</Button>;
<Button href="/">Anchor Element</Button>;
```
### Block
@ -162,17 +172,19 @@ import { Button } from '../ui/component-library';
<Button loading>Loading Button</Button>;
```
### Icon
### Icon Name
Use the `icon` prop and the `ICON_NAMES` object from `./ui/components/component-library/icon` to select icon.
Use the `iconName` prop and the `ICON_NAMES` object from `./ui/components/component-library/icon` to select icon.
Use the [IconSearch](/story/ui-components-component-library-icon-icon-stories-js--default-story) story to find the icon you want to use.
<Canvas>
<Story id="ui-components-component-library-button-button-stories-js--icon" />
<Story id="ui-components-component-library-button-button-stories-js--icon-name" />
</Canvas>
```jsx
import { Button } from '../ui/component-library';
import { ICON_NAMES } from '../icon';
<Button icon={ICON_NAMES.ADD_SQUARE_FILLED}>Button</Button>;
<Button iconName={ICON_NAMES.ADD_SQUARE_FILLED}>Button</Button>;
```

View File

@ -3,11 +3,11 @@
exports[`Button should render button element correctly 1`] = `
<div>
<button
class="box mm-button mm-button--size-md mm-button-primary box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center"
class="box mm-button-base mm-button-base--size-md mm-button-primary box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-primary-inverse box--background-color-primary-default box--rounded-pill"
data-testid="button"
>
<span
class="box mm-text mm-button__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
class="box mm-text mm-button-base__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
>
Button
</span>
@ -18,31 +18,31 @@ exports[`Button should render button element correctly 1`] = `
exports[`Button should render with different button types 1`] = `
<div>
<button
class="box mm-button mm-button--size-md mm-button-primary box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center"
class="box mm-button-base mm-button-base--size-md mm-button-primary box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-primary-inverse box--background-color-primary-default box--rounded-pill"
data-testid="primary"
>
<span
class="box mm-text mm-button__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
class="box mm-text mm-button-base__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
>
Button
</span>
</button>
<button
class="box mm-button mm-button--size-md mm-button-secondary box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center"
class="box mm-button-base mm-button-base--size-md mm-button-secondary box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-primary-default box--background-color-transparent box--rounded-pill box--border-color-primary-default box--border-style-solid box--border-width-1"
data-testid="secondary"
>
<span
class="box mm-text mm-button__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
class="box mm-text mm-button-base__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
>
Button
</span>
</button>
<button
class="box mm-button mm-button--size-md mm-button-link box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--background-color-transparent"
class="box mm-button-base mm-button-base--size-md mm-button-link box--padding-right-4 box--padding-left-4 box--display-inline-flex box--flex-direction-row box--justify-content-center box--align-items-center box--color-primary-default box--background-color-transparent box--rounded-pill"
data-testid="link"
>
<span
class="box mm-text mm-button__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
class="box mm-text mm-button-base__content mm-text--body-md mm-text--color-inherit box--gap-2 box--flex-direction-row box--justify-content-center box--align-items-center box--display-flex"
>
Button
</span>

View File

@ -64,7 +64,7 @@ export default {
href: {
control: 'text',
},
icon: {
iconName: {
control: 'select',
options: Object.values(ICON_NAMES),
},
@ -167,7 +167,7 @@ export const Danger = (args) => (
</Box>
);
export const Href = (args) => <Button {...args}>Href Example</Button>;
export const Href = (args) => <Button {...args}>Anchor Element</Button>;
Href.args = {
href: '/metamask',
@ -205,8 +205,8 @@ Loading.args = {
loading: true,
};
export const Icon = (args) => (
<Button {...args} icon={ICON_NAMES.ADD_SQUARE_FILLED}>
Button
</Button>
);
export const IconName = (args) => <Button {...args}>Button</Button>;
IconName.args = {
iconName: ICON_NAMES.ADD_SQUARE_FILLED,
};

View File

@ -11,7 +11,7 @@ describe('Button', () => {
);
expect(getByText('Button')).toBeDefined();
expect(container.querySelector('button')).toBeDefined();
expect(getByTestId('button')).toHaveClass('mm-button');
expect(getByTestId('button')).toHaveClass('mm-button-base');
expect(container).toMatchSnapshot();
});
@ -21,7 +21,7 @@ describe('Button', () => {
Button
</Button>,
);
expect(getByTestId('button')).toHaveClass('mm-button');
expect(getByTestId('button')).toHaveClass('mm-button-base');
const anchor = container.getElementsByTagName('a').length;
expect(anchor).toBe(1);
});
@ -32,14 +32,14 @@ describe('Button', () => {
Visit Site
</Button>,
);
expect(getByTestId('button')).toHaveClass('mm-button');
expect(getByTestId('button')).toHaveClass('mm-button-base');
const anchor = container.getElementsByTagName('a').length;
expect(anchor).toBe(1);
});
it('should render button as block', () => {
const { getByTestId } = render(<Button block data-testid="block" />);
expect(getByTestId('block')).toHaveClass(`mm-button--block`);
expect(getByTestId('block')).toHaveClass(`mm-button-base--block`);
});
it('should render with different button types', () => {
@ -93,26 +93,26 @@ describe('Button', () => {
</>,
);
expect(getByTestId(BUTTON_SIZES.AUTO)).toHaveClass(
`mm-button--size-${BUTTON_SIZES.AUTO}`,
`mm-button-base--size-${BUTTON_SIZES.AUTO}`,
);
expect(getByTestId(BUTTON_SIZES.SM)).toHaveClass(
`mm-button--size-${BUTTON_SIZES.SM}`,
`mm-button-base--size-${BUTTON_SIZES.SM}`,
);
expect(getByTestId(BUTTON_SIZES.MD)).toHaveClass(
`mm-button--size-${BUTTON_SIZES.MD}`,
`mm-button-base--size-${BUTTON_SIZES.MD}`,
);
expect(getByTestId(BUTTON_SIZES.LG)).toHaveClass(
`mm-button--size-${BUTTON_SIZES.LG}`,
`mm-button-base--size-${BUTTON_SIZES.LG}`,
);
});
it('should render with added classname', () => {
const { getByTestId } = render(
<Button data-testid="classname" className="mm-button--test">
<Button data-testid="classname" className="mm-button-base--test">
Button
</Button>,
);
expect(getByTestId('classname')).toHaveClass('mm-button--test');
expect(getByTestId('classname')).toHaveClass('mm-button-base--test');
});
it('should render with different button states', () => {
@ -126,14 +126,14 @@ describe('Button', () => {
</Button>
</>,
);
expect(getByTestId('loading')).toHaveClass(`mm-button--loading`);
expect(getByTestId('disabled')).toHaveClass(`mm-button--disabled`);
expect(getByTestId('loading')).toHaveClass(`mm-button-base--loading`);
expect(getByTestId('disabled')).toHaveClass(`mm-button-base--disabled`);
});
it('should render with icon', () => {
const { getByTestId } = render(
<Button
data-testid="icon"
icon="add-square-filled"
iconName="add-square-filled"
iconProps={{ 'data-testid': 'base-button-icon' }}
>
Button

View File

@ -1,2 +1,2 @@
export { Button } from './button';
export { BUTTON_TYPES } from './button.constants';
export { BUTTON_TYPES, BUTTON_SIZES } from './button.constants';

View File

@ -230,7 +230,7 @@ return (
</Box>
</Box>
<ButtonSecondary
icon={ICON_NAMES.CLOSE_OUTLINE}
iconName={ICON_NAMES.CLOSE_OUTLINE}
onClick={handleClearForm}
danger
>

View File

@ -401,7 +401,7 @@ export const FormExample = () => {
</Box>
</Box>
<ButtonSecondary
icon={ICON_NAMES.CLOSE_OUTLINE}
iconName={ICON_NAMES.CLOSE_OUTLINE}
onClick={handleClearForm}
danger
>

View File

@ -13,12 +13,12 @@ export {
AVATAR_WITH_BADGE_POSTIONS,
} from './avatar-with-badge';
export { AvatarBase } from './avatar-base';
export { Button } from './button';
export { ButtonBase } from './button-base';
export { Button, BUTTON_TYPES, BUTTON_SIZES } from './button';
export { ButtonBase, BUTTON_BASE_SIZES } from './button-base';
export { ButtonIcon, BUTTON_ICON_SIZES } from './button-icon';
export { ButtonLink } from './button-link';
export { ButtonPrimary } from './button-primary';
export { ButtonSecondary } from './button-secondary';
export { ButtonLink, BUTTON_LINK_SIZES } from './button-link';
export { ButtonPrimary, BUTTON_PRIMARY_SIZES } from './button-primary';
export { ButtonSecondary, BUTTON_SECONDARY_SIZES } from './button-secondary';
export { FormTextField } from './form-text-field';
export { HelpText } from './help-text';
export { Icon, ICON_NAMES, ICON_SIZES } from './icon';

View File

@ -31,7 +31,7 @@ $text-variants: (
.mm-text {
// Set default styles
color: var(--color-text-default);
font-family: var(----font-family-sans);
font-family: var(--font-family-sans);
@each $type, $size-options in $text-variants {
&--#{$type} {