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

[Chip] Migrate component [Avatar] Support children, change default colors #5852

Merged
merged 1 commit into from
Jan 11, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ node_modules
/packages/**/lib
/packages/icon-builder
/packages/material-ui-codemod/modules/v0.15.0
/src/svg-icons
/test/coverage
/test/regressions/
/test/integration/
4 changes: 2 additions & 2 deletions docs/api/Avatar/Avatar.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ Props
| Name | Type | Default | Description |
|:-----|:-----|:--------|:------------|
| alt | string | '' | Used in combination with `src` or `srcSet` to provide an alt attribute for the rendered `img` element. |
| children | node | | Used to render icon or text elements inside the Avatar. `src` and `alt` props will not be used and no `img` will be rendered by default.<br>This can be an element, or just a string. |
| className | string | | The CSS class name of the root element. |
| component | string | 'div' | |
| icon | node | | Supply a custom icon. `src` and `alt` props will not be used and no `img` will be renderd by default.<br>This can be a custom element, or even just a string. |
| component | string | 'div' | The component type of the root element. |
| sizes | string | | sizes desc |
| src | string | | src desc |
| srcSet | string | | srcSet desc |
Expand Down
23 changes: 23 additions & 0 deletions docs/api/Chip/Chip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Chip
====

Chips represent complex entities in small blocks, such as a contact.

```jsx
<Chip avatar={<Avatar>} label="Label text" />
```

Props
-----

| Name | Type | Default | Description |
|:-----|:-----|:--------|:------------|
| avatar | node | | Avatar element. |
| className | string | | CSS `className` of the root element. |
| deleteIconClassName | string | | CSS `className` of the delete icon element. |
| label | string | | Label |
| labelClassName | string | | CSS `className` of the label. |
| onClick | function | | Callback function fired when the `Chip` element is clicked. If set, the chip will by styled for hover focus and active states.<br><br>**Signature:**<br>`function(event: object) => void`<br>*event:* `onClick` event targeting the root element. |
| onRequestDelete | function | | Callback function fired when the delete icon is clicked. If set, the delete icon will be shown.<br><br>**Signature:**<br>`function(event: object) => void`<br>*event:* `onClick` event targeting the delete icon element. |

Any other properties supplied will be spread to the root element.
Binary file added docs/site/assets/images/uxceo-128.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 9 additions & 12 deletions docs/site/src/demos/avatars/IconAvatars.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,15 @@ export default function IconAvatars(props, context) {
const classes = context.styleManager.render(styleSheet);
return (
<div className={classes.row}>
<Avatar
icon={<FolderIcon />}
className={classes.avatar}
/>
<Avatar
icon={<PageviewIcon />}
className={classes.pinkAvatar}
/>
<Avatar
icon={<AssignmentIcon />}
className={classes.greenAvatar}
/>
<Avatar className={classes.avatar}>
<FolderIcon />
</Avatar>
<Avatar className={classes.pinkAvatar}>
<PageviewIcon />
</Avatar>
<Avatar className={classes.greenAvatar}>
<AssignmentIcon />
</Avatar>
</div>
);
}
Expand Down
15 changes: 3 additions & 12 deletions docs/site/src/demos/avatars/LetterAvatars.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,9 @@ export default function LetterAvatars(props, context) {
const classes = context.styleManager.render(styleSheet);
return (
<div className={classes.row}>
<Avatar
icon="H"
className={classes.avatar}
/>
<Avatar
icon="N"
className={classes.orangeAvatar}
/>
<Avatar
icon="O"
className={classes.purpleAvatar}
/>
<Avatar className={classes.avatar}>H</Avatar>
<Avatar className={classes.orangeAvatar}>N</Avatar>
<Avatar className={classes.purpleAvatar}>OP</Avatar>
</div>
);
}
Expand Down
4 changes: 2 additions & 2 deletions docs/site/src/demos/avatars/avatars.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ Image avatars can be created by passing standard `img` props `src` or `srcSet` i

## Icon avatars

Icon avatars are created by passing an icon prop.
Icon avatars are created by passing an icon as `children`.

{{demo='demos/avatars/IconAvatars.js'}}

## Letter avatars

Avatars containing simple characters can be created by passing your string as the `icon` prop.
Avatars containing simple characters can be created by passing your string as `children`.

{{demo='demos/avatars/LetterAvatars.js'}}
65 changes: 65 additions & 0 deletions docs/site/src/demos/chips/Chips.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// @flow weak

import React, { PropTypes } from 'react';
import { createStyleSheet } from 'jss-theme-reactor';
import Avatar from 'material-ui/Avatar';
import Chip from 'material-ui/Chip';
import Face from 'material-ui/svg-icons/face';
import { grey } from 'material-ui/styles/colors';
import avatarImage from 'docs/site/assets/images/uxceo-128.jpg';

const styleSheet = createStyleSheet('Chips', () => ({
chip: {
margin: '0 8px',
},
svgIcon: {
color: grey[800],
},
row: {
display: 'flex',
justifyContent: 'center',
},
}));

function handleRequestDelete() {
alert('You clicked the delete icon.'); // eslint-ignore-line no-alert
}

function handleClick() {
alert('You clicked the Chip.'); // eslint-ignore-line no-alert
}

export default function Chips(props, context) {
const classes = context.styleManager.render(styleSheet);
return (
<div className={classes.row}>
<Chip
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This element is focusable but don't have :focus state.
Is that expected?
capture d ecran 2017-01-10 a 23 53 46

label="Basic Chip"
className={classes.chip}
/>
<Chip
avatar={<Avatar>MB</Avatar>}
label="Clickable Chip"
onClick={handleClick}
className={classes.chip}
/>
<Chip
avatar={<Avatar src={avatarImage} />}
label="Deletable Chip"
onRequestDelete={handleRequestDelete}
className={classes.chip}
/>
<Chip
avatar={<Avatar><Face className={classes.svgIcon} /></Avatar>}
label="Clickable Deletable Chip"
onClick={handleClick}
onRequestDelete={handleRequestDelete}
className={classes.chip}
/>
</div>
);
}

Chips.contextTypes = {
styleManager: PropTypes.object.isRequired,
};
73 changes: 73 additions & 0 deletions docs/site/src/demos/chips/ChipsArray.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// @flow weak

import React, { Component, PropTypes } from 'react';
import { createStyleSheet } from 'jss-theme-reactor';
import Chip from 'material-ui/Chip';


const styleSheet = createStyleSheet('ChipsArray', () => ({
chip: {
margin: '0 4px',
},
row: {
display: 'flex',
justifyContent: 'center',
},
}));

