Skip to content

Instantly share code, notes, and snippets.

@malectro
Created June 1, 2017 22:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save malectro/24556d84fafb672b4d65c35ce158b3d2 to your computer and use it in GitHub Desktop.
Save malectro/24556d84fafb672b4d65c35ce158b3d2 to your computer and use it in GitHub Desktop.
a simple expand/collapse container for single components
// @flow
import React, {Component, Children} from 'react';
import {findDOMNode} from 'react-dom';
import {TransitionGroup} from 'react-transition-group';
const OnlyChild = ({children}) => (
Children.toArray(children)[0] || null
);
export const Expander = ({duration, children}) => {
const child = Children.toArray(children)[0] || null;
return (
<TransitionGroup component={OnlyChild}>
{ child &&
<Expandee duration={duration}>
{child}
</Expandee>
}
</TransitionGroup>
);
};
export default Expander;
class Expandee extends Component {
static defaultProps = {
duration: 200,
};
state = {
prerender: false,
animate: false,
height: 0,
};
componentWillEnter(callback) {
this.setState({
prerender: true,
}, () => {
const element = findDOMNode(this);
const height = element && element.offsetHeight;
this.setState({
prerender: false,
animate: true,
height: 0,
}, () => {
// reflow
element && element.offsetHeight
this.setState({
height,
}, () => {
setTimeout(() => {
this.setState({
animate: false,
}, callback);
}, this.props.duration);
});
});
});
}
componentWillLeave(callback) {
const element = findDOMNode(this);
const height = element && element.offsetHeight;
this.setState({
animate: true,
height,
}, () => {
// reflow
element && element.offsetHeight;
this.setState({
height: 0,
}, () => {
setTimeout(() => {
this.setState({
animate: false,
}, callback);
}, this.props.duration);
});
});
}
render() {
const {children} = this.props;
const {prerender, animate, height} = this.state;
let style;
if (prerender) {
style = {
position: 'absolute',
height: 'auto',
visibility: 'hidden',
};
} else if (animate) {
style = {
height,
};
}
const child = Children.only(children);
return React.cloneElement(child, {style});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment