Repository: mui/material-ui (TypeScript) — Bug Fix

Issue:
[Avatar] Avatar does not apply colorDefault class when child is 0
The Avatar component does not apply its colorDefault class when its children are a falsey value, including 0
<!--
    Thank you very much for contributing to Material-UI by creating an issue! ❤️
    To avoid duplicate issues we ask you to check off the following list.
-->

<!-- Checked checkbox should look like this: [x] -->
- [X] This is not a v0.x issue. <!-- (v0.x is no longer maintained) -->
- [X] I have searched the [issues](https://github.com/mui-org/material-ui/issues) of this repository and believe that this is not a duplicate.

## Expected Behavior 🤔
<!---
    Describe what should happen.
-->
Avatar should render its defaultColor class with the child 0 the same as it does with "0"
<img width="377" alt="screen shot 2018-11-30 at 5 33 15 am" src="https://user-images.githubusercontent.com/32465602/49287483-41f03100-f463-11e8-910c-9750a7105133.png">

## Current Behavior 😯
<!---
    Describe what happens instead of the expected behavior.
-->
Avatar relies on the truthiness of its children to determine if the defaultColor class is applied to the component, so falsey values ( 0, "" ) that may be the desired output do not render as expected
<img width="375" alt="screen shot 2018-11-30 at 5 33 55 am" src="https://user-images.githubusercontent.com/32465602/49287078-baee8900-f461-11e8-9a1a-78974612a157.png">

## Steps to Reproduce 🕹
<!---
    Provide a link to a live example (you can use codesandbox.io) and an unambiguous set of steps to reproduce this bug.
    Include code to reproduce, if relevant (which it most likely is).

    This codesandbox.io template _may_ be a good starting point:
    https://codesandbox.io/s/github/mui-org/material-ui/tree/master/examples/create-react-app

    If you're using typescript a better starting point would be
    https://codesandbox.io/s/github/mui-org/material-ui/tree/master/examples/create-react-app-with-typescript

    If YOU DO NOT take time to provide a codesandbox.io reproduction, should the COMMUNITY take time to help you?

-->
Link: https://codesandbox.io/s/r7k333zzx4

## Context 🔦
<!---
    What are you trying to accomplish? How has this issue affected you?
    Providing context helps us come up with a solution that is most useful in the real world.
-->
N/A

## Your Environment 🌎
<!---
    Include as many relevant details about the environment with which you experienced the bug.
    If you encounter issues with typescript please include version and tsconfig.
-->

| Tech         | Version |
|--------------|---------|
| Material-UI  |  v3.3.2   |
| React        |  v16.3.1  |
| Browser      |         |
| TypeScript   |   N/A   |
| etc.         |         |

## Potential Solution
https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Avatar/Avatar.js

Current: 
```
  const className = classNames(
    classes.root,
    {
      [classes.colorDefault]: childrenProp && !src && !srcSet,
    },
    classNameProp,
  );
```

Suggestion: Rather than rely on truthiness, loose compare against undefined to allow 0 or "" to pass conditions

```
  const className = classNames(
    classes.root,
    {
      [classes.colorDefault]: childrenProp != undefined && !src && !srcSet,
    },
    classNameProp,
  );
```


Discussion:
@camilleryr Thank you for opening this issue. It's definitely wrong. I would try to push that one step further:
```diff
  const className = classNames(
    classes.root,
    {
-     [classes.colorDefault]: childrenProp && !src && !srcSet,
+     [classes.colorDefault]: !src && !srcSet,
    },
    classNameProp,
  );
```
The branch logic is present since the first implementation: https://github.com/mui-org/material-ui/commit/ecec90b46d9f150980bdd8142f1721ee6ac3c4f9. I see very use case for it. I believe it would be simpler without.
What do you think of this change? Do you want to submit a pull request? :)
I agree that removing the condition would be a fine move, I will submit a
pull request.
Chris


On Fri, Nov 30, 2018 at 1:54 PM Olivier Tassinari <notifications@github.com>
wrote:

