All files / src PacmanLoader.tsx

100% Statements 57/57
100% Branches 21/21
100% Functions 10/10
100% Lines 36/36

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  1x 1x   1x   1x                 1x                     5x 1x   5x 16x   16x           5x 16x   16x                             5x 8x   8x     5x 8x   8x     5x 8x   8x 8x   8x                           5x 4x   4x               5x 5x   1x 5x   5x                     1x   1x     1x 1x  
/** @jsx jsx */
import * as React from "react";
import { keyframes, css, jsx } from "@emotion/core";
import { Keyframes } from "@emotion/serialize";
import onlyUpdateForKeys from "recompose/onlyUpdateForKeys";
 
import { sizeMarginDefaults, sizeMarginKeys } from "./helpers";
import {
  StyleFunction,
  PrecompiledCss,
  LoaderSizeMarginProps,
  CalcFunction,
  StyleFunctionWithIndex
} from "./interfaces";
 
const pacman: Keyframes[] = [
  keyframes`
    0% {transform: rotate(0deg)}
    50% {transform: rotate(-44deg)}
  `,
  keyframes`
    0% {transform: rotate(0deg)}
    50% {transform: rotate(44deg)}
  `
];
 
class Loader extends React.PureComponent<LoaderSizeMarginProps> {
  public static defaultProps: LoaderSizeMarginProps = sizeMarginDefaults(25);
 
  public ball: CalcFunction<Keyframes> = (): Keyframes => {
    const { size, sizeUnit } = this.props;
 
    return keyframes`
      75% {opacity: 0.7}
      100% {transform: translate(${`${-4 * size!}${sizeUnit}`}, ${`${-size! / 4}${sizeUnit}`})}
    `;
  };
 
  public ballStyle: StyleFunctionWithIndex = (i: number): PrecompiledCss => {
    const { color, margin, size, sizeUnit } = this.props;
 
    return css`
      width: ${`${size! / 3}${sizeUnit}`};
      height: ${`${size! / 3}${sizeUnit}`};
      background-color: ${color};
      margin: ${margin};
      border-radius: 100%;
      transform: translate(0, ${`${-size! / 4}${sizeUnit}`});
      position: absolute;
      top: ${size}px;
      left: ${`${size! * 4}${sizeUnit}`};
      animation: ${this.ball()} 1s ${i * 0.25}s infinite linear;
      animation-fill-mode: both;
    `;
  };
 
  public s1: CalcFunction<string> = (): string => {
    const { size, sizeUnit } = this.props;
 
    return `${size}${sizeUnit} solid transparent`;
  };
 
  public s2: CalcFunction<string> = (): string => {
    const { size, sizeUnit, color } = this.props;
 
    return `${size}${sizeUnit} solid ${color}`;
  };
 
  public pacmanStyle: StyleFunctionWithIndex = (i: number): PrecompiledCss => {
    const { size, sizeUnit } = this.props;
 
    const s1: string = this.s1();
    const s2: string = this.s2();
 
    return css`
      width: 0;
      height: 0;
      border-right: ${s1};
      border-top: ${i === 0 ? s1 : s2};
      border-left: ${s2};
      border-bottom: ${i === 0 ? s2 : s1};
      border-radius: ${`${size}${sizeUnit}`};
      position: absolute;
      animation: ${pacman[i]} 0.8s infinite ease-in-out;
      animation-fill-mode: both;
    `;
  };
 
  public wrapper: StyleFunction = (): PrecompiledCss => {
    const { size, sizeUnit } = this.props;
 
    return css`
      position: relative;
      font-size: 0;
      height: ${`${size}${sizeUnit}`};
      width: ${`${size}${sizeUnit}`};
    `;
  };
 
  public pac: StyleFunction = (): PrecompiledCss => this.pacmanStyle(0);
  public man: StyleFunction = (): PrecompiledCss => this.pacmanStyle(1);
 
  public render(): JSX.Element | null {
    const { loading, css } = this.props;
 
    return loading ? (
      <div css={[this.wrapper(), css]}>
        <div css={this.pac()} />
        <div css={this.man()} />
        <div css={this.ballStyle(2)} />
        <div css={this.ballStyle(3)} />
        <div css={this.ballStyle(4)} />
        <div css={this.ballStyle(5)} />
      </div>
    ) : null;
  }
}
 
const Component: React.ComponentClass<LoaderSizeMarginProps> = onlyUpdateForKeys(sizeMarginKeys)(
  Loader
);
Component.defaultProps = Loader.defaultProps;
export default Component;