"use client"; import type { ReactNode } from "react"; import { Meter as AriaMeter } from "react-aria-components"; import type { MeterProps as AriaMeterProps } from "react-aria-components"; import { Label } from "@/components/base/input/label"; import { ProgressTrack, type ProgressSize } from "@/components/base/progress/progress"; import { cx, sortCx } from "@/utils/cx"; /** * Meter — a quantity within a known range: storage used, seats taken, a * password's strength. Unlike ProgressBar it describes a level rather than * a task moving towards done, and React Aria's Meter announces it that way * (role="meter"). * * * * * It is drawn on ProgressBar's track: the same rail, fill, and eased * translate when the value changes. `tone` colours the fill from semantic * tokens, so a meter can turn amber or red as it fills up. */ export type MeterTone = "accent" | "success" | "warning" | "error"; const tones = sortCx({ accent: "text-accent-500", success: "text-notification-success-foreground", warning: "text-chart-8-active", error: "text-notification-error-foreground", }); export interface MeterProps 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; /** Colour of the fill. Default `accent`. */ tone?: MeterTone; /** Track thickness: 4, 6 (default), or 8px. */ size?: ProgressSize; className?: string; } export function Meter({ label, showValueLabel, description, tone = "accent", size = "md", className, ...props }: MeterProps) { const showValue = showValueLabel ?? label != null; return ( {({ percentage, valueText }) => ( <> {label != null || showValue ? (
{label != null ? : } {showValue ? ( {valueText} ) : null}
) : null} {description ? {description} : null} )}
); }