diff --git a/CHANGELOG.md b/CHANGELOG.md
index 05ebb6b7f1c..292062fa85c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
- Added `paddingSize` prop to `EuiCard` ([#3638](https://github.com/elastic/eui/pull/3638))
- Added `isClearable` and `placeholder` options to `EuiColorPicker` ([#3689](https://github.com/elastic/eui/pull/3689))
- Added SASS helper files for EUI theme globals ([#3691](https://github.com/elastic/eui/pull/3691))
+- Add `label`, `labelProps` and `valueText` props to `EuiProgress` ([#3661](https://github.com/elastic/eui/pull/3661))
## [`26.3.0`](https://github.com/elastic/eui/tree/v26.3.0)
diff --git a/src-docs/src/views/progress/progress_chart.js b/src-docs/src/views/progress/progress_chart.js
new file mode 100644
index 00000000000..4af42fe9e0a
--- /dev/null
+++ b/src-docs/src/views/progress/progress_chart.js
@@ -0,0 +1,47 @@
+import React, { Fragment } from 'react';
+
+import { EuiProgress, EuiSpacer } from '../../../../src/components';
+
+const data = [
+ { label: "Men's Clothing", value: '80' },
+ { label: "Women's Clothing", value: '60' },
+ { label: "Women's Shoes", value: '45' },
+ { label: "Men's Shoes", value: '40' },
+ { label: "Women's Accessories", value: '24' },
+];
+
+export default () => (
+
+
+ {data.map(item => (
+ <>
+
+
+ >
+ ))}
+
+
+
+ {data.map(item => (
+ <>
+
+
+ >
+ ))}
+
+
+);
diff --git a/src-docs/src/views/progress/progress_example.js b/src-docs/src/views/progress/progress_example.js
index a5031a8e6d3..1f53304a29f 100644
--- a/src-docs/src/views/progress/progress_example.js
+++ b/src-docs/src/views/progress/progress_example.js
@@ -30,6 +30,22 @@ const progressFixedSnippet = `
import ProgressSizeColor from './progress_size_color';
const progressSizeColorSource = require('!!raw-loader!./progress_size_color');
const progressSizeColorHtml = renderToHtml(ProgressSizeColor);
+const progressSizeColorSnippet = ``;
+
+import ProgressChart from './progress_chart';
+const progressChartSource = require('!!raw-loader!./progress_chart');
+const progressChartHtml = renderToHtml(ProgressChart);
+const progressChartSnippet = ``;
export const ProgressExample = {
title: 'Progress',
@@ -139,6 +155,39 @@ export const ProgressExample = {
),
demo: ,
+ snippet: progressSizeColorSnippet,
+ },
+ {
+ title: 'Progress for charts',
+ source: [
+ {
+ type: GuideSectionTypes.JS,
+ code: progressChartSource,
+ },
+ {
+ type: GuideSectionTypes.HTML,
+ code: progressChartHtml,
+ },
+ ],
+ text: (
+
+
+ Determinate progress bar can be used as simple bar charts. Use them
+ with the label and valueText{' '}
+ props to show the data corresponding to each bar. The{' '}
+ valueText renders as the same color as the{' '}
+ EuiProgress.
+
+
+ Setting {'valueText={true}'} will
+ add a % sign next to thevalue passed. If you want
+ to display a custom valueText, you can pass a
+ node instead.
+
+
+ ),
+ demo: ,
+ snippet: progressChartSnippet,
},
],
};
diff --git a/src/components/progress/__snapshots__/progress.test.tsx.snap b/src/components/progress/__snapshots__/progress.test.tsx.snap
index b0e9f5d087e..8ab061269c2 100644
--- a/src/components/progress/__snapshots__/progress.test.tsx.snap
+++ b/src/components/progress/__snapshots__/progress.test.tsx.snap
@@ -1,7 +1,30 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`EuiProgress has labelProps 1`] = `
+Array [
+
+
+ 150
+
+
,
+ ,
+]
+`;
+
exports[`EuiProgress has max 1`] = `
`;
+exports[`EuiProgress has valueText and label 1`] = `
+Array [
+
+
+ Label
+
+
+ 150
+
+
,
+ ,
+]
+`;
+
exports[`EuiProgress is determinate 1`] = `
`;
+
+exports[`EuiProgress valueText is true 1`] = `
+Array [
+
+
+ 50%
+
+
,
+ ,
+]
+`;
diff --git a/src/components/progress/_progress.scss b/src/components/progress/_progress.scss
index 6178b1a6cbc..c07e82e53d5 100644
--- a/src/components/progress/_progress.scss
+++ b/src/components/progress/_progress.scss
@@ -117,6 +117,12 @@ $euiProgressColors: (
}
}
}
+
+ .euiProgress__data--#{$name} {
+ .euiProgress__valueText {
+ color: $color;
+ }
+ }
}
@keyframes euiProgress {
@@ -128,3 +134,33 @@ $euiProgressColors: (
transform: scaleX(1) translateX(100%);
}
}
+
+.euiProgress__data {
+ display: flex;
+ justify-content: space-between;
+
+ .euiProgress__label {
+ @include euiTextTruncate;
+ flex-basis: 80%;
+ flex-grow: 1;
+ }
+
+ .euiProgress__valueText {
+ @include euiTextTruncate;
+ margin-left: auto;
+ }
+}
+
+.euiProgress__label,
+.euiProgress__valueText {
+ @include euiText;
+ @include euiFontSize;
+ @include fontSize($euiFontSizeXS);
+}
+
+.euiProgress__data--l {
+ .euiProgress__label,
+ .euiProgress__valueText {
+ @include fontSize($euiFontSizeS);
+ }
+}
\ No newline at end of file
diff --git a/src/components/progress/progress.test.tsx b/src/components/progress/progress.test.tsx
index 6cccc5e4947..39aa8739747 100644
--- a/src/components/progress/progress.test.tsx
+++ b/src/components/progress/progress.test.tsx
@@ -59,4 +59,40 @@ describe('EuiProgress', () => {
expect(component).toMatchSnapshot();
});
+
+ test('has valueText and label', () => {
+ const component = render(
+
+ );
+
+ expect(component).toMatchSnapshot();
+ });
+
+ test('valueText is true', () => {
+ const component = render(
+
+ );
+
+ expect(component).toMatchSnapshot();
+ });
+
+ test('has labelProps', () => {
+ const component = render(
+
+ );
+
+ expect(component).toMatchSnapshot();
+ });
});
diff --git a/src/components/progress/progress.tsx b/src/components/progress/progress.tsx
index 53b1b5aef67..60709aef019 100644
--- a/src/components/progress/progress.tsx
+++ b/src/components/progress/progress.tsx
@@ -21,8 +21,11 @@ import React, {
FunctionComponent,
HTMLAttributes,
ProgressHTMLAttributes,
+ ReactNode,
+ Fragment,
} from 'react';
import classNames from 'classnames';
+import { EuiI18n } from '../i18n';
import { CommonProps, ExclusiveUnion } from '../common';
import { isNil } from '../../services/predicate';
@@ -49,6 +52,14 @@ export const COLORS = Object.keys(colorToClassNameMap);
export type EuiProgressColor = keyof typeof colorToClassNameMap;
+const dataColorToClassNameMap = {
+ primary: 'euiProgress__data--primary',
+ secondary: 'euiProgress__data--secondary',
+ danger: 'euiProgress__data--danger',
+ subdued: 'euiProgress__data--subdued',
+ accent: 'euiProgress__data--accent',
+};
+
const positionsToClassNameMap = {
fixed: 'euiProgress--fixed',
absolute: 'euiProgress--absolute',
@@ -70,6 +81,15 @@ type Indeterminate = EuiProgressProps & HTMLAttributes;
type Determinate = EuiProgressProps &
ProgressHTMLAttributes & {
max?: number;
+ /*
+ * If true, will render the percentage, otherwise pass a custom node
+ */
+ valueText?: boolean | ReactNode;
+ label?: ReactNode;
+ /**
+ * Object of props passed to the wrapping the determinate progress's label
+ */
+ labelProps?: HTMLAttributes;
};
export const EuiProgress: FunctionComponent<
@@ -80,7 +100,10 @@ export const EuiProgress: FunctionComponent<
size = 'm',
position = 'static',
max,
+ valueText = false,
+ label,
value,
+ labelProps,
...rest
}) => {
const determinate = !isNil(max);
@@ -95,17 +118,63 @@ export const EuiProgress: FunctionComponent<
positionsToClassNameMap[position],
className
);
+ const dataClasses = classNames(
+ 'euiProgress__data',
+ {
+ 'euiProgress__data--l': size === 'l',
+ },
+ dataColorToClassNameMap[color]
+ );
+ const labelClasses = classNames(
+ 'euiProgress__label',
+ labelProps && labelProps.className
+ );
+
+ let valueRender;
+ if (typeof valueText === 'boolean' && valueText) {
+ // valueText is a true boolean
+ valueRender = (
+
+ );
+ } else if (valueText) {
+ // valueText exists
+ valueRender = valueText;
+ }
// Because of a Firefox animation issue, indeterminate progress needs to not use .
// See https://css-tricks.com/html5-progress-element/
+
if (determinate) {
return (
-