Files
cadence-ui/packages/ui/src/components/progress.tsx
T

84 lines
2.0 KiB
TypeScript

import * as ProgressPrimitive from "@radix-ui/react-progress";
import { forwardRef, type ComponentPropsWithoutRef, type ElementRef } from "react";
import {
progressIndicatorVariants,
progressVariants
} from "./progress.variants";
import { cn } from "../lib/cn";
import type { VariantProps } from "../lib/cva";
import { createDataAttributes, createSlot } from "../lib/contracts";
function clampValue(value: number, max: number) {
return Math.min(Math.max(value, 0), max);
}
function getState(value: number | null | undefined, max: number) {
if (value == null) {
return "indeterminate";
}
return clampValue(value, max) >= max ? "complete" : "loading";
}
function getIndicatorWidth(value: number | null | undefined, max: number) {
if (value == null) {
return "38%";
}
return `${(clampValue(value, max) / max) * 100}%`;
}
export type ProgressProps = ComponentPropsWithoutRef<typeof ProgressPrimitive.Root> &
VariantProps<typeof progressVariants> &
VariantProps<typeof progressIndicatorVariants>;
export const Progress = forwardRef<
ElementRef<typeof ProgressPrimitive.Root>,
ProgressProps
>(function Progress(
{
className,
max = 100,
size,
tone,
value,
variant,
...props
},
ref
) {
const resolvedMax = max > 0 ? max : 100;
const state = getState(value, resolvedMax);
return (
<ProgressPrimitive.Root
{...props}
{...createSlot("root")}
{...createDataAttributes({
size,
state,
tone,
variant
})}
className={cn(progressVariants({ size, tone }), className)}
max={resolvedMax}
ref={ref}
value={value ?? undefined}
>
<ProgressPrimitive.Indicator
{...createSlot("indicator")}
{...createDataAttributes({
size,
state,
variant
})}
className={cn(progressIndicatorVariants({ variant }))}
style={{
width: getIndicatorWidth(value, resolvedMax)
}}
/>
</ProgressPrimitive.Root>
);
});