content: import React, { Component } from 'react';
  import PropTypes from 'prop-types';
  
  export default class InfiniteScroll extends Component {
      static propTypes = {
          children: PropTypes.node.isRequired,
          element: PropTypes.node,
          hasMore: PropTypes.bool,
          initialLoad: PropTypes.bool,
          isReverse: PropTypes.bool,
          loader: PropTypes.node,
          loadMore: PropTypes.func.isRequired,
          pageStart: PropTypes.number,
          ref: PropTypes.func,
          getScrollParent: PropTypes.func,
          threshold: PropTypes.number,
          useCapture: PropTypes.bool,
          useWindow: PropTypes.bool
      };
  
      static defaultProps = {
          element: 'div',
          hasMore: false,
          initialLoad: true,
          pageStart: 0,
          ref: null,
          threshold: 250,
          useWindow: true,
          isReverse: false,
          useCapture: false,
          loader: null,
          getScrollParent: null
      };
  
      constructor(props) {
          super(props);
  
          this.scrollListener = this.scrollListener.bind(this);
          this.eventListenerOptions = this.eventListenerOptions.bind(this);
          this.mousewheelListener = this.mousewheelListener.bind(this);
      }
  
      componentDidMount() {
          this.pageLoaded = this.props.pageStart;
          this.options = this.eventListenerOptions();
          this.attachScrollListener();
      }
  
      componentDidUpdate() {
          if (this.props.isReverse && this.loadMore) {
              const parentElement = this.getParentElement(this.scrollComponent);
              parentElement.scrollTop =
                  parentElement.scrollHeight -
                  this.beforeScrollHeight +
                  this.beforeScrollTop;
              this.loadMore = false;
          }
          this.attachScrollListener();
      }
  
      componentWillUnmount() {
          this.detachScrollListener();
          this.detachMousewheelListener();
      }
  
      isPassiveSupported() {
          let passive = false;
  
          const testOptions = {
              // eslint-disable-next-line getter-return
              get passive() {
                  passive = true;
              }
          };
  
          try {
              document.addEventListener('test', null, testOptions);
              document.removeEventListener('test', null, testOptions);
          } catch (e) {
              // ignore
          }
          return passive;
      }
  
      eventListenerOptions() {
          let options = this.props.useCapture;
  
          if (this.isPassiveSupported()) {
              options = {
                  useCapture: this.props.useCapture,
                  passive: true
              };
          } else {
              options = {
                  passive: false
              };
          }
          return options;
      }
  
      // Set a defaut loader for all your `InfiniteScroll` components
      setDefaultLoader(loader) {
          this.defaultLoader = loader;
      }
  
      detachMousewheelListener() {
          let scrollEl = window;
          if (this.props.useWindow === false) {
              scrollEl = this.scrollComponent.parentNode;
          }
  
          scrollEl.removeEventListener(
              'mousewheel',
              this.mousewheelListener,
              this.options ? this.options : this.props.useCapture
          );
      }
  
      detachScrollListener() {
          let scrollEl = window;
          if (this.props.useWindow === false) {
              scrollEl = this.getParentElement(this.scrollComponent);
          }
  
          scrollEl.removeEventListener(
              'scroll',
              this.scrollListener,
              this.options ? this.options : this.props.useCapture
          );
          scrollEl.removeEventListener(
              'resize',
              this.scrollListener,
              this.options ? this.options : this.props.useCapture
          );
      }
  
      getParentElement(el) {
          const scrollParent =
              this.props.getScrollParent && this.props.getScrollParent();
          if (scrollParent != null) {
              return scrollParent;
          }
          return el && el.parentNode;
      }
  
      filterProps(props) {
          return props;
      }
  
      attachScrollListener() {
          const parentElement = this.getParentElement(this.scrollComponent);
  
          if (!this.props.hasMore || !parentElement) {
              return;
          }
  
          let scrollEl = window;
          if (this.props.useWindow === false) {
              scrollEl = parentElement;
          }
  
          scrollEl.addEventListener(
              'mousewheel',
              this.mousewheelListener,
              this.options ? this.options : this.props.useCapture
          );
          scrollEl.addEventListener(
              'scroll',
              this.scrollListener,
              this.options ? this.options : this.props.useCapture
          );
          scrollEl.addEventListener(
              'resize',
              this.scrollListener,
              this.options ? this.options : this.props.useCapture
          );
  
          if (this.props.initialLoad) {
              this.scrollListener();
          }
      }
  
      mousewheelListener(e) {
          // Prevents Chrome hangups
          // See: https://stackoverflow.com/questions/47524205/random-high-content-download-time-in-chrome/47684257#47684257
          if (e.deltaY === 1 && !this.isPassiveSupported()) {
              e.preventDefault();
          }
      }
  
      scrollListener() {
          const el = this.scrollComponent;
          const scrollEl = window;
          const parentNode = this.getParentElement(el);
  
          let offset;
          if (this.props.useWindow) {
              const doc =
                  document.documentElement || document.body.parentNode || document.body;
              const scrollTop =
                  scrollEl.pageYOffset !== undefined
                      ? scrollEl.pageYOffset
                      : doc.scrollTop;
              if (this.props.isReverse) {
                  offset = scrollTop;
              } else {
                  offset = this.calculateOffset(el, scrollTop);
              }
          } else if (this.props.isReverse) {
              offset = parentNode.scrollTop;
          } else {
              offset = el.scrollHeight - parentNode.scrollTop - parentNode.clientHeight;
          }
  
          // Here we make sure the element is visible as well as checking the offset
          if (
              offset > 0 &&
              offset < Number(this.props.threshold) &&
              (el && el.offsetParent !== null)
          ) {
              this.detachScrollListener();
              this.beforeScrollHeight = parentNode.scrollHeight;
              this.beforeScrollTop = parentNode.scrollTop;
              // Call loadMore after detachScrollListener to allow for non-async loadMore functions
              if (typeof this.props.loadMore === 'function') {
                  this.props.loadMore((this.pageLoaded += 1));
                  this.loadMore = true;
              }
          }
      }
  
      calculateOffset(el, scrollTop) {
          if (!el) {
              return 0;
          }
  
          return (
              this.calculateTopPosition(el) +
              (el.offsetHeight - scrollTop - window.innerHeight)
          );
      }
  
      calculateTopPosition(el) {
          if (!el) {
              return 0;
          }
          return el.offsetTop + this.calculateTopPosition(el.offsetParent);
      }
  
      render() {
          const renderProps = this.filterProps(this.props);
          const {
              children,
              element,
              hasMore,
              initialLoad,
              isReverse,
              loader,
              loadMore,
              pageStart,
              ref,
              threshold,
              useCapture,
              useWindow,
              getScrollParent,
              ...props
          } = renderProps;
  
          props.ref = node => {
              this.scrollComponent = node;
              if (ref) {
                  ref(node);
              }
          };
  
          const childrenArray = [children];
          if (hasMore) {
              if (loader) {
                  isReverse ? childrenArray.unshift(loader) : childrenArray.push(loader);
              } else if (this.defaultLoader) {
                  isReverse
                      ? childrenArray.unshift(this.defaultLoader)
                      : childrenArray.push(this.defaultLoader);
              }
          }
          return React.createElement(element, props, childrenArray);
      }
  }