All files index.ts

100% Statements 29/29
100% Branches 15/15
100% Functions 3/3
100% Lines 28/28
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            1x 1x   1x 1x   3x 2x                                 2x   2x   2x 20x 20x   20x         2x   2x 2x 6x     6x 6x   1x     5x 2x     5x 5x 5x   5x 3x         20x       1x  
import * as ReactImport from 'react';
import * as ReactDOMImport from 'react-dom';
 
type TReact = typeof ReactImport;
type TReactDOM = typeof ReactDOMImport;
 
const HIGHLIGHT_CLASS = 'react-update-highlight';
const MATCHES_HIGHLIGHT_CLASS = /\s*\breact-update-highlight\b\s*/gi;
 
const STYLE = document.createElement('style');
STYLE.type = 'text/css';
 
export const highlightUpdates = (React: TReact, ReactDOM: TReactDOM, color: string = 'rgba(255, 0, 0, 0.5)') => {
  STYLE.innerHTML =
`.react-update-highlight {
  animation-name: react-update-highlight;
  animation-duration: 2s;
  animation-iteration-count: 1;
}
 
@keyframes react-update-highlight {
  from {
    background-color: ${color};
  }
 
  to {
    background-color: transparent;
  }
}`;
 
  document.head.appendChild(STYLE);
 
  const originalCreateElement = React.createElement;
 
  (React as any).createElement = function () {
    const args = Array.prototype.slice.call(arguments);
    const component = args[0];
 
    if (
      typeof component === 'function' &&
      component.prototype instanceof React.Component &&
      !component.prototype.hasReactUpdateHighlight
    ) {
      const originalComponentDidUpdate = (component as any).prototype.componentDidUpdate;
 
      component.prototype.hasReactUpdateHighlight = true;
      (component as any).prototype.componentDidUpdate = function () {
        const updateArgs = Array.prototype.slice.call(arguments);
        let node: Element;
 
        try {
          node = ReactDOM.findDOMNode(this);
        } catch (error) {
          return;
        }
 
        if (MATCHES_HIGHLIGHT_CLASS.test(node.className)) {
          node.className = node.className.replace(MATCHES_HIGHLIGHT_CLASS, '');
        }
 
        void (node as any).offsetWidth; // tslint:disable-line:no-unused-expression
        const needsSpace = node.className || node.className.lastIndexOf(' ') !== node.className.length - 1;
        node.className = `${node.className}${needsSpace ? ' ' + HIGHLIGHT_CLASS : HIGHLIGHT_CLASS}`;
 
        if (typeof originalComponentDidUpdate === 'function') {
          originalComponentDidUpdate.apply(this, updateArgs);
        }
      };
    }
 
    return originalCreateElement.apply(this, args);
  };
};
 
export default highlightUpdates;