Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions goldens/material/core/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ export class _ErrorStateTracker {
updateErrorState(): void;
}

// @public
export function _getAnimationsState(): 'enabled' | 'di-disabled' | 'reduced-motion';

// @public
export function _getOptionScrollPosition(optionOffset: number, optionHeight: number, currentScrollPosition: number, panelHeight: number): number;

Expand Down
20 changes: 15 additions & 5 deletions src/material/core/animation/animation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,28 @@ export class AnimationDurations {
static EXITING = '195ms';
}

let reducedMotion: boolean | null = null;

/**
* Returns whether animations have been disabled by DI. Must be called in a DI context.
* Gets the the configured animations state.
* @docs-private
*/
export function _animationsDisabled(): boolean {
export function _getAnimationsState(): 'enabled' | 'di-disabled' | 'reduced-motion' {
if (
inject(MATERIAL_ANIMATIONS, {optional: true})?.animationsDisabled ||
inject(ANIMATION_MODULE_TYPE, {optional: true}) === 'NoopAnimations'
) {
return true;
return 'di-disabled';
}

const mediaMatcher = inject(MediaMatcher);
return mediaMatcher.matchMedia('(prefers-reduced-motion)').matches;
reducedMotion ??= inject(MediaMatcher).matchMedia('(prefers-reduced-motion)').matches;
return reducedMotion ? 'reduced-motion' : 'enabled';
}

/**
* Returns whether animations have been disabled by DI. Must be called in a DI context.
* @docs-private
*/
export function _animationsDisabled(): boolean {
return _getAnimationsState() !== 'enabled';
}
26 changes: 20 additions & 6 deletions src/material/progress-bar/progress-bar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
$fallbacks: m3-progress-bar.get-tokens();

.mat-mdc-progress-bar {
--mat-progress-bar-animation-multiplier: 1;

// Explicitly set to `block` since the browser defaults custom elements to `inline`.
display: block;

Expand Down Expand Up @@ -35,6 +37,12 @@ $fallbacks: m3-progress-bar.get-tokens();
}
}

// Slow down the animation by 100% when the user configured their OS to reduce
// motion since some animations like the indeterminate one can be quite dynamic.
.mat-progress-bar-reduced-motion {
--mat-progress-bar-animation-multiplier: 2;
}

.mdc-linear-progress {
position: relative;
width: 100%;
Expand Down Expand Up @@ -105,15 +113,17 @@ $fallbacks: m3-progress-bar.get-tokens();
background-repeat: repeat-x;
flex: auto;
transform: rotate(180deg);
animation: mdc-linear-progress-buffering 250ms infinite linear;
animation: mdc-linear-progress-buffering
calc(250ms * var(--mat-progress-bar-animation-multiplier)) infinite linear;
background-color: token-utils.slot(progress-bar-track-color, $fallbacks);

@include cdk.high-contrast {
background-color: ButtonBorder;
}

[dir='rtl'] & {
animation: mdc-linear-progress-buffering-reverse 250ms infinite linear;
animation: mdc-linear-progress-buffering-reverse
calc(250ms * var(--mat-progress-bar-animation-multiplier)) infinite linear;
transform: rotate(0);
}
}
Expand All @@ -132,12 +142,14 @@ $fallbacks: m3-progress-bar.get-tokens();
}

.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready & {
animation: mdc-linear-progress-primary-indeterminate-translate 2s infinite linear;
animation: mdc-linear-progress-primary-indeterminate-translate
calc(2s * var(--mat-progress-bar-animation-multiplier)) infinite linear;
}

.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready & {
> .mdc-linear-progress__bar-inner {
animation: mdc-linear-progress-primary-indeterminate-scale 2s infinite linear;
animation: mdc-linear-progress-primary-indeterminate-scale
calc(2s * var(--mat-progress-bar-animation-multiplier)) infinite linear;
}
}

Expand All @@ -160,12 +172,14 @@ $fallbacks: m3-progress-bar.get-tokens();
}

.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready & {
animation: mdc-linear-progress-secondary-indeterminate-translate 2s infinite linear;
animation: mdc-linear-progress-secondary-indeterminate-translate
calc(2s * var(--mat-progress-bar-animation-multiplier)) infinite linear;
}

.mdc-linear-progress--indeterminate.mdc-linear-progress--animation-ready & {
> .mdc-linear-progress__bar-inner {
animation: mdc-linear-progress-secondary-indeterminate-scale 2s infinite linear;
animation: mdc-linear-progress-secondary-indeterminate-scale
calc(2s * var(--mat-progress-bar-animation-multiplier)) infinite linear;
}
}

Expand Down
12 changes: 10 additions & 2 deletions src/material/progress-bar/progress-bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
DOCUMENT,
} from '@angular/core';

import {_animationsDisabled, ThemePalette} from '../core';
import {_getAnimationsState, ThemePalette} from '../core';

