import * as React from 'react'; import { cva, type VariantProps } from 'class-variance-authority'; import { cn } from '@/lib/utils'; const progressVariants = cva( 'relative block', { variants: { variant: { default: '', }, isIndeterminate: { true: 'animate-progress-container', false: '', }, }, defaultVariants: { variant: 'default', isIndeterminate: false, }, }, ); const circleVariants = cva( 'fill-fill-content h-5 w-5', { variants: { variant: { default: 'stroke-fill-secondary', }, }, defaultVariants: { variant: 'default', }, }, ); const progressCircleVariants = cva( 'fill-fill-content transition-all h-5 w-5', { variants: { variant: { default: 'stroke-text-on-fill', }, }, defaultVariants: { variant: 'default', }, }, ); export interface ProgressProps extends React.HTMLAttributes, VariantProps { /** Progress value between 0 and 100. When undefined, shows indeterminate state */ value?: number; /** Line ending style */ strokeLinecap?: 'round' | 'square'; } export function Progress ({ value, variant = 'default', strokeLinecap = 'round', className, ...props }: ProgressProps) { // Calculate dimensions based on size variant const dimensions: number = 20; const strokeWidth = 2.5; const radius = dimensions / 2 - strokeWidth; const circumference = Math.ceil(2 * Math.PI * radius); const isIndeterminate = value === undefined; // Calculate percentage offset for the progress circle const offset = isIndeterminate ? circumference * 0.25 // 25% offset for indeterminate state : Math.ceil(circumference * ((100 - Math.min(Math.max(0, value || 0), 100)) / 100)); // Calculate viewBox to add padding around the circles const viewBox = `-${dimensions * 0.125} -${dimensions * 0.125} ${dimensions * 1.25} ${ dimensions * 1.25 }`; return (
{/* Base Circle */} {/* Progress Circle */}
); }