Skip to content

Commit 46d4ff4

Browse files
authored
Progress color (#835)
* Add regression test for progress bar custom colors * Restore custom colors in Progress
1 parent 75d42cf commit 46d4ff4

File tree

2 files changed

+127
-7
lines changed

2 files changed

+127
-7
lines changed

src/components/progress/Progress.js

Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,119 @@
1-
import React from 'react';
1+
import React, {cloneElement} from 'react';
22
import PropTypes from 'prop-types';
3+
import classNames from 'classnames';
4+
import {map} from 'react-bootstrap/ElementChildren';
35
import {omit} from 'ramda';
4-
import RBProgressBar from 'react-bootstrap/ProgressBar';
6+
57
import {bootstrapColors} from '../../private/BootstrapColors';
68

7-
/**
8-
* A component for creating progress bars just with CSS. Control the current
9-
* progress with a callback and the `value` prop.
9+
/*
10+
* Bulk of this file is vendored from react-bootstrap/src/ProgressBar, but we
11+
* add the ability to style the bar which is needed for setting colors more
12+
* freely.
1013
*/
14+
const ROUND_PRECISION = 1000;
15+
16+
function getPercentage(now, min, max) {
17+
const percentage = ((now - min) / (max - min)) * 100;
18+
return Math.round(percentage * ROUND_PRECISION) / ROUND_PRECISION;
19+
}
20+
21+
function renderProgressBar(
22+
{
23+
min,
24+
now,
25+
max,
26+
label,
27+
visuallyHidden,
28+
striped,
29+
animated,
30+
className,
31+
style,
32+
variant,
33+
barStyle,
34+
...props
35+
},
36+
ref
37+
) {
38+
return (
39+
<div
40+
ref={ref}
41+
{...props}
42+
role="progressbar"
43+
className={classNames(className, `progress-bar`, {
44+
[`bg-${variant}`]: variant,
45+
[`progress-bar-animated`]: animated,
46+
[`progress-bar-striped`]: animated || striped
47+
})}
48+
style={{width: `${getPercentage(now, min, max)}%`, ...style, ...barStyle}}
49+
aria-valuenow={now}
50+
aria-valuemin={min}
51+
aria-valuemax={max}
52+
>
53+
{visuallyHidden ? (
54+
<span className="visually-hidden">{label}</span>
55+
) : (
56+
label
57+
)}
58+
</div>
59+
);
60+
}
61+
62+
const ProgressBar = React.forwardRef(({isChild, ...props}, ref) => {
63+
if (isChild) {
64+
return renderProgressBar(props, ref);
65+
}
66+
67+
const {
68+
min,
69+
now,
70+
max,
71+
label,
72+
visuallyHidden,
73+
striped,
74+
animated,
75+
variant,
76+
className,
77+
children,
78+
barStyle,
79+
...wrapperProps
80+
} = props;
81+
82+
return (
83+
<div
84+
ref={ref}
85+
{...wrapperProps}
86+
className={classNames(className, 'progress')}
87+
>
88+
{children
89+
? map(children, child => cloneElement(child, {isChild: true}))
90+
: renderProgressBar(
91+
{
92+
min,
93+
now,
94+
max,
95+
label,
96+
visuallyHidden,
97+
striped,
98+
animated,
99+
variant,
100+
barStyle
101+
},
102+
ref
103+
)}
104+
</div>
105+
);
106+
});
107+
108+
ProgressBar.defaultProps = {
109+
min: 0,
110+
max: 100,
111+
animated: false,
112+
isChild: false,
113+
visuallyHidden: false,
114+
striped: false
115+
};
116+
11117
const Progress = props => {
12118
const {
13119
children,
@@ -22,7 +128,7 @@ const Progress = props => {
22128
} = props;
23129
const isBootstrapColor = bootstrapColors.has(color);
24130
return (
25-
<RBProgressBar
131+
<ProgressBar
26132
className={class_name || className}
27133
{...omit(['setProps'], otherProps)}
28134
data-dash-is-loading={
@@ -32,9 +138,10 @@ const Progress = props => {
32138
isChild={bar}
33139
variant={isBootstrapColor ? color : null}
34140
visuallyHidden={hide_label}
141+
barStyle={isBootstrapColor ? {} : {backgroundColor: color}}
35142
>
36143
{children}
37-
</RBProgressBar>
144+
</ProgressBar>
38145
);
39146
};
40147

src/components/progress/__tests__/Progress.test.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ describe('Progress', () => {
5353
expect(progressDark.firstChild).toHaveClass('bg-dark');
5454
});
5555

56+
test('applies custom colors with "color" prop', () => {
57+
const {
58+
container: {firstChild: progressCustom}
59+
} = render(<Progress color="#fff000" />);
60+
61+
expect(progressCustom.firstChild).toHaveStyle({backgroundColor: '#fff000'});
62+
});
63+
5664
test('nested bars', () => {
5765
const {
5866
container: {firstChild: progress}
@@ -61,6 +69,7 @@ describe('Progress', () => {
6169
<Progress value={25} color="success" bar />
6270
<Progress value={25} color="warning" bar />
6371
<Progress value={25} color="danger" bar />
72+
<Progress value={25} color="#fff000" bar />
6473
</Progress>
6574
);
6675

@@ -70,6 +79,10 @@ describe('Progress', () => {
7079
expect(progress.children[1]).toHaveStyle({width: '25%'});
7180
expect(progress.children[2]).toHaveClass('progress-bar bg-danger');
7281
expect(progress.children[2]).toHaveStyle({width: '25%'});
82+
expect(progress.children[3]).toHaveStyle({
83+
width: '25%',
84+
backgroundColor: '#fff000'
85+
});
7386
});
7487

7588
test('applies additional CSS classes when props are set', () => {

0 commit comments

Comments
 (0)