import { forwardRef, useMemo } from 'react'
import PropTypes from 'prop-types'
import { theme } from 'antd'
import CheckCircleFilled from '@ant-design/icons/CheckCircleFilled'
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled'
const validProgress = (progress) => {
if (!progress || progress < 0) return 0
if (progress > 100) return 100
return progress
}
const getSuccessPercent = ({ success, successPercent }) => {
if (success && 'progress' in success) return success.progress
if (success && 'percent' in success) return success.percent
return successPercent
}
const sortGradient = (gradients) => {
const entries = Object.keys(gradients)
.map((key) => ({
key: Number.parseFloat(key.replace(/%/g, '')),
value: gradients[key]
}))
.filter(({ key }) => !Number.isNaN(key))
.sort((a, b) => a.key - b.key)
return entries.map(({ key, value }) => `${value} ${key}%`).join(', ')
}
const resolveStrokeBackground = (strokeColor, direction = 'to right') => {
if (!strokeColor) return undefined
if (typeof strokeColor === 'string') {
return strokeColor
}
if (Array.isArray(strokeColor)) {
return strokeColor[0]
}
const { from, to, direction: gradientDirection, ...rest } = strokeColor
if (Object.keys(rest).length > 0) {
return `linear-gradient(${gradientDirection || direction}, ${sortGradient(rest)})`
}
return `linear-gradient(${gradientDirection || direction}, ${from}, ${to})`
}
const getBarHeight = ({ size, strokeWidth }) => {
if (typeof strokeWidth === 'number') return strokeWidth
if (size === 'small') return 6
if (typeof size === 'number') return size
if (Array.isArray(size)) return size[1] ?? 8
if (typeof size === 'object' && size?.height != null) return size.height
return 8
}
const getOuterWidth = ({ size, strokeWidth }) => {
if (typeof size === 'number') return size
if (Array.isArray(size)) return size[0] ?? -1
if (typeof size === 'object' && size?.width != null) return size.width
if (strokeWidth) return -1
return -1
}
const HProgress = forwardRef(function HProgress(
{
className,
rootClassName,
style,
percent = 0,
success,
successPercent,
status,
showInfo = true,
strokeColor,
trailColor,
strokeLinecap = 'round',
strokeWidth,
size = 'default',
format,
percentPosition = {}
},
ref
) {
const { token } = theme.useToken()
const { align: infoAlign = 'end', type: infoPosition = 'outer' } =
percentPosition
const resolvedPercent = validProgress(percent)
const resolvedSuccessPercent = getSuccessPercent({ success, successPercent })
const successValue =
resolvedSuccessPercent == null
? undefined
: validProgress(resolvedSuccessPercent)
const percentNumber = Number.parseInt(
String(successValue ?? resolvedPercent),
10
)
const progressStatus = useMemo(() => {
if (status === 'exception' || status === 'success' || status === 'active') {
return status
}
if (percentNumber >= 100) return 'success'
return status || 'normal'
}, [status, percentNumber])
const barHeight = getBarHeight({ size, strokeWidth })
const outerWidth = getOuterWidth({ size, strokeWidth })
const borderRadius =
strokeLinecap === 'square' || strokeLinecap === 'butt' ? 0 : barHeight
const trailBackground = trailColor || token.colorFillSecondary
const defaultFillColor =
progressStatus === 'exception'
? token.colorError
: progressStatus === 'success'
? token.colorSuccess
: token.colorPrimary
const fillBackground =
resolveStrokeBackground(strokeColor) || defaultFillColor
const successBackground =
success?.strokeColor || token.colorSuccess
const textFormatter = format || ((value) => `${value}%`)
const progressTextValue = textFormatter(
resolvedPercent,
successValue ?? undefined
)
const progressInfo = !showInfo ? null : (
{progressStatus === 'exception' ? (