@carbon/react
Version:
React components for the Carbon Design System
153 lines (149 loc) • 4.81 kB
JavaScript
/**
* Copyright IBM Corp. 2016, 2023
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
import React, { useRef } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import { ErrorFilled, CheckmarkFilled } from '@carbon/icons-react';
import { useId } from '../../internal/useId.js';
import { usePrefix } from '../../internal/usePrefix.js';
import useIsomorphicEffect from '../../internal/useIsomorphicEffect.js';
function ProgressBar({
className,
helperText,
hideLabel,
label,
max = 100,
size = 'big',
status = 'active',
type = 'default',
value
}) {
const labelId = useId('progress-bar');
const helperId = useId('progress-bar-helper');
const helperTextId = useId('progress-bar-helper-text');
const prefix = usePrefix();
const isFinished = status === 'finished';
const isError = status === 'error';
const indeterminate = !isFinished && !isError && (value === null || value === undefined);
let cappedValue = value;
if (cappedValue && cappedValue > max) {
cappedValue = max;
}
if (cappedValue && cappedValue < 0) {
cappedValue = 0;
}
if (isError) {
cappedValue = 0;
} else if (isFinished) {
cappedValue = max;
}
const percentage = (cappedValue ?? NaN) / max;
const wrapperClasses = cx(`${prefix}--progress-bar`, `${prefix}--progress-bar--${size}`, `${prefix}--progress-bar--${type}`, {
[`${prefix}--progress-bar--indeterminate`]: indeterminate,
[`${prefix}--progress-bar--finished`]: isFinished,
[`${prefix}--progress-bar--error`]: isError
}, className);
const labelClasses = cx(`${prefix}--progress-bar__label`, {
[`${prefix}--visually-hidden`]: hideLabel
});
let StatusIcon = null;
if (isError) {
StatusIcon = /*#__PURE__*/React.forwardRef(function ErrorFilled16(props, ref) {
return /*#__PURE__*/React.createElement(ErrorFilled, _extends({
ref: ref,
size: 16
}, props));
});
} else if (isFinished) {
StatusIcon = /*#__PURE__*/React.forwardRef(function CheckmarkFilled16(props, ref) {
return /*#__PURE__*/React.createElement(CheckmarkFilled, _extends({
ref: ref,
size: 16
}, props));
});
}
const ref = useRef(null);
useIsomorphicEffect(() => {
if (ref.current) {
if (!isFinished && !isError) {
ref.current.style.transform = `scaleX(${percentage})`;
} else {
ref.current.style.transform = '';
}
}
}, [percentage, isFinished, isError]);
return /*#__PURE__*/React.createElement("div", {
className: wrapperClasses
}, /*#__PURE__*/React.createElement("div", {
className: labelClasses,
id: labelId
}, /*#__PURE__*/React.createElement("span", {
className: `${prefix}--progress-bar__label-text`
}, label), StatusIcon && /*#__PURE__*/React.createElement(StatusIcon, {
className: `${prefix}--progress-bar__status-icon`
})), /*#__PURE__*/React.createElement("div", {
className: `${prefix}--progress-bar__track`,
role: "progressbar",
"aria-busy": !isFinished,
"aria-invalid": isError,
"aria-labelledby": labelId,
"aria-describedby": helperText ? helperTextId : undefined,
"aria-valuemin": !indeterminate ? 0 : undefined,
"aria-valuemax": !indeterminate ? max : undefined,
"aria-valuenow": !indeterminate ? cappedValue : undefined
}, /*#__PURE__*/React.createElement("div", {
className: `${prefix}--progress-bar__bar`,
ref: ref
})), helperText && /*#__PURE__*/React.createElement("div", {
id: helperTextId,
className: `${prefix}--progress-bar__helper-text`
}, helperText, /*#__PURE__*/React.createElement("div", {
className: `${prefix}--visually-hidden`,
"aria-live": "polite",
id: helperId
}, isFinished ? 'Done' : 'Loading')));
}
ProgressBar.propTypes = {
/**
* Additional CSS class names.
*/
className: PropTypes.string,
/**
* The current progress as a textual representation.
*/
helperText: PropTypes.string,
/**
* Whether the label should be visually hidden.
*/
hideLabel: PropTypes.bool,
/**
* A label describing the progress bar.
*/
label: PropTypes.string.isRequired,
/**
* The maximum value.
*/
max: PropTypes.number,
/**
* Specify the size of the ProgressBar.
*/
size: PropTypes.oneOf(['small', 'big']),
/**
* Specify the status.
*/
status: PropTypes.oneOf(['active', 'finished', 'error']),
/**
* Defines the alignment variant of the progress bar.
*/
type: PropTypes.oneOf(['default', 'inline', 'indented']),
/**
* The current value.
*/
value: PropTypes.number
};
export { ProgressBar as default };