Repository: mapbox/mr-ui
Pull request #40 (2018-08-15 16:42:40)

Update Icon
Changelog explains the changes. Here's a screenshot of the docs:

![screen shot 2018-08-15 at 9 38 34 am](https://user-images.githubusercontent.com/628431/44160519-8223d300-a06f-11e8-86f8-7fed7771c238.png)

@samanpwbb do you think these changes will work? For your review when you're able.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 003b74a..86ac4e5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -38,6 +38,12 @@
   - [feature] Add `padding`, `alert`, `primaryAction`, `secondaryAction`, and `tertiaryAction` props.
   - [fix] Modals taller than the viewport will now show padding above them: the browser will not longer automatically scroll down to the top of the modal.
   - [fix] Update `react-aria-modal` to get some bug fixes and focus-management improvements.
+- **Icon**
+  - 🚨 [breaking change] Remove `themeIcon` prop.
+  - 🚨 [breaking change] Arbitrary props will not be passed through to the `<svg>`. Use `passthroughProps`.
+  - [feature] Add `passthroughProps` prop.
+  - [feature] Add `size` prop.
+  - [fix] If `inline: true`, the corresponding style adjustment will be performed after updates as well as mounting.
 
 ## 0.2.1
 
diff --git a/src/components/icon/examples/icon-example-basic.js b/src/components/icon/examples/icon-a.js
similarity index 90%
rename from src/components/icon/examples/icon-example-basic.js
rename to src/components/icon/examples/icon-a.js
index 9258a07..606a5af 100644
--- a/src/components/icon/examples/icon-example-basic.js
+++ b/src/components/icon/examples/icon-a.js
@@ -1,5 +1,5 @@
 /*
-Basic.
+Basic Icon usage.
 */
 import React from 'react';
 import Icon from '../icon';
diff --git a/src/components/icon/examples/icon-b.js b/src/components/icon/examples/icon-b.js
new file mode 100644
index 0000000..8493acb
--- /dev/null
+++ b/src/components/icon/examples/icon-b.js
@@ -0,0 +1,39 @@
+/*
+Icons rendered inline with multi-line text.
+*/
+import React from 'react';
+import Icon from '../icon';
+
+export default class Example extends React.Component {
+  render() {
+    return (
+      <div style={{ lineHeight: '24px' }}>
+        The last thing you want in your kitchen is a{' '}
+        <span className="inline-block color-red">
+          <Icon name="flame" inline={true} /> fire
+        </span>{' '}
+        even though there is{' '}
+        <span className="inline-block color-blue">
+          <Icon name="water" inline={true} /> water
+        </span>{' '}
+        nearby. The last thing you want in your kitchen is a{' '}
+        <span className="inline-block color-red">
+          <Icon name="flame" inline={true} /> fire
+        </span>{' '}
+        even though there is{' '}
+        <span className="inline-block color-blue">
+          <Icon name="water" inline={true} /> water
+        </span>{' '}
+        nearby. The last thing you want in your kitchen is a{' '}
+        <span className="inline-block color-red">
+          <Icon name="flame" inline={true} /> fire
+        </span>{' '}
+        even though there is{' '}
+        <span className="inline-block color-blue">
+          <Icon name="water" inline={true} /> water
+        </span>{' '}
+        nearby.
+      </div>
+    );
+  }
+}
diff --git a/src/components/icon/examples/icon-example-options.js b/src/components/icon/examples/icon-example-options.js
deleted file mode 100644
index 54e7fcc..0000000
--- a/src/components/icon/examples/icon-example-options.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
-Options.
-*/
-import React from 'react';
-import Icon from '../icon';
-
-export default class Example extends React.Component {
-  render() {
-    return (
-      <Icon
-        name="antialias"
-        theme={{
-          icon: 'icon--l'
-        }}
-      />
-    );
-  }
-}
diff --git a/src/components/icon/icon.js b/src/components/icon/icon.js
index 52c1ed2..21869b9 100644
--- a/src/components/icon/icon.js
+++ b/src/components/icon/icon.js
@@ -1,29 +1,36 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import omit from '../utils/omit';
 import getWindow from '../utils/get-window';
+import shallowEqualObjects from '../utils/shallow-equal-objects';
 
-export default class Icon extends React.PureComponent {
-  // If you change propTypes, make sure to change propNames.
-  static propTypes = {
-    name: PropTypes.string.isRequired,
-    themeIcon: PropTypes.string,
-    inline: PropTypes.bool
-  };
-  static propNames = ['name', 'themeIcon', 'inline'];
+/**
+ * Display an Assembly icon.
+ *
+ * Besides providing a convenient shortcut, this component does the following:
+ *
+ * - Sets some accessibility props.
+ * - Provides an `inline` mode that automatically sizes icons to match their
+ *   surrounding text.
+ */
+export default class Icon extends React.Component {
+  componentDidMount() {
+    this.setHeight();
+  }
 
-  static defaultProps = {
-    inline: false
-  };
+  shouldComponentUpdate(nextProps) {
+    return !shallowEqualObjects(this.props, nextProps, ['passthroughProps']);
+  }
 
-  componentDidMount() {
+  componentDidUpdate() {
+    this.setHeight();
+  }
+
+  setHeight() {
     if (this.props.inline && this.iconElement) {
-      // Match height of icon element to line height, ensuring inlined icon
-      // doesn't displace text line height, is vertically centered,
-      // and wraps along with multi-line text.
-      this.iconElement.style.height = getWindow().getComputedStyle(
-        this.iconElement
-      )['line-height'];
+      const lineHeight = getWindow().getComputedStyle(this.iconElement)[
+        'line-height'
+      ];
+      this.iconElement.style.height = lineHeight;
     }
   }
 
@@ -35,19 +42,16 @@ export default class Icon extends React.PureComponent {
     const { props } = this;
 
     let iconClasses = 'events-none icon';
-    if (props.themeIcon !== undefined) iconClasses += ` ${props.themeIcon}`;
-
     if (props.inline) {
       iconClasses += ' inline-block align-t';
     }
 
-    const extraProps = omit(props, Icon.propNames.concat('style'));
-    const svgStyle = props.style || {};
-    if (!svgStyle.width) {
-      svgStyle.width = 18;
+    const svgStyle = props.passthroughProps.style || {};
+    if (!svgStyle.width && props.size) {
+      svgStyle.width = props.size;
     }
-    if (!svgStyle.height) {
-      svgStyle.height = 18;
+    if (!svgStyle.height && props.size) {
+      svgStyle.height = props.size;
     }
 
     const iconContent = (
@@ -56,8 +60,8 @@ export default class Icon extends React.PureComponent {
         role="presentation"
         focusable="false"
         className={iconClasses}
+        {...props.passthroughProps}
         style={svgStyle}
-        {...extraProps}
       >
         <use
           xmlnsXlink="http://www.w3.org/1999/xlink"
@@ -69,3 +73,46 @@ export default class Icon extends React.PureComponent {
     return iconContent;
   }
 }
+
+Icon.propTypes = {
+  /**
+   * The name of the [Assembly icon](https://www.mapbox.com/assembly/icons/) that
+   * you want to display.
+   */
+  name: PropTypes.string.isRequired,
+  /**
+   * The width and height of the icon. All icons fill up a square space,
+   * so this value will be applied to both width and height.
+   *
+   * If `inline: true`, the technical height will be controlled by the
+   * line-height of the container, but the appearance of the icon will still
+   * be in accordance with your `size` value (because it's limited by the
+   * width).
+   */
+  size: PropTypes.number,
+  /**
+   * If `true`, the icon will be adjusted after mounting so that its height
+   * matches the line-height of its container. The result of this is that
+   * the icon will not displace the text's established line-height and
+   * will be vertically centered with the text alongside it.
+   *
+   * This is most useful when you are inserting the icon within multiline text,
+   * so you can't use a flexbox layout to vertically center the icon and text.
+   *
+   * Be aware that there are edge cases that can cause problems with this
+   * setting. For example, it won't work well if you don't have a `line-height`
+   * set to a pixel value, or if there are dynamic adjustments to the
+   * line-height.
+   */
+  inline: PropTypes.bool,
+  /**
+   * Props to pass directly to the `<svg>` element.
+   */
+  passthroughProps: PropTypes.object
+};
+
+Icon.defaultProps = {
+  inline: false,
+  passthroughProps: {},
+  size: 18
+};


Test patch:
diff --git a/src/components/chevronous-text/__tests__/__snapshots__/chevronous-text.test.js.snap b/src/components/chevronous-text/__tests__/__snapshots__/chevronous-text.test.js.snap
index 8f25dc0..300865c 100644
--- a/src/components/chevronous-text/__tests__/__snapshots__/chevronous-text.test.js.snap
+++ b/src/components/chevronous-text/__tests__/__snapshots__/chevronous-text.test.js.snap
@@ -11,6 +11,8 @@ exports[`ChevronousText additional icon classes renders 1`] = `
     <Icon
       inline={true}
       name="chevron-right"
+      passthroughProps={Object {}}
+      size={18}
       themeIcon="color-blue"
     />
   </span>
@@ -28,6 +30,8 @@ exports[`ChevronousText basic renders 1`] = `
     <Icon
       inline={true}
       name="chevron-right"
+      passthroughProps={Object {}}
+      size={18}
     />
   </span>
 </span>
diff --git a/src/components/control-checkbox-set/__tests__/__snapshots__/control-checkbox-set.test.js.snap b/src/components/control-checkbox-set/__tests__/__snapshots__/control-checkbox-set.test.js.snap
index 1566f44..2d4af64 100644
--- a/src/components/control-checkbox-set/__tests__/__snapshots__/control-checkbox-set.test.js.snap
+++ b/src/components/control-checkbox-set/__tests__/__snapshots__/control-checkbox-set.test.js.snap
@@ -43,6 +43,8 @@ exports[`ControlCheckbox all options renders 1`] = `
           <Icon
             inline={false}
             name="check"
+            passthroughProps={Object {}}
+            size={18}
           />
         </div>
         <span>
@@ -69,6 +71,8 @@ exports[`ControlCheckbox all options renders 1`] = `
           <Icon
             inline={false}
             name="check"
+            passthroughProps={Object {}}
+            size={18}
           />
         </div>
         <span>
@@ -95,6 +99,8 @@ exports[`ControlCheckbox all options renders 1`] = `
           <Icon
             inline={false}
             name="check"
+            passthroughProps={Object {}}
+            size={18}
           />
         </div>
         <span>
@@ -142,6 +148,8 @@ exports[`ControlCheckbox basic onChange gets called with input id and value 1`]
           <Icon
             inline={false}
             name="check"
+            passthroughProps={Object {}}
+            size={18}
           />
         </div>
         Option 1
@@ -166,6 +174,8 @@ exports[`ControlCheckbox basic onChange gets called with input id and value 1`]
           <Icon
             inline={false}
             name="check"
+            passthroughProps={Object {}}
+            size={18}
           />
         </div>
         Option 2
@@ -211,6 +221,8 @@ exports[`ControlCheckbox basic renders 1`] = `
           <Icon
             inline={false}
             name="check"
+            passthroughProps={Object {}}
+            size={18}
           />
         </div>
         Option 1
@@ -235,6 +247,8 @@ exports[`ControlCheckbox basic renders 1`] = `
           <Icon
             inline={false}
             name="check"
+            passthroughProps={Object {}}
+            size={18}
           />
         </div>
         Option 2
@@ -280,6 +294,8 @@ exports[`ControlCheckbox disabled renders 1`] = `
           <Icon
             inline={false}
             name="check"
+            passthroughProps={Object {}}
+            size={18}
           />
         </div>
         Option 1
@@ -305,6 +321,8 @@ exports[`ControlCheckbox disabled renders 1`] = `
           <Icon
             inline={false}
             name="check"
+            passthroughProps={Object {}}
+            size={18}
           />
         </div>
         Option 2
diff --git a/src/components/control-file/__tests__/__snapshots__/control-file.test.js.snap b/src/components/control-file/__tests__/__snapshots__/control-file.test.js.snap
index d350170..b0d16a3 100644
--- a/src/components/control-file/__tests__/__snapshots__/control-file.test.js.snap
+++ b/src/components/control-file/__tests__/__snapshots__/control-file.test.js.snap
@@ -36,6 +36,8 @@ exports[`ControlFile all options renders 1`] = `
           <Icon
             inline={false}
             name="harddrive"
+            passthroughProps={Object {}}
+            size={18}
             themeIcon="mr6 inline-block align-middle"
           />
           Select an image
@@ -98,6 +100,8 @@ exports[`ControlFile basic receives an array of one file as value, displaying it
           <Icon
             inline={false}
             name="harddrive"
+            passthroughProps={Object {}}
+            size={18}
             themeIcon="mr6 inline-block align-middle"
           />
           bon jovi.mp3
@@ -146,6 +150,8 @@ exports[`ControlFile basic receives an array of one file as value, displaying it
           <Icon
             inline={false}
             name="trash"
+            passthroughProps={Object {}}
+            size={18}
           />
         </button>
       </Tooltip>
@@ -184,6 +190,8 @@ exports[`ControlFile basic renders 1`] = `
           <Icon
             inline={false}
             name="harddrive"
+            passthroughProps={Object {}}
+            size={18}
             themeIcon="mr6 inline-block align-middle"
           />
           Select a file
@@ -242,6 +250,8 @@ exports[`ControlFile disabled renders 1`] = `
           <Icon
             inline={false}
             name="harddrive"
+            passthroughProps={Object {}}
+            size={18}
             themeIcon="mr6 inline-block align-middle"
           />
           Select a file
@@ -300,6 +310,8 @@ exports[`ControlFile multiple receives an array of files as value, displaying th
           <Icon
             inline={false}
             name="harddrive"
+            passthroughProps={Object {}}
+            size={18}
             themeIcon="mr6 inline-block align-middle"
           />
           bon jovi.mp3, aerosmith.mp3
@@ -349,6 +361,8 @@ exports[`ControlFile multiple receives an array of files as value, displaying th
           <Icon
             inline={false}
             name="trash"
+            passthroughProps={Object {}}
+            size={18}
           />
         </button>
       </Tooltip>
diff --git a/src/components/control-text/__tests__/__snapshots__/control-text.test.js.snap b/src/components/control-text/__tests__/__snapshots__/control-text.test.js.snap
index e073629..e468fee 100644
--- a/src/components/control-text/__tests__/__snapshots__/control-text.test.js.snap
+++ b/src/components/control-text/__tests__/__snapshots__/control-text.test.js.snap
@@ -60,6 +60,8 @@ exports[`ControlText all options renders 1`] = `
         <Icon
           inline={false}
           name="alert"
+          passthroughProps={Object {}}
+          size={18}
           themeIcon="cursor-pointer"
         />
       </span>
@@ -217,6 +219,8 @@ exports[`ControlText error inline option renders 1`] = `
         <Icon
           inline={false}
           name="alert"
+          passthroughProps={Object {}}
+          size={18}
           themeIcon="cursor-pointer"
         />
       </span>
diff --git a/src/components/copy-button/__tests__/__snapshots__/copy-button.test.js.snap b/src/components/copy-button/__tests__/__snapshots__/copy-button.test.js.snap
index ee01717..ecfdd9e 100644
--- a/src/components/copy-button/__tests__/__snapshots__/copy-button.test.js.snap
+++ b/src/components/copy-button/__tests__/__snapshots__/copy-button.test.js.snap
@@ -22,6 +22,8 @@ exports[`CopyButton Defaults changes state on click 1`] = `
     <Icon
       inline={false}
       name="check"
+      passthroughProps={Object {}}
+      size={18}
     />
     <Popover
       accessibleTitle={null}
@@ -71,6 +73,8 @@ exports[`CopyButton Defaults changes state on click 2`] = `
     <Icon
       inline={false}
       name="clipboard"
+      passthroughProps={Object {}}
+      size={18}
     />
   </button>
 </Tooltip>
@@ -98,6 +102,8 @@ exports[`CopyButton Defaults renders as expected 1`] = `
     <Icon
       inline={false}
       name="clipboard"
+      passthroughProps={Object {}}
+      size={18}
     />
   </button>
 </Tooltip>
@@ -126,6 +132,8 @@ exports[`CopyButton all props changes state on click 1`] = `
     <Icon
       inline={false}
       name="check"
+      passthroughProps={Object {}}
+      size={18}
     />
     <Popover
       accessibleTitle={null}
@@ -176,6 +184,8 @@ exports[`CopyButton all props changes state on click 2`] = `
     <Icon
       inline={false}
       name="clipboard"
+      passthroughProps={Object {}}
+      size={18}
     />
   </button>
 </Tooltip>
@@ -204,6 +214,8 @@ exports[`CopyButton all props renders as expected 1`] = `
     <Icon
       inline={false}
       name="clipboard"
+      passthroughProps={Object {}}
+      size={18}
     />
   </button>
 </Tooltip>
diff --git a/src/components/icon-text/__tests__/__snapshots__/icon-text.test.js.snap b/src/components/icon-text/__tests__/__snapshots__/icon-text.test.js.snap
index fcfad5f..3e205ea 100644
--- a/src/components/icon-text/__tests__/__snapshots__/icon-text.test.js.snap
+++ b/src/components/icon-text/__tests__/__snapshots__/icon-text.test.js.snap
@@ -15,6 +15,8 @@ exports[`icon after renders as expected 1`] = `
     <Icon
       inline={false}
       name="chevron-right"
+      passthroughProps={Object {}}
+      size={18}
     />
   </span>
 </span>
@@ -30,6 +32,8 @@ exports[`icon before renders as expected 1`] = `
     <Icon
       inline={false}
       name="clipboard"
+      passthroughProps={Object {}}
+      size={18}
     />
   </span>
   <span
@@ -50,6 +54,8 @@ exports[`icons on both sides, including a non-string one renders as expected 1`]
     <Icon
       inline={false}
       name="check"
+      passthroughProps={Object {}}
+      size={18}
     />
   </span>
   <span
@@ -63,6 +69,8 @@ exports[`icons on both sides, including a non-string one renders as expected 1`]
     <Icon
       inline={false}
       name="github"
+      passthroughProps={Object {}}
+      size={18}
     />
   </span>
 </span>
@@ -78,6 +86,8 @@ exports[`large spacing renders as expected 1`] = `
     <Icon
       inline={false}
       name="check"
+      passthroughProps={Object {}}
+      size={18}
     />
   </span>
   <span
diff --git a/src/components/icon/__tests__/__snapshots__/icon.test.js.snap b/src/components/icon/__tests__/__snapshots__/icon.test.js.snap
index 75bac8f..a5a72c1 100644
--- a/src/components/icon/__tests__/__snapshots__/icon.test.js.snap
+++ b/src/components/icon/__tests__/__snapshots__/icon.test.js.snap
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`Icon basic renders 1`] = `
+exports[`basic renders as expected 1`] = `
 <svg
   className="events-none icon"
   focusable="false"
@@ -19,9 +19,9 @@ exports[`Icon basic renders 1`] = `
 </svg>
 `;
 
-exports[`Icon extra props renders 1`] = `
+exports[`extra props renders as expected 1`] = `
 <svg
-  className="events-none icon color-red"
+  className="events-none icon"
   data-test="alert-icon"
   focusable="false"
   role="presentation"
@@ -39,9 +39,9 @@ exports[`Icon extra props renders 1`] = `
 </svg>
 `;
 
-exports[`Icon inline renders 1`] = `
+exports[`inline renders as expected 1`] = `
 <svg
-  className="events-none icon mr3 color-green inline-block align-t"
+  className="events-none icon inline-block align-t"
   focusable="false"
   role="presentation"
   style={
@@ -58,16 +58,16 @@ exports[`Icon inline renders 1`] = `
 </svg>
 `;
 
-exports[`Icon special size with classes renders 1`] = `
+exports[`special size applied with a style renders as expected 1`] = `
 <svg
-  className="events-none icon h36 w36"
+  className="events-none icon"
   data-test="alert-icon"
   focusable="false"
   role="presentation"
   style={
     Object {
-      "height": 18,
-      "width": 18,
+      "height": 36,
+      "width": 36,
     }
   }
 >
@@ -78,10 +78,9 @@ exports[`Icon special size with classes renders 1`] = `
 </svg>
 `;
 
-exports[`Icon special size with styles renders 1`] = `
+exports[`special size renders as expected 1`] = `
 <svg
   className="events-none icon"
-  data-test="alert-icon"
   focusable="false"
   role="presentation"
   style={
diff --git a/src/components/icon/__tests__/icon-test-cases.js b/src/components/icon/__tests__/icon-test-cases.js
index 8ec3b7d..f463efb 100644
--- a/src/components/icon/__tests__/icon-test-cases.js
+++ b/src/components/icon/__tests__/icon-test-cases.js
@@ -16,39 +16,49 @@ testCases.extraProps = {
   component: Icon,
   props: {
     name: 'alert',
-    'data-test': 'alert-icon',
-    themeIcon: 'color-red'
+    passthroughProps: {
+      'data-test': 'alert-icon'
+    }
   }
 };
 
-testCases.specialSizeClasses = {
-  description: 'special size with classes',
+testCases.specialSize = {
+  description: 'special size',
   component: Icon,
   props: {
     name: 'alert',
-    'data-test': 'alert-icon',
-    themeIcon: 'h36 w36'
+    size: 36
   }
 };
 
 testCases.specialSizeStyle = {
-  description: 'special size with styles',
+  description: 'special size applied with a style',
   component: Icon,
   props: {
     name: 'alert',
-    'data-test': 'alert-icon',
-    style: { height: 36, width: 36 }
+    passthroughProps: {
+      'data-test': 'alert-icon',
+      style: { height: 36, width: 36 }
+    }
   }
 };
 
 testCases.inline = {
-  noDisplay: true,
   description: 'inline',
   component: Icon,
+  props: {
+    name: 'check',
+    inline: true
+  }
+};
+
+testCases.inlineWithSize = {
+  description: 'inline with size',
+  component: Icon,
   props: {
     name: 'check',
     inline: true,
-    themeIcon: 'mr3 color-green'
+    size: 45
   }
 };
 
@@ -56,7 +66,21 @@ testCases.inlineSmallDisplay = {
   description: 'inline txt-s',
   element: (
     <div className="txt-s">
-      <Icon name="check" themeIcon="mr3 color-green" inline={true} />
+      <span className="mr3 color-green">
+        <Icon name="check" inline={true} />
+      </span>
+      You did it
+    </div>
+  )
+};
+
+testCases.inlineLargeText = {
+  description: 'inline txt-xl',
+  element: (
+    <div className="txt-xl">
+      <span className="mr3 color-green">
+        <Icon name="check" inline={true} />
+      </span>
       You did it
     </div>
   )
@@ -66,10 +90,23 @@ testCases.inlineLargeDisplay = {
   description: 'inline txt-xl',
   element: (
     <div className="txt-xl">
-      <Icon name="check" themeIcon="mr3 color-green" inline={true} />
+      <span className="mr3 color-green">
+        <Icon name="check" inline={true} size={45} />
+      </span>
       You did it
     </div>
   )
 };
 
+testCases.inlineMultiline = {
+  description: 'inline txt-xl',
+  element: (
+    <div>
+      The last thing you want in your kitchen is a{' '}
+      <Icon name="flame" inline={true} /> fire even though there is{' '}
+      <Icon name="water" inline={true} /> water nearby.
+    </div>
+  )
+};
+
 export { testCases };
diff --git a/src/components/icon/__tests__/icon.test.js b/src/components/icon/__tests__/icon.test.js
index 3538dcf..6ffe176 100644
--- a/src/components/icon/__tests__/icon.test.js
+++ b/src/components/icon/__tests__/icon.test.js
@@ -7,85 +7,85 @@ jest.mock('../../utils/get-window', () => {
   return jest.fn();
 });
 
-describe('Icon', () => {
-  let testCase;
-  let wrapper;
+let testCase;
+let wrapper;
 
-  describe(testCases.basic.description, () => {
-    beforeEach(() => {
-      testCase = testCases.basic;
-    });
+describe(testCases.basic.description, () => {
+  beforeEach(() => {
+    testCase = testCases.basic;
+  });
+
+  test('renders as expected', () => {
+    const wrapper = shallow(
+      React.createElement(testCase.component, testCase.props)
+    );
+    expect(wrapper).toMatchSnapshot();
+  });
+});
 
-    test('renders', () => {
-      const wrapper = shallow(
-        React.createElement(testCase.component, testCase.props)
-      );
-      expect(wrapper).toMatchSnapshot();
-    });
+describe(testCases.extraProps.description, () => {
+  beforeEach(() => {
+    testCase = testCases.extraProps;
+    wrapper = shallow(React.createElement(testCase.component, testCase.props));
   });
 
-  describe(testCases.extraProps.description, () => {
-    beforeEach(() => {
-      testCase = testCases.extraProps;
-      wrapper = shallow(
-        React.createElement(testCase.component, testCase.props)
-      );
-    });
+  test('renders as expected', () => {
+    expect(wrapper).toMatchSnapshot();
+  });
+});
 
-    test('renders', () => {
-      expect(wrapper).toMatchSnapshot();
-    });
+describe(testCases.specialSize.description, () => {
+  beforeEach(() => {
+    testCase = testCases.specialSize;
+    wrapper = shallow(React.createElement(testCase.component, testCase.props));
   });
 
-  describe(testCases.specialSizeClasses.description, () => {
-    beforeEach(() => {
-      testCase = testCases.specialSizeClasses;
-      wrapper = shallow(
-        React.createElement(testCase.component, testCase.props)
-      );
-    });
+  test('renders as expected', () => {
+    expect(wrapper).toMatchSnapshot();
+  });
+});
 
-    test('renders', () => {
-      expect(wrapper).toMatchSnapshot();
-    });
+describe(testCases.specialSizeStyle.description, () => {
+  beforeEach(() => {
+    testCase = testCases.specialSizeStyle;
+    wrapper = shallow(React.createElement(testCase.component, testCase.props));
   });
 
-  describe(testCases.specialSizeStyle.description, () => {
-    beforeEach(() => {
-      testCase = testCases.specialSizeStyle;
-      wrapper = shallow(
-        React.createElement(testCase.component, testCase.props)
-      );
-    });
+  test('renders as expected', () => {
+    expect(wrapper).toMatchSnapshot();
+  });
+});
 
-    test('renders', () => {
-      expect(wrapper).toMatchSnapshot();
-    });
+describe(testCases.inline.description, () => {
+  beforeEach(() => {
+    testCase = testCases.inline;
+    const mockWindow = {
+      getComputedStyle: jest.fn(() => ({
+        'line-height': '14px'
+      }))
+    };
+    getWindow.mockReturnValueOnce(mockWindow);
   });
 
-  describe(testCases.inline.description, () => {
-    beforeEach(() => {
-      testCase = testCases.inline;
-      const mockWindow = {
-        getComputedStyle: jest.fn(() => ({
-          'line-height': '14px'
-        }))
-      };
-      getWindow.mockReturnValueOnce(mockWindow);
-    });
+  test('renders as expected', () => {
+    const wrapper = shallow(
+      React.createElement(testCase.component, testCase.props)
+    );
+    expect(wrapper).toMatchSnapshot();
+  });
 
-    test('renders', () => {
-      const wrapper = shallow(
-        React.createElement(testCase.component, testCase.props)
-      );
-      expect(wrapper).toMatchSnapshot();
-    });
+  test('after mount, adjusts height to match line-height', () => {
+    const wrapper = mount(
+      React.createElement(testCase.component, testCase.props)
+    );
+    expect(wrapper.instance().iconElement.style.height).toBe('14px');
+  });
 
-    test('after mount, adjusts height to match line-height', () => {
-      const wrapper = mount(
-        React.createElement(testCase.component, testCase.props)
-      );
-      expect(wrapper.instance().iconElement.style.height).toBe('14px');
-    });
+  test('after update, adjusts height to match line-height', () => {
+    const wrapper = mount(
+      React.createElement(testCase.component, testCase.props)
+    );
+    wrapper.setProps({ size: 45 });
+    expect(wrapper.instance().iconElement.style.height).toBe('14px');
   });
 });
diff --git a/src/components/modal/__tests__/__snapshots__/modal.test.js.snap b/src/components/modal/__tests__/__snapshots__/modal.test.js.snap
index b4b4649..56f8edc 100644
--- a/src/components/modal/__tests__/__snapshots__/modal.test.js.snap
+++ b/src/components/modal/__tests__/__snapshots__/modal.test.js.snap
@@ -49,6 +49,8 @@ exports[`Modal No fixed width, display only renders 1`] = `
           <Icon
             inline={false}
             name="close"
+            passthroughProps={Object {}}
+            size={18}
           />
         </button>
       </Tooltip>
@@ -116,6 +118,8 @@ exports[`Modal all options renders 1`] = `
           <Icon
             inline={false}
             name="close"
+            passthroughProps={Object {}}
+            size={18}
           />
         </button>
       </Tooltip>
@@ -198,6 +202,8 @@ exports[`Modal basic default renders 1`] = `
           <Icon
             inline={false}
             name="close"
+            passthroughProps={Object {}}
+            size={18}
           />
         </button>
       </Tooltip>
@@ -267,6 +273,8 @@ exports[`Modal basic small renders 1`] = `
           <Icon
             inline={false}
             name="close"
+            passthroughProps={Object {}}
+            size={18}
           />
         </button>
       </Tooltip>