Skip to content

Commit b5b5149

Browse files
authored
[material-ui][CircularProgress] Add track slot via enableTrackSlot (#46907)
1 parent 82e502e commit b5b5149

File tree

12 files changed

+213
-67
lines changed

12 files changed

+213
-67
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import * as React from 'react';
2+
import Stack from '@mui/material/Stack';
3+
import CircularProgress from '@mui/material/CircularProgress';
4+
5+
export default function CircularEnableTrack() {
6+
const [progress, setProgress] = React.useState(0);
7+
8+
React.useEffect(() => {
9+
const timer = setInterval(() => {
10+
setProgress((prevProgress) => (prevProgress >= 100 ? 0 : prevProgress + 10));
11+
}, 800);
12+
13+
return () => {
14+
clearInterval(timer);
15+
};
16+
}, []);
17+
18+
return (
19+
<Stack spacing={2} direction="row">
20+
<CircularProgress enableTrackSlot size="30px" />
21+
<CircularProgress enableTrackSlot size={40} />
22+
<CircularProgress enableTrackSlot size="3rem" />
23+
<CircularProgress enableTrackSlot variant="determinate" value={70} />
24+
<CircularProgress
25+
enableTrackSlot
26+
variant="determinate"
27+
color="secondary"
28+
value={progress}
29+
/>
30+
</Stack>
31+
);
32+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import * as React from 'react';
2+
import Stack from '@mui/material/Stack';
3+
import CircularProgress from '@mui/material/CircularProgress';
4+
5+
export default function CircularEnableTrack() {
6+
const [progress, setProgress] = React.useState(0);
7+
8+
React.useEffect(() => {
9+
const timer = setInterval(() => {
10+
setProgress((prevProgress) => (prevProgress >= 100 ? 0 : prevProgress + 10));
11+
}, 800);
12+
13+
return () => {
14+
clearInterval(timer);
15+
};
16+
}, []);
17+
18+
return (
19+
<Stack spacing={2} direction="row">
20+
<CircularProgress enableTrackSlot size="30px" />
21+
<CircularProgress enableTrackSlot size={40} />
22+
<CircularProgress enableTrackSlot size="3rem" />
23+
<CircularProgress enableTrackSlot variant="determinate" value={70} />
24+
<CircularProgress
25+
enableTrackSlot
26+
variant="determinate"
27+
color="secondary"
28+
value={progress}
29+
/>
30+
</Stack>
31+
);
32+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<CircularProgress enableTrackSlot size="30px" />
2+
<CircularProgress enableTrackSlot size={40} />
3+
<CircularProgress enableTrackSlot size="3rem" />
4+
<CircularProgress enableTrackSlot variant="determinate" value={70} />
5+
<CircularProgress
6+
enableTrackSlot
7+
variant="determinate"
8+
color="secondary"
9+
value={progress}
10+
/>

docs/data/material/components/progress/CustomizedProgressBars.js

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as React from 'react';
22
import { styled } from '@mui/material/styles';
3-
import Box from '@mui/material/Box';
43
import Stack from '@mui/material/Stack';
54
import CircularProgress, {
65
circularProgressClasses,
@@ -28,40 +27,31 @@ const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({
2827
// Inspired by the former Facebook spinners.
2928
function FacebookCircularProgress(props) {
3029
return (
31-
<Box sx={{ position: 'relative' }}>
32-
<CircularProgress
33-
variant="determinate"
34-
sx={(theme) => ({
35-
color: theme.palette.grey[200],
30+
<CircularProgress
31+
variant="indeterminate"
32+
disableShrink
33+
enableTrackSlot
34+
sx={(theme) => ({
35+
color: '#1a90ff',
36+
animationDuration: '550ms',
37+
[`& .${circularProgressClasses.circle}`]: {
38+
strokeLinecap: 'round',
39+
},
40+
[`& .${circularProgressClasses.track}`]: {
41+
opacity: 1,
42+
stroke: (theme.vars || theme).palette.grey[200],
3643
...theme.applyStyles('dark', {
37-
color: theme.palette.grey[800],
44+
stroke: (theme.vars || theme).palette.grey[800],
3845
}),
39-
})}
40-
size={40}
41-
thickness={4}
42-
{...props}
43-
value={100}
44-
/>
45-
<CircularProgress
46-
variant="indeterminate"
47-
disableShrink
48-
sx={(theme) => ({
49-
color: '#1a90ff',
50-
animationDuration: '550ms',
51-
position: 'absolute',
52-
left: 0,
53-
[`& .${circularProgressClasses.circle}`]: {
54-
strokeLinecap: 'round',
55-
},
56-
...theme.applyStyles('dark', {
57-
color: '#308fe8',
58-
}),
59-
})}
60-
size={40}
61-
thickness={4}
62-
{...props}
63-
/>
64-
</Box>
46+
},
47+
...theme.applyStyles('dark', {
48+
color: '#308fe8',
49+
}),
50+
})}
51+
size={40}
52+
thickness={4}
53+
{...props}
54+
/>
6555
);
6656
}
6757

docs/data/material/components/progress/CustomizedProgressBars.tsx

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as React from 'react';
22
import { styled } from '@mui/material/styles';
3-
import Box from '@mui/material/Box';
43
import Stack from '@mui/material/Stack';
54
import CircularProgress, {
65
circularProgressClasses,
@@ -29,40 +28,31 @@ const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({
2928
// Inspired by the former Facebook spinners.
3029
function FacebookCircularProgress(props: CircularProgressProps) {
3130
return (
32-
<Box sx={{ position: 'relative' }}>
33-
<CircularProgress
34-
variant="determinate"
35-
sx={(theme) => ({
36-
color: theme.palette.grey[200],
31+
<CircularProgress
32+
variant="indeterminate"
33+
disableShrink
34+
enableTrackSlot
35+
sx={(theme) => ({
36+
color: '#1a90ff',
37+
animationDuration: '550ms',
38+
[`& .${circularProgressClasses.circle}`]: {
39+
strokeLinecap: 'round',
40+
},
41+
[`& .${circularProgressClasses.track}`]: {
42+
opacity: 1,
43+
stroke: (theme.vars || theme).palette.grey[200],
3744
...theme.applyStyles('dark', {
38-
color: theme.palette.grey[800],
45+
stroke: (theme.vars || theme).palette.grey[800],
3946
}),
40-
})}
41-
size={40}
42-
thickness={4}
43-
{...props}
44-
value={100}
45-
/>
46-
<CircularProgress
47-
variant="indeterminate"
48-
disableShrink
49-
sx={(theme) => ({
50-
color: '#1a90ff',
51-
animationDuration: '550ms',
52-
position: 'absolute',
53-
left: 0,
54-
[`& .${circularProgressClasses.circle}`]: {
55-
strokeLinecap: 'round',
56-
},
57-
...theme.applyStyles('dark', {
58-
color: '#308fe8',
59-
}),
60-
})}
61-
size={40}
62-
thickness={4}
63-
{...props}
64-
/>
65-
</Box>
47+
},
48+
...theme.applyStyles('dark', {
49+
color: '#308fe8',
50+
}),
51+
})}
52+
size={40}
53+
thickness={4}
54+
{...props}
55+
/>
6656
);
6757
}
6858

docs/data/material/components/progress/progress.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ The animations of the components rely on CSS as much as possible to work even be
3838

3939
{{"demo": "CircularDeterminate.js"}}
4040

41+
### Circular track
42+
43+
{{"demo": "CircularEnableTrack.js"}}
44+
4145
### Interactive integration
4246

4347
{{"demo": "CircularIntegration.js"}}

docs/pages/material-ui/api/circular-progress.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"default": "'primary'"
1010
},
1111
"disableShrink": { "type": { "name": "custom", "description": "bool" }, "default": "false" },
12+
"enableTrackSlot": { "type": { "name": "bool" }, "default": "false" },
1213
"size": {
1314
"type": { "name": "union", "description": "number<br>&#124;&nbsp;string" },
1415
"default": "40"
@@ -94,6 +95,12 @@
9495
"className": "MuiCircularProgress-svg",
9596
"description": "Styles applied to the svg element.",
9697
"isGlobal": false
98+
},
99+
{
100+
"key": "track",
101+
"className": "MuiCircularProgress-track",
102+
"description": "Styles applied to the track slot if `enableTrackSlot={true}`.",
103+
"isGlobal": false
97104
}
98105
],
99106
"spread": true,

docs/translations/api-docs/circular-progress/circular-progress.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
"disableShrink": {
99
"description": "If <code>true</code>, the shrink animation is disabled. This only works if variant is <code>indeterminate</code>."
1010
},
11+
"enableTrackSlot": {
12+
"description": "If <code>true</code>, a track circle slot is mounted to show a subtle background for the progress. The <code>size</code> and <code>thickness</code> apply to the track slot to be consistent with the progress circle."
13+
},
1114
"size": {
1215
"description": "The size of the component. If using a number, the pixel unit is assumed. If using a string, you need to provide the CSS unit, for example &#39;3rem&#39;."
1316
},
@@ -65,6 +68,11 @@
6568
"conditions": "<code>variant=\"indeterminate\"</code>"
6669
},
6770
"root": { "description": "Styles applied to the root element." },
68-
"svg": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the svg element" }
71+
"svg": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the svg element" },
72+
"track": {
73+
"description": "Styles applied to {{nodeName}} if {{conditions}}.",
74+
"nodeName": "the track slot",
75+
"conditions": "<code>enableTrackSlot={true}</code>"
76+
}
6977
}
7078
}

packages/mui-material/src/CircularProgress/CircularProgress.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ export interface CircularProgressProps
3030
* @default false
3131
*/
3232
disableShrink?: boolean;
33+
/**
34+
* If `true`, a track circle slot is mounted to show a subtle background for the progress.
35+
* The `size` and `thickness` apply to the track slot to be consistent with the progress circle.
36+
* @default false
37+
*/
38+
enableTrackSlot?: boolean;
3339
/**
3440
* The size of the component.
3541
* If using a number, the pixel unit is assumed.

packages/mui-material/src/CircularProgress/CircularProgress.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ const useUtilityClasses = (ownerState) => {
6363
const slots = {
6464
root: ['root', variant, `color${capitalize(color)}`],
6565
svg: ['svg'],
66+
track: ['track'],
6667
circle: ['circle', `circle${capitalize(variant)}`, disableShrink && 'circleDisableShrink'],
6768
};
6869

@@ -166,6 +167,16 @@ const CircularProgressCircle = styled('circle', {
166167
})),
167168
);
168169

170+
const CircularProgressTrack = styled('circle', {
171+
name: 'MuiCircularProgress',
172+
slot: 'Track',
173+
})(
174+
memoTheme(({ theme }) => ({
175+
stroke: 'currentColor',
176+
opacity: (theme.vars || theme).palette.action.activatedOpacity,
177+
})),
178+
);
179+
169180
/**
170181
* ## ARIA
171182
*
@@ -179,6 +190,7 @@ const CircularProgress = React.forwardRef(function CircularProgress(inProps, ref
179190
className,
180191
color = 'primary',
181192
disableShrink = false,
193+
enableTrackSlot = false,
182194
size = 40,
183195
style,
184196
thickness = 3.6,
@@ -195,6 +207,7 @@ const CircularProgress = React.forwardRef(function CircularProgress(inProps, ref
195207
thickness,
196208
value,
197209
variant,
210+
enableTrackSlot,
198211
};
199212

200213
const classes = useUtilityClasses(ownerState);
@@ -226,6 +239,18 @@ const CircularProgress = React.forwardRef(function CircularProgress(inProps, ref
226239
ownerState={ownerState}
227240
viewBox={`${SIZE / 2} ${SIZE / 2} ${SIZE} ${SIZE}`}
228241
>
242+
{enableTrackSlot ? (
243+
<CircularProgressTrack
244+
className={classes.track}
245+
ownerState={ownerState}
246+
cx={SIZE}
247+
cy={SIZE}
248+
r={(SIZE - thickness) / 2}
249+
fill="none"
250+
strokeWidth={thickness}
251+
aria-hidden="true"
252+
/>
253+
) : null}
229254
<CircularProgressCircle
230255
className={classes.circle}
231256
style={circleStyle}
@@ -279,6 +304,12 @@ CircularProgress.propTypes /* remove-proptypes */ = {
279304

280305
return null;
281306
}),
307+
/**
308+
* If `true`, a track circle slot is mounted to show a subtle background for the progress.
309+
* The `size` and `thickness` apply to the track slot to be consistent with the progress circle.
310+
* @default false
311+
*/
312+
enableTrackSlot: PropTypes.bool,
282313
/**
283314
* The size of the component.
284315
* If using a number, the pixel unit is assumed.

0 commit comments

Comments
 (0)