Skip to content

Instantly share code, notes, and snippets.

@shark0der
Created May 16, 2016 00:45
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 shark0der/e540e26892ebbe196a11a2fafd55bbf2 to your computer and use it in GitHub Desktop.
Save shark0der/e540e26892ebbe196a11a2fafd55bbf2 to your computer and use it in GitHub Desktop.
import React from 'react';
import pureRender from 'pure-render-decorator';
import classes from './Navbar.scss';
const REST = 'REST';
const MEASURE = 'MEASURE';
const PREPARE = 'PREPARE';
const ANIMATE = 'ANIMATE';
@pureRender
export default class Navbar extends React.Component {
constructor(props) {
super(props);
this.timeoutID = false;
}
state = {
collapse: true,
animationPhase: REST,
elementHeight: 0,
}
componentWillUnmount() {
clearTimeout(this.timeoutID);
}
onCollapseClick = () => {
if (this.state.animationPhase !== REST) return;
// set target element state
const collapse = !this.state.collapse;
this.setState({
collapse,
animationPhase: MEASURE,
}, this.onMeasuringInitiated); // callback is called after render
}
onMeasuringInitiated = () => {
const { collapseTarget } = this.refs;
const elementHeight = collapseTarget.offsetHeight;
this.setState({
elementHeight,
animationPhase: PREPARE,
}, this.onAnimationPrepared);
}
onAnimationPrepared = () => {
// animate!
this.timeoutID = setTimeout(() => {
this.setState({
animationPhase: ANIMATE,
}, this.onAnimationStarted);
}, 50); // "nextTick", sort of
}
onAnimationStarted = () => {
this.timeoutID = setTimeout(this.onTimeout, 350);
}
onTimeout = () => {
this.setState({
animationPhase: REST,
});
clearTimeout(this.timeoutID);
};
/*
* CSS classes:
* .collapse - hides content
* .collapsing - is applied during transitions
* .collapse.in - shows content
*/
render() {
const {
collapse, elementHeight, animationPhase,
} = this.state;
const navbarClasses = [
classes.navbarCollapse,
'navbar-collapse',
];
const navbarStyle = {};
switch (animationPhase) {
case REST:
navbarClasses.push(collapse ? 'collapse' : 'collapse in');
break;
case MEASURE:
// smile and wave, guys!
navbarClasses.push(collapse ? 'collapse in' : '');
break;
case PREPARE:
// explicitly setting the starting height
navbarStyle.height = collapse ? elementHeight : 0;
navbarClasses.push('collapsing');
break;
case ANIMATE:
// everybody do the flop!
navbarClasses.push('collapsing');
navbarStyle.height = collapse ? 0 : elementHeight;
break;
default:
}
return (
<nav className={`navbar navbar-default ${classes.navbar}`}>
<div className="navbar-header">
<div className="navbar-brand">
<a className={classes.headerLogo} href={'/'}>Logo</a>
</div>
<button
type="button"
className="navbar-toggle"
onClick={this.onCollapseClick}
>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
</button>
</div>
<div
className={navbarClasses.join(' ')}
style={navbarStyle}
ref="collapseTarget"
>
<ul className={`nav navbar-nav navbar-right text-center ${classes.headerMenu}`}>
<li><a href="#">Acasa</a></li>
<li><a href="#">Despre noi</a></li>
<li><a href="#">Programe</a></li>
<li><a href="#">Evenimente</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Contact</a></li>
</ul>
</div>
</nav>
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment