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;