{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "circular-progress", "title": "Circular Progress", "description": "Circular progress indicator for showing completion percentage in a ring format.", "dependencies": [ "@base-ui/react", "class-variance-authority" ], "files": [ { "path": "packages/ui/src/circular-progress.tsx", "content": "\"use client\";\n\nimport { Progress as ProgressPrimitive } from \"@base-ui/react/progress\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { createContext, useContext, useMemo } from \"react\";\n\nimport { cn } from \"./utils\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst VIEW_BOX_SIZE = 100;\nconst STROKE_WIDTH = 8;\nconst RADIUS = (VIEW_BOX_SIZE - STROKE_WIDTH) / 2;\nconst CIRCUMFERENCE = 2 * Math.PI * RADIUS;\n\n// ---------------------------------------------------------------------------\n// Variants\n// ---------------------------------------------------------------------------\n\nconst circularProgressVariants = cva(\"\", {\n variants: {\n color: {\n default: \"[--progress-indicator:var(--primary)]\",\n success: \"[--progress-indicator:oklch(0.627_0.194_149.214)]\",\n warning: \"[--progress-indicator:oklch(0.769_0.188_70.08)]\",\n destructive: \"[--progress-indicator:var(--destructive)]\",\n },\n size: {\n sm: \"size-12\",\n default: \"size-16\",\n lg: \"size-24\",\n },\n },\n defaultVariants: {\n color: \"default\",\n size: \"default\",\n },\n});\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\ninterface CircularProgressContextValue {\n max: number;\n min: number;\n value: number | null;\n}\n\nconst CircularProgressContext = createContext({\n value: 0,\n min: 0,\n max: 100,\n});\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type CircularProgressColor = NonNullable<\n VariantProps[\"color\"]\n>;\n\nexport type CircularProgressSize = NonNullable<\n VariantProps[\"size\"]\n>;\n\nexport interface CircularProgressProps extends ProgressPrimitive.Root.Props {\n /** Color variant of the progress indicator */\n color?: CircularProgressColor;\n /** Size variant */\n size?: CircularProgressSize;\n}\n\nexport interface CircularProgressTrackProps\n extends React.ComponentProps<\"circle\"> {}\nexport interface CircularProgressIndicatorProps\n extends React.ComponentProps<\"circle\"> {}\nexport interface CircularProgressValueProps\n extends ProgressPrimitive.Value.Props {}\nexport interface CircularProgressLabelProps\n extends ProgressPrimitive.Label.Props {}\n\n// ---------------------------------------------------------------------------\n// CircularProgress (Root)\n// ---------------------------------------------------------------------------\n\nfunction CircularProgress({\n className,\n children,\n color = \"default\",\n size = \"default\",\n value = 0,\n ...props\n}: CircularProgressProps) {\n const contextValue = useMemo(\n () => ({\n value: value ?? null,\n min: (props.min as number) ?? 0,\n max: (props.max as number) ?? 100,\n }),\n [value, props.min, props.max]\n );\n\n return (\n \n \n {children ?? (\n <>\n \n \n \n \n )}\n \n \n );\n}\n\n// ---------------------------------------------------------------------------\n// CircularProgressTrack\n// ---------------------------------------------------------------------------\n\nfunction CircularProgressTrack({\n className,\n ...props\n}: CircularProgressTrackProps) {\n return (\n \n \n \n );\n}\n\n// ---------------------------------------------------------------------------\n// CircularProgressIndicator\n// ---------------------------------------------------------------------------\n\nfunction CircularProgressIndicator({\n className,\n ...props\n}: CircularProgressIndicatorProps) {\n const { value, min, max } = useContext(CircularProgressContext);\n\n const normalizedValue =\n value === null\n ? null\n : Math.min(100, Math.max(0, ((value - min) / (max - min)) * 100));\n\n const strokeDashoffset =\n normalizedValue === null\n ? CIRCUMFERENCE * 0.75\n : CIRCUMFERENCE - (normalizedValue / 100) * CIRCUMFERENCE;\n\n return (\n \n \n \n );\n}\n\n// ---------------------------------------------------------------------------\n// CircularProgressValue\n// ---------------------------------------------------------------------------\n\nfunction CircularProgressValue({\n className,\n ...props\n}: CircularProgressValueProps) {\n return (\n \n );\n}\n\n// ---------------------------------------------------------------------------\n// CircularProgressLabel\n// ---------------------------------------------------------------------------\n\nfunction CircularProgressLabel({\n className,\n ...props\n}: CircularProgressLabelProps) {\n return (\n \n );\n}\n\n// ---------------------------------------------------------------------------\n// Exports\n// ---------------------------------------------------------------------------\n\nexport {\n CircularProgress,\n CircularProgressIndicator,\n CircularProgressLabel,\n CircularProgressTrack,\n CircularProgressValue,\n circularProgressVariants,\n};\n", "type": "registry:ui" } ], "type": "registry:ui" }