Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import React from 'react'
- import { string, object } from 'prop-types'
- import styles from './AnimatedHeightContainer.css'
- class AnimatedHeightContainer extends React.Component {
- static propTypes = {
- className: string,
- style: object,
- }
- constructor () {
- super()
- this.el = null
- this.manualUpdate = this.manualUpdate.bind(this)
- }
- componentDidMount () {
- this.manualUpdate()
- window.addEventListener('resize', this.manualUpdate)
- }
- componentWillUnmount () {
- window.removeEventListener('resize', this.manualUpdate)
- }
- componentDidUpdate () {
- this.manualUpdate()
- }
- async manualUpdate () {
- const animationFrame = async () => new Promise(res => requestAnimationFrame(() => res()))
- // Compute the height of the content
- const originalHeight = this.el.style.height
- this.el.style.height = 'auto'
- const computedHeight = this.el.getBoundingClientRect().height
- await animationFrame() // [0]
- this.el.style.height = originalHeight
- // Manually set the height to the computed height to force a css transition
- // (this is needed since css won't transition to 'auto')
- await animationFrame()
- this.el.style.height = computedHeight + 'px'
- // [0] If we have multiple AnimatedHeightContainer's nested, the ancestor's height
- // calculation (above) is dependent on all it's decendant's computed heights
- // (i.e height: auto) So we need to pause somehow until they've all been
- // calculated.
- // All the browsers seem to handle this timing stuff differently. setTimeout
- // doesn't work half the time on Chrome, but requestAnimationFrame results in
- // a 1-frame flash of bad animation on Safari. I've picked the lesser of two
- // evils for now.
- }
- render () {
- return (
- <div
- className={`${styles.container} ${this.props.className}`}
- style={this.props.style}
- ref={el => this.el = el}
- >
- {this.props.children}
- </div>
- )
- }
- }
- export default AnimatedHeightContainer
Add Comment
Please, Sign In to add comment