export default class ChipsArray extends Component {
static contextTypes = {
styleManager: PropTypes.object.isRequired,
};

state = { chipData: [
{ key: 0, label: 'Angular' },
{ key: 1, label: 'JQuery' },
{ key: 2, label: 'Polymer' },
{ key: 3, label: 'ReactJS' },
{ key: 4, label: 'Vue.js' },
] };

styles = {
chip: {
margin: 4,
},
wrapper: {
display: 'flex',
flexWrap: 'wrap',
},
};

handleRequestDelete = (key) => {
if (key === 3) {
alert('Why would you want to delete React?! :)'); // eslint-ignore-line no-alert
return;
}

const chipData = [...this.state.chipData];
const chipToDelete = chipData.indexOf(chipData.find((chip) => chip.key === key));
chipData.splice(chipToDelete, 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it's a great example. splice mutate the array. It would be good to clone chipData first 😁 .

const chipData = [...this.state.chipData];

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 47? (Or am I misunderstanding?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, indeed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, right. I'm surprised React doesn't scream about that!

this.setState({ chipData });
};

render() {
const classes = this.context.styleManager.render(styleSheet);

const renderChip = (data) => {
return (
<Chip
label={data.label}
key={data.key}
onRequestDelete={() => this.handleRequestDelete(data.key)}
className={classes.chip}
/>
);
};

return (
<div className={classes.row}>
{this.state.chipData.map(renderChip, this)}
</div>
);
}
}
28 changes: 28 additions & 0 deletions docs/site/src/demos/chips/chips.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Chips

[Chips](https://www.google.com/design/spec/components/chips.html)
represent complex entities in small blocks, such as a contact.

While included here as a standalone component, the most common use will
be in some form of input, so some of the behaviour demonstrated here is
not shown in context.

## Chip

Examples of Chips, using an image Avatar, SVG Icon Avatar, "Letter"
and (string) Avatar.
Chips with the `onClick` property defined change appearance on focus,
hover, and click.

Chips with the `onRequestDelete` property defined will display a delete
icon which changes appearance on hover.

{{demo='demos/chips/Chips.js'}}

## Chip array
An example of rendering multiple Chips from an array of values.
Deleting a chip removes it from the array. Note that since no
`onClick` property is defined, the Chip can be focused, but does not
gain depth while clicked or touched.

{{demo='demos/chips/ChipsArray.js'}}
4 changes: 2 additions & 2 deletions docs/site/src/demos/lists/FolderList.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ function FolderList(props, context) {
<div className={classes.root}>
<List>
<ListItem button>
<Avatar icon={<FolderIcon />} />
<Avatar><FolderIcon /></Avatar>
<ListItemText primary="Photos" secondary="Jan 9, 2016" />
</ListItem>
<ListItem button>
<Avatar icon={<FolderIcon />} />
<Avatar><FolderIcon /></Avatar>
<ListItemText primary="Work" secondary="Jan 7, 2016" />
</ListItem>
</List>
Expand Down
45 changes: 31 additions & 14 deletions src/Avatar/Avatar.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import React, { PropTypes } from 'react';
import { createStyleSheet } from 'jss-theme-reactor';
import classNames from 'classnames';
import { emphasize } from '../styles/colorManipulator';

export const styleSheet = createStyleSheet('Avatar', (theme) => {
const { palette } = theme;
Expand All @@ -14,13 +15,14 @@ export const styleSheet = createStyleSheet('Avatar', (theme) => {
justifyContent: 'center',
width: 40,
height: 40,
fontSize: 24,
fontSize: 20,
borderRadius: '50%',
overflow: 'hidden',
userSelect: 'none',
},
defaultColor: {
color: palette.getContrastText(palette.text.disabled),
background: palette.text.disabled,
color: palette.background.default,
backgroundColor: emphasize(palette.background.default, 0.26),
},
img: {
maxWidth: '100%',
Expand All @@ -34,8 +36,9 @@ export default function Avatar(props, context) {
const {
alt,
className: classNameProp,
children: childrenProp,
childrenClassName: childrenClassNameProp,
component,
icon,
sizes,
src,
srcSet,
Expand All @@ -44,18 +47,22 @@ export default function Avatar(props, context) {

const classes = context.styleManager.render(styleSheet);
const className = classNames(classes.root, {
[classes.defaultColor]: icon && !src && !srcSet,
[classes.defaultColor]: childrenProp && !src && !srcSet,
}, classNameProp);

const containerProps = {
className,
...other,
};

let children = null;

if (icon) {
children = icon;
if (childrenProp) {
if (childrenClassNameProp && React.isValidElement(childrenProp)) {
const childrenClassName = classNames(childrenClassNameProp, childrenProp.props.className);
children = React.cloneElement(childrenProp, { className: childrenClassName });
} else {
children = childrenProp;
}
} else if (src || srcSet) {
const imgProps = {
alt,
Expand All @@ -76,18 +83,28 @@ Avatar.propTypes = {
* provide an alt attribute for the rendered `img` element.
*/
alt: PropTypes.string,
/**
* Used to render icon or text elements inside the Avatar.
* `src` and `alt` props will not be used and no `img` will
* be rendered by default.
*
* This can be an element, or just a string.
*/
children: PropTypes.node,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was the issue with the icon property? I mean, we could have simply renamed it children. Why keeping both or do we need a different logic?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not keeping both, I just didn't want to barge in and change the API without discussing it first, so it left both options in place until everyone was agreed. I'll strip it back to just children.

/**
* @ignore
* The className of the child element.
* Used by Chip to style the Avatar icon.
*/
childrenClassName: PropTypes.string,
/**
* The CSS class name of the root element.
*/
className: PropTypes.string,
component: PropTypes.string,
/**
* Supply a custom icon. `src` and `alt` props will
* not be used and no `img` will be renderd by default.
*
* This can be a custom element, or even just a string.
* The component type of the root element.
*/
icon: PropTypes.node,
component: PropTypes.string,
/**
* sizes desc
*/
Expand Down
Loading