/** Last animation end data. */
export interface ProgressAnimationEnd {
Expand Down Expand Up @@ -121,10 +121,18 @@ export class MatProgressBar implements AfterViewInit, OnDestroy {
constructor(...args: unknown[]);

constructor() {
const animationsState = _getAnimationsState();

const defaults = inject<MatProgressBarDefaultOptions>(MAT_PROGRESS_BAR_DEFAULT_OPTIONS, {
optional: true,
});

this._isNoopAnimation = animationsState === 'di-disabled';

if (animationsState === 'reduced-motion') {
this._elementRef.nativeElement.classList.add('mat-progress-bar-reduced-motion');
}

if (defaults) {
if (defaults.color) {
this.color = this._defaultColor = defaults.color;
Expand All @@ -135,7 +143,7 @@ export class MatProgressBar implements AfterViewInit, OnDestroy {
}

/** Flag that indicates whether NoopAnimations mode is set to true. */
_isNoopAnimation = _animationsDisabled();
_isNoopAnimation: boolean;

// TODO: should be typed as `ThemePalette` but internal apps pass in arbitrary strings.
/**
Expand Down
21 changes: 17 additions & 4 deletions src/material/progress-spinner/progress-spinner.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
$fallbacks: m3-progress-spinner.get-tokens();

.mat-mdc-progress-spinner {
--mat-progress-spinner-animation-multiplier: 1;

// Explicitly set to `block` since the browser defaults custom elements to `inline`.
display: block;

Expand Down Expand Up @@ -54,6 +56,11 @@ $fallbacks: m3-progress-spinner.get-tokens();
}
}

// Slow down the animation by 25% when the user configured their OS to reduce motion.
.mat-progress-spinner-reduced-motion {
--mat-progress-spinner-animation-multiplier: 1.25;
}

.mdc-circular-progress__determinate-container,
.mdc-circular-progress__indeterminate-circle-graphic,
.mdc-circular-progress__indeterminate-container,
Expand All @@ -79,7 +86,8 @@ $fallbacks: m3-progress-spinner.get-tokens();

.mdc-circular-progress--indeterminate & {
opacity: 1;
animation: mdc-circular-progress-container-rotate 1568.2352941176ms linear infinite;
animation: mdc-circular-progress-container-rotate
calc(1568.2352941176ms * var(--mat-progress-spinner-animation-multiplier)) linear infinite;
}
}

Expand Down Expand Up @@ -127,11 +135,15 @@ $fallbacks: m3-progress-spinner.get-tokens();
}

.mdc-circular-progress--indeterminate .mdc-circular-progress__circle-left & {
animation: mdc-circular-progress-left-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
animation: mdc-circular-progress-left-spin
calc(1333ms * var(--mat-progress-spinner-animation-multiplier))
cubic-bezier(0.4, 0, 0.2, 1) infinite both;
}

.mdc-circular-progress--indeterminate .mdc-circular-progress__circle-right & {
animation: mdc-circular-progress-right-spin 1333ms cubic-bezier(0.4, 0, 0.2, 1) infinite both;
animation: mdc-circular-progress-right-spin
calc(1333ms * var(--mat-progress-spinner-animation-multiplier))
cubic-bezier(0.4, 0, 0.2, 1) infinite both;
}
}

Expand All @@ -145,7 +157,8 @@ $fallbacks: m3-progress-spinner.get-tokens();

.mdc-circular-progress__spinner-layer {
.mdc-circular-progress--indeterminate & {
animation: mdc-circular-progress-spinner-layer-rotate 5332ms cubic-bezier(0.4, 0, 0.2, 1)
animation: mdc-circular-progress-spinner-layer-rotate
calc(5332ms * var(--mat-progress-spinner-animation-multiplier)) cubic-bezier(0.4, 0, 0.2, 1)
infinite both;
}
}
Expand Down
16 changes: 10 additions & 6 deletions src/material/progress-spinner/progress-spinner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
numberAttribute,
inject,
} from '@angular/core';
import {_animationsDisabled, ThemePalette} from '../core';
import {_getAnimationsState, ThemePalette} from '../core';
import {NgTemplateOutlet} from '@angular/common';

/** Possible mode for a progress spinner. */
Expand Down Expand Up @@ -128,12 +128,16 @@ export class MatProgressSpinner {

constructor() {
const defaults = inject<MatProgressSpinnerDefaultOptions>(MAT_PROGRESS_SPINNER_DEFAULT_OPTIONS);
const animationsState = _getAnimationsState();
const element = this._elementRef.nativeElement;

this._noopAnimations = _animationsDisabled() && !!defaults && !defaults._forceAnimations;
this.mode =
this._elementRef.nativeElement.nodeName.toLowerCase() === 'mat-spinner'
? 'indeterminate'
: 'determinate';
this._noopAnimations =
animationsState === 'di-disabled' && !!defaults && !defaults._forceAnimations;
this.mode = element.nodeName.toLowerCase() === 'mat-spinner' ? 'indeterminate' : 'determinate';

if (!this._noopAnimations && animationsState === 'reduced-motion') {
element.classList.add('mat-progress-spinner-reduced-motion');
}

if (defaults) {
if (defaults.color) {
Expand Down
Loading