Skip to content

Commit

Permalink
[FocusRipple] Only render focus ripple when shown
Browse files Browse the repository at this point in the history
  • Loading branch information
Hai Nguyen committed Jul 18, 2015
1 parent 604a485 commit d303cac
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 45 deletions.
40 changes: 22 additions & 18 deletions src/enhanced-button.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
let React = require('react');
let KeyCode = require('./utils/key-code');
let Colors = require('./styles/colors');
let StylePropable = require('./mixins/style-propable');
let Colors = require('./styles/colors');
let KeyCode = require('./utils/key-code');
let FocusRipple = require('./ripples/focus-ripple');
let TouchRipple = require('./ripples/touch-ripple');


let _tabPressed = false;

let EnhancedButton = React.createClass({
Expand Down Expand Up @@ -76,11 +77,14 @@ let EnhancedButton = React.createClass({
componentDidMount() {
if (!EnhancedButton.hasStyleBeenInjected) {
let style = document.createElement("style");
style.innerHTML = 'button::-moz-focus-inner,' +
'input::-moz-focus-inner {' +
' border: 0;' +
' padding: 0;' +
' }';
style.innerHTML = `
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
`;

document.body.appendChild(style);
EnhancedButton.hasStyleBeenInjected = true;
}
Expand Down Expand Up @@ -139,6 +143,17 @@ let EnhancedButton = React.createClass({

let buttonChildren = [];

if (!disabled && !disableFocusRipple && !disableKeyboardFocus) {
buttonChildren.push(
<FocusRipple
key="focusRipple"
color={focusRippleColor}
opacity={focusRippleOpacity}
show={this.state.isKeyboardFocused}
/>
);
}

// Create ripples if we need to
if (!disabled && !disableTouchRipple) {
buttonChildren.push(
Expand All @@ -155,17 +170,6 @@ let EnhancedButton = React.createClass({
buttonChildren.push(this.props.children);
}

if (!disabled && !disableFocusRipple && !disableKeyboardFocus) {
buttonChildren.push(
<FocusRipple
key="focusRipple"
color={focusRippleColor}
opacity={focusRippleOpacity}
show={this.state.isKeyboardFocused}
/>
);
}

if (disabled && linkButton) {
return (
<span
Expand Down
70 changes: 48 additions & 22 deletions src/ripples/focus-ripple.jsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
let React = require('react');
let React = require('react/addons');
let PureRenderMixin = React.addons.PureRenderMixin;
let StylePropable = require('../mixins/style-propable');
let Transitions = require('../styles/transitions');
let Colors = require('../styles/colors');
let AutoPrefix = require('../styles/auto-prefix');
let Colors = require('../styles/colors');
let Transitions = require('../styles/transitions');
let ScaleInTransitionGroup = require('../transition-groups/scale-in');

const pulsateDuration = 750;


let FocusRipple = React.createClass({

mixins: [StylePropable],
mixins: [PureRenderMixin, StylePropable],

propTypes: {
color: React.PropTypes.string,
innerStyle: React.PropTypes.object,
opacity: React.PropTypes.number,
show: React.PropTypes.bool,
innerStyle: React.PropTypes.object,
},

getDefaultProps() {
Expand All @@ -25,46 +27,70 @@ let FocusRipple = React.createClass({
},

componentDidMount() {
this._setRippleSize();
this._pulsate();
if (this.props.show) {
this._setRippleSize();
this._pulsate();
}
},

componentDidUpdate() {
if (this.props.show) {
this._setRippleSize();
this._pulsate();
} else {
if (this._timeout) clearTimeout(this._timeout);
}
},

render() {
let outerStyles = this.mergeAndPrefix({

let {
color,
innerStyle,
opacity,
show,
style,
} = this.props;

let mergedRootStyles = this.mergeStyles({
height: '100%',
width: '100%',
position: 'absolute',
top: 0,
left: 0,
transition: Transitions.easeOut(null, ['transform', 'opacity']),
transform: this.props.show ? 'scale(1)' : 'scale(0)',
opacity: this.props.show ? 1 : 0,
overflow: 'hidden',
}, this.props.style);
}, style);

let innerStyles = this.mergeAndPrefix({
position: 'absolute',
height: '100%',
width: '100%',
borderRadius: '50%',
opacity: this.props.opacity ? this.props.opacity : 0.16,
backgroundColor: this.props.color,
opacity: opacity ? opacity : 0.16,
backgroundColor: color,
transition: Transitions.easeOut(pulsateDuration + 'ms', 'transform', null, Transitions.easeInOutFunction),
}, this.props.innerStyle);
}, innerStyle);

let ripple = show ? (
<div ref="innerCircle" style={innerStyles} />
) : null;

return (
<div style={outerStyles}>
<div ref="innerCircle" style={innerStyles} />
</div>
<ScaleInTransitionGroup
maxScale={0.85}
style={mergedRootStyles}>
{ripple}
</ScaleInTransitionGroup>
);
},

_pulsate() {
if (!this.isMounted()) return;

let startScale = 'scale(0.75)';
let endScale = 'scale(0.85)';
let innerCircle = React.findDOMNode(this.refs.innerCircle);
if (!innerCircle) return;

let startScale = 'scale(1)';
let endScale = 'scale(0.85)';
let currentScale = innerCircle.style[AutoPrefix.single('transform')];
let nextScale;

Expand All @@ -73,7 +99,7 @@ let FocusRipple = React.createClass({
endScale : startScale;

innerCircle.style[AutoPrefix.single('transform')] = nextScale;
setTimeout(this._pulsate, pulsateDuration);
this._timeout = setTimeout(this._pulsate, pulsateDuration);
},

_setRippleSize() {
Expand Down
76 changes: 76 additions & 0 deletions src/transition-groups/scale-in-child.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
let React = require('react/addons');
let StylePropable = require('../mixins/style-propable');
let AutoPrefix = require('../styles/auto-prefix');
let Transitions = require('../styles/transitions');


let ScaleInChild = React.createClass({

mixins: [StylePropable],

propTypes: {
enterDelay: React.PropTypes.number,
maxScale: React.PropTypes.number,
minScale: React.PropTypes.number,
},

getDefaultProps: function() {
return {
enterDelay: 0,
maxScale: 1,
minScale: 0,
};
},

componentWillEnter(callback) {
let style = React.findDOMNode(this).style;

style.opacity = '0';
AutoPrefix.set(style, 'transform', 'scale(0)');

setTimeout(callback, this.props.enterDelay);
},

componentDidEnter() {
let style = React.findDOMNode(this).style;

style.opacity = '1';
AutoPrefix.set(style, 'transform', 'scale(' + this.props.maxScale + ')');
},

componentWillLeave(callback) {
let style = React.findDOMNode(this).style;

style.opacity = '0';
AutoPrefix.set(style, 'transform', 'scale(' + this.props.minScale + ')');

setTimeout(callback, 450);
},

render() {
let {
children,
enterDelay,
style,
...other,
} = this.props;

let mergedRootStyles = this.mergeAndPrefix({
position: 'absolute',
height: '100%',
width: '100%',
top: 0,
left: 0,
transition: Transitions.easeOut(null, ['transform', 'opacity']),
}, style);

return (
<div {...other} style={mergedRootStyles}>
{children}
</div>
);
},

});

module.exports = ScaleInChild;
66 changes: 66 additions & 0 deletions src/transition-groups/scale-in.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
let React = require('react/addons');
let ReactTransitionGroup = React.addons.TransitionGroup;
let StylePropable = require('../mixins/style-propable');
let ScaleInChild = require('./scale-in-child');


let ScaleIn = React.createClass({

mixins: [StylePropable],

propTypes: {
childStyle: React.PropTypes.object,
enterDelay: React.PropTypes.number,
maxScale: React.PropTypes.number,
minScale: React.PropTypes.number,
},

getDefaultProps() {
return {
enterDelay: 0,
};
},

render() {
let {
children,
childStyle,
enterDelay,
maxScale,
minScale,
style,
...other,
} = this.props;

let mergedRootStyles = this.mergeAndPrefix({
position: 'relative',
overflow: 'hidden',
height: '100%',
}, style);

let newChildren = React.Children.map(children, (child) => {
return (
<ScaleInChild
key={child.key}
enterDelay={enterDelay}
maxScale={maxScale}
minScale={minScale}
style={childStyle}>
{child}
</ScaleInChild>
);
});

return (
<ReactTransitionGroup
{...other}
style={mergedRootStyles}
component="div">
{newChildren}
</ReactTransitionGroup>
);
},

});

module.exports = ScaleIn;
2 changes: 1 addition & 1 deletion src/transition-groups/slide-in-child.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ let SlideInChild = React.createClass({
width: '100%',
top: 0,
left: 0,
transition: Transitions.easeOut(),
transition: Transitions.easeOut(null, ['transform', 'opacity']),
}, style);

return (
Expand Down
8 changes: 4 additions & 4 deletions src/transition-groups/slide-in.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ let SlideIn = React.createClass({
mixins: [StylePropable],

propTypes: {
childEnterDelay: React.PropTypes.number,
enterDelay: React.PropTypes.number,
childStyle: React.PropTypes.object,
direction: React.PropTypes.oneOf(['left', 'right', 'up', 'down']),
},

getDefaultProps() {
return {
childEnterDelay: 0,
enterDelay: 0,
direction: 'left',
};
},

render() {
let {
childEnterDelay,
enterDelay,
children,
childStyle,
direction,
Expand All @@ -42,7 +42,7 @@ let SlideIn = React.createClass({
<SlideInChild
key={child.key}
direction={direction}
enterDelay={childEnterDelay}
enterDelay={enterDelay}
getLeaveDirection={this._getLeaveDirection}
style={childStyle}>
{child}
Expand Down

0 comments on commit d303cac

Please sign in to comment.