import { type CSSProperties, type HTMLAttributes, type ReactElement, useMemo, } from "react"; import { type LabelRequiredForA11y, type PropsWithRef } from "../types.js"; import { useEnsuredId } from "../useEnsuredId.js"; import { getPercentage } from "../utils/getPercentage.js"; import { type BaseLinearProgressClassNameOptions, linearProgress, linearProgressBar, } from "./linearProgressStyles.js"; import { type ProgressProps } from "./types.js"; /** * @since 6.0.0 Added the `theme` prop * @since 6.3.1 extends BaseLinearProgressClassNameOptions for CSSProperties * module augmentation. */ export interface LinearProgressProps extends Omit, "id" | "children">, BaseLinearProgressClassNameOptions, ProgressProps { /** * An optional style to apply to the progress bar. This will be merged with * the current width or height tracking the progress when a `value` is also * provided. */ barStyle?: CSSProperties; /** * An optional className to apply to the progress bar. */ barClassName?: string; /** * @since 6.1.0 */ barProps?: PropsWithRef>; /** * Boolean if the progress should be reversed. This will change the progress * direction from `left-to-right` to be `right-to-left`. If the current * language is a rtl language and this prop is enabled, the direction will * still be `left-to-right`. * * @defaultValue `false` */ reverse?: boolean; /** * Since there isn't really a good way to have "auto height", you'll need to * manually set the progress bar's height with this prop to some pixel value. * If you'd prefer to set the height in Sass/css, set this value to `null` * instead since this value would be passed down as a `height` inline style. * * @defaultValue `240` */ verticalHeight?: number | null; } /** * @example Indeterminate Example * ```tsx * import { LinearProgress } from "@react-md/core/progress/LinearProgress"; * import { type ReactElement } from "react"; * * function Example(): ReactElement { * return ; * } * ``` * * @example Determinate Example * ```tsx * import { LinearProgress } from "@react-md/core/progress/LinearProgress"; * import { useState, type ReactElement } from "react"; * * function Example(): ReactElement { * // a number from 0 - 100 * const [progress, setProgress] = useState(0); * * return ; * } * ``` * * @see {@link https://react-md.dev/components/progress#linear-progress | Progress Demos} * @since 6.0.0 Supports rendering as any of the theme colors and * requires a label for accessibility. */ export function LinearProgress( props: LabelRequiredForA11y ): ReactElement { const { ref, id: propId, style: propStyle, className, barStyle: propBarStyle, barClassName, barProps, min = 0, max = 100, value, reverse, theme, disableTransition, vertical, verticalHeight = 240, ...remaining } = props; const id = useEnsuredId(propId, "linear-progress"); const style = useMemo(() => { if (!vertical || verticalHeight === null) { return propStyle; } return { ...propStyle, height: verticalHeight, }; }, [propStyle, vertical, verticalHeight]); let progress: number | undefined; if (typeof value === "number") { progress = getPercentage({ min, max, value, validate: true }); } const barStyle = useMemo(() => { if (typeof progress !== "number") { return propBarStyle; } const key = vertical ? "height" : "width"; return { ...propBarStyle, [key]: `${progress * 100}%`, }; }, [progress, propBarStyle, vertical]); const indeterminate = typeof progress !== "number"; return ( ); }