Repository: mui/material-ui (TypeScript)
Date: 2018-05-17 12:20:38+00:00
Task type: Feature

Issue:
[Feature Request] StepIcon should be more customizable
Hello, folks!

I'm having a problem in customize the component __StepIcon__ inside of __StepLabel__ specifically in line __86__, component is like this in the last version of material-ui-next __(v1.0.0-beta.47)__:

```
{icon && (
        <span
          className={classNames(classes.iconContainer, {
            [classes.alternativeLabel]: alternativeLabel,
          })}
        >
          <StepIcon
            completed={completed}
            active={active}
            error={error}
            icon={icon}
            alternativeLabel={alternativeLabel}
          />
        </span>
      )}
```

This property didn't permit edit the properties of the icon. Ok, but you will tell me that I can create a custom Icon but I will loss access to the props that is passed through __Step__, so, my proposal is do something like:

* add a __stepIconProps__ to edit the props of __StepIcon__ props including access to __CSS API__ through **classes** prop.

```
{icon && (
        <span
          className={classNames(classes.iconContainer, {
            [classes.alternativeLabel]: alternativeLabel,
          })}
        >
          <StepIcon
            completed={completed}
            active={active}
            error={error}
            icon={icon}
            alternativeLabel={alternativeLabel}
           {...stepIconProps}
          />
        </span>
      )}
```

* Another way is transform this in a callback, so the user can access the __icon number__ that is passed through __Step__ component but is unacessible by the user that is using the component: 

```
{icon && iconCallback(icon, ...other)}
```
So when you use StepLabel would  be:
```
<StepLabel iconCallback={{ (icon) => {
return (
 <MyCustomStepIcon>{icon}</MyCustomStepIcon>
)
} }} />
```

Regards, 


Issue discussion:
@lucas-viewup Thanks for opening this issue. I'm not sure to fully understand your problem. What are you trying to achieve precisely? This would help me evaluate the best solution.
Thanks for feedback, @oliviertassinari! The problem I'm trying to solve is style the __StepIcon__ without modify the __behaviour__ of icon and without __change__ the icon. The component is ok, the only problem is I can't access the props (props of StepIcon) using the __StepLabel__ component. I think a good solution for this is add a property to modify these properties. This solution only will bind two wires that are well implemented, allowing the use of CSS API of __StepIcon__ through __StepLabel__.

Take this example:

```
const styles = {
    stepIconRoot: (
       width: 24,
      height: 'auto',
     }
...

};

const {classes} = props;
...
<Stepper activeStep={activeStep}>
         
      <Step>
           <StepLabel iconProps={{
                 classes: {
                   root: classes.stepIconRoot,
...
                 }
          }}>Payment</StepLabel>
      </Step>
</Stepper>
```

> The problem I'm trying to solve is style the StepIcon

Ok, I see different alternatives:
1. We add a `classes.stepIcon` or `classes.icon` key to the StepLabel. This is for the simple use cases
2. We add a `StepIconProps` property. We add the `xxxProps` over `xxxComponent` for frequent use cases. It's handier but less powerful.
3. We add a `StepIconComponent` property. This allows full customization.
The first option is good but you will be restricted to the **root** of the **StepIcon**.

I guess the 2nd option is better, because you will only bind that already exists, you will bind the **StepIcon** to the **StepLabel**, all the logic already implemented in **StepIcon** will be available in **StepLabel** through **StepIconProps** as you mentioned. 

The 3rd option already exists (icon property of **StepLabel**), the problem is having a prop to pass the component is that you will lost the behavior of default icon (the default icon property of **StepIcon** renders the **index of the step** and another props like alternativeLabel, etc, the custom one doesn't).
I'm fine with option two too :). 

Solution patch:
diff --git a/packages/material-ui/src/StepLabel/StepLabel.d.ts b/packages/material-ui/src/StepLabel/StepLabel.d.ts
--- a/packages/material-ui/src/StepLabel/StepLabel.d.ts
+++ b/packages/material-ui/src/StepLabel/StepLabel.d.ts
@@ -2,6 +2,7 @@ import * as React from 'react';
 import { StandardProps } from '..';
 import { Orientation } from '../Stepper';
 import { StepButtonIcon } from '../StepButton';
+import { StepIconProps } from '../StepIcon';
 
 export interface StepLabelProps
   extends StandardProps<React.HTMLAttributes<HTMLDivElement>, StepLabelClasskey> {
@@ -15,6 +16,7 @@ export interface StepLabelProps
   last?: boolean;
   optional?: React.ReactNode;
   orientation?: Orientation;
+  StepIconProps?: Partial<StepIconProps>;
 }
 
 export type StepLabelClasskey =
diff --git a/packages/material-ui/src/StepLabel/StepLabel.js b/packages/material-ui/src/StepLabel/StepLabel.js
--- a/packages/material-ui/src/StepLabel/StepLabel.js
+++ b/packages/material-ui/src/StepLabel/StepLabel.js
@@ -66,6 +66,7 @@ function StepLabel(props) {
     last,
     optional,
     orientation,
+    StepIconProps,
     ...other
   } = props;
 
@@ -89,7 +90,13 @@ function StepLabel(props) {
             [classes.alternativeLabel]: alternativeLabel,
           })}
         >
-          <StepIcon completed={completed} active={active} error={error} icon={icon} />
+          <StepIcon
+            completed={completed}
+            active={active}
+            error={error}
+            icon={icon}
+            {...StepIconProps}
+          />
         </span>
       )}
       <span className={classes.labelContainer}>
@@ -165,6 +172,10 @@ StepLabel.propTypes = {
    * @ignore
    */
   orientation: PropTypes.oneOf(['horizontal', 'vertical']),
+  /**
+   * Properties applied to the `StepIcon` element.
+   */
+  StepIconProps: PropTypes.object,
 };
 
 StepLabel.defaultProps = {
diff --git a/pages/api/step-label.md b/pages/api/step-label.md
--- a/pages/api/step-label.md
+++ b/pages/api/step-label.md
@@ -18,6 +18,7 @@ filename: /packages/material-ui/src/StepLabel/StepLabel.js
 | <span class="prop-name">error</span> | <span class="prop-type">bool | <span class="prop-default">false</span> | Mark the step as failed. |
 | <span class="prop-name">icon</span> | <span class="prop-type">node |  | Override the default icon. |
 | <span class="prop-name">optional</span> | <span class="prop-type">node |  | The optional node to display. |
+| <span class="prop-name">StepIconProps</span> | <span class="prop-type">object |  | Properties applied to the `StepIcon` element. |
 
 Any other properties supplied will be [spread to the root element](/guides/api#spread).
 


Test patch:
diff --git a/packages/material-ui/src/StepLabel/StepLabel.test.js b/packages/material-ui/src/StepLabel/StepLabel.test.js
--- a/packages/material-ui/src/StepLabel/StepLabel.test.js
+++ b/packages/material-ui/src/StepLabel/StepLabel.test.js
@@ -44,8 +44,9 @@ describe('<StepLabel />', () => {
     });
 
     it('renders <StepIcon>', () => {
+      const stepIconProps = { prop1: 'value1', prop2: 'value2' };
       const wrapper = shallow(
-        <StepLabel icon={1} active completed alternativeLabel>
+        <StepLabel icon={1} active completed alternativeLabel StepIconProps={stepIconProps}>
           Step One
         </StepLabel>,
       );
@@ -53,6 +54,8 @@ describe('<StepLabel />', () => {
       assert.strictEqual(stepIcon.length, 1, 'should have an <StepIcon />');
       const props = stepIcon.props();
       assert.strictEqual(props.icon, 1, 'should set icon');
+      assert.strictEqual(props.prop1, 'value1', 'should have inherited custom prop1');
+      assert.strictEqual(props.prop2, 'value2', 'should have inherited custom prop2');
     });
   });