Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CardMedia] Add component property #8376

Merged
merged 1 commit into from Sep 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 12 additions & 7 deletions docs/src/pages/customization/api.md
Expand Up @@ -26,9 +26,11 @@ Aside from the above composition trade-off, we enforce the following rules:

### Spread

Undocumented properties supplied are spread to the root element.
Let's say you want to disable the ripples on the `MenuItem`.
You can take advantage of this behavior:
Undocumented properties supplied are spread to the root element.
For instance, the `className` property is applied to the root.

Now, let's say you want to disable the ripples on the `MenuItem`.
You can take advantage of the spread behavior:
```jsx
<MenuItem disableRipple />
```
Expand All @@ -47,13 +49,16 @@ All the components accept a `classes` property to customize the styles.
Internal components have:
- their own `xxxProps` property when users might need to tweak internal render method's components. For instance, we expose a `inputProps` and a `InputProps` properties.
- their own `xxxClassName` property when `classes` isn't enough.
- their own flattened properties when they are key to the abstraction. For instance, we expose a `value` property.
- their own `xxxRef` property when user might need to perform so imperative action.
For instance, we expose a `inputRef` property.
- their own flattened properties when they are key to the abstraction.
For instance, we expose a `value` property.
- their own `xxxRef` property when user might need to perform imperative actions.
For instance, we expose a `inputRef` property to access the native `input` on the `Input` component.
You fill often find a `rootRef` property, this property is applied as a `ref` to the root element of the component

### Property naming

The name of the boolean properties should be chosen based on the default value. We are following the HTML specification. For instance, the `disabled` attribute on an input element. This choice allows the shorthand notation.
The name of the boolean properties should be chosen based on the default value. We are following the HTML specification.
For instance, the `disabled` attribute on an input element. This choice allows the shorthand notation.

### Controllable components

Expand Down
5 changes: 4 additions & 1 deletion pages/api/card-media.md
Expand Up @@ -8,7 +8,9 @@
| Name | Type | Default | Description |
|:-----|:-----|:--------|:------------|
| classes | Object | | Useful to extend the style applied to components. |
| <span style="color: #31a148">image *</span> | string | | Image to be displayed as a background image. Note that caller must specify height otherwise the image will not be visible. |
| component | ElementType | 'div' | Component for rendering image. |
| image | string | | Image to be displayed as a background image. Either `image` or `src` prop must be specified. Note that caller must specify height otherwise the image will not be visible. |
| src | string | | An alias for `image` property. Available only with media components. Media components: `video`, `audio`, `picture`, `iframe`, `img`. |

