import React, { HTMLAttributes, forwardRef, useEffect } from "react"; import type { AkselColor } from "../types"; import { cl } from "../utils/helpers"; import { useTimeout, useValueAsRef } from "../utils/hooks"; import { useI18n } from "../utils/i18n/i18n.hooks"; interface ProgressBarPropsBase extends Omit< HTMLAttributes, "role" > { /** * Changes height. * @default "medium" */ size?: "large" | "medium" | "small"; /** * Current progress. If set, the `simulated` prop overrides `value`. */ value?: number; /** * Maximum progress. * @default 100 */ valueMax?: number; /** * Visually simulates loading. * ProgressBar grows with a preset animation for set number of seconds, * then shows an indeterminate animation on timeout. */ simulated?: { /** * Duration in seconds. */ seconds: number; /** * Callback function when progress is indeterminate. */ onTimeout: () => void; }; /** * String ID of the element that labels the progress bar. * Not needed if `aria-label` is used. */ "aria-labelledby"?: string; /** * String value that labels the progress bar. * Not needed if `aria-labelledby` is used. */ "aria-label"?: string; /** * Overrides inherited color. * @see 🏷️ {@link AkselColor} * @see [📝 Documentation](https://aksel.nav.no/grunnleggende/styling/farger-tokens) */ "data-color"?: AkselColor; } export type ProgressBarProps = ProgressBarPropsBase & ( | { "aria-hidden": true; } | { "aria-labelledby": string; "aria-label"?: never; } | { "aria-label": string; "aria-labelledby"?: never; } ); /** * ProgressBar * A component for visualizing progression in a process. * * @see [📝 Documentation](https://aksel.nav.no/komponenter/core/progress-bar) * @see 🏷️ {@link ProgressBarProps} * * @example * // For loading content with an approximate duration in sec. * console.log("Oops, this is taking more time than expected!") * }} * /> * * @example * // As a step indicator for forms, questionnaires, etc. * */ export const ProgressBar = forwardRef( ( { size = "medium", value = 0, valueMax = 100, "aria-labelledby": ariaLabelledBy, "aria-label": ariaLabel, className, simulated, ...rest }, ref, ) => { const translateX = 100 - (Math.round(value) / valueMax) * 100; const onTimeoutRef = useValueAsRef(simulated?.onTimeout); const translate = useI18n("ProgressBar"); const timeout = useTimeout(); useEffect(() => { if (!simulated?.seconds || !onTimeoutRef.current) { return; } timeout.start(simulated.seconds * 1000, onTimeoutRef.current); return timeout.clear; }, [onTimeoutRef, simulated?.seconds, timeout]); return (
); }, ); export default ProgressBar;