> @camilleryr <https://github.com/camilleryr> Thank you for opening this
> issue. It's definitely wrong. I would try to push that one step further:
>
>   const className = classNames(
>     classes.root,
>     {-     [classes.colorDefault]: childrenProp && !src && !srcSet,+     [classes.colorDefault]: !src && !srcSet,
>     },
>     classNameProp,
>   );
>
> The branch logic is present since the first implementation: ecec90b
> <https://github.com/mui-org/material-ui/commit/ecec90b46d9f150980bdd8142f1721ee6ac3c4f9>.
> I see very use case for it. I believe it would be simpler without.
> What do you think of this change? Do you want to submit a pull request? :)
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <https://github.com/mui-org/material-ui/issues/13751#issuecomment-443320291>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/Ae9iwi8ZsgZxfG-nNKcZvYSTSub6DFgCks5u0YztgaJpZM4Y7ho3>
> .
>


Resolving patch:
diff --git a/packages/material-ui/src/Avatar/Avatar.js b/packages/material-ui/src/Avatar/Avatar.js
--- a/packages/material-ui/src/Avatar/Avatar.js
+++ b/packages/material-ui/src/Avatar/Avatar.js
@@ -20,7 +20,6 @@ export const styles = theme => ({
     userSelect: 'none',
   },
   /* Styles applied to the root element if there are children and not `src` or `srcSet` */
-  /* Styles applied to the root element if `color="default"`. */
   colorDefault: {
     color: theme.palette.background.default,
     backgroundColor:
@@ -51,16 +50,10 @@ function Avatar(props) {
     ...other
   } = props;
 
-  const className = classNames(
-    classes.root,
-    {
-      [classes.colorDefault]: childrenProp && !src && !srcSet,
-    },
-    classNameProp,
-  );
   let children = null;
+  const img = src || srcSet;
 
-  if (src || srcSet) {
+  if (img) {
     children = (
       <img
         alt={alt}
@@ -80,7 +73,16 @@ function Avatar(props) {
   }
 
   return (
-    <Component className={className} {...other}>
+    <Component
+      className={classNames(
+        classes.root,
+        {
+          [classes.colorDefault]: !img,
+        },
+        classNameProp,
+      )}
+      {...other}
+    >
       {children}
     </Component>
   );
diff --git a/pages/api/avatar.md b/pages/api/avatar.md
--- a/pages/api/avatar.md
+++ b/pages/api/avatar.md
@@ -38,7 +38,7 @@ This property accepts the following keys:
 | Name | Description |
 |:-----|:------------|
 | <span class="prop-name">root</span> | Styles applied to the root element.
-| <span class="prop-name">colorDefault</span> | Styles applied to the root element if `color="default"`.
+| <span class="prop-name">colorDefault</span> | Styles applied to the root element if there are children and not `src` or `srcSet`
 | <span class="prop-name">img</span> | Styles applied to the img element if either `src` or `srcSet` is defined.
 
 Have a look at [overriding with classes](/customization/overrides/#overriding-with-classes) section


Test patch:
diff --git a/packages/material-ui/src/Avatar/Avatar.test.js b/packages/material-ui/src/Avatar/Avatar.test.js
--- a/packages/material-ui/src/Avatar/Avatar.test.js
+++ b/packages/material-ui/src/Avatar/Avatar.test.js
@@ -134,4 +134,31 @@ describe('<Avatar />', () => {
       assert.strictEqual(wrapper.hasClass(classes.colorDefault), true);
     });
   });
+
+  describe('falsey avatar', () => {
+    let wrapper;
+
+    before(() => {
+      wrapper = shallow(
+        <Avatar className="my-avatar" data-my-prop="woofAvatar">
+          {0}
+        </Avatar>,
+      );
+    });
+
+    it('should render with defaultColor class when supplied with a child with falsey value', () => {
+      assert.strictEqual(wrapper.name(), 'div');
+      assert.strictEqual(wrapper.text(), '0');
+    });
+
+    it('should merge user classes & spread custom props to the root node', () => {
+      assert.strictEqual(wrapper.hasClass(classes.root), true);
+      assert.strictEqual(wrapper.hasClass('my-avatar'), true);
+      assert.strictEqual(wrapper.props()['data-my-prop'], 'woofAvatar');
+    });
+
+    it('should apply the colorDefault class', () => {
+      assert.strictEqual(wrapper.hasClass(classes.colorDefault), true);
+    });
+  });
 });