Any other properties supplied will be [spread to the root element](/customization/api#spread).

Expand All @@ -17,6 +19,7 @@ Any other properties supplied will be [spread to the root element](/customizatio
You can override all the class names injected by Material-UI thanks to the `classes` property.
This property accepts the following keys:
- `root`
- `rootMedia`

Have a look at [overriding with classes](/customization/overrides#overriding-with-classes)
section for more detail.
Expand Down
2 changes: 1 addition & 1 deletion pages/api/linear-progress.md
Expand Up @@ -10,7 +10,7 @@
| classes | Object | | Useful to extend the style applied to components. |
| color | union:&nbsp;'primary'<br>&nbsp;'accent'<br> | 'primary' | The color of the component. It's using the theme palette when that makes sense. |
| mode | union:&nbsp;'determinate'<br>&nbsp;'indeterminate'<br>&nbsp;'buffer'<br>&nbsp;'query'<br> | 'indeterminate' | The mode of show your progress, indeterminate for when there is no value for progress. |
| value | number | 0 | The value of progress, only works in determinate and buffer mode. Value between 0 and 100. |
| value | number | | The value of progress, only works in determinate and buffer mode. Value between 0 and 100. |
| valueBuffer | number | | The value of buffer, only works in buffer mode. Value between 0 and 100. |

Any other properties supplied will be [spread to the root element](/customization/api#spread).
Expand Down
3 changes: 2 additions & 1 deletion pages/api/typography.md
Expand Up @@ -10,7 +10,7 @@
| align | union:&nbsp;'inherit', 'left', 'center', 'right', 'justify'<br> | 'inherit' | |
| children | Node | | |
| classes | Object | | Useful to extend the style applied to components. |
| color | union:&nbsp;'inherit'<br>&nbsp;'secondary'<br>&nbsp;'accent'<br>&nbsp;'default'<br> | 'default' | The color of the component. It's using the theme palette when that makes sense. |
| color | union:&nbsp;'inherit', 'primary', 'secondary', 'accent', 'default'<br> | 'default' | The color of the component. It's using the theme palette when that makes sense. |
| component | ElementType | | The component used for the root node. Either a string to use a DOM element or a component. By default we map the type to a good default headline component. |
| gutterBottom | boolean | false | If `true`, the text will have a bottom margin. |
| headlineMapping | signature | { display4: 'h1', display3: 'h1', display2: 'h1', display1: 'h1', headline: 'h1', title: 'h2', subheading: 'h3', body2: 'aside', body1: 'p',} | We are empirically mapping the type property to a range of different DOM element type. For instance, h1 to h6. If you wish to change that mapping, you can provide your own. Alternatively, you can use the `component` property. |
Expand Down Expand Up @@ -44,6 +44,7 @@ This property accepts the following keys:
- `gutterBottom`
- `paragraph`
- `colorInherit`
- `colorPrimary`
- `colorSecondary`
- `colorAccent`

Expand Down
4 changes: 3 additions & 1 deletion src/Card/CardMedia.d.ts
Expand Up @@ -2,7 +2,9 @@ import * as React from 'react';
import { StyledComponent } from '..';

export interface CardMediaProps extends React.HTMLAttributes<HTMLDivElement> {
image: string;
image?: string;
src?: string;
component?: React.ReactType;
}

declare const CardMedia: StyledComponent<CardMediaProps>;
Expand Down
50 changes: 46 additions & 4 deletions src/Card/CardMedia.js
Expand Up @@ -2,6 +2,8 @@

import React from 'react';
import classNames from 'classnames';
import warning from 'warning';
import type { ElementType } from 'react';
import withStyles from '../styles/withStyles';

export const styles = {
Expand All @@ -10,10 +12,16 @@ export const styles = {
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center',
},
rootMedia: {
width: '100%',
},
};

const mediaComponents = ['video', 'audio', 'picture', 'iframe', 'img'];

type DefaultProps = {
classes: Object,
component: ElementType,
};

export type Props = {
Expand All @@ -27,20 +35,54 @@ export type Props = {
className?: string,
/**
* Image to be displayed as a background image.
* Either `image` or `src` prop must be specified.
* Note that caller must specify height otherwise the image will not be visible.
*/
image: string,
image?: string,
/**
* An alias for `image` property.
* Available only with media components.
* Media components: `video`, `audio`, `picture`, `iframe`, `img`.
*/
src?: string,
/**
* @ignore
*/
style?: Object,
/**
* Component for rendering image.
*/
component?: ElementType,
};

function CardMedia(props: DefaultProps & Props) {
const { classes, className, image, style, ...other } = props;
const composedStyle = { backgroundImage: `url(${image})`, ...style };
const { classes, className, image, style, src, component: ComponentProp, ...other } = props;

warning(image || src, 'Material-UI: either `image` or `src` property must be specified.');

const isMediaComponent = mediaComponents.indexOf(ComponentProp) !== -1;
const composedStyle =
!isMediaComponent && image ? { backgroundImage: `url(${image})`, ...style } : style;
const composedClassName = classNames(
{
[classes.root]: !isMediaComponent,
[classes.rootMedia]: isMediaComponent,
},
className,
);

return <div className={classNames(classes.root, className)} style={composedStyle} {...other} />;
return (
<ComponentProp
className={composedClassName}
style={composedStyle}
src={isMediaComponent ? image || src : undefined}
{...other}
/>
);
}

CardMedia.defaultProps = {
component: 'div',
};

export default withStyles(styles, { name: 'MuiCardMedia' })(CardMedia);
22 changes: 22 additions & 0 deletions src/Card/CardMedia.spec.js
Expand Up @@ -46,4 +46,26 @@ describe('<CardMedia />', () => {
);
assert.strictEqual(wrapper.prop('style').backgroundImage, 'url(/bar.jpg)');
});

describe('prop: component', () => {
it('should render `img` component when `img` specified', () => {
const wrapper = shallow(<CardMedia image="/foo.jpg" component="img" />);
assert.isTrue(wrapper.is('img'));
});

it('should have `src` prop when media component specified', () => {
const wrapper = shallow(<CardMedia image="/foo.jpg" component="iframe" />);
assert.strictEqual(wrapper.prop('src'), '/foo.jpg');
});

it('should not have default inline style when media component specified', () => {
const wrapper = shallow(<CardMedia src="/foo.jpg" component="picture" />);
assert.strictEqual(wrapper.prop('style'), undefined);
});

it('should not have `src` prop if not media component specified', () => {
const wrapper = shallow(<CardMedia image="/foo.jpg" component="table" />);
assert.strictEqual(wrapper.prop('src'), undefined);
});
});
});
2 changes: 1 addition & 1 deletion test/typescript/components.spec.tsx
Expand Up @@ -158,7 +158,7 @@ const CardMediaTest = () =>
title="Shrimp and Chorizo Paella"
subheader="September 14, 2016"
/>
<CardMedia image="src.png">
<CardMedia image="src.png" component="div">
<img src={'image/src.png'} alt="Contemplative Reptile" />
</CardMedia>
<CardContent>
Expand Down