Skip to content

Commit

Permalink
Decouple animation from popover
Browse files Browse the repository at this point in the history
  • Loading branch information
chrismcv committed Dec 4, 2015
1 parent 9381098 commit 1741f62
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 75 deletions.
140 changes: 140 additions & 0 deletions src/popover/popover-default-animation.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import Transitions from '../styles/transitions';
import React from 'react';
import PropTypes from '../utils/prop-types';
import StylePropable from '../mixins/style-propable';
import DefaultRawTheme from '../styles/raw-themes/light-raw-theme';
import ThemeManager from '../styles/theme-manager';
import Paper from '../paper';

const PopoverAnimation = React.createClass({
mixins: [StylePropable],

propTypes: {
children: React.PropTypes.node,
className: React.PropTypes.string,
open: React.PropTypes.bool.isRequired,
style: React.PropTypes.object,
targetOrigin: PropTypes.origin,
zDepth: PropTypes.zDepth,
},

getInitialState() {
return {
muiTheme: this.context.muiTheme ? this.context.muiTheme : ThemeManager.getMuiTheme(DefaultRawTheme),
open: false,
};
},

contextTypes: {
muiTheme: React.PropTypes.object,
},

//for passing default theme context to children
childContextTypes: {
muiTheme: React.PropTypes.object,
},

getChildContext() {
return {
muiTheme: this.state.muiTheme,
};
},

getDefaultProps() {
return {
style: {},
zDepth: 1,
};
},

componentDidMount() {
this.setState({open:true}); //eslint-disable-line react/no-did-mount-set-state
},

componentWillReceiveProps(nextProps, nextContext) {
let newMuiTheme = nextContext.muiTheme ? nextContext.muiTheme : this.state.muiTheme;

this.setState({
open:nextProps.open,
muiTheme:newMuiTheme,
});
},


getStyles() {
let {targetOrigin} = this.props;
let horizontal = targetOrigin.horizontal.replace('middle', 'vertical');

return {
base: {
opacity:0,
transform:'scale(0, 0)',
transformOrigin: `${horizontal} ${targetOrigin.vertical}`,
position: 'fixed',
zIndex: this.state.muiTheme.zIndex.popover,
transition: Transitions.easeOut('250ms', ['transform', 'opacity']),
maxHeight:'100%',

},
horizontal: {
maxHeight:'100%',
overflowY:'auto',
transform:'scaleX(0)',
opacity:0,
transformOrigin: `${horizontal} ${targetOrigin.vertical}`,
transition: Transitions.easeOut('250ms', ['transform', 'opacity']),
},
vertical: {
opacity:0,
transform:'scaleY(0)',
transformOrigin: `${horizontal} ${targetOrigin.vertical}`,
transition: Transitions.easeOut('500ms', ['transform', 'opacity']),
},
};
},

getOpenStyles() {
return {
base: {
opacity: 1,
transform:'scale(1, 1)',
},
horizontal: {
opacity: 1,
transform:'scaleX(1)',
},
vertical: {
opacity: 1,
transform:'scaleY(1)',
},
};
},

render() {
let {
className,
style,
zDepth,
} = this.props;

let styles = this.getStyles();
let openStyles = {};
if (this.state.open)
openStyles = this.getOpenStyles();

return (
<Paper
style={this.mergeAndPrefix(styles.base, style, openStyles.base)}
zDepth={zDepth}
className={className}>
<div style={this.mergeAndPrefix(styles.horizontal, openStyles.horizontal)}>
<div style={this.mergeAndPrefix(styles.vertical, openStyles.vertical)}>
{this.props.children}
</div>
</div>
</Paper>
);
},
});

export default PopoverAnimation;
97 changes: 22 additions & 75 deletions src/popover/popover.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import WindowListenable from '../mixins/window-listenable';
import RenderToLayer from '../render-to-layer';
import StylePropable from '../mixins/style-propable';
import PropTypes from '../utils/prop-types';
import Transitions from '../styles/transitions';
import Paper from '../paper';
import throttle from 'lodash.throttle';
import AutoPrefix from '../styles/auto-prefix';
import DefaultRawTheme from '../styles/raw-themes/light-raw-theme';
import ThemeManager from '../styles/theme-manager';
import Extend from '../utils/extend';
import PopoverAnimation from './popover-default-animation';

