- Updated the HProgress component to include a mask and wave animation for a more visually appealing progress display. - Adjusted CSS styles in App.css to enhance the animation responsiveness and ensure seamless transitions. - Removed unnecessary postMessage calls in electrobun-bridge.js to streamline message handling. - Cleaned up rpc.js by removing the rendererResponseAck handler for better code clarity.
288 lines
7.6 KiB
JavaScript
288 lines
7.6 KiB
JavaScript
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 : (
|
|
<span
|
|
className={[
|
|
'h-progress-text',
|
|
infoPosition === 'outer' && infoAlign === 'start'
|
|
? 'h-progress-text-start'
|
|
: null
|
|
]
|
|
.filter(Boolean)
|
|
.join(' ')}
|
|
title={typeof progressTextValue === 'string' ? progressTextValue : undefined}
|
|
style={{ color: token.colorText }}
|
|
>
|
|
{progressStatus === 'exception' ? (
|
|
<CloseCircleFilled style={{ color: token.colorError }} />
|
|
) : progressStatus === 'success' ? (
|
|
<CheckCircleFilled style={{ color: token.colorSuccess }} />
|
|
) : (
|
|
progressTextValue
|
|
)}
|
|
</span>
|
|
)
|
|
|
|
const innerInfo =
|
|
infoPosition === 'inner' && showInfo ? (
|
|
<span className='h-progress-text-inner'>{progressTextValue}</span>
|
|
) : null
|
|
|
|
const lineInner = (
|
|
<div
|
|
className='h-progress-inner'
|
|
style={{
|
|
height: barHeight,
|
|
backgroundColor: trailBackground,
|
|
borderRadius
|
|
}}
|
|
>
|
|
<div
|
|
className='h-progress-bg'
|
|
style={{
|
|
width: `${resolvedPercent}%`,
|
|
height: barHeight,
|
|
borderRadius,
|
|
background: fillBackground,
|
|
overflow: 'hidden'
|
|
}}
|
|
>
|
|
{innerInfo}
|
|
</div>
|
|
{progressStatus === 'active' && (
|
|
<div
|
|
className='h-progress-bg-mask'
|
|
style={{ width: `${resolvedPercent}%`, borderRadius }}
|
|
>
|
|
<div className='h-progress-bg-wave' />
|
|
</div>
|
|
)}
|
|
{successValue != null && (
|
|
<div
|
|
className='h-progress-success-bg'
|
|
style={{
|
|
width: `${successValue}%`,
|
|
height: barHeight,
|
|
borderRadius,
|
|
background: successBackground
|
|
}}
|
|
/>
|
|
)}
|
|
</div>
|
|
)
|
|
|
|
const isOuterStart = infoPosition === 'outer' && infoAlign === 'start'
|
|
const isOuterEnd = infoPosition === 'outer' && infoAlign === 'end'
|
|
const isLayoutBottom =
|
|
infoPosition === 'outer' && infoAlign === 'center'
|
|
|
|
const content = isLayoutBottom ? (
|
|
<div className='h-progress-layout-bottom'>
|
|
{lineInner}
|
|
{progressInfo}
|
|
</div>
|
|
) : (
|
|
<div
|
|
className='h-progress-outer'
|
|
style={{ width: outerWidth < 0 ? '100%' : outerWidth }}
|
|
>
|
|
{isOuterStart && progressInfo}
|
|
{lineInner}
|
|
{isOuterEnd && progressInfo}
|
|
</div>
|
|
)
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className={['h-progress', className, rootClassName]
|
|
.filter(Boolean)
|
|
.join(' ')}
|
|
style={style}
|
|
role='progressbar'
|
|
aria-valuemin={0}
|
|
aria-valuemax={100}
|
|
aria-valuenow={resolvedPercent}
|
|
>
|
|
{content}
|
|
</div>
|
|
)
|
|
})
|
|
|
|
HProgress.propTypes = {
|
|
className: PropTypes.string,
|
|
rootClassName: PropTypes.string,
|
|
style: PropTypes.object,
|
|
percent: PropTypes.number,
|
|
success: PropTypes.shape({
|
|
percent: PropTypes.number,
|
|
progress: PropTypes.number,
|
|
strokeColor: PropTypes.string
|
|
}),
|
|
successPercent: PropTypes.number,
|
|
status: PropTypes.oneOf(['normal', 'exception', 'active', 'success']),
|
|
showInfo: PropTypes.bool,
|
|
strokeColor: PropTypes.oneOfType([
|
|
PropTypes.string,
|
|
PropTypes.arrayOf(PropTypes.string),
|
|
PropTypes.object
|
|
]),
|
|
trailColor: PropTypes.string,
|
|
strokeLinecap: PropTypes.oneOf(['butt', 'square', 'round']),
|
|
strokeWidth: PropTypes.number,
|
|
size: PropTypes.oneOfType([
|
|
PropTypes.oneOf(['default', 'small']),
|
|
PropTypes.number,
|
|
PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.number, PropTypes.string])),
|
|
PropTypes.shape({
|
|
width: PropTypes.number,
|
|
height: PropTypes.number
|
|
})
|
|
]),
|
|
format: PropTypes.func,
|
|
percentPosition: PropTypes.shape({
|
|
align: PropTypes.oneOf(['start', 'center', 'end']),
|
|
type: PropTypes.oneOf(['inner', 'outer'])
|
|
})
|
|
}
|
|
|
|
export default HProgress
|