All files / atom/progressBar/src/ProgressBarCircle/Circle index.js

89.47% Statements 17/19
42.85% Branches 3/7
100% Functions 4/4
89.47% Lines 17/19

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                1x                     3x 3x   3x   2x       2x 2x           3x 6x         3x 6x 6x     6x 6x         6x           3x                                                             1x                                            
import {useEffect, useState} from 'react'
 
import cx from 'classnames'
import PropTypes from 'prop-types'
 
import {COLORS} from '../../settings.js'
import {MAX_TRANSITION_TIME_IN_MS, MODIFIERS, SIZES} from './settings.js'
 
const Circle = ({
  baseClassName,
  modifier,
  percentage,
  size,
  withAnimation = true,
  mainStrokeWidth,
  progressStrokeWidth,
  strokeLineCap,
  color
}) => {
  const [currentPercentage, setCurrentPercentage] = useState(percentage)
  const [transitionTime, setTransitionTime] = useState(0)
 
  useEffect(
    (currentPercentage, percentage) => {
      Iif (Math.abs(percentage - currentPercentage) < 5) {
        setCurrentPercentage(percentage)
        setTransitionTime(0)
      } else {
        setCurrentPercentage(percentage)
        setTransitionTime((MAX_TRANSITION_TIME_IN_MS * percentage) / 100 / 1000)
      }
    },
    [currentPercentage, percentage]
  )
 
  const getRadius = () => {
    return mainStrokeWidth === progressStrokeWidth
      ? 50 - mainStrokeWidth / 2
      : 50 - Math.max(...[progressStrokeWidth, mainStrokeWidth]) / 2
  }
 
  const getPathStyles = ({percentage, strokeWidth}) => {
    const radius = getRadius()
    const d = `M 50,50 m 0,-${radius}
     a ${radius},${radius} 0 1 1 0,${2 * radius}
     a ${radius},${radius} 0 1 1 0,-${2 * radius}`
    const len = Math.PI * 2 * radius
    const style = {
      strokeDasharray: `${len}px ${len}px`,
      strokeDashoffset: `${((100 - percentage) / 100) * len}px`,
      transition: withAnimation ? `stroke-dashoffset ${transitionTime}s ease 0s, stroke ${transitionTime}s ease` : ''
    }
    return {
      d,
      style
    }
  }
 
  return (
    <svg
      className={cx(`${baseClassName}-circle`, {
        [`${baseClassName}-circle--${modifier}`]: !!modifier,
        [`${baseClassName}-circle--${size}`]: !!size
      })}
      viewBox="0 0 100 100"
    >
      <path
        className={cx(`${baseClassName}-trail`, {
          [`${baseClassName}-trail--${modifier}`]: !!modifier,
          [`${baseClassName}-trail--color-${color}`]: !!color
        })}
        {...getPathStyles({percentage: 100, strokeWidth: mainStrokeWidth})}
        strokeWidth={mainStrokeWidth}
        fillOpacity="0"
      />
      <path
        className={cx(`${baseClassName}-path`, {
          [`${baseClassName}-path--${modifier}`]: !!modifier,
          [`${baseClassName}-path--color-${color}`]: !!color
        })}
        {...getPathStyles({percentage, strokeWidth: progressStrokeWidth})}
        strokeLinecap={strokeLineCap}
        strokeWidth={progressStrokeWidth}
        fillOpacity="0"
      />
    </svg>
  )
}
 
Circle.propTypes = {
  /** Base className to be used in this component  */
  baseClassName: PropTypes.string.isRequired,
  /** CSS modifier for ERROR, LOADING variants  */
  modifier: PropTypes.oneOf(Object.values(MODIFIERS)),
  /** The percentage of the current progress */
  percentage: PropTypes.number.isRequired,
  /** boolean to activate/desactivate animations */
  withAnimation: PropTypes.bool,
  /** The size of the progress stroke, by default it is undefined, it can be "small", "medium" or "large" */
  progressStrokeWidth: PropTypes.number,
  /** The size of the main stroke, by default it is undefined, it can be "small", "medium" or "large" */
  mainStrokeWidth: PropTypes.number,
  /** The shape of the end of line, it can be "round" or "square" */
  strokeLineCap: PropTypes.string,
  /** size of the circle [small, large]  */
  size: PropTypes.oneOf(Object.values(SIZES)).isRequired,
  /** color of the circle */
  color: PropTypes.oneOf(Object.values(COLORS))
}
 
export default Circle