const Popover = React.createClass({
mixins: [
Expand All @@ -22,6 +21,7 @@ const Popover = React.createClass({
anchorEl: React.PropTypes.object,
anchorOrigin: PropTypes.origin,
animated: React.PropTypes.bool,
animation: React.PropTypes.func,
autoCloseWhenOffScreen: React.PropTypes.bool,
canAutoPosition: React.PropTypes.bool,
children: React.PropTypes.object,
Expand All @@ -40,6 +40,7 @@ const Popover = React.createClass({
vertical: 'bottom',
horizontal: 'left',
},
animation: PopoverAnimation,
animated: true,
autoCloseWhenOffScreen: true,
canAutoPosition: true,
Expand All @@ -60,6 +61,7 @@ const Popover = React.createClass({

return {
open: this.props.open,
closing:false,
muiTheme: this.context.muiTheme ? this.context.muiTheme : ThemeManager.getMuiTheme(DefaultRawTheme),
};
},
Expand Down Expand Up @@ -88,13 +90,12 @@ const Popover = React.createClass({
this.anchorEl = nextProps.anchorEl || this.props.anchorEl;
this.setState({
open: true,
closing:false,
muiTheme: newMuiTheme,
}, () => {
this._animate(true);
});
} else {
if (nextProps.animated) {
this._animate(false);
this.setState({closing:true});
this._isAnimating = true;
this._timeout = setTimeout(() => {
if (this.isMounted()) {
Expand Down Expand Up @@ -130,56 +131,28 @@ const Popover = React.createClass({
},

renderLayer() {
const {
let {
animated,
targetOrigin,
className,
zDepth,
animation,
children,
style,
...other,
} = this.props;

const anchorEl = this.props.anchorEl || this.anchorEl;
const anchor = this.getAnchorPosition(anchorEl);
const horizontal = targetOrigin.horizontal.replace('middle', 'vertical');

const wrapperStyle = this.mergeAndPrefix({
position: 'fixed',
top: anchor.top,
left: anchor.left,
zIndex: this.state.muiTheme.zIndex.popover,
opacity: 1,
overflow: 'auto',
maxHeight: '100%',
transform: 'scale(0,0)',
transformOrigin: `${horizontal} ${targetOrigin.vertical}`,
transition: animated ? Transitions.easeOut('500ms', ['transform', 'opacity']) : null,
}, this.props.style);

const horizontalAnimation = {
maxHeight: '100%',
overflowY: 'auto',
transform: 'scaleX(0)',
opacity: 1,
transition: animated ? Transitions.easeOut('250ms', ['transform', 'opacity']) : null,
transformOrigin: `${horizontal} ${targetOrigin.vertical}`,
};
let Animation = animation;

const verticalAnimation = {
opacity: 1,
transform: 'scaleY(0)',
transformOrigin: `${horizontal} ${targetOrigin.vertical}`,
transition: animated ? Transitions.easeOut('500ms', ['transform', 'opacity']) : null,
};
if (!animated) {
Animation = Paper;
style = {position: 'fixed'};
if (!this.state.open) {
return null;
}
}

return (
<Paper style={wrapperStyle} zDepth={zDepth} className={className} >
<div>
<div style={horizontalAnimation}>
<div style={verticalAnimation}>
{this.props.children}
</div>
</div>
</div>
</Paper>
<Animation {...this.props} style={style} open={this.state.open && !this.state.closing} {...other} >
{children}
</Animation>
);
},

Expand All @@ -197,32 +170,6 @@ const Popover = React.createClass({
this.setPlacement();
},

_animate(open) {
if (!this.refs.layer || !this.refs.layer.getLayer()) {
return;
}

const el = this.refs.layer.getLayer().children[0];
let value = '0';
const inner = el.children[0];
const innerInner = inner.children[0];
const innerInnerInner = innerInner.children[0];
const rootStyle = inner.style;
const innerStyle = innerInner.style;

if (open) {
value = '1';
}

AutoPrefix.set(el.style, 'transform', `scale(${value},${value})`);
AutoPrefix.set(innerInner.style, 'transform', `scaleX(${value})`);
AutoPrefix.set(innerInnerInner.style, 'transform', `scaleY(${value})`);
AutoPrefix.set(rootStyle, 'opacity', value);
AutoPrefix.set(innerStyle, 'opacity', value);
AutoPrefix.set(innerInnerInner.style, 'opacity', value);
AutoPrefix.set(el.style, 'opacity', value);
},

getAnchorPosition(el) {
if (!el) {
el = ReactDOM.findDOMNode(this);
Expand Down

0 comments on commit 1741f62

Please sign in to comment.