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              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 {MAX_TRANSITION_TIME_IN_MS, MODIFIERS, SIZES} from './settings.js'
 
const Circle = ({
  baseClassName,
  modifier,
  percentage,
  size,
  withAnimation = true,
  mainStrokeWidth,
  progressStrokeWidth,
  strokeLineCap
}) => {
  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
        })}
        {...getPathStyles({percentage: 100, strokeWidth: mainStrokeWidth})}
        strokeWidth={mainStrokeWidth}
        fillOpacity="0"
      />
      <path
        className={cx(`${baseClassName}-path`, {
          [`${baseClassName}-path--${modifier}`]: !!modifier
        })}
        {...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,
  /** width of the stroke  */
  strokeWidth: PropTypes.node.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.literal,
  /** The size of the main stroke, by default it is undefined, it can be "small", "medium" or "large" */
  mainStrokeWidth: PropTypes.literal,
  /** 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
}
 
export default Circle