Skip to content

Commit

Permalink
feat(chips): Update chips to use ids and add input chips (#246)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Updated API for `selectedChipIds` and `handleSelect` props in ChipSet and `id` prop in Chip.
  • Loading branch information
bonniezhou authored Sep 20, 2018
1 parent e1918fa commit 14353ab
Show file tree
Hide file tree
Showing 13 changed files with 878 additions and 272 deletions.
105 changes: 37 additions & 68 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"allowed": [
"button",
"card",
"chips",
"fab",
"floating-label",
"line-ripple",
Expand Down Expand Up @@ -104,6 +105,7 @@
"resemblejs": "^2.10.3",
"sass-loader": "^6.0.7",
"testdouble": "^3.6.0",
"uuid": "^3.3.2",
"validate-commit-msg": "^2.14.0",
"webpack": "^3.11.0",
"webpack-dev-server": "^2.11.2"
Expand Down
116 changes: 95 additions & 21 deletions packages/chips/Chip.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import withRipple from '../ripple';
import {MDCChipFoundation} from '@material/chips/dist/mdc.chips';

export class Chip extends Component {
chipElement_ = null;
foundation_ = null;
state = {
classList: new Set(),
Expand All @@ -35,18 +36,28 @@ export class Chip extends Component {
componentDidMount() {
this.foundation_ = new MDCChipFoundation(this.adapter);
this.foundation_.init();
this.foundation_.setSelected(this.props.selected);
}

componentDidUpdate(prevProps) {
if (this.props.selected !== prevProps.selected) {
this.foundation_.setSelected(this.props.selected);
}
}

componentWillUnmount() {
this.foundation_.destroy();
}

init = (el) => {
this.chipElement_ = el;
this.props.initRipple(el);
}

get classes() {
const {classList} = this.state;
const {className, selected} = this.props;
return classnames('mdc-chip', Array.from(classList), className, {
'mdc-chip--selected': selected,
});
const {className} = this.props;
return classnames('mdc-chip', Array.from(classList), className);
}

get adapter() {
Expand All @@ -62,63 +73,126 @@ export class Chip extends Component {
this.setState({classList});
},
hasClass: (className) => this.classes.split(' ').includes(className),
eventTargetHasClass: (target, className) => target.classList.contains(className),
getComputedStyleValue:
(propertyName) => window.getComputedStyle(this.chipElement_).getPropertyValue(propertyName),
setStyleProperty: (propertyName, value) => this.chipElement_.style.setProperty(propertyName, value),
notifyRemoval: () => this.props.handleRemove(this.props.id),
};
}

handleClick = (e) => {
if (typeof this.props.onClick === 'function') {
this.props.onClick(e);
}
this.props.handleSelect(this.props.id);
onClick = (e) => {
const {onClick, handleSelect, id} = this.props;
onClick(e);
handleSelect(id);
}

handleRemoveIconClick = (e) => this.foundation_.handleTrailingIconInteraction(e);

handleTransitionEnd = (e) => this.foundation_.handleTransitionEnd(e);

renderLeadingIcon = (leadingIcon) => {
const {
className,
...otherProps
} = leadingIcon.props;

const props = {
className: classnames(
className,
'mdc-chip__icon',
'mdc-chip__icon--leading',
),
...otherProps,
};

return React.cloneElement(leadingIcon, props);
};

renderRemoveIcon = (removeIcon) => {
const {
className,
...otherProps
} = removeIcon.props;

const props = {
className: classnames(
className,
'mdc-chip__icon',
'mdc-chip__icon--trailing',
),
onClick: this.handleRemoveIconClick,
onKeyDown: this.handleRemoveIconClick,
tabIndex: 0,
role: 'button',
...otherProps,
};

return React.cloneElement(removeIcon, props);
};

render() {
const {
className, // eslint-disable-line no-unused-vars
label,
handleSelect, // eslint-disable-line no-unused-vars
onClick, // eslint-disable-line no-unused-vars
chipCheckmark,
computeBoundingRect, // eslint-disable-line no-unused-vars
/* eslint-disable no-unused-vars */
id,
className,
selected,
handleSelect,
handleRemove,
onClick,
computeBoundingRect,
initRipple,
unbounded, // eslint-disable-line no-unused-vars
unbounded,
/* eslint-enable no-unused-vars */
chipCheckmark,
leadingIcon,
removeIcon,
label,
...otherProps
} = this.props;

return (
<div
tabIndex='0'
className={this.classes}
onClick={this.handleClick}
ref={initRipple}
onClick={this.onClick}
onTransitionEnd={this.handleTransitionEnd}
ref={this.init}
{...otherProps}
>
{leadingIcon ? this.renderLeadingIcon(leadingIcon) : null}
{chipCheckmark}
<div className='mdc-chip__text'>{label}</div>
{removeIcon ? this.renderRemoveIcon(removeIcon) : null}
</div>
);
}
}

Chip.propTypes = {
id: PropTypes.number,
id: PropTypes.string.isRequired,
label: PropTypes.string,
className: PropTypes.string,
selected: PropTypes.bool,
handleSelect: PropTypes.func,
handleRemove: PropTypes.func,
onClick: PropTypes.func,
// The following props are handled by withRipple and do not require defaults.
initRipple: PropTypes.func,
unbounded: PropTypes.bool,
chipCheckmark: PropTypes.node,
leadingIcon: PropTypes.element,
removeIcon: PropTypes.element,
computeBoundingRect: PropTypes.func,
};

Chip.defaultProps = {
id: -1,
label: '',
className: '',
selected: false,
onClick: () => {},
initRipple: () => {},
handleSelect: () => {},
handleRemove: () => {},
};

export default withRipple(Chip);
Loading

0 comments on commit 14353ab

Please sign in to comment.