import React, { PropTypes } from 'react';
import ResizeObserver from 'resize-observer-polyfill';

/**
 * Affix component
 * @description This component provides similar behavior to Facebook sidebar.
 * Affix component wraps content with two elements. relativeContainer and affixContainer.
 * <relativeContainer>
 *  <affixContainer>
 *    {children}
 *  </affixContainer>
 * </relativeContainer>
 * affixContainer uses absolute and fixed positioning, so its height has to be
 * observed and relativeContainer should be updated with that height.
 * affixContainer should make use of absolute and fixed positioning in order to
 * fix content in place when reaching edges, but also allow scrolling when user
 * want to reach content inside of it.
 */
class Affix extends React.Component {
  static propTypes = {
    children: PropTypes.element.isRequired,
    className: PropTypes.string,
    stickPosition: PropTypes.number,
  }

  static defaultProps = {
    className: '',
    stickPosition: 0,
  }

  constructor(props) {
    super(props);
    this.lastScroll = document.body.scrollTop;

    this.top = 0;
    this.bindedBottom = false;
    this.bindedTop = true;

    this.ro = new ResizeObserver((entries) => {
      entries.forEach((entry) => {
        const { height } = entry.contentRect;
        this.relativeContainer.style.height = `${height}px`;
        this.handleScroll();
      });
    });
  }

  componentDidMount() {
    document.addEventListener('scroll', this.handleScroll);
    this.ro.observe(this.affixContainer);
  }

  componentWillUnmount() {
    document.removeEventListener('scroll', this.handleScroll);
    this.ro.unobserve(this.affixContainer);
  }

  handleScroll = () => {
    const { stickPosition } = this.props;

    const windowHeight = document.body.clientHeight;
    const sidebarHeight = this.affixContainer.clientHeight;
    const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    const scrollBottom = scrollTop + windowHeight;
    const scrollDiff = scrollTop - this.lastScroll;
    const scrollingDown = scrollDiff > 0;
    const parent = this.relativeContainer.offsetParent;
    const parentSpace = parent.offsetTop - stickPosition;

    const viewportOffset = this.affixContainer.getBoundingClientRect();

    const fits = (windowHeight >= sidebarHeight);
    const overlaps = (viewportOffset.top < parent.getBoundingClientRect().top);
    const shouldBindTop = (viewportOffset.top >= stickPosition && !scrollingDown
      && !overlaps && scrollTop >= parent.offsetTop);
    const shouldFix = this.affixContainer.offsetTop > parent.offsetTop
      && viewportOffset.top > parentSpace && !scrollingDown;

    if (fits) {
      if (viewportOffset.top <= stickPosition) {
        this.affixContainer.style.position = 'fixed';
        this.affixContainer.style.top = `${stickPosition}px`;
      }

      if (overlaps) {
        this.affixContainer.style.position = 'absolute';
        this.affixContainer.style.top = 'auto';
      }
    } else {
      if (!this.bindedBottom && scrollingDown && viewportOffset.bottom <= windowHeight) {
        this.affixContainer.style.position = 'fixed';
        this.affixContainer.style.top = `${windowHeight - sidebarHeight}px`;
        this.bindedBottom = true;
      }
      if (shouldFix || shouldBindTop) {
        this.affixContainer.style.position = 'fixed';
        this.affixContainer.style.top = `${stickPosition}px`;
        this.bindedTop = true;
      }
      if (this.bindedBottom && !scrollingDown) {
        this.affixContainer.style.position = 'absolute';
        this.affixContainer.style.top = `${scrollBottom - (sidebarHeight + parentSpace)}px`;
        this.bindedBottom = false;
      }
      if (this.bindedTop && scrollingDown) {
        this.affixContainer.style.position = 'absolute';
        this.affixContainer.style.top = `${scrollTop - (parent.offsetTop - stickPosition)}px`;
        this.bindedTop = false;
      }
      if (overlaps) {
        this.affixContainer.style.position = 'absolute';
        this.affixContainer.style.top = 'auto';
      }
    }

    this.lastScroll = scrollTop;
  }

  render() {
    const { className } = this.props;
    return (
      <div
        className={className}
        ref={(relativeContainer) => { this.relativeContainer = relativeContainer; }}
      >
        <div
          style={{ position: 'absolute' }}
          ref={(affixContainer) => { this.affixContainer = affixContainer; }}
        >
          {this.props.children}
        </div>
      </div>
    );
  }
}

export default Affix;

@@ -1692,24 +1692,104 @@
 l = () =%3E %7B%0A
+    if (!this.relativeContainer %7C%7C !this.affixContainer) %7B%0A      return;%0A    %7D%0A%0A
     const %7B 

Check if containers are not undefined