Last active
January 27, 2017 17:53
-
-
Save msociety/e3f886ec75f1f0295db2b73beb2d499f to your computer and use it in GitHub Desktop.
React Component FloatingAside
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
const styles = { | |
wrapper: { | |
width: '100%', | |
padding: 0, | |
marginTop: '2.5em' | |
}, | |
fixed: { | |
marginTop: 0, | |
position: 'fixed', | |
zIndex: '99', | |
top: '20px' | |
} | |
}; | |
export default class FloatingAside extends Component { | |
constructor() { | |
super(); | |
this._asideFixedTop = 20; // css value of "top" when comp is .fixed | |
this.state = { | |
asideTop: null, | |
asideHeight: null, | |
windowHeight: window.innerHeight, | |
parentWidth: null | |
}; | |
this.bound_handleScroll = this.handleScroll.bind(this); | |
this.bound_handleResize = this.handleResize.bind(this); | |
} | |
// isScrolling: returns true it the top of this component is hidden | |
isScrolling() { | |
return ((this.state.asideTop !== null) && | |
this.state.asideTop < this._asideFixedTop); | |
} | |
// isTooBig: returns true if this component is higher than window | |
isTooBig() { | |
return ((this.state.asideTop !== null) && | |
((this.state.asideHeight + this._asideFixedTop) > this.state.windowHeight)); | |
} | |
componentDidMount() { | |
let parentRect = this._asideRef.parentElement.getBoundingClientRect(); | |
this.setState({ | |
asideTop: parentRect.top + this._asideRef.offsetTop, | |
asideHeight: this._asideRef.scrollHeight, // paddings + content height | |
windowHeight: window.innerHeight, | |
parentWidth: this._asideRef.parentElement.clientWidth | |
}); | |
window.addEventListener('scroll', this.bound_handleScroll); | |
window.addEventListener('resize', this.bound_handleResize); | |
} | |
componentWillUnmount() { | |
// http://stackoverflow.com/questions/11565471/removing-event-listener-which-was-added-with-bind | |
window.removeEventListener('scroll', this.bound_handleScroll); | |
window.removeEventListener('resize', this.bound_handleResize); | |
} | |
handleScroll() { | |
let parentRect = this._asideRef.parentElement.getBoundingClientRect(); | |
this.setState({ | |
asideTop: parentRect.top + this._asideRef.offsetTop, | |
asideHeight: this._asideRef.scrollHeight, | |
parentWidth: this._asideRef.parentElement.clientWidth | |
}); | |
} | |
handleResize() { | |
let parentRect = this._asideRef.parentElement.getBoundingClientRect(); | |
this.setState({ | |
asideTop: parentRect.top + this._asideRef.offsetTop, | |
asideHeight: this._asideRef.scrollHeight, // paddings + content height | |
windowHeight: window.innerHeight, | |
parentWidth: this._asideRef.parentElement.clientWidth | |
}); | |
} | |
render() { | |
let fixed = (this.isScrolling() && !this.isTooBig()); | |
return ( | |
<div style={styles.wrapper}> | |
<div class="clearfix"></div> | |
<aside | |
ref={(elem) => this._asideRef = elem} | |
style={fixed ? { ...styles.fixed, width: this.state.parentWidth } : {}} | |
> | |
{this.props.children} | |
</aside> | |
</div> | |
); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment