Material-ui: Can withStyles pass props to styles object?

Created on 17 Oct 2017  路  54Comments  路  Source: mui-org/material-ui

Currently, I developing a component that requires both props and themes object.

At first, it works great with theme object

const styles = theme => ({
  title: {
    ...theme.typography.headline,
    textAlign: 'center',
    padding: '8px 16px',
    margin: 0,
    color: theme.palette.common.white,
    backgroundColor: theme.palette.primary[500],
  },

withStyles(styles, { withTheme: true })(Component);
....

But I also need access to props in styles object.

I tried example but it not working.

{
 ....
display: (props) => props.display
}

I end up combine react-jss and withTheme to do that

import { withTheme } from 'material-ui/styles';
import injectSheet from 'react-jss';

function withStyles(styles, Component) {
  return withTheme()(injectSheet(styles)(Component));
}

export default withStyles;

....

const styles = {
  title: {
    display: (props) => props.display,
    textAlign: 'center',
    padding: '8px 16px',
    margin: 0,
    color: ({ theme }) => theme.palette.common.white,
    backgroundColor: ({ theme }) => theme.palette.primary[500],
  },

It works but I really miss

  title: {
    ...theme.typography.headline,
duplicate

Most helpful comment

@oliviertassinari It's very reassuring to hear that you'll consider prioritizing this! This would make it much easier to customize components. For example, I'd like to have a checkbox with a configurable size (i.e. width & height in pixels):

<CustomCheckbox size={16} />

If we could access props in styles, this would be very simple:

const styles = {
  root: {
    width: props => props.size,
    height: props => props.size
  }
}

or

const styles = props => ({
  root: {
    width: props.size,
    height: props.size
  }
})

and then:

const CustomCheckbox = ({size, classes}) => <Checkbox className={classes.root} />;

export default withStyles(styles)(CustomCheckbox);

For now, do you have any recommendations about how we should approach these types of use cases? Or do you have any estimates of when you might be able to add support for accessing props when using withStyles?

All 54 comments

We should probably be able to address the issue by making Material-UI using the same context key as react-jss: https://github.com/cssinjs/theming/blob/master/src/channel.js#L1.
Also, have a look at #7633

I have a PR ready with a react-jss interoperability example. I will add that into the docs. cc @kof

@oliviertassinari does the resolution of this mean that it should be possible now to get access to the props within the styles definition? It's not clear to me how...

@pelotom no, withStyles doesn't have access to the properties. But given how much people are asking for this feature. It's something I can prioritize, after the bug fixes. You can use the injectSheet HOC, but it's open the door to multiple issues: memory leak, hot reloading broken, no classes composition, no internal ref access, broken theme nesting handling. At least, it's some of the issues I have been facing in the past and motivated my rewrite. I think that step by step those issues will be addressed.

@oliviertassinari It's very reassuring to hear that you'll consider prioritizing this! This would make it much easier to customize components. For example, I'd like to have a checkbox with a configurable size (i.e. width & height in pixels):

<CustomCheckbox size={16} />

If we could access props in styles, this would be very simple:

const styles = {
  root: {
    width: props => props.size,
    height: props => props.size
  }
}

or

const styles = props => ({
  root: {
    width: props.size,
    height: props.size
  }
})

and then:

const CustomCheckbox = ({size, classes}) => <Checkbox className={classes.root} />;

export default withStyles(styles)(CustomCheckbox);

For now, do you have any recommendations about how we should approach these types of use cases? Or do you have any estimates of when you might be able to add support for accessing props when using withStyles?

@nmchaves You use case seems to fall perfectly for the inline-style approach, you can find a bit about it in the documentation. FAQ
https://github.com/callemall/material-ui/blob/75a30061e76eae93c711ec202a2c7e4238a4f19a/docs/src/pages/style/SvgIcons.js#L38-L44

Thanks @oliviertassinari ! I was hoping I could accomplish this using withStyles, but inline-styles will work great. And the fact that you're recommending it here + in the docs makes me feel very confident with this decision. Thanks again!

it would be nice to be able to pass a prop (image src) to the style for a backgroundImage

I'd wrap withStyle

const withStylesProps = styles =>
  Component =>
    props => {
      console.log(props);
      const Comp = withStyles(styles(props))(Component);
      // return <div>lol</div>;
      return <Comp {...props} />;
    };

const styles = props => ({
  foo: {
    height: `${props.y || 50}px`,
  }
});

export default withStylesProps(styles)(
  props => (
    <div className={props.classes.foo} style={{ ...props.style, background: 'yellow' }}>
      <h1>Hello!</h1>
    </div>
  )
);

demo: https://codesandbox.io/s/k2y01rj3w7

(I'm surprised ^ works without any ThemeProvider and JssProvider set up https://codesandbox.io/s/q6v7krx6, ah it initializes it)

@caub It's working, but you need to be cautious with this pattern. The injected CSS will grow with the number of instances of the component. It's a duplicate of #7633. I haven't dug into the topic. But I believe @kof version use some performance optimization.

@caub Thanks for sharing!

@oliviertassinari there's this https://github.com/cssinjs/react-jss/blob/master/readme.md#dynamic-values in react-jss, I wonder why it couldn't be used in material-ui? Also I understand your point where you say the inline style prop is perfect for dynamic values, but it's nicer to have all styles definitions in the same places. There's also https://github.com/airbnb/react-with-styles that would handle className and style for more efficient dynamic styles

I am facing the same issue can some one help me out
`import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import Drawer from 'material-ui/Drawer';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import List from 'material-ui/List';
import Typography from 'material-ui/Typography';
import IconButton from 'material-ui/IconButton';
import Hidden from 'material-ui/Hidden';
import Divider from 'material-ui/Divider';
import MenuIcon from 'material-ui-icons/Menu';
import { mailFolderListItems, otherMailFolderListItems } from './tileData';

const drawerWidth = 240;

const styles = theme => ({
root: {
width: '100%',
height: 430,
marginTop: theme.spacing.unit * 3,
zIndex: 1,
overflow: 'hidden',
},
appFrame: {
position: 'relative',
display: 'flex',
width: '100%',
height: '100%',
},
appBar: {
position: 'absolute',
marginLeft: drawerWidth,
[theme.breakpoints.up('md')]: {
width: calc(100% - ${drawerWidth}px),
},
},
navIconHide: {
[theme.breakpoints.up('md')]: {
display: 'none',
},
},
drawerHeader: theme.mixins.toolbar,
drawerPaper: {
width: 250,
[theme.breakpoints.up('md')]: {
width: drawerWidth,
position: 'relative',
height: '100%',
},
},
content: {
backgroundColor: theme.palette.background.default,
width: '100%',
padding: theme.spacing.unit * 3,
height: 'calc(100% - 56px)',
marginTop: 56,
[theme.breakpoints.up('sm')]: {
height: 'calc(100% - 64px)',
marginTop: 64,
},
},
});

export class ResponsiveDrawer extends React.Component {
state = {
mobileOpen: false,
};

handleDrawerToggle = () => {
this.setState({ mobileOpen: !this.state.mobileOpen });
};

render() {
const { classes, theme } = this.props;

const drawer = (
  <div>
    <div className={classes.drawerHeader} />
    <Divider />
    <List>{mailFolderListItems}</List>
    <Divider />
    <List>{otherMailFolderListItems}</List>
  </div>
);

return (
  <div className={classes.root}>
    <div className={classes.appFrame}>
      <AppBar className={classes.appBar}>
        <Toolbar>
          <IconButton
            color="inherit"
            aria-label="open drawer"
            onClick={this.handleDrawerToggle}
            className={classes.navIconHide}
          >
            <MenuIcon />
          </IconButton>
          <Typography variant="title" color="inherit" noWrap>
            Responsive drawer
          </Typography>
        </Toolbar>
      </AppBar>
      <Hidden mdUp>
        <Drawer
          variant="temporary"
          anchor={theme.direction === 'rtl' ? 'right' : 'left'}
          open={this.state.mobileOpen}
          classes={{
            paper: classes.drawerPaper,
          }}
          onClose={this.handleDrawerToggle}
          ModalProps={{
            keepMounted: true, // Better open performance on mobile.
          }}
        >
          {drawer}
        </Drawer>
      </Hidden>
      <Hidden smDown implementation="css">
        <Drawer
          variant="permanent"
          open
          classes={{
            paper: classes.drawerPaper,
          }}
        >
          {drawer}
        </Drawer>
      </Hidden>
      <main className={classes.content}>
        <Typography noWrap>{'You think water moves fast? You should see ice.'}</Typography>
      </main>
    </div>
  </div>
);

}
}

ResponsiveDrawer.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
};

export default withStyles(styles)(ResponsiveDrawer);
`

screen shot 2018-02-13 at 3 27 41 am

The injected CSS will grow with the number of instances of the component.

@oliviertassinari injected CSS will grow +- same way html would grow with inline styles. Static styles are rendered in separate sheets and reused across all component instances.

I did like this, though with stateless component it will re-render the withStyle from render to render, we can avoid by using full pure component.

import React from 'react';
import {
  withStyles,
  Grid,
  CircularProgress
} from 'material-ui';

const PreloadComponent = props => {
  const { classes,size } = props;
  return (
    <Grid className={classes.container} container justify={'center'} alignItems={'center'}>
      <CircularProgress size={size}/>
    </Grid>
  )
};

const StyleWithThemeProps = (props) => {
  return withStyles(theme => ({
    container: {
      paddingTop: props.size*2 || 50,
      paddingBottom: props.size*2 || 50,
    }
  }),{withTheme: true})(PreloadComponent)
};

const Preload = props => {
  const { size } = props;
  const WithStylesPreloadComponent = StyleWithThemeProps(props);
  return (
    <WithStylesPreloadComponent {...props}/>
  )
};

Preload.defaultProps = {
  size: 20
};

export default Preload;

We can use full pure component to avoid updating

const PreloadComponent = props => {
  const { classes,size } = props;
  return (
    <Grid className={classes.container} container justify={'center'} alignItems={'center'}>
      <CircularProgress size={size}/>
    </Grid>
  )
};

const StyleWithThemeProps = (props) => {
  return withStyles(theme => ({
    container: {
      paddingTop: props.size*2 || 50,
      paddingBottom: props.size*2 || 50,
    }
  }),{withTheme: true})(PreloadComponent)
};

class PreloadFull extends React.PureComponent {

  constructor(props,context) {
    super(props);
  }

  componentWillMount() {
    this.StyledPreloadFull = StyleWithThemeProps(this.props);
  }

  componentWillUpdate(nextProps) {
    this.StyledPreloadFull = StyleWithThemeProps(nextProps);
  }

  render() {
    const { StyledPreloadFull,props } = this;
    return (
      <StyledPreloadFull {...props}/>
    );
  }
}

PreloadFull.defaultProps = {
  size: 20
};

export default PreloadFull;

@up209d It works, but it's quite painful, I'll try to modify withStyles, to use more directly https://github.com/cssinjs/react-jss which can pass props in values

@SrikanthChebrolu could you move your message to a different issue, since it's not in-topic?

Just curious what the status is on this? I've been reading through this issue, the JSS docs, material-ui docs, and yet to find a solution for Mui+Jss+TypeScript that doesn't require me to use inline styles. Putting a few inline styles is sometimes unavoidable, but in my case there are multiple styles that have many different states, all relying on theme and props together :disappointed:

@chazsolo Hey Chaz, you actually can use injectSheet from react-jss instead of withStyles from mui. By that way you can have both props and theme.

import injectSheet from 'react-jss';

const styles = theme => ({
  container: {
     color: props => theme.palette[props.color || 'primary'].main
  }
});

...

export default injectSheet(styles)(AnyComponent);
import { JssProvider, jss, createGenerateClassName } from 'react-jss/lib';
import { MuiThemeProvider } from 'material-ui';

const generateClassName = createGenerateClassName();

...

<JssProvider jss={jss} generateClassName={generateClassName}>
  <MuiThemeProvider theme={props.theme} sheetsManager={new Map()}>
    <App/>
  </MuiThemeProvider>
</JssProvider>

@chazsolo I think you want to follow this issue https://github.com/cssinjs/jss/issues/682

Thanks @kof and @up209d - subscribed and giving up209d's example a shot.

@up209d
Unfortunately I don't think that's gonna work for me - I've implemented what you suggested, and I can see the props within the function call inside the styles object, but I continue to get errors. IAm I just missing types? I'm extending WithStyles in props Interfaces so I have access to the classes object in props (now I'm wondering if that's the problem referenced in https://github.com/mui-org/material-ui/issues/8726#issuecomment-337482040)

TS2344: Type '(theme: ITheme) => { arc: { stroke: string; strokeWidth: (props: any) => string | number; }; arcM...' does not satisfy the constraint 'string | Record<string, CSSProperties> | StyleRulesCallback<string>'.
  Type '(theme: ITheme) => { arc: { stroke: string; strokeWidth: (props: any) => string | number; }; arcM...' is not assignable to type 'StyleRulesCallback<string>'.
    Type '{ arc: { stroke: string; strokeWidth: (props: any) => string | number; }; arcMovement: { strokeDa...' is not assignable to type 'Record<string, CSSProperties>'.
      Property 'arc' is incompatible with index signature.
        Type '{ stroke: string; strokeWidth: (props: any) => string | number; }' is not assignable to type 'CSSProperties'.
          Types of property 'strokeWidth' are incompatible.
            Type '(props: any) => string | number' is not assignable to type 'string | number | undefined'.
              Type '(props: any) => string | number' is not assignable to type 'number'.

My theme looks like:

import { ITheme } from '...';

export default (theme: ITheme) => ({
  arc: {
    // ...
    strokeWidth: (props: any): number | string => {
      // this logs the correct data I'm expecting
      console.log(props.data[0].properties.name)
      return 1.5
    }
  },
  arcMovement: {
    // ...
  },
})

The interesting this is, when I use the classes object within my component, arc and arcMovement are valid properties:

// from Chrome console
{
  arc: "Arcs-arc-0-2-1 Arcs-arc-0-2-3",
  arcMovement: "Arcs-arcMovement-0-2-2"
}

Update

I was able to get this working, but as noted in the comment above, I had to strip out all references to WithStyles, withStyles, and I lose classes composition and theme nesting. I'm gonna give it a rest now and just keep an eye on the threads. Thanks for all the help!

@chazsolo Hey Chaz, I am not sure but is that you want to access to classes inside the props of the style object. If so, I think it is impossible since the classes only available after jss processed the style object, how can you access classes before a process of making classes even hasn't been triggered?

I think @caub already provided a solution. Just repost the solution with little twist. No need any extra library.

Build your own wrapper withStylesProps.

import { withStyles } from 'material-ui/styles';

const styles = ( theme, props ) => ({
    exampleStyle: {
           color: 'red'  // <-- or try theme.palette.primary[600]
    }
})

const withStylesProps = ( styles ) =>
  Component =>
    props => {
      const Comp = withStyles(theme => styles(theme, props))(Component);
      return <Comp {...props} />;
    };

const YourComponent = ({  classes }) => 
      <Typography type="display4" className={classes.exampleStyle}>{type}</Typography>

export default withStylesProps(styles)(YourComponent);

If you don't like create withStylesProps for every component, try adding it in separated file and import wherever you want.

@iamthuypham Thanks for the tip. However when i wrap my component with withStylesProps, the animation of transition component <Collapse i am using somewhere inside the wrapped component stops working.

@jdolinski1 Can you copy/paste your code example?

@iamthuypham your solution has the drawback of creating a new <style> tag each time a component gets created. Also, you might be careful when using defaultProps and add them to your HOC'd component and not the base components.

image

All of that is supported by react-jss, can't it be supported natively by material-ui?

Also, I think @jdolinski1 's problem is that your code does not propagate children the wrapped component may have.

@iamthuypham I think it is not recommended to do that, as I used to do like that in the past, and you might experience the poor performance as long as the app growth very soon. Creating a new instance of component with new jss style object is not good in term of coding principle because the style object gotta be re-rendered entirely, again and again, every time per props change. Using injectSheet from react-jss is better choice. If you look into the injectSheet you will see that it break your style object into 2 pieces (static & dynamic) so only the dynamic get re-rendered when props change.

how to use plugins such as jss-nested with injectSheet?.

with injectSheet i can't get '&:hover' statements work.
with withStyles i can't access to props...

@koutsenko Here is an example:

import React from "react";
import { makeStyles } from "@material-ui/styles";
import Button from "@material-ui/core/Button";

const useStyles = makeStyles({
  root: {
    background: props => props.color,
    "&:hover": {
      background: props => props.hover
    },
    border: 0,
    borderRadius: 3,
    color: "white",
    height: 48,
    padding: "0 30px"
  }
});

export default function Hook() {
  const classes = useStyles({
    color: "red",
    hover: "blue"
  });
  return <Button className={classes.root}>Hook</Button>;
}

https://codesandbox.io/s/pw32vw2j3m

I hope it helps.


Wow, it's amazing the progress we have made in ~1 year 馃槏.

now how do you typescript that?

@stunaz Good question. I don't know. I haven't looked into it. @eps1lon has done the TypeScript definition of the module. You can use it as a starting point.
https://github.com/mui-org/material-ui/blob/f4281a77d15b0d6eec9d33cdc358cfb89844996d/packages/material-ui-styles/src/index.d.ts#L72

@koutsenko Here is an example:

Thanks @oliviertassinari , with "react@next" it works now.

@koutsenko If you couldn't make jss-nested work, it must be a configuration issue somewhere in your coding. As jss-nested is included in jss-default-preset, so it just works oob

https://stackblitz.com/edit/react-py6w2v

@oliviertassinari

Can you also set the entire styles object for a given selector with props? To where you can conditionally apply a property?

For instance, like this

withStyles({
    root: {
        '& > path': (props) => {
            if(props.color)
                return {
                    fill: props.color
                };
           return {};
        }
    }
})

So that, if the prop does not exist, then it uses the previous fill value, rather than something else that I have to set it to? For instance, there are other rules that would normally apply to fill, but I only want to set this new fill property if the color prop is set.

Thanks!

@Guardiannw For some reason your variant doesn't work. Maybe @kof could raise our light on why 馃挕. You can do one of the following:

// 馃弳
const useStyles = makeStyles({
  root: {
    "& > span": {
      backgroundColor: props => props.color || null,
    }
  }
});

// or 

const useStyles = makeStyles({
  root: props => ({
    "& > span": {
      backgroundColor: props.color || null
    }
  })
});

@oliviertassinari I am having a hard time getting your second option to work with the withStyles function. Does it only work with makeStyles and hooks?

@Guardiannw It's working with any of the APIs of @material-ui/styles.

@oliviertassinari looks like a valid syntax, fn values were added in v10, so either v9 was used or I need a codesandbox reproduction

Ok, that's what I tried it with. Might have to try again.

@oliviertassinari I have a question about the use of @materia-ui/styles, is It available and to use in a production environment?, in the documentation indicates that it doesn't work with the stable version, I'm using the "3.9.1", the example https://github.com/mui-org/material-ui/issues/8726#issuecomment-452047345 that you present it has a powerful and useful feature that I need. In these issues, I saw many comments from a different perspective and also I like the solution https://github.com/mui-org/material-ui/issues/8726#issuecomment-363546636 of @caub, but your comment about his solution is good.

@contrerasjf0 @material-ui/styles is only available as an alpha release. We treat alpha versions like most packages in the react ecosystem. I would recommend you never use any alpha packages in production. If you do you should expect bugs and breaking changes between any release i.e. you should be able to handle the churn alpha versions add.

What I hope is that people use those versions either in hobby projects or use it on a separate branch that is not deployed to production but still tested just like the production branch. I do appreciate everyone that uses those alpha versions and gives us feedback for them.

@up209d yes, your solution work, but with
styles = { name: { cssprop: props => {} } notation, not
styles = props => ({ name: { cssprop: {} })

Also, JssProvider isn't necessary.

@koutsenko

// at value level:
styles = { name: { cssprop: props => value }
styles = theme => ({ name: { cssprop: props => value })

// at class name level
styles = { name: props => ({ cssprop: value })  }
styles = theme => ({ name: props => ({ cssprop: value })  })

You can't access props at the top level, even as a second argument after theme

I found a way

// MyComponent.tsx
import React, { PureComponent } from 'react';
import { myComponentWithStyles } from './myComponentWithStyles';

export interface MyComponentProps {
  copy: string;
  size?: number;
}

export class Twemoji extends PureComponent<myComponentWithStyles> {
  public render() {
    const { copy, classes } = this.props;

    return (
      <div className={classes.message}>
        {copy}
        <img src="https://via.placeholder.com/150" />
    </div>
    );
  }
}

// myComponentWithStyles.tsx
import React from 'react';
import { withStyles, WithStyles, Theme } from '@material-ui/core';
import { MyComponent, MyComponentProps } from './my-component';

const styles = (props: Theme & MyComponentProps) => ({
  message: {
    fontSize: props.typography.caption.fontSize,
    'box-sizing': 'content-box',
    '& img': {
      width: `${props.size || 24}px`,
      height: `${props.size || 24}px`,
      padding: '0 4px',
      verticalAlign: 'middle',
    },
  },
});

export type myComponentWithStyles = WithStyles<any>;

export const Component = (props: MyComponentProps) => {
  const StyledComponent = withStyles((theme: Theme) => styles({ ...props, ...theme }))(
    MyComponent
  );

  return <StyledComponent {...props} />;
};



md5-d0e1b51e375682cf2aad9c4d66b6c73a



<Component size={12} />

@andreasonny83 Avoid this pattern. We are providing a native API in v4.

@oliviertassinari thanks for the update. Is that pattern already available? Any documentation available?

One last question @oliviertassinari . Can I use makeStyles in combination with withStyles?

I cannot find documentation for that. What I'm trying to do is this:

const useStyles = makeStyles({
  message: {
    boxSizing: 'content-box'
  }
});

export const ComponentWithStyles = withStyles(useStyles())(MyComponent);

@andreasonny83

Use either one or the other, in your example just remove makeStyles:

const styles = { message: {boxSizing: 'content-box', background: props => props.bg} };
export const ComponentWithStyles = withStyles(styles)(MyComponent);

Gday folks thought id share my current solution with reference to the above discussion, hopefully it helps someone or someone could offer better advice on my current solution. For my signin page id like a random background image but id still like to maintain the power of the material ui api. The AuthPage is just the parent presentation layer that takes the individual auth components (signin, locked, forgotten-password, password-reset, etc) as children. Can confirm with each page refresh a new background loads aswell as a nice strongly typed props within AuthPageContainer prop

// AuthPage.styles.tsx

import { Container } from "@material-ui/core";
import { ContainerProps } from "@material-ui/core/Container";
import { withStyles } from "@material-ui/core/styles";
import React from "react";

interface IAuthContainerProps extends ContainerProps {
  background: string;
}

export const AuthContainer = withStyles({
  root: props => ({
    alignItems: "center",
    backgroundImage: `url(${props.background})`,
    backgroundPosition: "50% 50%",
    backgroundRepeat: "no-repeat",
    backgroundSize: "cover",
    display: "flex",
    height: "100vh",
    justifyContent: "center",
    margin: 0,
    padding: 0,
    width: "100%"
  })
})((props: IAuthContainerProps) => <Container maxWidth={false} {...props} />);

// AuthPage.tsx

import React from "react";
import forest from "../../assets/backgrounds/forest.jpg";
import sky from "../../assets/backgrounds/sky.jpg";
import uluru from "../../assets/backgrounds/uluru.jpg";
import { AuthContainer } from "./AuthPage.styles";

const AuthPage = ({ children }) => {
  const generateBackground = () => {
    const backgrounds = [forest, sky, uluru];
    const index = Math.floor(Math.random() * backgrounds.length);
    return backgrounds[index];
  };

  return (
    <AuthContainer background={generateBackground()}>{children}</AuthContainer>
  );
};

export default AuthPage;

simply do something like this:

// styles.js
export default theme => ({
    root: props => ({
        // some styles
    }),
    ...
});

//container.js
export default withStyles(styles)(MyComponent);

what about passing also state?

@luky1984
You can't. Instead you may do:

// Component.js
<Button
    className={`
        ${classes.button} 
        ${this.state.isEnable
            ? classes.enable
            : classes.disable}
    `}
/>

Or use clsx https://www.npmjs.com/package/clsx instead

@caub Your solution ruins the jss generated classname order.
Like written here: https://github.com/mui-org/material-ui/issues/8726#issuecomment-363546636
I have tried to use your solution, but your HOC component (withStylesProps) solution delays the call of it's withStyles, because it's wrapped, so calling it with classNames doesn't override the css.
Like: https://codesandbox.io/s/hocs-8uhw1?file=/index.js

background should be #0000000 and color: blue

Was this page helpful?
0 / 5 - 0 ratings