import React, { useMemo } from 'react'; import { tv } from 'tailwind-variants'; import { type ElementProps, type NumberExcluded } from '../../types'; import { cn } from '../../utils/cn'; import { mappingSizing, mappingThickness, type Sizing } from './progress-config'; interface CircleProps extends ElementProps<'circle', 'r'> { value?: number; r?: number; thickness?: number | string; } const CircleTrack = React.forwardRef(({ r, thickness, ...props }, ref) => { return ( ); }); const CircleProgress = React.forwardRef( ({ r = 70, value = 0, thickness, className, ...props }, ref) => { const { strokeDasharray, strokeDashoffset } = useMemo(() => { const circumference = 2 * Math.PI * r; const offset = value ? ((100 - value) * circumference) / 100 : circumference; return { strokeDasharray: circumference, strokeDashoffset: offset, }; }, [r, value]); return ( ); } ); export interface CircularProgressProps extends React.HTMLAttributes { value?: number; size?: Sizing | NumberExcluded; thickness?: number; } const labelVariant = tv({ base: 'inset-center text-foreground absolute font-semibold', variants: { size: { xxs: 'text-sm ', xs: 'text-2xl', sm: 'text-3xl', md: 'text-4xl', lg: 'text-5xl', }, }, defaultVariants: { size: 'md', }, }); const CircularProgress = React.forwardRef( ({ className, children, value: valueProp = 0, size: sizeProp = 'md', thickness: thicknessProp, ...props }, ref) => { const { size, r, thickness } = useMemo(() => { let sizer = sizeProp; let thickness = thicknessProp ?? sizeProp; if (typeof sizeProp !== 'number') { sizer = mappingSizing[sizeProp] || 0; } if (typeof thickness !== 'number') { thickness = mappingThickness[thickness] || 0; } return { size: Number(sizer), r: Math.floor(Number(sizer) / 2) - Number(thickness), thickness, }; }, [sizeProp, thicknessProp]); const value = valueProp ? Math.max(0, Math.min(100, Math.round(valueProp))) : 0; return (
{children}
{value}%
); } ); CircularProgress.displayName = 'CircularProgress'; export { CircularProgress };