Skip to content

Commit

Permalink
feat(framework-examples): Add ripple support to React checkbox example (
Browse files Browse the repository at this point in the history
#233)

Part of #211
  • Loading branch information
codesuki authored and traviskaufman committed Feb 3, 2017
1 parent 08ffe42 commit db6a6db
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 6 deletions.
3 changes: 2 additions & 1 deletion framework-examples/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
"react-scripts": "0.8.4"
},
"dependencies": {
"@material/checkbox": "^0.1.0",
"@material/checkbox": "^0.1.2",
"@material/form-field": "^0.1.0",
"@material/ripple": "^0.1.2",
"classnames": "^2.2.5",
"immutable": "^3.8.1",
"react": "^15.4.1",
Expand Down
66 changes: 61 additions & 5 deletions framework-examples/react/src/Checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,23 @@
*/

import React, {PureComponent, PropTypes} from 'react';
import {Set as ImmutableSet} from 'immutable';
import {Set as ImmutableSet, Map as ImmutableMap} from 'immutable';
// Temporarily using relative reference until we publish on npm.
import {getCorrectEventName} from '@material/animation/dist/mdc.animation';
import {MDCRipple, MDCRippleFoundation} from '@material/ripple/dist/mdc.ripple';
import {MDCCheckboxFoundation} from '@material/checkbox/dist/mdc.checkbox';
import '@material/checkbox/dist/mdc.checkbox.css';

function getMatchesProperty(HTMLElementPrototype) {
return [
'webkitMatchesSelector', 'msMatchesSelector', 'matches',
].filter((p) => p in HTMLElementPrototype).pop();
}

const {ANIM_END_EVENT_NAME} = MDCCheckboxFoundation.strings;

const MATCHES = getMatchesProperty(HTMLElement.prototype);

export default class Checkbox extends PureComponent {
static propTypes = {
id: PropTypes.string,
Expand All @@ -47,11 +57,10 @@ export default class Checkbox extends PureComponent {

state = {
classes: new ImmutableSet(),
rippleCss: new ImmutableMap(),
checkedInternal: false,
indeterminateInternal: false
}
classesToAdd = new ImmutableSet();
classesToRemove = new ImmutableSet();

// Here we initialize a foundation class, passing it an adapter which tells it how to
// work with the React component in an idiomatic way.
Expand All @@ -64,12 +73,12 @@ export default class Checkbox extends PureComponent {
})),
registerAnimationEndHandler: handler => {
if (this.refs.root) {
this.refs.root.addEventListener(ANIM_END_EVENT_NAME, handler);
this.refs.root.addEventListener(getCorrectEventName(window, 'animationend'), handler);
}
},
deregisterAnimationEndHandler: handler => {
if (this.refs.root) {
this.refs.root.removeEventListener(ANIM_END_EVENT_NAME, handler);
this.refs.root.removeEventListener(getCorrectEventName(window, 'animationend'), handler)
}
},
registerChangeHandler: handler => {
Expand Down Expand Up @@ -101,6 +110,45 @@ export default class Checkbox extends PureComponent {
isAttachedToDOM: () => Boolean(this.refs.nativeCb),
});

// For browser compatibility we extend the default adapter which checks for css variable support.
rippleFoundation = new MDCRippleFoundation(Object.assign(MDCRipple.createAdapter(this), {
isUnbounded: () => true,
isSurfaceActive: () => this.refs.nativeCb[MATCHES](':active'),
addClass: className => {
this.setState(prevState => ({
classes: prevState.classes.add(className)
}));
},
removeClass: className => {
this.setState(prevState => ({
classes: prevState.classes.remove(className)
}));
},
registerInteractionHandler: (evtType, handler) => {
this.refs.nativeCb.addEventListener(evtType, handler);
},
deregisterInteractionHandler: (evtType, handler) => {
this.refs.nativeCb.removeEventListener(evtType, handler);
},
updateCssVariable: (varName, value) => {
this.setState(prevState => ({
rippleCss: prevState.rippleCss.set(varName, value)
}));
},
computeBoundingRect: () => {
const {left, top} = this.refs.root.getBoundingClientRect();
const DIM = 40;
return {
top,
left,
right: left + DIM,
bottom: top + DIM,
width: DIM,
height: DIM,
};
},
}));

render() {
// Within render, we generate the html needed to render a proper MDC-Web checkbox.
return (
Expand Down Expand Up @@ -138,8 +186,10 @@ export default class Checkbox extends PureComponent {
// so that proper work can be performed.
componentDidMount() {
this.foundation.init();
this.rippleFoundation.init();
}
componentWillUnmount() {
this.rippleFoundation.destroy();
this.foundation.destroy();
}

Expand All @@ -160,5 +210,11 @@ export default class Checkbox extends PureComponent {
if (this.refs.nativeCb) {
this.refs.nativeCb.indeterminate = this.state.indeterminateInternal;
}
// To make the ripple animation work we update the css properties after React finished building the DOM.
if (this.refs.root) {
this.state.rippleCss.forEach((v, k) => {
this.refs.root.style.setProperty(k, v);
});
}
}
}

0 comments on commit db6a6db

Please sign in to comment.