import React, { useMemo } from 'react'
import Block from '../Primitives/Block/Block'
import Text from '../Text/Text'
import { ProgressBarSize, ProgressBarVariant, ProgressBarType } from './types'
import type { ProgressBarProps } from './types'
import type { ProgressBarTokenType } from './progressbar.tokens'
import { useResponsiveTokens } from '../../hooks/useResponsiveTokens'
import {
clampValue,
calculatePercentage,
extractAriaProps,
generateDefaultAriaLabel,
getCircularDimensions,
calculateCircularStroke,
} from './utils'
import { FOUNDATION_THEME } from '../../tokens'
type ProgressBarInternalProps = {
value: number
min: number
max: number
ariaLabel?: string
ariaLabelledby?: string
showLabel: boolean
tokens: ProgressBarTokenType
}
const CircularProgressBar: React.FC<
ProgressBarInternalProps & {
size: ProgressBarSize
type: ProgressBarType
}
> = ({
value,
size,
type,
tokens,
showLabel,
ariaLabel,
ariaLabelledby,
min,
max,
}) => {
const clampedValue = useMemo(
() => clampValue(value, min, max),
[value, min, max]
)
const percentage = useMemo(
() => calculatePercentage(value, min, max),
[value, min, max]
)
const { circularSize, strokeWidth, radius, center, circumference } =
useMemo(() => getCircularDimensions(size, tokens), [size, tokens])
const { strokeDasharray, strokeDashoffset, dashArray } = useMemo(
() =>
calculateCircularStroke(
type === ProgressBarType.SEGMENTED ? 'segmented' : 'solid',
circumference,
percentage
),
[type, circumference, percentage]
)
return (
{showLabel && (
{Math.round(percentage)}%
)}
)
}
const LinearProgressBar: React.FC<
ProgressBarInternalProps & {
size: ProgressBarSize
variant: Exclude
}
> = ({
value,
size,
variant,
tokens,
showLabel,
ariaLabel,
ariaLabelledby,
min,
max,
}) => {
const clampedValue = useMemo(
() => clampValue(value, min, max),
[value, min, max]
)
const percentage = useMemo(
() => calculatePercentage(value, min, max),
[value, min, max]
)
const containerHeight = tokens.linear.height[size]
const fillBackgroundColor = tokens.linear.fill.backgroundColor[variant]
const fillBorderRadius = tokens.linear.fill.borderRadius[variant]
const emptyBackgroundColor = tokens.linear.empty.backgroundColor[variant]
const containerBorderRadius = tokens.linear.borderRadius[variant]
return (
{variant === ProgressBarVariant.SEGMENTED && (
)}
{showLabel && (
{Math.round(percentage)}%
)}
)
}
const ProgressBar: React.FC = ({
value,
size = ProgressBarSize.MEDIUM,
variant = ProgressBarVariant.SOLID,
type = ProgressBarType.SOLID,
showLabel = false,
min = 0,
max = 100,
...rest
}) => {
const progressBarToken =
useResponsiveTokens('PROGRESS_BAR')
const {
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledby,
restProps,
} = extractAriaProps(rest)
const defaultAriaLabel = useMemo(() => {
if (ariaLabel || ariaLabelledby) return ariaLabel
return generateDefaultAriaLabel(value, min, max)
}, [value, min, max, ariaLabel, ariaLabelledby])
const sharedProps: ProgressBarInternalProps = {
value,
min,
max,
ariaLabel: defaultAriaLabel,
ariaLabelledby,
showLabel,
tokens: progressBarToken,
}
if (variant === ProgressBarVariant.CIRCULAR) {
return (
)
}
return (
)
}
ProgressBar.displayName = 'ProgressBar'
export default ProgressBar