All files index.js

14.71% Statements 5/34
0% Branches 0/18
18.75% Functions 3/16
12.12% Lines 4/33

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152                          3x 3x                                                                                                                                                                                                                                                   1x                     3x        
import React from 'react' // eslint-disable-line semi
import ScrollReveal from 'scrollreveal' // eslint-disable-line semi
 
 
/**
 * Creates React Component that will have animated elements on scroll
 *
 * @param {Array|object} srOptions
 * @param {string} srOptions.selector
 * @param {object} srOptions.options
 * @param {number} srOptions.interval
 * @return {function} React component
 */
const ReactScrollreveal = (srOptions = {}) => (Component) => {
  const sr = ScrollReveal();
 
  class ComponentWithScrollReveal extends React.Component {
    static displayName = 'ComponentWithScrollReveal';
 
    componentDidMount() {
      this.initialize();
    }
 
    componentWillUpdate() {
      this.refresh();
    }
 
    componentWillUnmount() {
      this.clean();
    }
 
    /**
     *
     * @param {function} fn
     */
    forEachSrElement = (fn) => {
      const elements = [];
 
      this.forEachSrOption(({ selector }) => {
        elements.concat(Array.prototype.slice.apply(document.querySelectorAll(selector)));
      });
 
      elements.forEach(fn);
    };
 
    /**
     * Iterates through all srOptions and applies given function
     *
     * @param {function} fn
     * @return undefined
     */
    forEachSrOption = (fn) => {
      if (Array.isArray(srOptions)) {
        srOptions.forEach((options) => {
          fn(options);
        });
      } else if (typeof srOptions === 'object') {
        fn(srOptions);
      } else {
        throw new TypeError('Invalid arguments were passed');
      }
    };
 
    /**
     * Get reveal elements by given selector
     *
     * @param {string} selector
     * @return {NodeList}
     */
    getRevealElements(selector) {
      return selector ? this.animationContainer.querySelectorAll(selector) :
        this.animationContainer;
    }
 
    /**
     * Init scrollreveal for all reveal elements by selector
     *
     * @param {number} interval - ScrollReveal's interval value to make sequential animation
     * @param {object} options - ScrollReveal's options (see https://github.com/jlmakes/scrollreveal#2-configuration)
     * @param {string} selector - selector that gets elements to reveal
     */
    applyRevealAnimation = ({ selector, options = {}, interval }) => {
      const revealElements = this.getRevealElements(selector);
      const opts = Object.assign({}, options);
 
      // revealElements can be NodeList or single node
      if (revealElements.length || !!revealElements.nodeType) {
        sr.reveal(revealElements, opts, interval);
      }
    };
 
    /**
     * Initialize sr animations for every reveal element by given selector
     *
     * @return undefined
     */
    initialize() {
      if (!this.animationContainer) {
        return;
      }
 
      this.forEachSrOption(this.applyRevealAnimation);
    }
 
    clean(cleanStyles) {
      // cleaning styles makes sr animation initialize again
      // on same element that were still in DOM
      if (cleanStyles) {
        this.forEachSrElement(sr.clean);
      } else {
        // remove event listeners
        // on component unmount event
        sr.destroy();
      }
    }
 
    refresh() {
      this.clean(true);
      this.initialize();
    }
 
    /**
     * Gets ref to the child's component desired animation container DOM node
     *
     * @param {object} node
     * @return undefined
     */
    getRef = (node) => {
      if (typeof node.nodeType === 'number') {
        this.animationContainer = node;
      } else {
        throw new Error('You should put animationContainerReference on DOM node, not React component.');
      }
    };
 
    render() {
      return (
        <Component
          animationContainerReference={this.getRef}
          destroyRevealAnimation={this.clean}
          refreshRevealAnimation={this.refresh}
          {...this.props}
        />
      );
    }
  }
 
  return ComponentWithScrollReveal;
};
 
export default ReactScrollreveal;