Repository: uber-web/baseui
Pull request #205 (2018-09-07 06:33:25)

feat(button): initial button component implementation
### Button Component

This is the initial implementation for `Buttons`, outlined in https://github.com/uber-web/baseui/pull/164

I already had much of this code implemented elsewhere; and this is blocking `Pagination` so trying to fast-track it through.

[Storybook Preview](https://deploy-preview-205--baseui.netlify.com/?selectedKind=Button&selectedStory=Buttons&full=0&addons=1&stories=1&panelRight=0&addonPanel=REACT_STORYBOOK%2Freadme%2Fpanel)

#### Not In Scope

* Button Groups
* Special kind for `spinner`
* A11Y Check-thru
* Design Review

kahwee: There's one violation in the Accessibility panel about the button background color contrast.

https://dequeuniversity.com/rules/axe/2.6/color-contrast?application=axeAPI

Place foreground as white, background as `30, 102, 240`
abmai: @kahwee I'm gonna save the `a11y` checks for a follow up PR/task.

Patch:
diff --git a/rfcs/button-component.md b/rfcs/button-component.md
index 99a65a0bb..4c636f888 100644
--- a/rfcs/button-component.md
+++ b/rfcs/button-component.md
@@ -57,7 +57,6 @@ Rough DOM composition:
 
 * `Button`
 * `StyledButton`
-* `StyledButtonLabel`
 * `StyledStartEnhancer`
 * `StyledEndEnhancer`
 * `KIND`
@@ -80,7 +79,7 @@ Rough DOM composition:
   * `EndEnhancer: ReactComponent` - Optional
 * `size: 'default' | 'compact'`
   Defines the size of a button.
-* `shape: 'round' | 'square'`
+* `shape: 'default' | 'round' | 'square'`
   Defines the shape of a button.
 * `kind: 'primary' | 'secondary' | 'tertiary' | 'minimal'`
   Defines the kind (purpose) of a button
@@ -92,7 +91,7 @@ Rough DOM composition:
 These properties are passed to every presentational (styled) component that is exported:
 
 * `$size: 'default' | 'compact'`
-* `$shape: 'round' | 'square'`
+* `$shape: 'default' | 'round' | 'square'`
 * `$kind: 'primary' | 'secondary' | 'tertiary' | 'minimal'`
 * `$theme: theme`
 
diff --git a/src/button/button.js b/src/button/button.js
new file mode 100644
index 000000000..c44f348a7
--- /dev/null
+++ b/src/button/button.js
@@ -0,0 +1,71 @@
+// @flow
+import * as React from 'react';
+import {
+  BaseButton as StyledBaseButton,
+  StartEnhancer as StyledStartEnhancer,
+  EndEnhancer as StyledEndEnhancer,
+} from './styled-components';
+import {getOverrideObject} from '../helpers/overrides';
+import {KIND, SHAPE, SIZE} from './constants';
+
+import type {ButtonPropsT} from './types';
+
+export default function Button({
+  children,
+  disabled,
+  startEnhancer,
+  endEnhancer,
+  overrides = {},
+  size,
+  kind,
+  shape,
+  ...restProps
+}: ButtonPropsT) {
+  // Base UI override logic goes here
+  const {component: BaseButton, props: baseButtonProps} = getOverrideObject(
+    overrides.BaseButton,
+    StyledBaseButton,
+  );
+  const {
+    component: StartEnhancer,
+    props: startEnhancerProps,
+  } = getOverrideObject(overrides.StartEnhancer, StyledStartEnhancer);
+  const {component: EndEnhancer, props: endEnhancerProps} = getOverrideObject(
+    overrides.EndEnhancer,
+    StyledEndEnhancer,
+  );
+  const sharedProps = {
+    $size: size,
+    $kind: kind,
+    $shape: shape,
+  };
+  return (
+    <BaseButton
+      disabled={disabled}
+      {...sharedProps}
+      {...restProps}
+      {...baseButtonProps}
+    >
+      {startEnhancer && (
+        <StartEnhancer {...sharedProps} {...startEnhancerProps}>
+          {typeof startEnhancer === 'function'
+            ? startEnhancer()
+            : startEnhancer}
+        </StartEnhancer>
+      )}
+      {children}
+      {endEnhancer && (
+        <EndEnhancer {...sharedProps} {...endEnhancerProps}>
+          {typeof endEnhancer === 'function' ? endEnhancer() : endEnhancer}
+        </EndEnhancer>
+      )}
+    </BaseButton>
+  );
+}
+
+Button.defaultProps = {
+  overrides: {},
+  size: SIZE.default,
+  kind: KIND.primary,
+  shape: SHAPE.square,
+};
diff --git a/src/button/constants.js b/src/button/constants.js
new file mode 100644
index 000000000..ada64a2bf
--- /dev/null
+++ b/src/button/constants.js
@@ -0,0 +1,19 @@
+/* eslint-disable flowtype/require-valid-file-annotation */
+
+export const KIND = {
+  primary: 'primary',
+  secondary: 'secondary',
+  tertiary: 'tertiary',
+  minimal: 'minimal',
+};
+
+export const SHAPE = {
+  default: 'default',
+  round: 'round',
+  square: 'square',
+};
+
+export const SIZE = {
+  default: 'default',
+  compact: 'compact',
+};
diff --git a/src/button/examples.js b/src/button/examples.js
new file mode 100644
index 000000000..db42c9044
--- /dev/null
+++ b/src/button/examples.js
@@ -0,0 +1,175 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+import * as React from 'react';
+import {styled} from '../styles';
+import Button from './button';
+import {SIZE, KIND, SHAPE} from './constants';
+
+function CloudComponent() {
+  return (
+    <svg
+      width={24}
+      height={24}
+      viewBox="0 0 24 24"
+      fill="none"
+      style={{width: 24, height: 24}}
+    >
+      <rect width={24} height={24} />
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M14.5 5C12.8755 5 11.4519 5.86084 10.6609 7.15112C10.2905 7.05249 9.90137 7 9.5 7C7.14185 7 5.20752 8.81372 5.01562 11.1221C3.28247 11.5605 2 13.1304 2 15C2 17.2092 3.79077 19 6 19H11V14.4143L9.70703 15.707C9.31665 16.0977 8.68335 16.0977 8.29297 15.707C7.90234 15.3167 7.90234 14.6833 8.29297 14.293L11.293 11.293C11.6833 10.9023 12.3167 10.9023 12.707 11.293L15.707 14.293C16.0977 14.6833 16.0977 15.3167 15.707 15.707C15.3167 16.0977 14.6833 16.0977 14.293 15.707L13 14.4143V19H17C19.7615 19 22 16.7615 22 14C22 11.9492 20.7656 10.187 18.9993 9.41577C18.9543 6.96924 16.9573 5 14.5 5Z"
+        fill="white"
+      />
+    </svg>
+  );
+}
+
+const ButtonContainer = styled('div', {
+  display: 'flex',
+  width: '100%',
+  height: '100%',
+  alignItems: 'flex-start',
+  flexDirection: 'column',
+});
+
+const ButtonRow = styled('div', {
+  display: 'flex',
+  ':not(:first-child)': {
+    marginTop: '20px',
+  },
+});
+
+export const suite = 'Button Test Suite';
+export const examples = {
+  BUTTON: 'Buttons',
+  BUTTON_COMPACT: 'Buttons Compact',
+  BUTTON_WITH_ENHANCERS: 'Buttons with Enhancers',
+  BUTTON_COMPACT_WITH_ENHANCERS: 'Buttons Compact with Enhancers',
+};
+
+export default {
+  [examples.BUTTON]: function Story1() {
+    return (
+      <ButtonContainer>
+        <ButtonRow>
+          <Button>Primary</Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button kind={KIND.secondary}>Secondary</Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button kind={KIND.tertiary}>Tertiary</Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button kind={KIND.minimal}>Minimal</Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button disabled={true}>Disabled</Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button>
+            <CloudComponent />
+          </Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button shape={SHAPE.round}>
+            <CloudComponent />
+          </Button>
+        </ButtonRow>
+      </ButtonContainer>
+    );
+  },
+  [examples.BUTTON_COMPACT]: function Story2() {
+    return (
+      <ButtonContainer>
+        <ButtonRow>
+          <Button size={SIZE.compact}>Primary</Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button size={SIZE.compact} kind={KIND.secondary}>
+            Secondary
+          </Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button size={SIZE.compact} kind={KIND.tertiary}>
+            Tertiary
+          </Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button size={SIZE.compact} kind={KIND.minimal}>
+            Minimal
+          </Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button size={SIZE.compact} disabled={true}>
+            Disabled
+          </Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button size={SIZE.compact} shape={SHAPE.square}>
+            <CloudComponent />
+          </Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button size={SIZE.compact} shape={SHAPE.round}>
+            <CloudComponent />
+          </Button>
+        </ButtonRow>
+      </ButtonContainer>
+    );
+  },
+  [examples.BUTTON_WITH_ENHANCERS]: function Story3() {
+    return (
+      <ButtonContainer>
+        <ButtonRow>
+          <Button>Primary</Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button startEnhancer={CloudComponent}>Start Enhancer</Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button endEnhancer={CloudComponent}>End Enhancer</Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button startEnhancer={CloudComponent} endEnhancer={CloudComponent}>
+            Both Enhancers
+          </Button>
+        </ButtonRow>
+      </ButtonContainer>
+    );
+  },
+  [examples.BUTTON_COMPACT_WITH_ENHANCERS]: function Story4() {
+    return (
+      <ButtonContainer>
+        <ButtonRow>
+          <Button size={SIZE.compact}>Primary</Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button size={SIZE.compact} startEnhancer={CloudComponent}>
+            Start Enhancer
+          </Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button size={SIZE.compact} endEnhancer={CloudComponent}>
+            End Enhancer
+          </Button>
+        </ButtonRow>
+        <ButtonRow>
+          <Button
+            size={SIZE.compact}
+            startEnhancer={CloudComponent}
+            endEnhancer={CloudComponent}
+          >
+            Both Enhancers
+          </Button>
+        </ButtonRow>
+      </ButtonContainer>
+    );
+  },
+};
diff --git a/src/button/index.js b/src/button/index.js
new file mode 100644
index 000000000..8856f9f6e
--- /dev/null
+++ b/src/button/index.js
@@ -0,0 +1,12 @@
+/* eslint-disable flowtype/require-valid-file-annotation */
+export {default as Button} from './button';
+// Constants
+export {KIND, SIZE, SHAPE} from './constants';
+// Styled elements
+export {
+  BaseButton as StyledBaseButton,
+  StartEnhancer as StyledStartEnhancer,
+  EndEnhancer as StyledEndEnhancer,
+} from './styled-components';
+// Types
+export * from './types';
diff --git a/src/button/stories.js b/src/button/stories.js
new file mode 100644
index 000000000..99aca79ea
--- /dev/null
+++ b/src/button/stories.js
@@ -0,0 +1,21 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+/* global module */
+import {storiesOf} from '@storybook/react';
+import {withReadme} from 'storybook-readme';
+import examples from './examples';
+
+// $FlowFixMe
+import ButtonReadme from '../../rfcs/button-component.md';
+
+Object.entries(examples).forEach(([description, example]) =>
+  storiesOf('Button', module)
+    .addDecorator(withReadme(ButtonReadme))
+    // $FlowFixMe
+    .add(description, example),
+);
diff --git a/src/button/styled-components.js b/src/button/styled-components.js
new file mode 100644
index 000000000..6cd683996
--- /dev/null
+++ b/src/button/styled-components.js
@@ -0,0 +1,116 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+import {styled} from '../styles';
+import {KIND, SIZE, SHAPE} from './constants';
+
+export const BaseButton = styled(
+  'button',
+  ({$theme, $size, $kind, $shape}) => ({
+    ...$theme.typography[$size === SIZE.compact ? 'font200' : 'font300'],
+    display: 'flex',
+    alignItems: 'center',
+    justifyContent: 'space-between',
+    border: 'none',
+    borderRadius: $shape === SHAPE.round ? '50%' : $theme.borders.radius200,
+    textDecoration: 'none',
+    outline: 'none',
+    WebkitAppearance: 'none',
+    transitionProperty: 'background',
+    transitionDuration: $theme.animation.timing100,
+    transitionTimingFunction: $theme.animation.easeOutCurve,
+    cursor: 'pointer',
+    ':disabled': {
+      cursor: 'not-allowed',
+      backgroundColor: $theme.colors.mono300,
+      color: $theme.colors.mono600,
+    },
+    // Padding
+    ...($shape === SHAPE.round || $shape === SHAPE.square
+      ? {
+          paddingTop:
+            $theme.sizing[$size === SIZE.compact ? 'scale400' : 'scale500'],
+          paddingBottom:
+            $theme.sizing[$size === SIZE.compact ? 'scale400' : 'scale500'],
+          paddingLeft:
+            $theme.sizing[$size === SIZE.compact ? 'scale400' : 'scale500'],
+          paddingRight:
+            $theme.sizing[$size === SIZE.compact ? 'scale400' : 'scale500'],
+        }
+      : {
+          paddingTop:
+            $theme.sizing[$size === SIZE.compact ? 'scale200' : 'scale300'],
+          paddingBottom:
+            $theme.sizing[$size === SIZE.compact ? 'scale200' : 'scale300'],
+          paddingLeft: $theme.sizing.scale600,
+          paddingRight: $theme.sizing.scale600,
+        }),
+    // Kind style override
+    ...getStyleForKind({$theme, $kind}),
+  }),
+);
+
+export const EndEnhancer = styled('div', ({$theme}) => ({
+  display: 'flex',
+  marginLeft: $theme.sizing.scale500,
+}));
+
+export const StartEnhancer = styled('div', ({$theme}) => ({
+  display: 'flex',
+  marginRight: $theme.sizing.scale500,
+}));
+
+function getStyleForKind({$theme, $kind}) {
+  switch ($kind) {
+    case KIND.primary:
+      return {
+        color: $theme.colors.white,
+        backgroundColor: $theme.colors.primary,
+        ':hover:enabled': {
+          backgroundColor: $theme.colors.primary500,
+        },
+        ':active:enabled': {
+          backgroundColor: $theme.colors.primary600,
+        },
+      };
+    case KIND.secondary:
+      return {
+        color: $theme.colors.primary,
+        backgroundColor: $theme.colors.primary50,
+        ':hover:enabled': {
+          backgroundColor: $theme.colors.primary100,
+        },
+        ':active:enabled': {
+          backgroundColor: $theme.colors.primary200,
+        },
+      };
+    case KIND.tertiary:
+      return {
+        color: $theme.colors.primary,
+        backgroundColor: $theme.colors.mono200,
+        ':hover:enabled': {
+          backgroundColor: $theme.colors.mono400,
+        },
+        ':active:enabled': {
+          backgroundColor: $theme.colors.mono500,
+        },
+      };
+    case KIND.minimal:
+      return {
+        color: $theme.colors.primary,
+        backgroundColor: 'transparent',
+        ':hover:enabled': {
+          backgroundColor: $theme.colors.mono200,
+        },
+        ':active:enabled': {
+          backgroundColor: $theme.colors.mono400,
+        },
+      };
+    default:
+      return {};
+  }
+}
diff --git a/src/button/types.js b/src/button/types.js
new file mode 100644
index 000000000..db2916497
--- /dev/null
+++ b/src/button/types.js
@@ -0,0 +1,26 @@
+/*
+Copyright (c) 2018 Uber Technologies, Inc.
+
+This source code is licensed under the MIT license found in the
+LICENSE file in the root directory of this source tree.
+*/
+// @flow
+import {KIND, SIZE, SHAPE} from './constants';
+import type {OverrideT} from '../helpers/overrides';
+
+export type OverridesT = {
+  BaseButton?: OverrideT<*>,
+  StartEnhancer?: OverrideT<*>,
+  EndEnhancer?: OverrideT<*>,
+};
+
+export type ButtonPropsT = {
+  startEnhancer?: () => React$Node | React$Node,
+  endEnhancer?: () => React$Node | React$Node,
+  disabled?: boolean,
+  overrides?: OverridesT,
+  size?: $Keys<typeof SIZE>,
+  kind?: $Keys<typeof KIND>,
+  shape?: $Keys<typeof SHAPE>,
+  children?: React$Node,
+};


Test patch:
diff --git a/src/button/__tests__/__snapshots__/styled-components.test.js.snap b/src/button/__tests__/__snapshots__/styled-components.test.js.snap
new file mode 100644
index 000000000..18016fc39
--- /dev/null
+++ b/src/button/__tests__/__snapshots__/styled-components.test.js.snap
@@ -0,0 +1,927 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Button Styled Components BaseButton - minimal compact default: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.mono400",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.mono200",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "transparent",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font200.fontFamily",
+  "fontSize": "$theme.typography.font200.fontSize",
+  "fontWeight": "$theme.typography.font200.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font200.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale200",
+  "paddingLeft": "$theme.sizing.scale600",
+  "paddingRight": "$theme.sizing.scale600",
+  "paddingTop": "$theme.sizing.scale200",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - minimal compact round: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.mono400",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.mono200",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "transparent",
+  "border": "none",
+  "borderRadius": "50%",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font200.fontFamily",
+  "fontSize": "$theme.typography.font200.fontSize",
+  "fontWeight": "$theme.typography.font200.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font200.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale400",
+  "paddingLeft": "$theme.sizing.scale400",
+  "paddingRight": "$theme.sizing.scale400",
+  "paddingTop": "$theme.sizing.scale400",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - minimal compact square: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.mono400",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.mono200",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "transparent",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font200.fontFamily",
+  "fontSize": "$theme.typography.font200.fontSize",
+  "fontWeight": "$theme.typography.font200.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font200.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale400",
+  "paddingLeft": "$theme.sizing.scale400",
+  "paddingRight": "$theme.sizing.scale400",
+  "paddingTop": "$theme.sizing.scale400",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - minimal default default: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.mono400",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.mono200",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "transparent",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font300.fontFamily",
+  "fontSize": "$theme.typography.font300.fontSize",
+  "fontWeight": "$theme.typography.font300.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font300.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale300",
+  "paddingLeft": "$theme.sizing.scale600",
+  "paddingRight": "$theme.sizing.scale600",
+  "paddingTop": "$theme.sizing.scale300",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - minimal default round: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.mono400",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.mono200",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "transparent",
+  "border": "none",
+  "borderRadius": "50%",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font300.fontFamily",
+  "fontSize": "$theme.typography.font300.fontSize",
+  "fontWeight": "$theme.typography.font300.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font300.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale500",
+  "paddingLeft": "$theme.sizing.scale500",
+  "paddingRight": "$theme.sizing.scale500",
+  "paddingTop": "$theme.sizing.scale500",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - minimal default square: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.mono400",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.mono200",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "transparent",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font300.fontFamily",
+  "fontSize": "$theme.typography.font300.fontSize",
+  "fontWeight": "$theme.typography.font300.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font300.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale500",
+  "paddingLeft": "$theme.sizing.scale500",
+  "paddingRight": "$theme.sizing.scale500",
+  "paddingTop": "$theme.sizing.scale500",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - primary compact default: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.primary600",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.primary500",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.primary",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.white",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font200.fontFamily",
+  "fontSize": "$theme.typography.font200.fontSize",
+  "fontWeight": "$theme.typography.font200.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font200.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale200",
+  "paddingLeft": "$theme.sizing.scale600",
+  "paddingRight": "$theme.sizing.scale600",
+  "paddingTop": "$theme.sizing.scale200",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - primary compact round: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.primary600",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.primary500",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.primary",
+  "border": "none",
+  "borderRadius": "50%",
+  "color": "$theme.colors.white",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font200.fontFamily",
+  "fontSize": "$theme.typography.font200.fontSize",
+  "fontWeight": "$theme.typography.font200.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font200.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale400",
+  "paddingLeft": "$theme.sizing.scale400",
+  "paddingRight": "$theme.sizing.scale400",
+  "paddingTop": "$theme.sizing.scale400",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - primary compact square: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.primary600",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.primary500",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.primary",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.white",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font200.fontFamily",
+  "fontSize": "$theme.typography.font200.fontSize",
+  "fontWeight": "$theme.typography.font200.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font200.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale400",
+  "paddingLeft": "$theme.sizing.scale400",
+  "paddingRight": "$theme.sizing.scale400",
+  "paddingTop": "$theme.sizing.scale400",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - primary default default: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.primary600",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.primary500",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.primary",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.white",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font300.fontFamily",
+  "fontSize": "$theme.typography.font300.fontSize",
+  "fontWeight": "$theme.typography.font300.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font300.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale300",
+  "paddingLeft": "$theme.sizing.scale600",
+  "paddingRight": "$theme.sizing.scale600",
+  "paddingTop": "$theme.sizing.scale300",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - primary default round: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.primary600",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.primary500",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.primary",
+  "border": "none",
+  "borderRadius": "50%",
+  "color": "$theme.colors.white",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font300.fontFamily",
+  "fontSize": "$theme.typography.font300.fontSize",
+  "fontWeight": "$theme.typography.font300.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font300.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale500",
+  "paddingLeft": "$theme.sizing.scale500",
+  "paddingRight": "$theme.sizing.scale500",
+  "paddingTop": "$theme.sizing.scale500",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - primary default square: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.primary600",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.primary500",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.primary",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.white",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font300.fontFamily",
+  "fontSize": "$theme.typography.font300.fontSize",
+  "fontWeight": "$theme.typography.font300.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font300.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale500",
+  "paddingLeft": "$theme.sizing.scale500",
+  "paddingRight": "$theme.sizing.scale500",
+  "paddingTop": "$theme.sizing.scale500",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - secondary compact default: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.primary200",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.primary100",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.primary50",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font200.fontFamily",
+  "fontSize": "$theme.typography.font200.fontSize",
+  "fontWeight": "$theme.typography.font200.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font200.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale200",
+  "paddingLeft": "$theme.sizing.scale600",
+  "paddingRight": "$theme.sizing.scale600",
+  "paddingTop": "$theme.sizing.scale200",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - secondary compact round: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.primary200",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.primary100",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.primary50",
+  "border": "none",
+  "borderRadius": "50%",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font200.fontFamily",
+  "fontSize": "$theme.typography.font200.fontSize",
+  "fontWeight": "$theme.typography.font200.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font200.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale400",
+  "paddingLeft": "$theme.sizing.scale400",
+  "paddingRight": "$theme.sizing.scale400",
+  "paddingTop": "$theme.sizing.scale400",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - secondary compact square: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.primary200",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.primary100",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.primary50",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font200.fontFamily",
+  "fontSize": "$theme.typography.font200.fontSize",
+  "fontWeight": "$theme.typography.font200.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font200.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale400",
+  "paddingLeft": "$theme.sizing.scale400",
+  "paddingRight": "$theme.sizing.scale400",
+  "paddingTop": "$theme.sizing.scale400",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - secondary default default: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.primary200",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.primary100",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.primary50",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font300.fontFamily",
+  "fontSize": "$theme.typography.font300.fontSize",
+  "fontWeight": "$theme.typography.font300.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font300.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale300",
+  "paddingLeft": "$theme.sizing.scale600",
+  "paddingRight": "$theme.sizing.scale600",
+  "paddingTop": "$theme.sizing.scale300",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - secondary default round: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.primary200",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.primary100",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.primary50",
+  "border": "none",
+  "borderRadius": "50%",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font300.fontFamily",
+  "fontSize": "$theme.typography.font300.fontSize",
+  "fontWeight": "$theme.typography.font300.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font300.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale500",
+  "paddingLeft": "$theme.sizing.scale500",
+  "paddingRight": "$theme.sizing.scale500",
+  "paddingTop": "$theme.sizing.scale500",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - secondary default square: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.primary200",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.primary100",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.primary50",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font300.fontFamily",
+  "fontSize": "$theme.typography.font300.fontSize",
+  "fontWeight": "$theme.typography.font300.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font300.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale500",
+  "paddingLeft": "$theme.sizing.scale500",
+  "paddingRight": "$theme.sizing.scale500",
+  "paddingTop": "$theme.sizing.scale500",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - tertiary compact default: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.mono500",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.mono400",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.mono200",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font200.fontFamily",
+  "fontSize": "$theme.typography.font200.fontSize",
+  "fontWeight": "$theme.typography.font200.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font200.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale200",
+  "paddingLeft": "$theme.sizing.scale600",
+  "paddingRight": "$theme.sizing.scale600",
+  "paddingTop": "$theme.sizing.scale200",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - tertiary compact round: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.mono500",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.mono400",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.mono200",
+  "border": "none",
+  "borderRadius": "50%",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font200.fontFamily",
+  "fontSize": "$theme.typography.font200.fontSize",
+  "fontWeight": "$theme.typography.font200.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font200.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale400",
+  "paddingLeft": "$theme.sizing.scale400",
+  "paddingRight": "$theme.sizing.scale400",
+  "paddingTop": "$theme.sizing.scale400",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - tertiary compact square: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.mono500",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.mono400",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.mono200",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font200.fontFamily",
+  "fontSize": "$theme.typography.font200.fontSize",
+  "fontWeight": "$theme.typography.font200.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font200.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale400",
+  "paddingLeft": "$theme.sizing.scale400",
+  "paddingRight": "$theme.sizing.scale400",
+  "paddingTop": "$theme.sizing.scale400",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - tertiary default default: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.mono500",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.mono400",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.mono200",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font300.fontFamily",
+  "fontSize": "$theme.typography.font300.fontSize",
+  "fontWeight": "$theme.typography.font300.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font300.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale300",
+  "paddingLeft": "$theme.sizing.scale600",
+  "paddingRight": "$theme.sizing.scale600",
+  "paddingTop": "$theme.sizing.scale300",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - tertiary default round: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.mono500",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.mono400",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.mono200",
+  "border": "none",
+  "borderRadius": "50%",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font300.fontFamily",
+  "fontSize": "$theme.typography.font300.fontSize",
+  "fontWeight": "$theme.typography.font300.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font300.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale500",
+  "paddingLeft": "$theme.sizing.scale500",
+  "paddingRight": "$theme.sizing.scale500",
+  "paddingTop": "$theme.sizing.scale500",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components BaseButton - tertiary default square: correct styles 1`] = `
+Object {
+  ":active:enabled": Object {
+    "backgroundColor": "$theme.colors.mono500",
+  },
+  ":disabled": Object {
+    "backgroundColor": "$theme.colors.mono300",
+    "color": "$theme.colors.mono600",
+    "cursor": "not-allowed",
+  },
+  ":hover:enabled": Object {
+    "backgroundColor": "$theme.colors.mono400",
+  },
+  "WebkitAppearance": "none",
+  "alignItems": "center",
+  "backgroundColor": "$theme.colors.mono200",
+  "border": "none",
+  "borderRadius": "$theme.borders.radius200",
+  "color": "$theme.colors.primary",
+  "cursor": "pointer",
+  "display": "flex",
+  "fontFamily": "$theme.typography.font300.fontFamily",
+  "fontSize": "$theme.typography.font300.fontSize",
+  "fontWeight": "$theme.typography.font300.fontWeight",
+  "justifyContent": "space-between",
+  "lineHeight": "$theme.typography.font300.lineHeight",
+  "outline": "none",
+  "paddingBottom": "$theme.sizing.scale500",
+  "paddingLeft": "$theme.sizing.scale500",
+  "paddingRight": "$theme.sizing.scale500",
+  "paddingTop": "$theme.sizing.scale500",
+  "textDecoration": "none",
+  "transitionDuration": "$theme.animation.timing100",
+  "transitionProperty": "background",
+  "transitionTimingFunction": "$theme.animation.easeOutCurve",
+}
+`;
+
+exports[`Button Styled Components EndEnhancer - basic render: correct styles 1`] = `
+Object {
+  "display": "flex",
+  "marginLeft": "$theme.sizing.scale500",
+}
+`;
+
+exports[`Button Styled Components StartEnhancer - basic render: correct styles 1`] = `
+Object {
+  "display": "flex",
+  "marginRight": "$theme.sizing.scale500",
+}
+`;
diff --git a/src/button/__tests__/button.test.js b/src/button/__tests__/button.test.js
new file mode 100644
index 000000000..9cde1609e
--- /dev/null
+++ b/src/button/__tests__/button.test.js
@@ -0,0 +1,38 @@
+/* eslint-disable flowtype/require-valid-file-annotation, react/prop-types */
+import React from 'react';
+import {mount} from 'enzyme';
+import {StartEnhancer, EndEnhancer} from '../styled-components';
+import Button from '../button';
+
+describe('Button Component', () => {
+  test('basic render', () => {
+    const component = mount(<Button />);
+
+    expect(component.find(StartEnhancer)).not.toExist();
+    expect(component.find(EndEnhancer)).not.toExist();
+
+    component.setProps({
+      startEnhancer: 'start',
+      endEnhancer: 'end',
+    });
+
+    expect(component.find(StartEnhancer)).toExist();
+    expect(component.find(EndEnhancer)).toExist();
+  });
+
+  test('renders with components overrides', () => {
+    const NewStartEnhancer = () => <div />;
+
+    const props = {
+      startEnhancer: 'start',
+      overrides: {
+        StartEnhancer: NewStartEnhancer,
+      },
+    };
+
+    const component = mount(<Button {...props} />);
+
+    expect(component.find(StartEnhancer)).not.toExist();
+    expect(component.find(NewStartEnhancer)).toExist();
+  });
+});
diff --git a/src/button/__tests__/styled-components.test.js b/src/button/__tests__/styled-components.test.js
new file mode 100644
index 000000000..8377ed4ec
--- /dev/null
+++ b/src/button/__tests__/styled-components.test.js
@@ -0,0 +1,50 @@
+/* eslint-disable flowtype/require-valid-file-annotation, react/prop-types */
+import React from 'react';
+import {shallow} from 'enzyme';
+import {BaseButton, StartEnhancer, EndEnhancer} from '../styled-components';
+import {KIND, SIZE, SHAPE} from '../constants';
+
+function makeTest({
+  title,
+  component: Component,
+  props = {},
+  children = null,
+  snapshotName = 'correct styles',
+}) {
+  test(title, () => {
+    const shallowed = shallow(<Component {...props}>{children}</Component>);
+    expect(shallowed.instance().getStyles()).toMatchSnapshot(snapshotName);
+  });
+}
+
+const allKinds = Object.values(KIND);
+const allSizes = Object.values(SIZE);
+const allShapes = Object.values(SHAPE);
+
+describe('Button Styled Components', () => {
+  allKinds.forEach(kind => {
+    allSizes.forEach(size => {
+      allShapes.forEach(shape => {
+        makeTest({
+          title: `BaseButton - ${kind} ${size} ${shape}`,
+          component: BaseButton,
+          props: {
+            $kind: kind,
+            $shape: shape,
+            $size: size,
+          },
+        });
+      });
+    });
+  });
+
+  makeTest({
+    title: 'StartEnhancer - basic render',
+    component: StartEnhancer,
+  });
+
+  makeTest({
+    title: 'EndEnhancer - basic render',
+    component: EndEnhancer,
+  });
+});