Skip to content

Commit

Permalink
Add destructive button variant (#923)
Browse files Browse the repository at this point in the history
Co-authored-by: Robin Métral <robin.metral@sumup.com>
  • Loading branch information
connor-baer and Robin Métral authored May 7, 2021
1 parent cb343cd commit c41a735
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 22 deletions.
5 changes: 5 additions & 0 deletions .changeset/short-bikes-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sumup/circuit-ui': minor
---

Added a `destructive` prop to the Button component to be used for irreversible actions that require special care from users.
6 changes: 6 additions & 0 deletions packages/circuit-ui/components/Button/Button.docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ The **secondary button** should be used for secondary actions to compliment a pr

The **tertiary button** should be used for supportive actions, and can be paired with the primary or the secondary button.

### Destructive

<Story id="components-button--destructive" />

The **destructive button** should be used for irreversible or other actions that require special attention from the user.

### Sizes

The button component supports 2 different sizes:
Expand Down
14 changes: 14 additions & 0 deletions packages/circuit-ui/components/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@ export const Variants = (args: ButtonProps) => (
</Stack>
);

export const Destructive = (args: ButtonProps) => (
<Stack>
<Button {...args} variant="primary" destructive>
Primary
</Button>
<Button {...args} variant="secondary" destructive>
Secondary
</Button>
<Button {...args} variant="tertiary" destructive>
Tertiary
</Button>
</Stack>
);

export const Sizes = (args: ButtonProps) => (
<Stack>
<Button {...args} size="kilo">
Expand Down
100 changes: 78 additions & 22 deletions packages/circuit-ui/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ export interface BaseProps {
* Visually and functionally disable the button.
*/
'disabled'?: boolean;
/**
* Change the color from blue to red to signal to the user that the action
* is irreversible or otherwise dangerous.
*/
'destructive'?: boolean;
/**
* Stretch the button across the full width of its parent.
*/
Expand Down Expand Up @@ -82,6 +87,34 @@ export type ButtonProps = BaseProps & LinkElProps & ButtonElProps;

const BORDER_WIDTH = '1px';

const COLOR_MAP = {
default: {
default: 'p500',
hover: 'p700',
active: 'p900',
},
destructive: {
default: 'danger',
hover: 'r700',
active: 'r900',
},
} as const;

const SECONDARY_COLOR_MAP = {
default: {
text: 'black',
default: 'n500',
hover: 'n700',
active: 'n800',
},
destructive: {
text: 'danger',
default: 'danger',
hover: 'r700',
active: 'r900',
},
} as const;

const baseStyles = ({ theme }: StyleProps) => css`
label: button;
display: inline-flex;
Expand Down Expand Up @@ -116,66 +149,89 @@ const baseStyles = ({ theme }: StyleProps) => css`
const primaryStyles = ({
theme,
variant = 'secondary',
}: ButtonProps & StyleProps) =>
variant === 'primary' &&
css`
destructive,
}: ButtonProps & StyleProps) => {
if (variant !== 'primary') {
return null;
}

const colors = destructive ? COLOR_MAP.destructive : COLOR_MAP.default;

return css`
label: button--primary;
background-color: ${theme.colors.p500};
border-color: ${theme.colors.p500};
background-color: ${theme.colors[colors.default]};
border-color: ${theme.colors[colors.default]};
color: ${theme.colors.white};
&:hover {
background-color: ${theme.colors.p700};
border-color: ${theme.colors.p700};
background-color: ${theme.colors[colors.hover]};
border-color: ${theme.colors[colors.hover]};
}
&:active {
background-color: ${theme.colors.p900};
border-color: ${theme.colors.p900};
background-color: ${theme.colors[colors.active]};
border-color: ${theme.colors[colors.active]};
}
`;
};

const secondaryStyles = ({
theme,
variant = 'secondary',
}: ButtonProps & StyleProps) =>
variant === 'secondary' &&
css`
destructive,
}: ButtonProps & StyleProps) => {
if (variant !== 'secondary') {
return null;
}

const colors = destructive
? SECONDARY_COLOR_MAP.destructive
: SECONDARY_COLOR_MAP.default;

return css`
label: button--secondary;
background-color: ${theme.colors.white};
border-color: ${theme.colors.n500};
color: ${theme.colors.black};
border-color: ${theme.colors[colors.default]};
color: ${theme.colors[colors.text]};
&:hover {
background-color: ${theme.colors.n100};
border-color: ${theme.colors.n700};
border-color: ${theme.colors[colors.hover]};
}
&:active {
background-color: ${theme.colors.n200};
border-color: ${theme.colors.n800};
border-color: ${theme.colors[colors.active]};
}
`;
};

const tertiaryStyles = ({
theme,
variant = 'secondary',
}: ButtonProps & StyleProps) =>
variant === 'tertiary' &&
css`
destructive,
}: ButtonProps & StyleProps) => {
if (variant !== 'tertiary') {
return null;
}

const colors = destructive ? COLOR_MAP.destructive : COLOR_MAP.default;

return css`
label: button--tertiary;
background-color: transparent;
border-color: transparent;
color: ${theme.colors.p500};
color: ${theme.colors[colors.default]};
&:hover {
color: ${theme.colors.p700};
color: ${theme.colors[colors.hover]};
}
&:active {
color: ${theme.colors.p900};
color: ${theme.colors[colors.active]};
}
`;
};

const sizeStyles = ({ theme, size = 'mega' }: ButtonProps & StyleProps) => {
const sizeMap = {
Expand Down

1 comment on commit c41a735

@vercel
Copy link

@vercel vercel bot commented on c41a735 May 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.