"use client";
import type { ReactNode } from "react";
import { ProgressBar as AriaProgressBar } from "react-aria-components";
import type { ProgressBarProps as AriaProgressBarProps } from "react-aria-components";
import { Label } from "@/components/base/input/label";
import { SpinnerGlyph } from "@/components/base/spinner/spinner";
import { useDirection } from "@/components/foundations/direction/direction";
import { cx, sortCx } from "@/utils/cx";
/**
* Progress — how far along a task is: an upload, an import, an onboarding
* checklist. Built on React Aria's ProgressBar, so it is announced with its
* label and value, and formats the value for the locale.
*
*
*
*
*
* The bar is the agent limits card's rounded rail with an accent fill, on
* File Upload's track colour. The fill moves by translate rather than width, so it eases
* to each new value on the compositor (500ms, the card's ease-out).
*
* Indeterminate, a band of light sweeps the track, drawn like Spinner and
* Composer Loader: a crisp core with a rounded head, a tight glow and a wide
* bloom that bleed a few pixels past the rail, the soft layers pulled back
* so the sharp head leads. It runs right to left in RTL. The ring's
* indeterminate state is Spinner's orbiting light. Reduced motion slows the
* sweep rather than stopping it.
*/
export type ProgressSize = "sm" | "md" | "lg";
const EASE = "ease-[cubic-bezier(0.22,1,0.36,1)]";
const styles = sortCx({
track: {
sm: "h-1",
md: "h-1.5",
lg: "h-2",
},
ring: {
sm: { box: 16, line: 2, spinner: "sm" },
md: { box: 24, line: 2.5, spinner: "lg" },
lg: { box: 32, line: 3, spinner: "xl" },
},
});
/* -------------------------------------------------------------------- bar */
export interface ProgressBarProps extends Omit {
label?: ReactNode;
/** Show the formatted value at the end of the label row. Default: shown with a label. */
showValueLabel?: boolean;
/** Helper text under the bar. */
description?: ReactNode;
/** Track thickness: 4, 6 (default), or 8px. */
size?: ProgressSize;
className?: string;
}
/** The sweeping band of light for an indeterminate bar. */
function Sweep() {
return (
// The clip keeps the light inside the rail's length but lets the glow
// and bloom bleed past its thickness.
);
}
export interface ProgressTrackProps {
/** 0 to 100. */
percentage: number;
size?: ProgressSize;
/** Draw the indeterminate sweep instead of a fill. */
isIndeterminate?: boolean;
/** Colour of the fill, from the text colour. Default accent. */
className?: string;
}
/** The rail and its fill, shared by ProgressBar and Meter. */
export function ProgressTrack({ percentage, size = "md", isIndeterminate = false, className }: ProgressTrackProps) {
const direction = useDirection();
return (
// The rail is File Upload's ring track colour, which keeps an edge on
// every surface in both themes (chart-track matches dark cards).