ChristopherJKoen's picture
V0.1.5
74b1b27
type LoadingBarProps = {
active: boolean;
progress?: number | null;
label?: string;
className?: string;
};
function clampProgress(value: number): number {
if (Number.isNaN(value)) return 0;
if (value < 0) return 0;
if (value > 100) return 100;
return value;
}
export function LoadingBar({
active,
progress = null,
label,
className = "",
}: LoadingBarProps) {
if (!active) return null;
const numericProgress = typeof progress === "number" ? clampProgress(progress) : null;
return (
<div className={className}>
{label ? (
<div className="mb-1 text-xs font-medium text-gray-600">
{label}
{numericProgress !== null ? ` (${Math.round(numericProgress)}%)` : ""}
</div>
) : null}
<div
role="progressbar"
aria-valuemin={0}
aria-valuemax={100}
aria-valuenow={numericProgress ?? undefined}
className="h-2 w-full overflow-hidden rounded-full bg-gray-200"
>
<div
className={[
"h-full rounded-full bg-blue-600",
numericProgress === null ? "w-2/5 animate-pulse" : "transition-all duration-200",
].join(" ")}
style={numericProgress === null ? undefined : { width: `${numericProgress}%` }}
/>
</div>
</div>
);
}