Skip to content

Instantly share code, notes, and snippets.

@tgecho
Last active April 16, 2018 12:40
Show Gist options
  • Save tgecho/4332a21f4d2df4ce3725 to your computer and use it in GitHub Desktop.
Save tgecho/4332a21f4d2df4ce3725 to your computer and use it in GitHub Desktop.
Directional React Animations

Directional React Animations

This is a demo of dynamic directional transitions using React's CSSTransitionGroup.

A Pen by tgecho on CodePen.

License.

const {CSSTransitionGroup} = React.addons;
const SlideTransition = React.createClass({
propTypes: {
depth: React.PropTypes.number.isRequired,
name: React.PropTypes.string,
},
getDefaultProps() {
return {
name: 'slider',
};
},
getInitialState() {
return {direction: 'right'};
},
componentWillReceiveProps(newProps) {
const direction = newProps.depth > this.props.depth ? 'right' : 'left';
this.setState({direction});
},
render() {
const {name, depth} = this.props;
const outerProps = {
className: `${name}-outer-wrapper ${this.props.className}`,
};
const transProps = {
component: 'div',
transitionName: `${name}-${this.state.direction}`,
className: `${name}-transition-group`,
};
const innerProps = {
ref: 'inner',
key: depth,
className: `${name}-inner-wrapper`,
};
return <div {...this.props} {...outerProps}>
<CSSTransitionGroup {...transProps}>
<div {...innerProps}>
{this.props.children}
</div>
</CSSTransitionGroup>
</div>;
}
});
const Browser = React.createClass({
getInitialState() {
return {
path: []
}
},
navUp() {
this.setState({path: this.state.path.slice(0, -1)})
},
navDown(index) {
this.setState({path: this.state.path.concat(index)})
},
render() {
const {path} = this.state;
const items = path.reduce(function(items, key) {
return items[key].children;
}, this.props.items);
return <div className="browser">
<h3>{path.length > 0 ? <a onClick={this.navUp}>← Back</a> : 'Home'}</h3>
<SlideTransition depth={path.length} className="items-container">
{items.map(function(item, index) {
if (item.children) {
return <a className="item" onClick={e => this.navDown(index)} key={item.name}>{item.name}</a>;
} else {
return <div className="item" key={item.name}>{item.name}</div>;
}
}.bind(this))}
</SlideTransition>
</div>;
}
});
const data = [
{name: 'Animal', children: [
{name: 'Land', children: [
{name: 'Cheetah'},
{name: 'Ant'},
]},
{name: 'Air', children: [
{name: 'Eagle'},
]},
{name: 'Water', children: [
{name: 'Nessy'},
]},
]},
{name: 'Vegetable', children: [
{name: 'Broccoli'},
{name: 'IE6'},
]},
{name: 'Mineral', children: [
{name: 'Granite'},
{name: 'Uraninite'},
]},
];
React.render(<Browser items={data} />, document.body);
<script src="//cdnjs.cloudflare.com/ajax/libs/react/0.13.3/react-with-addons.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/es6-shim/0.32.0/es6-shim.js"></script>
a {
cursor: pointer;
display: block;
}
.items-container {
max-width: 20rem;
border: 2px solid #000;
border-radius: .25rem;
}
.item {
padding: .25rem .5rem;
background: linear-gradient(to right, rgba(237,237,237,1) 0%, rgba(246,246,246,1) 47%, rgba(255,255,255,1) 100%);
}
a.item:after {
content: '→';
float: right;
}
a.item:hover {
background: #eee;
}
/* Generic slider styles */
.slider-outer-wrapper {
position: relative;
overflow: hidden;
transition: max-height .2s ease-in;
}
.slider-transition-group {
width: 200%;
overflow: hidden;
}
.slider-inner-wrapper {
width: 50%;
float: right;
transition: all .2s ease-in-out;
&:first-child {
position: relative;
left: -50%;
}
}
.slider-right-enter {
transform: translate3d(100%, 0, 0);
}
.slider-left-enter {
transform: translate3d(-100%, 0, 0);
}
.slider-right-enter-active,
.slider-left-enter-active,
.slider-right-leave,
.slider-left-leave {
transform: translate3d(0, 0, 0);
}
.slider-right-leave-active {
transform: translate3d(-100%, 0, 0);
}
.slider-left-leave-active {
transform: translate3d(100%, 0, 0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment