Skip to content

Commit 3f769c1

Browse files
crisbetovictoriaaa234
authored andcommitted
fix(progress-spinner): circle not rendering correctly when switching modes in Safari (#12151)
Fixes the SVG `circle` element not rendering property when switching from `indeterminate` to `determinate` mode. Fixes #12140.
1 parent fad1dbd commit 3f769c1

File tree

3 files changed

+42
-4
lines changed

3 files changed

+42
-4
lines changed

src/lib/progress-spinner/progress-spinner-module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88
import {NgModule} from '@angular/core';
9+
import {CommonModule} from '@angular/common';
910
import {MatCommonModule} from '@angular/material/core';
1011
import {MatProgressSpinner, MatSpinner} from './progress-spinner';
1112

1213

1314
@NgModule({
14-
imports: [MatCommonModule],
15+
imports: [MatCommonModule, CommonModule],
1516
exports: [
1617
MatProgressSpinner,
1718
MatSpinner,

src/lib/progress-spinner/progress-spinner.html

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,32 @@
1010
[style.height.px]="diameter"
1111
[attr.viewBox]="_viewBox"
1212
preserveAspectRatio="xMidYMid meet"
13-
focusable="false">
13+
focusable="false"
14+
[ngSwitch]="mode === 'indeterminate'">
1415

16+
<!--
17+
Technically we can reuse the same `circle` element, however Safari has an issue that breaks
18+
the SVG rendering in determinate mode, after switching between indeterminate and determinate.
19+
Using a different element avoids the issue. An alternative to this is adding `display: none`
20+
for a split second and then removing it when switching between modes, but it's hard to know
21+
for how long to hide the element and it can cause the UI to blink.
22+
-->
1523
<circle
24+
*ngSwitchCase="true"
1625
cx="50%"
1726
cy="50%"
1827
[attr.r]="_circleRadius"
1928
[style.animation-name]="'mat-progress-spinner-stroke-rotate-' + diameter"
2029
[style.stroke-dashoffset.px]="_strokeDashOffset"
2130
[style.stroke-dasharray.px]="_strokeCircumference"
2231
[style.stroke-width.%]="_circleStrokeWidth"></circle>
32+
33+
<circle
34+
*ngSwitchCase="false"
35+
cx="50%"
36+
cy="50%"
37+
[attr.r]="_circleRadius"
38+
[style.stroke-dashoffset.px]="_strokeDashOffset"
39+
[style.stroke-dasharray.px]="_strokeCircumference"
40+
[style.stroke-width.%]="_circleStrokeWidth"></circle>
2341
</svg>

src/lib/progress-spinner/progress-spinner.spec.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,24 @@ describe('MatProgressSpinner', () => {
8383
expect(progressElement.componentInstance.value).toBe(75);
8484
});
8585

86+
it('should use different `circle` elements depending on the mode', () => {
87+
const fixture = TestBed.createComponent(ProgressSpinnerWithValueAndBoundMode);
88+
89+
fixture.componentInstance.mode = 'determinate';
90+
fixture.detectChanges();
91+
92+
const determinateCircle = fixture.nativeElement.querySelector('circle');
93+
94+
fixture.componentInstance.mode = 'indeterminate';
95+
fixture.detectChanges();
96+
97+
const indeterminateCircle = fixture.nativeElement.querySelector('circle');
98+
99+
expect(determinateCircle).toBeTruthy();
100+
expect(indeterminateCircle).toBeTruthy();
101+
expect(determinateCircle).not.toBe(indeterminateCircle);
102+
});
103+
86104
it('should clamp the value of the progress between 0 and 100', () => {
87105
let fixture = TestBed.createComponent(BasicProgressSpinner);
88106
fixture.detectChanges();
@@ -138,12 +156,13 @@ describe('MatProgressSpinner', () => {
138156

139157
it('should allow a custom stroke width', () => {
140158
const fixture = TestBed.createComponent(ProgressSpinnerCustomStrokeWidth);
141-
const circleElement = fixture.nativeElement.querySelector('circle');
142-
const svgElement = fixture.nativeElement.querySelector('svg');
143159

144160
fixture.componentInstance.strokeWidth = 40;
145161
fixture.detectChanges();
146162

163+
const circleElement = fixture.nativeElement.querySelector('circle');
164+
const svgElement = fixture.nativeElement.querySelector('svg');
165+
147166
expect(parseInt(circleElement.style.strokeWidth)).toBe(40, 'Expected the custom stroke ' +
148167
'width to be applied to the circle element as a percentage of the element size.');
149168
expect(svgElement.getAttribute('viewBox'))

0 commit comments

Comments
 (0)